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