File indexing completed on 2024-05-19 04:24:59

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