All Classes Namespaces Functions Variables Enumerations Properties Pages
selecttool.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 #include "selecttool.h"
18 #include <QSettings>
19 #include "pointerevent.h"
20 #include "vectorimage.h"
21 #include "editor.h"
22 #include "strokemanager.h"
23 #include "layervector.h"
24 #include "scribblearea.h"
25 #include "layermanager.h"
26 #include "toolmanager.h"
27 #include "selectionmanager.h"
28 #include "preferencemanager.h"
29 
30 SelectTool::SelectTool(QObject* parent) : BaseTool(parent)
31 {
32 }
33 
34 void SelectTool::loadSettings()
35 {
36  properties.width = -1;
37  properties.feather = -1;
38  properties.stabilizerLevel = -1;
39  properties.useAA = -1;
40  QSettings settings(PENCIL2D, PENCIL2D);
41  properties.showSelectionInfo = settings.value("ShowSelectionInfo").toBool();
42  mPropertyEnabled[SHOWSELECTIONINFO] = true;
43 }
44 
45 QCursor SelectTool::cursor()
46 {
47  MoveMode mode = mEditor->select()->getMoveModeForSelectionAnchor(getCurrentPoint());
48  return this->selectMoveCursor(mode, type());
49 }
50 
51 void SelectTool::resetToDefault()
52 {
53  setShowSelectionInfo(false);
54 }
55 
56 void SelectTool::setShowSelectionInfo(const bool b)
57 {
58  properties.showSelectionInfo = b;
59 
60  QSettings settings(PENCIL2D, PENCIL2D);
61  settings.setValue("ShowSelectionInfo", b);
62 }
63 
64 void SelectTool::beginSelection()
65 {
66  // Store original click position for help with selection rectangle.
67  mAnchorOriginPoint = getLastPoint();
68 
69  auto selectMan = mEditor->select();
70  selectMan->calculateSelectionTransformation();
71 
72  // paint and apply the transformation
73  if (selectMan->transformHasBeenModified()) {
74  mScribbleArea->paintTransformedSelection();
75  mScribbleArea->applyTransformedSelection();
76  }
77  mMoveMode = selectMan->validateMoveMode(getLastPoint());
78 
79  if (selectMan->somethingSelected() && mMoveMode != MoveMode::NONE) // there is something selected
80  {
81  if (mCurrentLayer->type() == Layer::VECTOR)
82  {
83  VectorImage* vectorImage = static_cast<LayerVector*>(mCurrentLayer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
84  if (vectorImage != nullptr) {
85  vectorImage->deselectAll();
86  }
87  }
88 
89  mAnchorOriginPoint = selectMan->whichAnchorPoint(getLastPoint());
90  }
91  else
92  {
93  selectMan->setSelection(QRectF(getCurrentPoint().x(), getCurrentPoint().y(), 1, 1), mEditor->layers()->currentLayer()->type() == Layer::BITMAP);
94  }
95  mScribbleArea->updateCurrentFrame();
96 }
97 
98 void SelectTool::pointerPressEvent(PointerEvent* event)
99 {
100  mCurrentLayer = mEditor->layers()->currentLayer();
101  if (mCurrentLayer == nullptr) return;
102  if (!mCurrentLayer->isPaintable()) { return; }
103  if (event->button() != Qt::LeftButton) { return; }
104  auto selectMan = mEditor->select();
105 
106  mMoveMode = selectMan->validateMoveMode(getCurrentPoint());
107 
108  if (!mEditor->select()->somethingSelected())
109  mScribbleArea->updateOriginalPolygonF();
110 
111  selectMan->updatePolygons();
112 
113  beginSelection();
114 }
115 
116 void SelectTool::pointerMoveEvent(PointerEvent*)
117 {
118  mCurrentLayer = mEditor->layers()->currentLayer();
119  if (mCurrentLayer == nullptr) { return; }
120  if (!mCurrentLayer->isPaintable()) { return; }
121  auto selectMan = mEditor->select();
122 
123  if (!selectMan->somethingSelected()) { return; }
124 
125  selectMan->updatePolygons();
126 
127  mScribbleArea->updateToolCursor();
128 
129  if (mScribbleArea->isPointerInUse())
130  {
131  controlOffsetOrigin(getCurrentPoint(), mAnchorOriginPoint);
132 
133  if (mCurrentLayer->type() == Layer::VECTOR)
134  {
135  VectorImage* vectorImage = static_cast<LayerVector*>(mCurrentLayer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
136  if (vectorImage != nullptr) {
137  vectorImage->select(selectMan->myTempTransformedSelectionRect());
138  }
139  }
140  }
141 
142  mScribbleArea->updateCurrentFrame();
143 }
144 
145 void SelectTool::pointerReleaseEvent(PointerEvent* event)
146 {
147  mCurrentLayer = mEditor->layers()->currentLayer();
148  if (mCurrentLayer == nullptr) return;
149  if (event->button() != Qt::LeftButton) return;
150  auto selectMan = mEditor->select();
151 
152  // if there's a small very small distance between current and last point
153  // discard the selection...
154  // TODO: improve by adding a timer to check if the user is deliberately selecting
155  if (QLineF(mAnchorOriginPoint, getCurrentPoint()).length() < 5.0)
156  {
157  mEditor->deselectAll();
158  }
159  if (maybeDeselect())
160  {
161  mEditor->deselectAll();
162  }
163  else
164  {
165  keepSelection();
166  }
167 
168  selectMan->updatePolygons();
169 
170  if (mScribbleArea->getOriginalPolygonF().boundingRect().size() !=
171  selectMan->currentSelectionPolygonF().boundingRect().size())
172  mScribbleArea->updateOriginalPolygonF();
173 
174  mScribbleArea->updateToolCursor();
175  mScribbleArea->updateCurrentFrame();
176 }
177 
178 bool SelectTool::maybeDeselect()
179 {
180  return (!isSelectionPointValid() && mEditor->select()->validateMoveMode(getLastPoint()) == MoveMode::NONE);
181 }
182 
188 {
189  auto selectMan = mEditor->select();
190  if (mCurrentLayer->type() == Layer::BITMAP) {
191  if (!selectMan->myTempTransformedSelectionRect().isValid())
192  {
193  selectMan->setSelection(selectMan->myTempTransformedSelectionRect().normalized(), true);
194  }
195  else
196  {
197  selectMan->setSelection(selectMan->myTempTransformedSelectionRect(), true);
198  }
199  }
200  else if (mCurrentLayer->type() == Layer::VECTOR)
201  {
202  VectorImage* vectorImage = static_cast<LayerVector*>(mCurrentLayer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
203  if (vectorImage == nullptr) { return; }
204  selectMan->setSelection(vectorImage->getSelectionRect(), false);
205  }
206 }
207 
208 void SelectTool::controlOffsetOrigin(QPointF currentPoint, QPointF anchorPoint)
209 {
210  QPointF offset = offsetFromPressPos();
211 
212  if (mMoveMode != MoveMode::NONE)
213  {
214  if (editor()->layers()->currentLayer()->type() == Layer::BITMAP) {
215  offset = QPointF(offset).toPoint();
216  }
217 
218  auto selectMan = mEditor->select();
219 
220  selectMan->adjustSelection(getCurrentPoint(), offset.x(), offset.y(), selectMan->myRotation(), 0);
221  }
222  else
223  {
224  // when the selection is none, manage the selection Origin
225  manageSelectionOrigin(currentPoint, anchorPoint);
226  }
227 }
228 
233 void SelectTool::manageSelectionOrigin(QPointF currentPoint, QPointF originPoint)
234 {
235  qreal mouseX = currentPoint.x();
236  qreal mouseY = currentPoint.y();
237 
238  QRectF selectRect;
239 
240  if (mouseX <= originPoint.x())
241  {
242  selectRect.setLeft(mouseX);
243  selectRect.setRight(originPoint.x());
244  }
245  else
246  {
247  selectRect.setLeft(originPoint.x());
248  selectRect.setRight(mouseX);
249  }
250 
251  if (mouseY <= originPoint.y())
252  {
253  selectRect.setTop(mouseY);
254  selectRect.setBottom(originPoint.y());
255  }
256  else
257  {
258  selectRect.setTop(originPoint.y());
259  selectRect.setBottom(mouseY);
260  }
261 
262  mEditor->select()->setTempTransformedSelectionRect(selectRect);
263 }
264 
265 bool SelectTool::keyPressEvent(QKeyEvent* event)
266 {
267  switch (event->key())
268  {
269  case Qt::Key_Alt:
270  if (mEditor->tools()->setTemporaryTool(MOVE, {}, Qt::AltModifier))
271  {
272  return true;
273  }
274  break;
275  default:
276  break;
277  }
278 
279  // Follow the generic behaviour anyway
280  return BaseTool::keyPressEvent(event);
281 }
282 
283 QPointF SelectTool::offsetFromPressPos()
284 {
285  return getCurrentPoint() - getCurrentPressPoint();
286 }
AltModifier
void setRight(qreal x)
QSizeF size() const const
LeftButton
void deselectAll()
VectorImage::deselectAll.
void setLeft(qreal x)
void manageSelectionOrigin(QPointF currentPoint, QPointF originPoint)
SelectTool::manageSelectionOrigin switches anchor point when crossing threshold.
Definition: selecttool.cpp:233
qreal x() const const
qreal y() const const
int key() const const
QRectF boundingRect() const const
QPoint toPoint() const const
void setBottom(qreal y)
void setTop(qreal y)
void keepSelection()
SelectTool::keepSelection Keep selection rect and normalize if invalid.
Definition: selecttool.cpp:187
Qt::MouseButton button() const
Returns Qt::MouseButton()
void updateCurrentFrame()
Update current frame.