Pencil2D  ff90c0872e88be3bf81c548cd60f01983012ec49
Pencil2D is an animation software for both bitmap and vector graphics. It is free, multi-platform, and open source.
 All Classes Functions
movetool.cpp
1 /*
2 
3 Pencil - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2017 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 "editor.h"
19 #include "toolmanager.h"
20 #include "scribblearea.h"
21 #include "layervector.h"
22 #include "layermanager.h"
23 
24 #include "movetool.h"
25 
26 MoveTool::MoveTool(QObject *parent) :
27  BaseTool(parent)
28 {
29 }
30 
31 ToolType MoveTool::type()
32 {
33  return MOVE;
34 }
35 
36 void MoveTool::loadSettings()
37 {
38  properties.width = -1;
39  properties.feather = -1;
40  properties.useFeather = false;
41  properties.inpolLevel = -1;
42  properties.useAA = -1;
43 }
44 
45 QCursor MoveTool::cursor()
46 {
47  return Qt::ArrowCursor;
48 }
49 
50 void MoveTool::mousePressEvent( QMouseEvent *event )
51 {
52  Layer *layer = mEditor->layers()->currentLayer();
53  if ( layer == NULL ) { return; }
54 
55  if ( event->button() == Qt::LeftButton )
56  {
57  pressOperation(event, layer);
58  }
59 }
60 
61 void MoveTool::mouseReleaseEvent( QMouseEvent* )
62 {
63  // update selection position
64  mScribbleArea->myTransformedSelection = mScribbleArea->myTempTransformedSelection;
65 
66  // make sure transform is correct
67  mScribbleArea->calculateSelectionTransformation();
68 
69  // paint and apply
70  paintTransformedSelection();
71  applyChanges();
72 
73  // set selection again to avoid scaling issues.
74  mScribbleArea->setSelection( mScribbleArea->myTransformedSelection, true );
75  resetSelectionProperties();
76 }
77 
78 void MoveTool::mouseMoveEvent( QMouseEvent *event )
79 {
80  Layer* layer = mEditor->layers()->currentLayer();
81  if ( layer == NULL ) {
82  return;
83  }
84 
85  if ( layer->type() != Layer::BITMAP && layer->type() != Layer::VECTOR )
86  {
87  return;
88  }
89 
90  if ( event->buttons() & Qt::LeftButton ) // the user is also pressing the mouse (dragging)
91  {
92  if( mScribbleArea->somethingSelected )
93  {
94  QPointF offset = QPointF(mScribbleArea->mOffset.x(),
95  mScribbleArea->mOffset.y());
96 
97  if ( event->modifiers() == Qt::ShiftModifier ) // maintain aspect ratio
98  {
99  offset = maintainAspectRatio(offset.x(), offset.y());
100  }
101 
102  transformSelection(offset.x(), offset.y());
103 
104  mScribbleArea->calculateSelectionTransformation();
105  paintTransformedSelection();
106  }
107  else // there is nothing selected
108  {
109  mScribbleArea->deselectAll();
110  mScribbleArea->mMoveMode = ScribbleArea::NONE;
111  }
112  }
113  else // the user is moving the mouse without pressing it
114  {
115  if ( layer->type() == Layer::VECTOR )
116  {
117  onHoverOutlineStroke(layer);
118  }
119  mScribbleArea->update();
120  }
121 }
122 
123 
124 void MoveTool::pressOperation(QMouseEvent* event, Layer* layer)
125 {
126  if ( (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR) )
127  {
128  mEditor->backup( tr( "Move" ) );
129  mScribbleArea->setMoveMode( ScribbleArea::MIDDLE ); // was MIDDLE
130 
131  if ( mScribbleArea->somethingSelected ) // there is an area selection
132  {
133  whichTransformationPoint();
134 
135  // calculate new transformation in case click only
136  mScribbleArea->calculateSelectionTransformation();
137 
138  paintTransformedSelection();
139  applyChanges();
140 
141  mScribbleArea->setSelection( mScribbleArea->myTransformedSelection, true );
142  resetSelectionProperties();
143  }
144 
145  if ( mScribbleArea->getMoveMode() == ScribbleArea::MIDDLE )
146  {
147 
148  if ( event->modifiers() == Qt::ControlModifier ) // --- rotation
149  {
150  mScribbleArea->setMoveMode( ScribbleArea::ROTATION );
151  }
152  else if (event->modifiers() == Qt::AltModifier ) // --- symmetry
153  {
154  mScribbleArea->setMoveMode(ScribbleArea::SYMMETRY );
155  }
156 
157  if ( layer->type() == Layer::VECTOR )
158  {
159  actionOnVector(event, layer);
160  }
161  if ( !(mScribbleArea->myTransformedSelection.contains( getLastPoint() )) ) // click is outside the transformed selection with the MOVE tool
162  {
163  applyChanges();
164  }
165  }
166  }
167 }
168 
169 void MoveTool::actionOnVector(QMouseEvent* event, Layer* layer)
170 {
171  VectorImage *vectorImage = ((LayerVector *)layer)->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
172  if ( mScribbleArea->mClosestCurves.size() > 0 ) // the user clicks near a curve
173  {
174  // editor->backup();
175  if ( !vectorImage->isSelected( mScribbleArea->mClosestCurves ) )
176  {
177  if ( event->modifiers() != Qt::ShiftModifier )
178  {
179  applyChanges();
180  }
181  vectorImage->setSelected( mScribbleArea->mClosestCurves, true );
182  mScribbleArea->setSelection( vectorImage->getSelectionRect(), true );
183  mScribbleArea->update();
184  }
185  }
186  else
187  {
188  int areaNumber = vectorImage->getLastAreaNumber( getLastPoint() );
189  if ( areaNumber != -1 ) // the user clicks on an area
190  {
191  if ( !vectorImage->isAreaSelected( areaNumber ) )
192  {
193  if ( event->modifiers() != Qt::ShiftModifier )
194  {
195  applyChanges();
196  }
197  vectorImage->setAreaSelected( areaNumber, true );
198  mScribbleArea->setSelection( QRectF( 0, 0, 0, 0 ), true );
199  mScribbleArea->update();
200  }
201  }
202  }
203 }
204 
205 void MoveTool::whichTransformationPoint()
206 {
207  QRectF transformPoint = mScribbleArea->myTransformedSelection;
208 
209  if ( QLineF( getLastPoint(), transformPoint.topLeft() ).length() < 10 )
210  {
211  mScribbleArea->setMoveMode( ScribbleArea::TOPLEFT );
212  }
213  if ( QLineF( getLastPoint(), transformPoint.topRight() ).length() < 10 )
214  {
215  mScribbleArea->setMoveMode( ScribbleArea::TOPRIGHT );
216  }
217  if ( QLineF( getLastPoint(), transformPoint.bottomLeft() ).length() < 10 )
218  {
219  mScribbleArea->setMoveMode( ScribbleArea::BOTTOMLEFT );
220  }
221  if ( QLineF( getLastPoint(), transformPoint.bottomRight() ).length() < 10 )
222  {
223  mScribbleArea->setMoveMode( ScribbleArea::BOTTOMRIGHT );
224  }
225 }
226 
227 void MoveTool::transformSelection(qreal offsetX, qreal offsetY)
228 {
229  switch ( mScribbleArea->mMoveMode )
230  {
231  case ScribbleArea::MIDDLE:
232  if ( QLineF( getLastPressPixel(), getCurrentPixel() ).length() > 4 )
233  {
234  mScribbleArea->myTempTransformedSelection =
235  mScribbleArea->myTransformedSelection.translated( QPointF(offsetX, offsetY) );
236  }
237  break;
238 
239  case ScribbleArea::TOPRIGHT:
240  mScribbleArea->myTempTransformedSelection =
241  mScribbleArea->myTransformedSelection.adjusted( 0, offsetY, offsetX, 0 );
242  break;
243 
244  case ScribbleArea::TOPLEFT:
245  mScribbleArea->myTempTransformedSelection =
246  mScribbleArea->myTransformedSelection.adjusted( offsetX, offsetY, 0, 0 );
247  break;
248 
249  case ScribbleArea::BOTTOMLEFT:
250  mScribbleArea->myTempTransformedSelection =
251  mScribbleArea->myTransformedSelection.adjusted( offsetX, 0, 0, offsetY );
252  break;
253 
254  case ScribbleArea::BOTTOMRIGHT:
255  mScribbleArea->myTempTransformedSelection =
256  mScribbleArea->myTransformedSelection.adjusted( 0, 0, offsetX, offsetY );
257  break;
258 
259  case ScribbleArea::ROTATION:
260  mScribbleArea->myTempTransformedSelection =
261  mScribbleArea->myTransformedSelection; // @ necessary?
262  mScribbleArea->myRotatedAngle = getCurrentPixel().x() - getLastPressPixel().x();
263  break;
264  default:
265  break;
266  }
267  mScribbleArea->update();
268 
269 }
270 
271 QPointF MoveTool::maintainAspectRatio(qreal offsetX, qreal offsetY)
272 {
273  qreal factor = mScribbleArea->mySelection.width() / mScribbleArea->mySelection.height();
274 
275  if (mScribbleArea->mMoveMode == ScribbleArea::TOPLEFT || mScribbleArea->mMoveMode == ScribbleArea::BOTTOMRIGHT) {
276  offsetY = offsetX / factor;
277  }
278  else if (mScribbleArea->mMoveMode == ScribbleArea::TOPRIGHT || mScribbleArea->mMoveMode == ScribbleArea::BOTTOMLEFT) {
279  offsetY = -(offsetX / factor);
280  }
281  else if (mScribbleArea->mMoveMode == ScribbleArea::MIDDLE) {
282 
283  qreal absX = offsetX;
284  if (absX < 0) {absX = -absX;}
285 
286  qreal absY = offsetY;
287  if (absY < 0) {absY = -absY;}
288 
289  if (absX > absY) {
290  offsetY = 0;
291  }
292  if (absY > absX) {
293  offsetX = 0;
294  }
295  }
296  return QPointF(offsetX,offsetY);
297 }
298 
299 void MoveTool::onHoverOutlineStroke(Layer* layer)
300 {
301  auto layerVector = static_cast< LayerVector* >( layer );
302  VectorImage* pVecImg = layerVector->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
303  mScribbleArea->mClosestCurves = pVecImg->getCurvesCloseTo( getCurrentPoint(), mScribbleArea->tol / mEditor->view()->scaling() );
304 }
305 
306 void MoveTool::cancelChanges()
307 {
308  mScribbleArea->cancelTransformedSelection();
309 }
310 
311 void MoveTool::applyChanges()
312 {
313  mScribbleArea->applyTransformedSelection();
314 }
315 
316 void MoveTool::paintTransformedSelection()
317 {
318  mScribbleArea->paintTransformedSelection();
319 }
320 
321 void MoveTool::leavingThisTool()
322 {
323  // make sure correct transformation is applied
324  // before leaving
325  mScribbleArea->calculateSelectionTransformation();
326  applyChanges();
327 }
328 
329 void MoveTool::switchingLayers(){
330  applyChanges();
331 }
332 
333 void MoveTool::resetSelectionProperties()
334 {
335  mScribbleArea->resetSelectionProperties();
336 }
Definition: layer.h:32
void resetSelectionProperties()
ScribbleArea::resetSelectionProperties should be used whenever translate, rotate, transform...