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 */