All Classes Namespaces Functions Variables Enumerations Properties Pages
movetool.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2020 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
10 
11 This program 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 */
17 
18 #include "movetool.h"
19 
20 #include <cassert>
21 #include <QMessageBox>
22 
23 #include "pointerevent.h"
24 #include "editor.h"
25 #include "toolmanager.h"
26 #include "viewmanager.h"
27 #include "strokemanager.h"
28 #include "selectionmanager.h"
29 #include "scribblearea.h"
30 #include "layervector.h"
31 #include "layermanager.h"
32 #include "mathutils.h"
33 #include "vectorimage.h"
34 
35 
36 MoveTool::MoveTool(QObject* parent) : BaseTool(parent)
37 {
38 }
39 
40 ToolType MoveTool::type()
41 {
42  return MOVE;
43 }
44 
45 void MoveTool::loadSettings()
46 {
47  properties.width = -1;
48  properties.feather = -1;
49  properties.useFeather = false;
50  properties.stabilizerLevel = -1;
51  properties.useAA = -1;
52  mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
53 
54  connect(mEditor->preference(), &PreferenceManager::optionChanged, this, &MoveTool::updateSettings);
55 }
56 
57 QCursor MoveTool::cursor()
58 {
59  MoveMode mode = mEditor->select()->getMoveModeForSelectionAnchor(getCurrentPoint());
60  return mScribbleArea->currentTool()->selectMoveCursor(mode, type());
61 }
62 
63 void MoveTool::updateSettings(const SETTING setting)
64 {
65  switch (setting)
66  {
67  case SETTING::ROTATION_INCREMENT:
68  {
69  mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
70  break;
71  }
72  default:
73  break;
74 
75  }
76 }
77 
78 void MoveTool::pointerPressEvent(PointerEvent* event)
79 {
80  mCurrentLayer = currentPaintableLayer();
81  if (mCurrentLayer == nullptr) return;
82 
83  mEditor->select()->updatePolygons();
84 
85  setAnchorToLastPoint();
86  beginInteraction(event->modifiers(), mCurrentLayer);
87 }
88 
89 void MoveTool::pointerMoveEvent(PointerEvent* event)
90 {
91  mCurrentLayer = currentPaintableLayer();
92  if (mCurrentLayer == nullptr) return;
93 
94  mEditor->select()->updatePolygons();
95 
96  if (mScribbleArea->isPointerInUse()) // the user is also pressing the mouse (dragging)
97  {
98  transformSelection(event->modifiers(), mCurrentLayer);
99  }
100  else
101  {
102  // the user is moving the mouse without pressing it
103  // update cursor to reflect selection corner interaction
104  mScribbleArea->updateToolCursor();
105 
106  if (mCurrentLayer->type() == Layer::VECTOR)
107  {
108  storeClosestVectorCurve(mCurrentLayer);
109  }
110  }
111  mScribbleArea->updateCurrentFrame();
112 }
113 
114 void MoveTool::pointerReleaseEvent(PointerEvent*)
115 {
116  auto selectMan = mEditor->select();
117  if (!selectMan->somethingSelected())
118  return;
119 
120  mRotatedAngle = selectMan->myRotation();
121  updateTransformation();
122 
123  Layer* layer = mEditor->layers()->currentLayer();
124  if (layer->type() == Layer::VECTOR) {
125  applyTransformation();
126  }
127 
128  selectMan->updatePolygons();
129 
130  mScribbleArea->updateToolCursor();
131  mScribbleArea->updateCurrentFrame();
132 }
133 
134 void MoveTool::updateTransformation()
135 {
136  auto selectMan = mEditor->select();
137  selectMan->updateTransformedSelection();
138 
139  // make sure transform is correct
140  selectMan->calculateSelectionTransformation();
141 
142  // paint the transformation
143  paintTransformedSelection();
144 }
145 
146 void MoveTool::transformSelection(Qt::KeyboardModifiers keyMod, Layer* layer)
147 {
148  auto selectMan = mEditor->select();
149  if (selectMan->somethingSelected())
150  {
151 
152  QPointF offset = offsetFromPressPos();
153 
154  // maintain aspect ratio
155  if (keyMod == Qt::ShiftModifier)
156  {
157  offset = selectMan->offsetFromAspectRatio(offset.x(), offset.y());
158  }
159 
160  int rotationIncrement = 0;
161  if (selectMan->getMoveMode() == MoveMode::ROTATION && keyMod & Qt::ShiftModifier)
162  {
163  rotationIncrement = mRotationIncrement;
164  }
165 
166  if(layer->type() == Layer::BITMAP)
167  {
168  offset = offset.toPoint();
169  }
170 
171  selectMan->adjustSelection(getCurrentPoint(), offset.x(), offset.y(), mRotatedAngle, rotationIncrement);
172 
173  selectMan->calculateSelectionTransformation();
174  paintTransformedSelection();
175 
176  }
177  else // there is nothing selected
178  {
179  selectMan->setMoveMode(MoveMode::NONE);
180  }
181 }
182 
183 void MoveTool::beginInteraction(Qt::KeyboardModifiers keyMod, Layer* layer)
184 {
185  auto selectMan = mEditor->select();
186  QRectF selectionRect = selectMan->myTransformedSelectionRect();
187  if (!selectionRect.isNull())
188  {
189  mEditor->backup(typeName());
190  }
191 
192  if (keyMod != Qt::ShiftModifier)
193  {
194  if (selectMan->isOutsideSelectionArea(getCurrentPoint()))
195  {
196  applyTransformation();
197  mEditor->deselectAll();
198  }
199  }
200 
201  if (selectMan->validateMoveMode(getLastPoint()) == MoveMode::MIDDLE)
202  {
203  if (keyMod == Qt::ControlModifier) // --- rotation
204  {
205  selectMan->setMoveMode(MoveMode::ROTATION);
206  }
207  }
208 
209  if (layer->type() == Layer::VECTOR)
210  {
211  createVectorSelection(keyMod, layer);
212  }
213 
214  if(selectMan->getMoveMode() == MoveMode::ROTATION) {
215  QPointF curPoint = getCurrentPoint();
216  QPointF anchorPoint = selectionRect.center();
217  mRotatedAngle = qRadiansToDegrees(MathUtils::getDifferenceAngle(anchorPoint, curPoint)) - selectMan->myRotation();
218  }
219 }
220 
227 {
228  assert(layer->type() == Layer::VECTOR);
229  LayerVector* vecLayer = static_cast<LayerVector*>(layer);
230  VectorImage* vectorImage = vecLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
231  if (vectorImage == nullptr) { return; }
232 
233  if (!mEditor->select()->closestCurves().empty()) // the user clicks near a curve
234  {
235  setCurveSelected(vectorImage, keyMod);
236  }
237  else if (vectorImage->getLastAreaNumber(getLastPoint()) > -1)
238  {
239  setAreaSelected(vectorImage, keyMod);
240  }
241  mScribbleArea->update();
242 }
243 
244 void MoveTool::setCurveSelected(VectorImage* vectorImage, Qt::KeyboardModifiers keyMod)
245 {
246  auto selectMan = mEditor->select();
247  if (!vectorImage->isSelected(selectMan->closestCurves()))
248  {
249  if (keyMod != Qt::ShiftModifier)
250  {
251  applyTransformation();
252  }
253  vectorImage->setSelected(selectMan->closestCurves(), true);
254  selectMan->setSelection(vectorImage->getSelectionRect(), false);
255  }
256 }
257 
258 void MoveTool::setAreaSelected(VectorImage* vectorImage, Qt::KeyboardModifiers keyMod)
259 {
260  int areaNumber = vectorImage->getLastAreaNumber(getLastPoint());
261  if (!vectorImage->isAreaSelected(areaNumber))
262  {
263  if (keyMod != Qt::ShiftModifier)
264  {
265  applyTransformation();
266  }
267  vectorImage->setAreaSelected(areaNumber, true);
268  mEditor->select()->setSelection(vectorImage->getSelectionRect(), false);
269  }
270 }
271 
277 {
278  auto selectMan = mEditor->select();
279  auto layerVector = static_cast<LayerVector*>(layer);
280  VectorImage* pVecImg = layerVector->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
281  if (pVecImg == nullptr) { return; }
282  selectMan->setCurves(pVecImg->getCurvesCloseTo(getCurrentPoint(), selectMan->selectionTolerance()));
283 }
284 
285 void MoveTool::setAnchorToLastPoint()
286 {
287  anchorOriginPoint = getLastPoint();
288 }
289 
290 void MoveTool::cancelChanges()
291 {
292  auto selectMan = mEditor->select();
293  mScribbleArea->cancelTransformedSelection();
294  selectMan->resetSelectionProperties();
295  mEditor->deselectAll();
296 }
297 
298 void MoveTool::applySelectionChanges()
299 {
300  mEditor->select()->setRotation(0);
301  mRotatedAngle = 0;
302 
303  mScribbleArea->applySelectionChanges();
304 }
305 
306 void MoveTool::applyTransformation()
307 {
308  mScribbleArea->applyTransformedSelection();
309 }
310 
311 void MoveTool::paintTransformedSelection()
312 {
313  mScribbleArea->paintTransformedSelection();
314 }
315 
316 bool MoveTool::leavingThisTool()
317 {
318  if (mCurrentLayer)
319  {
320  switch (mCurrentLayer->type())
321  {
322  case Layer::BITMAP: applySelectionChanges(); break;
323  case Layer::VECTOR: applyTransformation(); break;
324  default: break;
325  }
326  }
327  return true;
328 }
329 
330 bool MoveTool::switchingLayer()
331 {
332  auto selectMan = mEditor->select();
333  if (!selectMan->transformHasBeenModified())
334  {
335  mEditor->deselectAll();
336  return true;
337  }
338 
339  int returnValue = showTransformWarning();
340 
341  if (returnValue == QMessageBox::Yes)
342  {
343  if (mCurrentLayer->type() == Layer::BITMAP)
344  {
345  applySelectionChanges();
346  }
347  else if (mCurrentLayer->type() == Layer::VECTOR)
348  {
349  applyTransformation();
350  }
351 
352  mEditor->deselectAll();
353  return true;
354  }
355  else if (returnValue == QMessageBox::No)
356  {
357  cancelChanges();
358  return true;
359  }
360  else if (returnValue == QMessageBox::Cancel)
361  {
362  return false;
363  }
364  return true;
365 }
366 
367 int MoveTool::showTransformWarning()
368 {
369  int returnValue = QMessageBox::warning(nullptr,
370  tr("Layer switch", "Windows title of layer switch pop-up."),
371  tr("You are about to switch away, do you want to apply the transformation?"),
374  return returnValue;
375 }
376 
377 Layer* MoveTool::currentPaintableLayer()
378 {
379  Layer* layer = mEditor->layers()->currentLayer();
380  if (layer == nullptr)
381  return nullptr;
382  if (!layer->isPaintable())
383  return nullptr;
384  return layer;
385 }
386 
387 QPointF MoveTool::offsetFromPressPos()
388 {
389  return getCurrentPoint() - getCurrentPressPoint();
390 }
typedef KeyboardModifiers
Qt::KeyboardModifiers modifiers() const
Returns the modifier created by keyboard while a device was in use.
int getLastAreaNumber(QPointF point)
VectorImage::getLastAreaNumber.
QList< int > getCurvesCloseTo(QPointF thisPoint, qreal maxDistance)
VectorImage::getCurvesCloseTo.
QString tr(const char *sourceText, const char *disambiguation, int n)
void update()
qreal x() const const
qreal y() const const
bool empty() const const
bool isSelected(int curveNumber)
VectorImage::isSelected.
Definition: layer.h:39
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:226
QPointF center() const const
void storeClosestVectorCurve(Layer *layer)
MoveTool::storeClosestVectorCurve stores the curves closest to the mouse position in mClosestCurves...
Definition: movetool.cpp:276
bool isNull() const const
bool isAreaSelected(int areaNumber)
VectorImage::isAreaSelected.
QPoint toPoint() const const
void setAreaSelected(int areaNumber, bool YesOrNo)
VectorImage::setAreaSelected.
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setSelected(int curveNumber, bool YesOrNo)
VectorImage::setSelected.