Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_rotate_canvas_action.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2012 Arjen Hiemstra <ahiemstra@heimr.nl>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QApplication>
10#include <QNativeGestureEvent>
11#include <klocalizedstring.h>
12
13#include "kis_cursor.h"
15#include <kis_canvas2.h>
16#include "kis_input_manager.h"
18
19#include <math.h>
20
23
24constexpr qreal DISCRETE_ANGLE_STEP = 15.0; // discrete rotation snapping angle
25
27{
28public:
30
31 // Coverity requires sane defaults for all variables (CID 36429)
33
34 qreal snapRotation {0.0};
35 bool allowRotation {false};
36
37 std::unique_ptr<KisCanvasNavigationActionStrategy> actionStrategy;
38};
39
40
42 : KisAbstractInputAction("Rotate Canvas")
43 , d(new Private())
44{
45 setName(i18n("Rotate Canvas"));
46 setDescription(i18n("The <i>Rotate Canvas</i> action rotates the canvas."));
47
48 QHash<QString, int> shortcuts;
49 shortcuts.insert(i18n("Rotate Mode"), RotateModeShortcut);
50 shortcuts.insert(i18n("Discrete Rotate Mode"), DiscreteRotateModeShortcut);
51 shortcuts.insert(i18n("Rotate Left"), RotateLeftShortcut);
52 shortcuts.insert(i18n("Rotate Right"), RotateRightShortcut);
53 shortcuts.insert(i18n("Reset Rotation"), RotateResetShortcut);
54 setShortcutIndexes(shortcuts);
55}
56
61
63{
64 return 3;
65}
66
68{
69 if (shortcut == DiscreteRotateModeShortcut) {
70 QApplication::setOverrideCursor(KisCursor::rotateCanvasDiscreteCursor());
71 } else /* if (shortcut == SmoothRotateModeShortcut) */ {
72 QApplication::setOverrideCursor(KisCursor::rotateCanvasSmoothCursor());
73 }
74}
75
77{
78 Q_UNUSED(shortcut);
79 QApplication::restoreOverrideCursor();
80}
81
82void KisRotateCanvasAction::begin(int shortcut, QEvent *event)
83{
84 KisAbstractInputAction::begin(shortcut, event);
85
86 KisCanvasController *canvasController =
88 KIS_SAFE_ASSERT_RECOVER_RETURN(canvasController);
89
90 if (event
91 && (event->type() == QEvent::NativeGesture || event->type() == QEvent::TouchBegin
92 || event->type() == QEvent::TouchUpdate)
93 && (shortcut == RotateModeShortcut || shortcut == DiscreteRotateModeShortcut)) {
94
96 using Flags = KisCanvasNavigationActionStrategyNativeGesture::Flags;
97
98 Flags flags;
99 flags.setFlag(Flag::PanEnabled);
100 flags.setFlag(Flag::RotationEnabled);
101 flags.setFlag(Flag::RotationDescrete, shortcut == DiscreteRotateModeShortcut);
102
103 if (event->type() == QEvent::NativeGesture) {
105 } else {
106 const QTouchEvent *tevent = static_cast<const QTouchEvent*>(event);
108 }
109
110 // native gestures don't have cursor tracking by the OS, so they shouldn't show any cursor
111 QApplication::restoreOverrideCursor();
112 return;
113 }
114
115 d->allowRotation = false;
116 d->snapRotation = 0;
117
118 d->mode = (Shortcut)shortcut;
119
120 switch(shortcut) {
123 // If the canvas has been rotated to an angle that is not an exact multiple of DISCRETE_ANGLE_STEP,
124 // we need to adjust the final discrete rotation by that angle difference.
125 // trunc() is used to round the negative numbers towards zero.
126 const qreal startRotation = inputManager()->canvas()->rotationAngle();
127 d->snapRotation = startRotation - std::trunc(startRotation / DISCRETE_ANGLE_STEP) * DISCRETE_ANGLE_STEP;
128 canvasController->beginCanvasRotation();
129 break;
130 }
132 canvasController->rotateCanvasLeft15();
133 break;
135 canvasController->rotateCanvasRight15();
136 break;
138 canvasController->resetCanvasRotation();
139 break;
140 }
141}
142
143void KisRotateCanvasAction::end(QEvent *event)
144{
145 Q_UNUSED(event);
146
147 if (d->actionStrategy) {
148 d->actionStrategy.reset();
149 } else {
150 KisCanvasController *canvasController =
152 KIS_SAFE_ASSERT_RECOVER_RETURN(canvasController);
153
154 switch (d->mode) {
157 canvasController->endCanvasRotation();
158 break;
159 default:
160 break;
161 }
162 }
163}
164
165void KisRotateCanvasAction::cursorMovedAbsolute(const QPointF &startPos, const QPointF &pos)
166{
167 if (d->mode == RotateResetShortcut) {
168 return;
169 }
170
172 const QPointF centerPoint = converter->flakeToWidget(converter->flakeCenterPoint());
173 const QPointF startPoint = startPos - centerPoint;
174 const QPointF newPoint = pos - centerPoint;
175
176 const qreal oldAngle = atan2(startPoint.y(), startPoint.x());
177 const qreal newAngle = atan2(newPoint.y(), newPoint.x());
178
179 qreal newRotation = (180 / M_PI) * (newAngle - oldAngle);
180
182 // Do not snap unless the user rotated half-way in the desired direction.
183 if (qAbs(newRotation) > 0.5 * DISCRETE_ANGLE_STEP || d->allowRotation) {
184 d->allowRotation = true;
185 newRotation = qRound((newRotation + d->snapRotation) / DISCRETE_ANGLE_STEP) * DISCRETE_ANGLE_STEP - d->snapRotation;
186 } else {
187 newRotation = 0.0;
188 }
189 }
190
191 KisCanvasController *canvasController =
193 KIS_SAFE_ASSERT_RECOVER_RETURN(canvasController);
194 canvasController->rotateCanvas(newRotation);
195}
196
198{
199 if(!event) {
200 return;
201 }
202
203 if (d->actionStrategy && d->actionStrategy->supportsEvent(event)) {
204 d->actionStrategy->inputEvent(event);
205 } else {
207 }
208}
209
211{
212 Q_UNUSED(shortcut);
214}
215
217{
218 Q_UNUSED(shortcut);
219 return true;
220}
KisInputActionGroup
@ ViewTransformActionGroup
Abstract base class for input actions.
virtual void inputEvent(QEvent *event)
static KisInputManager * inputManager
void setShortcutIndexes(const QHash< QString, int > &indexes)
QPointF eventPosF(const QEvent *event)
void setName(const QString &name)
void setDescription(const QString &description)
virtual void begin(int shortcut, QEvent *event)
qreal rotationAngle() const
canvas rotation in degrees
KisCoordinatesConverter * coordinatesConverter
void rotateCanvas(qreal angle, const std::optional< KoViewTransformStillPoint > &stillPoint, bool isNativeGesture=false)
_Private::Traits< T >::Result flakeToWidget(const T &obj) const
static QCursor rotateCanvasDiscreteCursor()
static QCursor rotateCanvasSmoothCursor()
KisCanvas2 * canvas() const
std::unique_ptr< KisCanvasNavigationActionStrategy > actionStrategy
KisInputActionGroup inputActionGroup(int shortcut) const override
void deactivate(int shortcut) override
void inputEvent(QEvent *event) override
@ RotateLeftShortcut
Rotate left by a fixed amount.
@ RotateResetShortcut
Reset the rotation to 0.
@ DiscreteRotateModeShortcut
Toggle Discrete Rotate mode.
@ RotateRightShortcut
Rotate right by a fixed amount.
@ RotateModeShortcut
Toggle Rotate mode.
bool supportsHiResInputEvents(int shortcut) const override
void cursorMovedAbsolute(const QPointF &startPos, const QPointF &pos) override
void activate(int shortcut) override
void end(QEvent *event) override
void begin(int shortcut, QEvent *event) override
KoCanvasController * canvasController() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define M_PI
Definition kis_global.h:111
constexpr qreal DISCRETE_ANGLE_STEP
KisCanvas2 * canvas