1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2015-2016 Calle Laakkonen
5 
6    Drawpile is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    Drawpile is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Drawpile.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef TOOLCONTROLLER_H
21 #define TOOLCONTROLLER_H
22 
23 #include "strokesmoother.h"
24 #include "tool.h"
25 #include "brushes/brush.h"
26 #include "canvas/features.h"
27 
28 #include <QObject>
29 
30 class QCursor;
31 
32 namespace canvas { class CanvasModel; }
33 namespace net { class Client; }
34 
35 namespace tools {
36 
37 class Tool;
38 
39 /**
40  * @brief The ToolController dispatches user input to the currently active tool
41  */
42 class ToolController : public QObject
43 {
44 	Q_PROPERTY(QCursor activeToolCursor READ activeToolCursor() NOTIFY toolCursorChanged)
45 	Q_PROPERTY(int smoothing READ smoothing WRITE setSmoothing NOTIFY smoothingChanged)
46 	Q_PROPERTY(uint16_t activeLayer READ activeLayer WRITE setActiveLayer NOTIFY activeLayerChanged)
47 	Q_PROPERTY(uint16_t activeAnnotation READ activeAnnotation WRITE setActiveAnnotation NOTIFY activeAnnotationChanged)
48 	Q_PROPERTY(brushes::ClassicBrush activeBrush READ activeBrush WRITE setActiveBrush NOTIFY activeBrushChanged)
49 	Q_PROPERTY(canvas::CanvasModel* model READ model WRITE setModel NOTIFY modelChanged)
50 
51 	Q_OBJECT
52 public:
53 	explicit ToolController(net::Client *client, QObject *parent=nullptr);
54 	~ToolController();
55 
56 	void setActiveTool(Tool::Type tool);
57 	Tool::Type activeTool() const;
58 
59 	QCursor activeToolCursor() const;
60 
61 	void setActiveLayer(uint16_t id);
activeLayer()62 	uint16_t activeLayer() const { return m_activeLayer; }
63 
64 	void setActiveAnnotation(uint16_t id);
activeAnnotation()65 	uint16_t activeAnnotation() const { return m_activeAnnotation; }
66 
67 	void setActiveBrush(const brushes::ClassicBrush &b);
activeBrush()68 	const brushes::ClassicBrush &activeBrush() const { return m_activebrush; }
69 
70 	void setModel(canvas::CanvasModel *model);
model()71 	canvas::CanvasModel *model() const { return m_model; }
72 
73 	void setSmoothing(int smoothing);
smoothing()74 	int smoothing() const { return m_smoothing; }
75 
76 	// TODO this is used just for sending the commands. Replace with a signal?
client()77 	inline net::Client *client() const { return m_client; }
78 
79 	Tool *getTool(Tool::Type type);
80 
81 	//! Is there a multipart drawing operation in progress?
82 	bool isMultipartDrawing() const;
83 
84 	/**
85 	 * Apply an offset to the position of the active tool
86 	 *
87 	 * This is used to correct the tool position when the canvas is
88 	 * resized while the local user is still drawing.
89 	 */
90 	void offsetActiveTool(int xOffset, int yOffset);
91 
92 public slots:
93 	//! Start a new stroke
94 	void startDrawing(const QPointF &point, qreal pressure, bool right, float zoom);
95 
96 	//! Continue a stroke
97 	void continueDrawing(const QPointF &point, qreal pressure, bool shift, bool alt);
98 
99 	//! Stylus hover (not yet drawing)
100 	void hoverDrawing(const QPointF &point);
101 
102 	//! End a stroke
103 	void endDrawing();
104 
105 	/**
106 	 * @brief Undo the latest part of a multipart drawing
107 	 *
108 	 * Multipart drawings are not committed until finishMultipartDrawing is
109 	 * called, so undoing is a local per-tool operation.
110 	 *
111 	 * @return false if there was nothing to undo
112 	 */
113 	bool undoMultipartDrawing();
114 
115 	//! Commit the current multipart drawing (if any)
116 	void finishMultipartDrawing();
117 
118 	//! Cancel the current multipart drawing (if any)
119 	void cancelMultipartDrawing();
120 
121 signals:
122 	void activeToolChanged(Tool::Type type);
123 	void toolCursorChanged(const QCursor &cursor);
124 	void activeLayerChanged(int layerId);
125 	void activeAnnotationChanged(uint16_t annotationId);
126 	void activeBrushChanged(const brushes::ClassicBrush&);
127 	void modelChanged(canvas::CanvasModel *model);
128 	void smoothingChanged(int smoothing);
129 
130 	void colorUsed(const QColor &color);
131 	void zoomRequested(const QRect &rect, int steps);
132 
133 private slots:
134 	void onAnnotationRowDelete(const QModelIndex&, int first, int last);
135 	void onFeatureAccessChange(canvas::Feature feature, bool canUse);
136 
137 private:
138 	void registerTool(Tool *tool);
139 
140 	Tool *m_toolbox[Tool::_LASTTOOL];
141 	net::Client *m_client;
142 
143 	canvas::CanvasModel *m_model;
144 
145 	brushes::ClassicBrush m_activebrush;
146 	Tool *m_activeTool;
147 	uint16_t m_activeLayer;
148 	uint16_t m_activeAnnotation;
149 	bool m_prevShift, m_prevAlt;
150 
151 	int m_smoothing;
152 	StrokeSmoother m_smoother;
153 };
154 
155 }
156 
157 #endif // TOOLCONTROLLER_H
158