1 /*
2  *  Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef KIS_TOOL_H_
20 #define KIS_TOOL_H_
21 
22 #include <QCursor>
23 
24 #include <KoColor.h>
25 #include <KoToolBase.h>
26 #include <KoID.h>
27 #include <KoCanvasResourceProvider.h>
28 #include <kritaui_export.h>
29 #include <kis_types.h>
30 
31 #ifdef __GNUC__
32 #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come to" << __func__ << "while being mode" << _mode << "!"
33 #else
34 #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come while being mode" << _mode << "!"
35 #endif
36 
37 #define CHECK_MODE_SANITY_OR_RETURN(_mode) if (mode() != _mode) { WARN_WRONG_MODE(mode()); return; }
38 
39 class KoCanvasBase;
40 class KoPattern;
41 class KoAbstractGradient;
42 class KisFilterConfiguration;
43 class QPainter;
44 class QPainterPath;
45 class QPolygonF;
46 
47 /// Definitions of the toolgroups of Krita
48 static const QString TOOL_TYPE_SHAPE = "0 Krita/Shape";         // Geometric shapes like ellipses and lines
49 static const QString TOOL_TYPE_TRANSFORM = "2 Krita/Transform"; // Tools that transform the layer;
50 static const QString TOOL_TYPE_FILL = "3 Krita/Fill";                // Tools that fill parts of the canvas
51 static const QString TOOL_TYPE_VIEW = "4 Krita/View";                // Tools that affect the canvas: pan, zoom, etc.
52 static const QString TOOL_TYPE_SELECTION = "5 Krita/Select";          // Tools that select pixels
53 
54 //activation id for Krita tools, Krita tools are always active and handle locked and invisible layers by themself
55 static const QString KRITA_TOOL_ACTIVATION_ID = "flake/always";
56 
57 class  KRITAUI_EXPORT KisTool
58         : public KoToolBase
59 {
60     Q_OBJECT
61 
62     Q_PROPERTY(bool isActive READ isActive NOTIFY isActiveChanged)
63 
64 public:
65     enum { FLAG_USES_CUSTOM_PRESET=0x01, FLAG_USES_CUSTOM_COMPOSITEOP=0x02, FLAG_USES_CUSTOM_SIZE=0x04 };
66 
67     KisTool(KoCanvasBase * canvas, const QCursor & cursor);
68     ~KisTool() override;
69 
flags()70     virtual int flags() const { return 0; }
71 
72     void deleteSelection() override;
73 // KoToolBase Implementation.
74 
75 public:
76 
77     /**
78      * Called by KisToolProxy when the primary action of the tool is
79      * going to be started now, that is when all the modifiers are
80      * pressed and the only thing left is just to press the mouse
81      * button.  On coming of this callback the tool is supposed to
82      * prepare the cursor and/or the outline to show the user shat is
83      * going to happen next
84      */
85     virtual void activatePrimaryAction();
86 
87     /**
88      * Called by KisToolProxy when the primary is no longer possible
89      * to be started now, e.g. when its modifiers and released. The
90      * tool is supposed to revert all the preparations it has done in
91      * activatePrimaryAction().
92      */
93     virtual void deactivatePrimaryAction();
94 
95     /**
96      * Called by KisToolProxy when a primary action for the tool is
97      * started. The \p event stores the original event that
98      * started the stroke. The \p event is _accepted_ by default. If
99      * the tool decides to ignore this particular action (e.g. when
100      * the node is not editable), it should call event->ignore(). Then
101      * no further continuePrimaryAction() or endPrimaryAction() will
102      * be called until the next user action.
103      */
104     virtual void beginPrimaryAction(KoPointerEvent *event);
105 
106     /**
107      * Called by KisToolProxy when the primary action is in progress
108      * of pointer movement.  If the tool has ignored the event in
109      * beginPrimaryAction(), this method will not be called.
110      */
111     virtual void continuePrimaryAction(KoPointerEvent *event);
112 
113     /**
114      * Called by KisToolProxy when the primary action is being
115      * finished, that is while mouseRelease or tabletRelease event.
116      * If the tool has ignored the event in beginPrimaryAction(), this
117      * method will not be called.
118      */
119     virtual void endPrimaryAction(KoPointerEvent *event);
120 
121     /**
122      * The same as beginPrimaryAction(), but called when the stroke is
123      * started by a double-click
124      *
125      * \see beginPrimaryAction()
126      */
127     virtual void beginPrimaryDoubleClickAction(KoPointerEvent *event);
128 
129     /**
130      * Returns true if the tool can handle (and wants to handle) a
131      * very tight flow of input events from the tablet
132      */
133     virtual bool primaryActionSupportsHiResEvents() const;
134 
135     enum ToolAction {
136         Primary,
137         AlternateChangeSize,
138         AlternateChangeSizeSnap,
139         AlternatePickFgNode,
140         AlternatePickBgNode,
141         AlternatePickFgImage,
142         AlternatePickBgImage,
143         AlternateSecondary,
144         AlternateThird,
145         AlternateFourth,
146         AlternateFifth,
147         Alternate_NONE = 10000
148     };
149 
150     // Technically users are allowed to configure this, but nobody ever would do that.
151     // So these can basically be thought of as aliases to ctrl+click, etc.
152     enum AlternateAction {
153         ChangeSize = AlternateChangeSize, // Default: Shift+Left click
154         ChangeSizeSnap = AlternateChangeSizeSnap, // Default: Shift+Z+Left click
155         PickFgNode = AlternatePickFgNode, // Default: Ctrl+Alt+Left click
156         PickBgNode = AlternatePickBgNode, // Default: Ctrl+Alt+Right click
157         PickFgImage = AlternatePickFgImage, // Default: Ctrl+Left click
158         PickBgImage = AlternatePickBgImage, // Default: Ctrl+Right click
159         Secondary = AlternateSecondary,
160         Third = AlternateThird,
161         Fourth = AlternateFourth,
162         Fifth = AlternateFifth,
163         NONE = 10000
164     };
165 
166     enum NodePaintAbility {
167         VECTOR,
168         CLONE,
169         PAINT,
170         UNPAINTABLE
171     };
172     Q_ENUMS(NodePaintAbility)
173 
174     static AlternateAction actionToAlternateAction(ToolAction action);
175 
176     virtual void activateAlternateAction(AlternateAction action);
177     virtual void deactivateAlternateAction(AlternateAction action);
178 
179     virtual void beginAlternateAction(KoPointerEvent *event, AlternateAction action);
180     virtual void continueAlternateAction(KoPointerEvent *event, AlternateAction action);
181     virtual void endAlternateAction(KoPointerEvent *event, AlternateAction action);
182     virtual void beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action);
183     virtual bool alternateActionSupportsHiResEvents(AlternateAction action) const;
184 
185     void mousePressEvent(KoPointerEvent *event) override;
186     void mouseDoubleClickEvent(KoPointerEvent *event) override;
187     void mouseTripleClickEvent(KoPointerEvent *event) override;
188     void mouseReleaseEvent(KoPointerEvent *event) override;
189     void mouseMoveEvent(KoPointerEvent *event) override;
190 
191     bool isActive() const;
192 
193     KisTool::NodePaintAbility nodePaintAbility();
194 
195 public Q_SLOTS:
196     void activate(ToolActivation activation, const QSet<KoShape*> &shapes) override;
197     void deactivate() override;
198     void canvasResourceChanged(int key, const QVariant & res) override;
199     // Implement this slot in case there are any widgets or properties which need
200     // to be updated after certain operations, to reflect the inner state correctly.
201     // At the moment this is used for smoothing options in the freehand brush, but
202     // this will likely be expanded.
203     virtual void updateSettingsViews();
204 
205 Q_SIGNALS:
206     void isActiveChanged(bool isActivated);
207 
208 protected:
209     // conversion methods are also needed by the paint information builder
210     friend class KisToolPaintingInformationBuilder;
211 
212     /// Convert from native (postscript points) to image pixel
213     /// coordinates.
214     QPointF convertToPixelCoord(KoPointerEvent *e);
215     QPointF convertToPixelCoord(const QPointF& pt);
216 
217     QPointF convertToPixelCoordAndAlignOnWidget(const QPointF& pt);
218 
219     QPointF convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset = QPointF(), bool useModifiers = true);
220     QPointF convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset = QPointF());
221 
222 protected:
223     QPointF widgetCenterInWidgetPixels();
224     QPointF convertDocumentToWidget(const QPointF& pt);
225 
226     /// Convert from native (postscript points) to integer image pixel
227     /// coordinates. This rounds down (not truncate) the pixel coordinates and
228     /// should be used in preference to QPointF::toPoint(), which rounds,
229     /// to ensure the cursor acts on the pixel it is visually over.
230     QPoint convertToImagePixelCoordFloored(KoPointerEvent *e);
231 
232     QRectF convertToPt(const QRectF &rect);
233     qreal convertToPt(qreal value);
234 
235     QPointF viewToPixel(const QPointF &viewCoord) const;
236     /// Convert an integer pixel coordinate into a view coordinate.
237     /// The view coordinate is at the centre of the pixel.
238     QPointF pixelToView(const QPoint &pixelCoord) const;
239 
240     /// Convert a floating point pixel coordinate into a view coordinate.
241     QPointF pixelToView(const QPointF &pixelCoord) const;
242 
243     /// Convert a pixel rectangle into a view rectangle.
244     QRectF pixelToView(const QRectF &pixelRect) const;
245 
246     /// Convert a pixel path into a view path
247     QPainterPath pixelToView(const QPainterPath &pixelPath) const;
248 
249     /// Convert a pixel polygon into a view path
250     QPolygonF pixelToView(const QPolygonF &pixelPolygon) const;
251 
252     /// Update the canvas for the given rectangle in image pixel coordinates.
253     void updateCanvasPixelRect(const QRectF &pixelRect);
254 
255     /// Update the canvas for the given rectangle in view coordinates.
256     void updateCanvasViewRect(const QRectF &viewRect);
257 
258     QWidget* createOptionWidget() override;
259 
260     /**
261      * To determine whether this tool will change its behavior when
262      * modifier keys are pressed
263      */
264     virtual bool listeningToModifiers();
265     /**
266      * Request that this tool no longer listen to modifier keys
267      * (Responding to the request is optional)
268      */
269     virtual void listenToModifiers(bool listen);
270 
271 protected:
272     KisImageWSP image() const;
273     QCursor cursor() const;
274 
275     /// Call this to set the document modified
276     void notifyModified() const;
277 
278     KisImageWSP currentImage();
279     KoPattern* currentPattern();
280     KoAbstractGradient *currentGradient();
281     KisNodeSP currentNode() const;
282     KisNodeList selectedNodes() const;
283     KoColor currentFgColor();
284     KoColor currentBgColor();
285     KisPaintOpPresetSP currentPaintOpPreset();
286     KisFilterConfigurationSP currentGenerator();
287 
288     /// paint the path which is in view coordinates, default paint mode is XOR_MODE, BW_MODE is also possible
289     /// never apply transformations to the painter, they would be useless, if drawing in OpenGL mode. The coordinates in the path should be in view coordinates.
290     void paintToolOutline(QPainter * painter, const QPainterPath &path);
291 
292     /// Checks checks if the current node is editable
293     bool nodeEditable();
294 
295     /// Checks checks if the selection is editable, only applies to local selection as global selection is always editable
296     bool selectionEditable();
297 
298     /// Override the cursor appropriately if current node is not editable
299     bool overrideCursorIfNotEditable();
300 
301     bool blockUntilOperationsFinished();
302     void blockUntilOperationsFinishedForced();
303 
304 protected:
305     enum ToolMode: int {
306         HOVER_MODE,
307         PAINT_MODE,
308         SECONDARY_PAINT_MODE,
309         MIRROR_AXIS_SETUP_MODE,
310         GESTURE_MODE,
311         PAN_MODE,
312         OTHER, // tool-specific modes, like multibrush's symmetry axis setup
313         OTHER_1
314     };
315 
316     virtual void setMode(ToolMode mode);
317     virtual ToolMode mode() const;
318     void setCursor(const QCursor &cursor);
319 
320 protected Q_SLOTS:
321     /**
322      * Called whenever the configuration settings change.
323      */
324     virtual void resetCursorStyle();
325 
326 private:
327     struct Private;
328     Private* const d;
329 };
330 
331 
332 
333 #endif // KIS_TOOL_H_
334