1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2015 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 CANVASINPUTAREA_H
21 #define CANVASINPUTAREA_H
22 
23 #include "core/point.h"
24 #include "tabletstate.h"
25 #include "pressure.h"
26 
27 #include <QQuickItem>
28 #include <QCursor>
29 
30 /**
31  * @brief This item handles input (mouse, touch and tablet) for the canvas
32  */
33 class CanvasInputArea : public QQuickItem
34 {
35 	Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)
36 	Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
37 	Q_PROPERTY(qreal contentZoom READ contentZoom WRITE setContentZoom NOTIFY contentZoomChanged)
38 	Q_PROPERTY(qreal contentRotation READ contentRotation WRITE setContentRotation NOTIFY contentRotationChanged)
39 
40 	Q_PROPERTY(bool locked READ isLocked WRITE setLocked NOTIFY isLockedChanged)
41 	Q_PROPERTY(QCursor toolCursor READ toolCursor WRITE setToolCursor NOTIFY toolCursorChanged)
42 	Q_PROPERTY(PressureMapping pressureMapping READ pressureMapping WRITE setPressureMapping NOTIFY pressureMappingChanged)
43 
44 	Q_PROPERTY(QQuickItem* canvas READ canvas WRITE setCanvas NOTIFY canvasChanged)
45 	Q_PROPERTY(TabletState* tablet READ tabletState WRITE setTabletState NOTIFY tabletStateChanged)
46 
47 	Q_OBJECT
48 
49 public:
50 	explicit CanvasInputArea(QQuickItem *parent=nullptr);
51 
52 	//! Map a point from scene coordinates to canvas coordinates
53 	Q_INVOKABLE QPointF mapToCanvas(const QPointF &point) const;
mapToCanvas(const QPointF & point,qreal pressure)54 	Q_INVOKABLE inline paintcore::Point mapToCanvas(const QPointF &point, qreal	 pressure) const { return paintcore::Point(mapToCanvas(point), pressure); }
55 
canvas()56 	QQuickItem *canvas() const { return m_canvas; }
setCanvas(QQuickItem * canvas)57 	void setCanvas(QQuickItem *canvas) { m_canvas = canvas; emit canvasChanged(); }
58 
tabletState()59 	TabletState *tabletState() const { return m_tabletstate; }
setTabletState(TabletState * st)60 	void setTabletState(TabletState *st) { m_tabletstate = st; emit tabletStateChanged(); }
61 
contentX()62 	qreal contentX() const { return m_contentx; }
setContentX(qreal x)63 	void setContentX(qreal x) { m_contentx = x; emit contentXChanged(x); }
64 
contentY()65 	qreal contentY() const { return m_contenty; }
setContentY(qreal y)66 	void setContentY(qreal y) { m_contenty = y; emit contentYChanged(y); }
67 
contentZoom()68 	qreal contentZoom() const { return m_zoom; }
69 	void setContentZoom(qreal zoom);
70 
contentRotation()71 	qreal contentRotation() const { return m_rotation; }
setContentRotation(qreal rotation)72 	void setContentRotation(qreal rotation) { m_rotation = rotation; emit contentRotationChanged(rotation); }
73 
isLocked()74 	bool isLocked() const { return m_locked; }
75 	void setLocked(bool lock);
76 
toolCursor()77 	QCursor toolCursor() const { return m_toolcursor; }
78 	void setToolCursor(const QCursor &cursor);
79 
pressureMapping()80 	PressureMapping pressureMapping() const { return m_pressuremapping; }
setPressureMapping(const PressureMapping & pm)81 	void setPressureMapping(const PressureMapping &pm) { m_pressuremapping = pm; emit pressureMappingChanged(); }
82 
83 public slots:
84 	void zoomSteps(int steps);
85 
86 signals:
87 	void canvasChanged();
88 	void tabletStateChanged();
89 	void contentXChanged(qreal);
90 	void contentYChanged(qreal);
91 	void contentZoomChanged(qreal);
92 	void contentRotationChanged(qreal);
93 	void contentWidthChanged(qreal);
94 	void contentHeightChanged(qreal);
95 	void isLockedChanged(bool);
96 	void toolCursorChanged();
97 	void pressureMappingChanged();
98 
99 	void penDown(const QPointF &point, qreal pressure);
100 	void penMove(const QPointF &point, qreal pressure, bool shift, bool alt);
101 	void penUp();
102 	void quickAdjust(qreal value);
103 
104 	void colorPickRequested(const QPointF &point);
105 
106 protected:
107 	void mouseMoveEvent(QMouseEvent *event);
108 	void hoverMoveEvent(QHoverEvent *event);
109 	void mousePressEvent(QMouseEvent *event);
110 	void mouseReleaseEvent(QMouseEvent *event);
111 	void hoverEnterEvent(QHoverEvent *event);
112 	void wheelEvent(QWheelEvent *event);
113 	void keyPressEvent(QKeyEvent *event);
114 	void keyReleaseEvent(QKeyEvent *event);
115 	bool event(QEvent *event);
116 
117 private:
118 	void nativeGestureEvent(QNativeGestureEvent *event);
119 
120 	void resetCursor();
121 
122 	// Dragging modes
123 	enum ViewTransform {DRAG_NOTRANSFORM, DRAG_TRANSLATE, DRAG_ROTATE, DRAG_ZOOM, DRAG_QUICKADJUST1};
124 
125 	// unified mouse/stylus event handlers
126 	void penPressEvent(const QPointF &pos, float pressure, Qt::MouseButton button, Qt::KeyboardModifiers modifiers, bool isStylus);
127 	void penMoveEvent(const QPointF &pos, float pressure, Qt::KeyboardModifiers modifiers, bool isStylus);
128 	void penReleaseEvent(const QPointF &pos, Qt::MouseButton button);
129 
130 	qreal mapPressure(qreal pressure, bool stylus);
131 
132 	// View drag handlers
133 	void startDrag(const QPointF &pos, ViewTransform mode);
134 	void moveDrag(const QPointF &pos);
135 	void stopDrag();
136 
137 	QQuickItem *m_canvas;
138 	TabletState *m_tabletstate;
139 
140 	// View settings
141 	bool m_enableTouchScroll, m_enableTouchPinch, m_enableTouchRotate;
142 	PressureMapping m_pressuremapping;
143 
144 	// Cursors
145 	const QCursor m_colorPickerCursor;
146 	const QCursor m_crosshairCursor;
147 
148 	// View state
149 	bool m_locked;
150 	QCursor m_toolcursor;
151 
152 	// View transformation state
153 	qreal m_contentx;
154 	qreal m_contenty;
155 	qreal m_rotation;
156 	qreal m_zoom;
157 
158 	// Input device state
159 	bool m_specialpenmode;
160 
161 	ViewTransform m_isdragging;
162 	ViewTransform m_dragbtndown;
163 	qreal m_dragx, m_dragy;
164 
165 	QPointF m_prevpoint;
166 	paintcore::Point m_prevoutlinepoint;
167 	qreal m_pointerdistance;
168 	qreal m_pointervelocity;
169 
170 	bool m_prevshift;
171 	bool m_prevalt;
172 
173 	int m_zoomWheelDelta;
174 
175 	bool m_pendown;
176 	bool m_touching;
177 
178 };
179 
180 #endif // CANVASINPUTAREA_H
181