File indexing completed on 2024-05-12 15:56:51

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2006 Thomas Zander <zander@kde.org>
0003  * SPDX-FileCopyrightText: 2011 Jan Hambrecht <jaham@gmx.net>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 #ifndef KOTOOLBASE_H
0008 #define KOTOOLBASE_H
0009 
0010 #include <QObject>
0011 #include <QPointer>
0012 #include <QSet>
0013 #include <QList>
0014 #include <QHash>
0015 
0016 #include "kritaflake_export.h"
0017 
0018 class KoShape;
0019 class KoCanvasBase;
0020 class KoPointerEvent;
0021 class KoViewConverter;
0022 class KoToolFactoryBase;
0023 class KoToolSelection;
0024 class KoToolBasePrivate;
0025 class KoShapeControllerBase;
0026 class KisPopupWidgetInterface;
0027 
0028 class QAction;
0029 class QKeyEvent;
0030 class QWidget;
0031 class QCursor;
0032 class QPainter;
0033 class QString;
0034 class QStringList;
0035 class QRectF;
0036 class QPointF;
0037 class QInputMethodEvent;
0038 class QDragMoveEvent;
0039 class QDragLeaveEvent;
0040 class QDropEvent;
0041 class QTouchEvent;
0042 class QMenu;
0043 
0044 /**
0045  * Abstract base class for all tools. Tools can create or manipulate
0046  * flake shapes, canvas state or any other thing that a user may wish
0047  * to do to his document or his view on a document with a pointing
0048  * device.
0049  *
0050  * There exists an instance of every tool for every pointer device.
0051  * These instances are managed by the toolmanager..
0052  */
0053 class KRITAFLAKE_EXPORT KoToolBase : public QObject
0054 {
0055     Q_OBJECT
0056 public:
0057     /**
0058      * Constructor, normally only called by the factory (see KoToolFactoryBase)
0059      * @param canvas the canvas interface this tool will work for.
0060      */
0061     explicit KoToolBase(KoCanvasBase *canvas);
0062     ~KoToolBase() override;
0063 
0064     /**
0065      * The factory holds properties common to all instances of the same
0066      * tool type, such as the string identifying the class or the icon name.
0067      *
0068      * Not all tool instances have a factory reference, for example the
0069      * "delegated" inner implementations to which events are forwarded
0070      * don't have one, as well as instances created by regression tests.
0071      *
0072      * Every instance used by the tool manager has a factory reference and
0073      * a tool identifier, but they're not available during construction.
0074      */
0075     KoToolFactoryBase* factory() const;
0076 
0077     virtual QRectF decorationsRect() const;
0078 
0079     /**
0080      * Return if dragging (moving with the mouse down) to the edge of a canvas should scroll the
0081      * canvas (default is true).
0082      * @return if this tool wants mouse events to cause scrolling of canvas.
0083      */
0084     virtual bool wantsAutoScroll() const;
0085 
0086     /**
0087      * Called by the canvas to paint any decorations that the tool deems needed.
0088      * The painter has the top left of the canvas as its origin.
0089      * @param painter used for painting the shape
0090      * @param converter to convert between internal and view coordinates.
0091      */
0092     virtual void paint(QPainter &painter, const KoViewConverter &converter) = 0;
0093 
0094     /**
0095      * Return the option widgets for this tool. Create them if they
0096      * do not exist yet. If the tool does not have an option widget,
0097      * this method return an empty list. (After discussion with Thomas, who prefers
0098      * the toolmanager to handle that case.)
0099      *
0100      * @see m_optionWidgets
0101      */
0102     QList<QPointer<QWidget> > optionWidgets();
0103 
0104     /**
0105      * Retrieve an action by name.
0106      */
0107     QAction *action(const QString &name) const;
0108 
0109     /**
0110      * Called when (one of) the mouse or stylus buttons is pressed.
0111      * Implementors should call event->ignore() if they do not actually use the event.
0112      * @param event state and reason of this mouse or stylus press
0113      */
0114     virtual void mousePressEvent(KoPointerEvent *event) = 0;
0115 
0116     /**
0117      * Called when (one of) the mouse or stylus buttons is double clicked.
0118      * Implementors should call event->ignore() if they do not actually use the event.
0119      * Default implementation ignores this event.
0120      * @param event state and reason of this mouse or stylus press
0121      */
0122     virtual void mouseDoubleClickEvent(KoPointerEvent *event);
0123 
0124     /**
0125      * Called when (one of) the mouse or stylus buttons is triple clicked.
0126      * Implementors should call event->ignore() if they do not actually use the event.
0127      * Default implementation ignores this event.
0128      * @param event state and reason of this mouse or stylus press
0129      */
0130     virtual void mouseTripleClickEvent(KoPointerEvent *event);
0131 
0132     /**
0133      * Called when the mouse or stylus moved over the canvas.
0134      * Implementors should call event->ignore() if they do not actually use the event.
0135      * @param event state and reason of this mouse or stylus move
0136      */
0137     virtual void mouseMoveEvent(KoPointerEvent *event) = 0;
0138 
0139     /**
0140      * Called when (one of) the mouse or stylus buttons is released.
0141      * Implementors should call event->ignore() if they do not actually use the event.
0142      * @param event state and reason of this mouse or stylus release
0143      */
0144     virtual void mouseReleaseEvent(KoPointerEvent *event) = 0;
0145 
0146     /**
0147      * Called when a key is pressed.
0148      * Implementors should call event->ignore() if they do not actually use the event.
0149      * Default implementation ignores this event.
0150      * @param event state and reason of this key press
0151      */
0152     virtual void keyPressEvent(QKeyEvent *event);
0153 
0154     /**
0155      * Called when a key is released
0156      * Implementors should call event->ignore() if they do not actually use the event.
0157      * Default implementation ignores this event.
0158      * @param event state and reason of this key release
0159      */
0160     virtual void keyReleaseEvent(QKeyEvent *event);
0161 
0162     /**
0163      * @brief explicitUserStrokeEndRequest is called by the input manager
0164      *        when the user presses Enter key or any equivalent. This callback
0165      *        comes before requestStrokeEnd(), which comes from a different source.
0166      */
0167     virtual void explicitUserStrokeEndRequest();
0168 
0169     /**
0170      * This method is used to query a set of properties of the tool to be
0171      * able to support complex input method operations as support for surrounding
0172      * text and reconversions.
0173      * Default implementation returns simple defaults, for tools that want to provide
0174      * a more responsive text entry experience for CJK languages it would be good to reimplement.
0175      * @param query specifies which property is queried.
0176      * @param converter the view converter for the current canvas.
0177      */
0178     virtual QVariant inputMethodQuery(Qt::InputMethodQuery query, const KoViewConverter &converter) const;
0179 
0180     /**
0181      * Text entry of complex text, like CJK, can be made more interactive if a tool
0182      * implements this and the InputMethodQuery() methods.
0183      * Reimplementing this only provides the user with a more responsive text experience, since the
0184      * default implementation forwards the typed text as key pressed events.
0185      * @param event the input method event.
0186      */
0187     virtual void inputMethodEvent(QInputMethodEvent *event);
0188 
0189     /**
0190      * Called when (one of) a custom device buttons is pressed.
0191      * Implementors should call event->ignore() if they do not actually use the event.
0192      * @param event state and reason of this custom device press
0193      */
0194     virtual void customPressEvent(KoPointerEvent *event);
0195 
0196     /**
0197      * Called when (one of) a custom device buttons is released.
0198      * Implementors should call event->ignore() if they do not actually use the event.
0199      * @param event state and reason of this custom device release
0200      */
0201     virtual void customReleaseEvent(KoPointerEvent *event);
0202 
0203     /**
0204      * Called when a custom device moved over the canvas.
0205      * Implementors should call event->ignore() if they do not actually use the event.
0206      * @param event state and reason of this custom device move
0207      */
0208     virtual void customMoveEvent(KoPointerEvent *event);
0209 
0210     /**
0211      * @return true if synthetic mouse events on the canvas should be eaten.
0212      *
0213      * For example, the guides tool should allow click and drag with touch,
0214      * while the same touch events should be rejected by the freehand tool.
0215      *
0216      * These events are sent by the OS in Windows
0217      */
0218     bool maskSyntheticEvents() const;
0219 
0220     /**
0221      * get the identifier code from the KoToolFactoryBase that created this tool.
0222      * @return the toolId.
0223      * @see KoToolFactoryBase::id()
0224      */
0225     Q_INVOKABLE QString toolId() const;
0226 
0227     /// return the last emitted cursor
0228     QCursor cursor() const;
0229 
0230     /**
0231      * Returns the internal selection object of this tool.
0232      * Each tool can have a selection which is private to that tool and the specified shape that it comes with.
0233      * The default returns 0.
0234      */
0235     virtual KoToolSelection *selection();
0236 
0237     /**
0238      * @returns true if the tool has selected data.
0239      */
0240     virtual bool hasSelection();
0241 
0242     /**
0243      * copies the tools selection to the clipboard.
0244      * The default implementation is empty to aid tools that don't have any selection.
0245      * @see selection()
0246      */
0247     virtual void copy() const;
0248 
0249     /**
0250      * Delete the tools selection.
0251      * The default implementation is empty to aid tools that don't have any selection.
0252      * @see selection()
0253      */
0254     virtual void deleteSelection();
0255 
0256     /**
0257      * Cut the tools selection and copy it to the clipboard.
0258      * The default implementation calls copy() and then deleteSelection()
0259      * @see copy()
0260      * @see deleteSelection()
0261      */
0262     virtual void cut();
0263 
0264     /**
0265      * Paste the clipboard selection.
0266      * A tool typically has one or more shapes selected and pasting should do something meaningful
0267      * for this specific shape and tool combination.  Inserting text in a text tool, for example.
0268      * @return will return true if pasting succeeded. False if nothing happened.
0269      */
0270     virtual bool paste();
0271 
0272     /**
0273      * Handle the dragMoveEvent
0274      * A tool typically has one or more shapes selected and dropping into should do
0275      * something meaningful for this specific shape and tool combination. For example
0276      * dropping text in a text tool.
0277      * The tool should Accept the event if it is meaningful; Default implementation does not.
0278      */
0279     virtual void dragMoveEvent(QDragMoveEvent *event, const QPointF &point);
0280 
0281     /**
0282      * Handle the dragLeaveEvent
0283      * Basically just a noticification that the drag is no long relevant
0284      * The tool should Accept the event if it is meaningful; Default implementation does not.
0285      */
0286     virtual void dragLeaveEvent(QDragLeaveEvent *event);
0287 
0288     /**
0289      * Handle the dropEvent
0290      * A tool typically has one or more shapes selected and dropping into should do
0291      * something meaningful for this specific shape and tool combination. For example
0292      * dropping text in a text tool.
0293      * The tool should Accept the event if it is meaningful; Default implementation does not.
0294      */
0295     virtual void dropEvent(QDropEvent *event, const QPointF &point);
0296 
0297     /**
0298      * @return a menu with context-aware actions for the current selection. If
0299      *         the returned value is null, no context menu is shown.
0300      */
0301     virtual QMenu* popupActionsMenu() {return nullptr;}
0302 
0303     /**
0304      * @return a widget with useful controls to be popped up on top of the canvas.
0305      *         Will not be called if `popupActionsMenu()` does not return null.
0306      */
0307     virtual KisPopupWidgetInterface* popupWidget() {return nullptr;}
0308 
0309     /// Returns the canvas the tool is working on
0310     KoCanvasBase *canvas() const;
0311 
0312     /**
0313       * This method can be reimplemented in a subclass.
0314       * @return returns true, if the tool is in text mode. that means, that there is
0315       *   any kind of textual input and all single key shortcuts should be eaten.
0316       */
0317     bool isInTextMode() const;
0318 
0319 public Q_SLOTS:
0320 
0321     /**
0322      * Called when the user requested undo while the stroke is
0323      * active. If you tool supports undo of the part of its actions,
0324      * override this method and do the needed work there.
0325      *
0326      * NOTE: Default implementation forwards this request to
0327      *       requestStrokeCancellation() method, so that the stroke
0328      *       would be cancelled.
0329      */
0330     virtual void requestUndoDuringStroke();
0331 
0332     /**
0333      * Called when the user requested redo while the stroke is active. If your
0334      * tool supports redo and maintains an intermediate state which can
0335      * interfere with redo override this method to handle the state.
0336      */
0337     virtual void requestRedoDuringStroke();
0338 
0339     /**
0340      * Called when the user requested the cancellation of the current
0341      * stroke. If you tool supports cancelling, override this method
0342      * and do the needed work there
0343      */
0344     virtual void requestStrokeCancellation();
0345 
0346     /**
0347      * Called when the image decided that the stroke should better be
0348      * ended. If you tool supports long strokes, override this method
0349      * and do the needed work there
0350      */
0351     virtual void requestStrokeEnd();
0352 
0353 
0354     /**
0355      * This method is called when this tool instance is activated.
0356      * For any main window there is only one tool active at a time, which then gets all
0357      * user input.  Switching between tools will call deactivate on one and activate on the
0358      * new tool allowing the tool to flush items (like a selection)
0359      * when it is not in use.
0360      *
0361      * @param shapes the set of shapes that are selected or suggested for editing by a
0362      *      selected shape for the tool to work on.  Not all shapes will be meant for this
0363      *      tool.
0364      * @see deactivate()
0365      */
0366     virtual void activate(const QSet<KoShape*> &shapes);
0367 
0368     /**
0369      * This method is called whenever this tool is no longer the
0370      * active tool
0371      * @see activate()
0372      */
0373     virtual void deactivate();
0374 
0375     /**
0376      * This method is called whenever a property in the resource
0377      * provider associated with the canvas this tool belongs to
0378      * changes. An example is currently selected foreground color.
0379      */
0380     virtual void canvasResourceChanged(int key, const QVariant &res);
0381 
0382     /**
0383      * This method is called whenever a property in the resource
0384      * provider associated with the document this tool belongs to
0385      * changes. An example is the handle radius
0386      */
0387     virtual void documentResourceChanged(int key, const QVariant &res);
0388 
0389     /**
0390      * This method just relays the given text via the tools statusTextChanged signal.
0391      * @param statusText the new status text
0392      */
0393     void setStatusText(const QString &statusText);
0394 
0395     /**
0396      * request a repaint of the decorations to be made. This triggers
0397      * an update call on the canvas, but does not paint directly.
0398      */
0399     virtual void repaintDecorations();
0400 
0401     /**
0402      * force the update of the icons on the cached options widget
0403      */
0404     void updateOptionsWidgetIcons();
0405 
0406 Q_SIGNALS:
0407 
0408     /**
0409      * Emitted when this tool wants itself to be replaced by another tool.
0410      *
0411      * @param id the identification of the desired tool
0412      * @see toolId(), KoToolFactoryBase::id()
0413      */
0414     void activateTool(const QString &id);
0415 
0416     /**
0417      * Emitted by useCursor() when the cursor to display on the canvas is changed.
0418      * The KoToolManager should connect to this signal to handle cursors further.
0419      */
0420     void cursorChanged(const QCursor &cursor);
0421 
0422     /**
0423      * A tool can have a selection that is copy-able, this signal is emitted when that status changes.
0424      * @param hasSelection is true when the tool holds selected data.
0425      */
0426     void selectionChanged(bool hasSelection);
0427 
0428     /**
0429      * Emitted when the tool wants to display a different status text
0430      * @param statusText the new status text
0431      */
0432     void statusTextChanged(const QString &statusText);
0433 
0434 protected:
0435     /**
0436      * Classes inheriting from this one can call this method to signify which cursor
0437      * the tool wants to display at this time.  Logical place to call it is after an
0438      * incoming event has been handled.
0439      * @param cursor the new cursor.
0440      */
0441     void useCursor(const QCursor &cursor);
0442 
0443     /**
0444      * Reimplement this if your tool actually has an option widget.
0445      * Sets the option widget to 0 by default.
0446      */
0447     virtual QWidget *createOptionWidget();
0448     virtual QList<QPointer<QWidget> > createOptionWidgets();
0449 
0450     /// Convenience function to get the current handle radius
0451     int handleRadius() const;
0452 
0453     /// Convenience function to get the current handle radius measured in document
0454     /// coordinates (points)
0455     qreal handleDocRadius() const;
0456 
0457     /// Convencience function to get the current grab sensitivity
0458     int grabSensitivity() const;
0459 
0460     /**
0461     * Returns a handle grab rect at the given position.
0462     *
0463     * The position is expected to be in document coordinates. The grab sensitivity
0464     * canvas resource is used for the dimension of the rectangle.
0465     *
0466     * @return the handle rectangle in document coordinates
0467     */
0468     QRectF handleGrabRect(const QPointF &position) const;
0469 
0470     /**
0471     * Returns a handle paint rect at the given position.
0472     *
0473     * The position is expected to be in document coordinates. The handle radius
0474     * canvas resource is used for the dimension of the rectangle.
0475     *
0476     * @return the handle rectangle in document coordinates
0477     */
0478     QRectF handlePaintRect(const QPointF &position) const;
0479 
0480     /**
0481       * You should set the text mode to true in subclasses, if this tool is in text input mode, eg if the users
0482       * are able to type. If you don't set it, then single key shortcuts will get the key event and not this tool.
0483       */
0484     void setTextMode(bool value);
0485 
0486     /**
0487      * Allows subclasses to specify whether synthetic mouse events should be accepted.
0488      */
0489     void setMaskSyntheticEvents(bool value);
0490 
0491     /**
0492      * Returns true if activate() has been called (more times than deactivate :) )
0493      */
0494     bool isActivated() const;
0495 
0496     /**
0497      * Returns the last pointer event that was delivered to the canvas, the tool
0498      * belongs to. This event might be used as an approximation for the event0
0499      * handlers not having their own events, like activate()/deactivate().
0500      */
0501     KoPointerEvent* lastDeliveredPointerEvent() const;
0502 
0503 protected:
0504     KoToolBase(KoToolBasePrivate &dd);
0505 
0506     KoToolBasePrivate *d_ptr;
0507 
0508 
0509 private:
0510 
0511     friend class KoToolManager;
0512 
0513     /**
0514      * Set the KoToolFactoryBase that created this tool.
0515      * @param factory the KoToolFactoryBase
0516      * @see KoToolFactoryBase
0517      */
0518     void setFactory(KoToolFactoryBase *factory);
0519 
0520     KoToolBase();
0521     KoToolBase(const KoToolBase&);
0522     KoToolBase& operator=(const KoToolBase&);
0523 
0524     Q_DECLARE_PRIVATE(KoToolBase)
0525 };
0526 
0527 #endif /* KOTOOL_H */