Pencil2D Animation
Download Community News Docs Contribute

core_lib/src/tool/movetool.cpp Source File

  • Main Page
  • Related Pages
  • Classes
  • Files
  •  
  • File List
Loading...
Searching...
No Matches
  • core_lib
  • src
  • tool
movetool.cpp
1/*
2
3Pencil2D - Traditional Animation Software
4Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5Copyright (C) 2012-2020 Matthew Chiawen Chang
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation; version 2 of the License.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16*/
17
18#include "movetool.h"
19
20#include <cassert>
21#include <QMessageBox>
22#include <QSettings>
23
24#include "pointerevent.h"
25#include "editor.h"
26#include "toolmanager.h"
27#include "viewmanager.h"
28#include "strokemanager.h"
29#include "selectionmanager.h"
30#include "overlaymanager.h"
31#include "scribblearea.h"
32#include "layervector.h"
33#include "layermanager.h"
34#include "layercamera.h"
35#include "mathutils.h"
36#include "vectorimage.h"
37
38MoveTool::MoveTool(QObject* parent) : BaseTool(parent)
39{
40}
41
42ToolType MoveTool::type()
43{
44 return MOVE;
45}
46
47void MoveTool::loadSettings()
48{
49 properties.width = -1;
50 properties.feather = -1;
51 properties.useFeather = false;
52 properties.stabilizerLevel = -1;
53 properties.useAA = -1;
54 mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
55 QSettings settings(PENCIL2D, PENCIL2D);
56 properties.showSelectionInfo = settings.value("ShowSelectionInfo").toBool();
57 mPropertyEnabled[SHOWSELECTIONINFO] = true;
58
59 connect(mEditor->preference(), &PreferenceManager::optionChanged, this, &MoveTool::updateSettings);
60}
61
62QCursor MoveTool::cursor()
63{
64 MoveMode mode = MoveMode::NONE;
65 SelectionManager* selectMan = mEditor->select();
66 if (selectMan->somethingSelected())
67 {
68 mode = mEditor->select()->getMoveMode();
69 }
70 else if (mEditor->overlays()->anyOverlayEnabled())
71 {
72 LayerCamera* layerCam = mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex());
73 Q_ASSERT(layerCam);
74 mode = mEditor->overlays()->getMoveModeForPoint(getCurrentPoint(), layerCam->getViewAtFrame(mEditor->currentFrame()));
75 mPerspMode = mode;
76 }
77
78 return cursor(mode);
79}
80
81void MoveTool::updateSettings(const SETTING setting)
82{
83 switch (setting)
84 {
85 case SETTING::ROTATION_INCREMENT:
86 mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
87 break;
88 case SETTING::OVERLAY_PERSPECTIVE1:
89 mEditor->overlays()->settingsUpdated(setting, mEditor->preference()->isOn(setting));
90 break;
91 case SETTING::OVERLAY_PERSPECTIVE2:
92 mEditor->overlays()->settingsUpdated(setting, mEditor->preference()->isOn(setting));
93 break;
94 case SETTING::OVERLAY_PERSPECTIVE3:
95 mEditor->overlays()->settingsUpdated(setting, mEditor->preference()->isOn(setting));
96 break;
97 default:
98 break;
99 }
100}
101
102void MoveTool::pointerPressEvent(PointerEvent* event)
103{
104 mCurrentLayer = currentPaintableLayer();
105 if (mCurrentLayer == nullptr) return;
106
107 if (mEditor->select()->somethingSelected())
108 {
109 beginInteraction(event->modifiers(), mCurrentLayer);
110 }
111 if (mEditor->overlays()->anyOverlayEnabled())
112 {
113 mEditor->overlays()->setMoveMode(mPerspMode);
114
115 LayerCamera* layerCam = mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex());
116 Q_ASSERT(layerCam);
117
118 QPoint mapped = layerCam->getViewAtFrame(mEditor->currentFrame()).map(getCurrentPoint()).toPoint();
119 mEditor->overlays()->updatePerspective(mapped);
120 }
121
122 mEditor->updateCurrentFrame();
123}
124
125void MoveTool::pointerMoveEvent(PointerEvent* event)
126{
127 mCurrentLayer = currentPaintableLayer();
128 if (mCurrentLayer == nullptr) return;
129
130 if (mScribbleArea->isPointerInUse()) // the user is also pressing the mouse (dragging)
131 {
132 transformSelection(event->modifiers());
133
134 if (mEditor->overlays()->anyOverlayEnabled())
135 {
136 LayerCamera* layerCam = mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex());
137 Q_ASSERT(layerCam);
138 mEditor->overlays()->updatePerspective(layerCam->getViewAtFrame(mEditor->currentFrame()).map(getCurrentPoint()));
139 }
140 if (mEditor->select()->somethingSelected())
141 {
142 transformSelection(event->modifiers());
143 }
144 }
145 else
146 {
147 // the user is moving the mouse without pressing it
148 // update cursor to reflect selection corner interaction
149 mEditor->select()->setMoveModeForAnchorInRange(getCurrentPoint());
150 mScribbleArea->updateToolCursor();
151
152 if (mCurrentLayer->type() == Layer::VECTOR)
153 {
154 storeClosestVectorCurve(mCurrentLayer);
155 }
156 }
157 mEditor->updateCurrentFrame();
158}
159
160void MoveTool::pointerReleaseEvent(PointerEvent*)
161{
162 if (mEditor->overlays()->anyOverlayEnabled())
163 {
164 mEditor->overlays()->setMoveMode(MoveMode::NONE);
165 mPerspMode = MoveMode::NONE;
166 }
167
168 auto selectMan = mEditor->select();
169 if (!selectMan->somethingSelected())
170 return;
171
172 mScribbleArea->updateToolCursor();
173 mEditor->frameModified(mEditor->currentFrame());
174}
175
176void MoveTool::transformSelection(Qt::KeyboardModifiers keyMod)
177{
178 auto selectMan = mEditor->select();
179 if (selectMan->somethingSelected())
180 {
181 int rotationIncrement = 0;
182 if (selectMan->getMoveMode() == MoveMode::ROTATION && keyMod & Qt::ShiftModifier)
183 {
184 rotationIncrement = mRotationIncrement;
185 }
186
187 selectMan->maintainAspectRatio(keyMod == Qt::ShiftModifier);
188 selectMan->alignPositionToAxis(keyMod == Qt::ShiftModifier);
189
190 qreal newAngle = 0;
191 if (selectMan->getMoveMode() == MoveMode::ROTATION) {
192 QPointF anchorPoint = selectMan->currentTransformAnchor();
193 newAngle = selectMan->angleFromPoint(getCurrentPoint(), anchorPoint) - mRotatedAngle;
194 mPreviousAngle = newAngle;
195 }
196
197 selectMan->adjustSelection(getCurrentPoint(), mOffset, newAngle, rotationIncrement);
198 }
199 else // there is nothing selected
200 {
201 selectMan->setMoveMode(MoveMode::NONE);
202 }
203}
204
205void MoveTool::beginInteraction(Qt::KeyboardModifiers keyMod, Layer* layer)
206{
207 auto selectMan = mEditor->select();
208 QRectF selectionRect = selectMan->mySelectionRect();
209 if (!selectionRect.isNull())
210 {
211 mEditor->backup(typeName());
212 }
213
214 if (keyMod != Qt::ShiftModifier)
215 {
216 if (selectMan->isOutsideSelectionArea(getCurrentPoint()))
217 {
218 applyTransformation();
219 mEditor->deselectAll();
220 }
221 }
222
223 if (selectMan->getMoveMode() == MoveMode::MIDDLE)
224 {
225 if (keyMod == Qt::ControlModifier) // --- rotation
226 {
227 selectMan->setMoveMode(MoveMode::ROTATION);
228 }
229 }
230
231 if (layer->type() == Layer::VECTOR)
232 {
233 createVectorSelection(keyMod, layer);
234 }
235
236 selectMan->setTransformAnchor(selectMan->getSelectionAnchorPoint());
237 selectMan->setDragOrigin(getCurrentPressPoint());
238 mOffset = selectMan->myTranslation();
239
240 if(selectMan->getMoveMode() == MoveMode::ROTATION) {
241 mRotatedAngle = selectMan->angleFromPoint(getCurrentPoint(), selectMan->currentTransformAnchor()) - mPreviousAngle;
242 }
243}
244
250void MoveTool::createVectorSelection(Qt::KeyboardModifiers keyMod, Layer* layer)
251{
252 assert(layer->type() == Layer::VECTOR);
253 LayerVector* vecLayer = static_cast<LayerVector*>(layer);
254 VectorImage* vectorImage = vecLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
255 if (vectorImage == nullptr) { return; }
256
257 if (!mEditor->select()->closestCurves().empty()) // the user clicks near a curve
258 {
259 setCurveSelected(vectorImage, keyMod);
260 }
261 else if (vectorImage->getLastAreaNumber(getLastPoint()) > -1)
262 {
263 setAreaSelected(vectorImage, keyMod);
264 }
265}
266
267void MoveTool::setCurveSelected(VectorImage* vectorImage, Qt::KeyboardModifiers keyMod)
268{
269 auto selectMan = mEditor->select();
270 if (!vectorImage->isSelected(selectMan->closestCurves()))
271 {
272 if (keyMod != Qt::ShiftModifier)
273 {
274 applyTransformation();
275 }
276 vectorImage->setSelected(selectMan->closestCurves(), true);
277 selectMan->setSelection(vectorImage->getSelectionRect(), false);
278 }
279}
280
281void MoveTool::setAreaSelected(VectorImage* vectorImage, Qt::KeyboardModifiers keyMod)
282{
283 int areaNumber = vectorImage->getLastAreaNumber(getLastPoint());
284 if (!vectorImage->isAreaSelected(areaNumber))
285 {
286 if (keyMod != Qt::ShiftModifier)
287 {
288 applyTransformation();
289 }
290 vectorImage->setAreaSelected(areaNumber, true);
291 mEditor->select()->setSelection(vectorImage->getSelectionRect(), false);
292 }
293}
294
299void MoveTool::storeClosestVectorCurve(Layer* layer)
300{
301 auto selectMan = mEditor->select();
302 auto layerVector = static_cast<LayerVector*>(layer);
303 VectorImage* pVecImg = layerVector->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
304 if (pVecImg == nullptr) { return; }
305 selectMan->setCurves(pVecImg->getCurvesCloseTo(getCurrentPoint(), selectMan->selectionTolerance()));
306}
307
308void MoveTool::cancelChanges()
309{
310 mScribbleArea->cancelTransformedSelection();
311 mEditor->deselectAll();
312}
313
314void MoveTool::applyTransformation()
315{
316 SelectionManager* selectMan = mEditor->select();
317 mScribbleArea->applyTransformedSelection();
318
319 // When the selection has been applied, a new rect is applied based on the bounding box.
320 // This ensures that if the selection has been rotated, it will still fit the bounds of the image.
321 selectMan->setSelection(selectMan->mapToSelection(QPolygonF(selectMan->mySelectionRect())).boundingRect());
322 mRotatedAngle = 0;
323 mPreviousAngle = 0;
324}
325
326bool MoveTool::leavingThisTool()
327{
328 if (mCurrentLayer)
329 {
330 switch (mCurrentLayer->type())
331 {
332 case Layer::BITMAP: applyTransformation(); break;
333 case Layer::VECTOR: applyTransformation(); break;
334 default: break;
335 }
336 }
337 return true;
338}
339
340void MoveTool::resetToDefault()
341{
342 setShowSelectionInfo(false);
343}
344
345void MoveTool::setShowSelectionInfo(const bool b)
346{
347 properties.showSelectionInfo = b;
348
349 QSettings settings(PENCIL2D, PENCIL2D);
350 settings.setValue("ShowSelectionInfo", b);
351
352}
353
354Layer* MoveTool::currentPaintableLayer()
355{
356 Layer* layer = mEditor->layers()->currentLayer();
357 if (layer == nullptr)
358 return nullptr;
359 if (!layer->isPaintable())
360 return nullptr;
361 return layer;
362}
363
364QCursor MoveTool::cursor(MoveMode mode) const
365{
366 QPixmap cursorPixmap = QPixmap(24, 24);
367
368 cursorPixmap.fill(QColor(255, 255, 255, 0));
369 QPainter cursorPainter(&cursorPixmap);
370 cursorPainter.setRenderHint(QPainter::Antialiasing);
371
372 switch(mode)
373 {
374 case MoveMode::PERSP_LEFT:
375 case MoveMode::PERSP_RIGHT:
376 case MoveMode::PERSP_MIDDLE:
377 case MoveMode::PERSP_SINGLE:
378 {
379 cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/svg/cursor-move.svg"));
380 break;
381 }
382 case MoveMode::TOPLEFT:
383 case MoveMode::BOTTOMRIGHT:
384 {
385 cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/svg/cursor-diagonal-left.svg"));
386 break;
387 }
388 case MoveMode::TOPRIGHT:
389 case MoveMode::BOTTOMLEFT:
390 {
391 cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/svg/cursor-diagonal-right.svg"));
392 break;
393 }
394 case MoveMode::ROTATIONLEFT:
395 case MoveMode::ROTATIONRIGHT:
396 case MoveMode::ROTATION:
397 {
398 cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/svg/cursor-rotate.svg"));
399 break;
400 }
401 case MoveMode::MIDDLE:
402 case MoveMode::CENTER:
403 {
404 cursorPainter.drawImage(QPoint(6,6),QImage("://icons/new/svg/cursor-move.svg"));
405 break;
406 }
407 default:
408 return Qt::ArrowCursor;
409 break;
410 }
411 cursorPainter.end();
412
413 return QCursor(cursorPixmap);
414}
BaseTool
Definition: basetool.h:70
Editor::updateCurrentFrame
void updateCurrentFrame()
Will call update() and update the canvas Only call this directly If you need the cache to be intact a...
Definition: editor.cpp:1117
Editor::frameModified
void frameModified(int frameNumber)
This should be emitted after modifying the frame content.
LayerCamera
Definition: layercamera.h:30
Layer
Definition: layer.h:38
LayerVector
Definition: layervector.h:26
MoveTool::createVectorSelection
void createVectorSelection(Qt::KeyboardModifiers keyMod, Layer *layer)
MoveTool::createVectorSelection In vector the selection rectangle is based on the bounding box of the...
Definition: movetool.cpp:250
MoveTool::storeClosestVectorCurve
void storeClosestVectorCurve(Layer *layer)
MoveTool::storeClosestVectorCurve stores the curves closest to the mouse position in mClosestCurves.
Definition: movetool.cpp:299
PointerEvent
Definition: pointerevent.h:8
SelectionManager
Definition: selectionmanager.h:33
SelectionManager::setDragOrigin
void setDragOrigin(const QPointF point)
The point from where the dragging will be based of inside the selection area.
Definition: selectionmanager.h:118
SelectionManager::alignPositionToAxis
void alignPositionToAxis(bool state)
Locks movement either horizontally or vertically depending on drag direction.
Definition: selectionmanager.h:55
VectorImage
Definition: vectorimage.h:32
VectorImage::isAreaSelected
bool isAreaSelected(int areaNumber)
VectorImage::isAreaSelected.
Definition: vectorimage.cpp:697
VectorImage::setSelected
void setSelected(int curveNumber, bool YesOrNo)
VectorImage::setSelected.
Definition: vectorimage.cpp:617
VectorImage::getLastAreaNumber
int getLastAreaNumber(QPointF point)
VectorImage::getLastAreaNumber.
Definition: vectorimage.cpp:2263
VectorImage::setAreaSelected
void setAreaSelected(int areaNumber, bool YesOrNo)
VectorImage::setAreaSelected.
Definition: vectorimage.cpp:685
VectorImage::isSelected
bool isSelected(int curveNumber)
VectorImage::isSelected.
Definition: vectorimage.cpp:727
VectorImage::getCurvesCloseTo
QList< int > getCurvesCloseTo(QPointF thisPoint, qreal maxDistance)
VectorImage::getCurvesCloseTo.
Definition: vectorimage.cpp:1405
QColor
QCursor
QImage
QList::empty
bool empty() const const
QObject
QObject::connect
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::event
virtual bool event(QEvent *e)
QPainter
QPainter::Antialiasing
Antialiasing
QPixmap
QPixmap::fill
void fill(const QColor &color)
QPoint
QPointF
QPolygonF
QRectF
QRectF::isNull
bool isNull() const const
QSettings
Qt::ArrowCursor
ArrowCursor
Qt::KeyboardModifiers
typedef KeyboardModifiers
QTransform::map
QPoint map(const QPoint &point) const const
Generated on Sun Sep 24 2023 19:39:35 for Pencil2D by doxygen 1.9.6 based on revision 1395c86cb17dafbb32de44cbabe1f4c58636468d