All Classes Namespaces Functions Variables Enumerations Properties Pages
polylinetool.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 "polylinetool.h"
19 
20 #include <QSettings>
21 #include "editor.h"
22 #include "scribblearea.h"
23 
24 #include "strokemanager.h"
25 #include "layermanager.h"
26 #include "colormanager.h"
27 #include "viewmanager.h"
28 #include "pointerevent.h"
29 #include "layervector.h"
30 #include "layerbitmap.h"
31 #include "vectorimage.h"
32 
33 
34 PolylineTool::PolylineTool(QObject* parent) : BaseTool(parent)
35 {
36 }
37 
38 ToolType PolylineTool::type()
39 {
40  return POLYLINE;
41 }
42 
43 void PolylineTool::loadSettings()
44 {
45  mPropertyEnabled[WIDTH] = true;
46  mPropertyEnabled[BEZIER] = true;
47  mPropertyEnabled[ANTI_ALIASING] = true;
48 
49  QSettings settings(PENCIL2D, PENCIL2D);
50 
51  properties.width = settings.value("polyLineWidth", 8.0).toDouble();
52  properties.feather = -1;
53  properties.pressure = false;
54  properties.invisibility = OFF;
55  properties.preserveAlpha = OFF;
56  properties.useAA = settings.value("brushAA").toBool();
57  properties.stabilizerLevel = -1;
58 }
59 
60 void PolylineTool::resetToDefault()
61 {
62  setWidth(8.0);
63  setBezier(false);
64 }
65 
66 void PolylineTool::setWidth(const qreal width)
67 {
68  // Set current property
69  properties.width = width;
70 
71  // Update settings
72  QSettings settings(PENCIL2D, PENCIL2D);
73  settings.setValue("polyLineWidth", width);
74  settings.sync();
75 }
76 
77 void PolylineTool::setFeather(const qreal feather)
78 {
79  Q_UNUSED(feather);
80  properties.feather = -1;
81 }
82 
83 void PolylineTool::setAA(const int AA)
84 {
85  // Set current property
86  properties.useAA = AA;
87 
88  // Update settings
89  QSettings settings(PENCIL2D, PENCIL2D);
90  settings.setValue("brushAA", AA);
91  settings.sync();
92 }
93 
95 {
96  return !mPoints.isEmpty();
97 }
98 
99 QCursor PolylineTool::cursor()
100 {
101  return QCursor(QPixmap(":icons/cross.png"), 10, 10);
102 }
103 
104 void PolylineTool::clearToolData()
105 {
106  mPoints.clear();
107 }
108 
109 void PolylineTool::pointerPressEvent(PointerEvent* event)
110 {
111  Layer* layer = mEditor->layers()->currentLayer();
112 
113  if (event->button() == Qt::LeftButton)
114  {
115  if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
116  {
117  mScribbleArea->handleDrawingOnEmptyFrame();
118 
119  if (layer->type() == Layer::VECTOR)
120  {
121  VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
122  Q_CHECK_PTR(vectorImage);
123  vectorImage->deselectAll();
124  if (mScribbleArea->makeInvisible() && !mEditor->preference()->isOn(SETTING::INVISIBLE_LINES))
125  {
126  mScribbleArea->toggleThinLines();
127  }
128  }
129  mPoints << getCurrentPoint();
130  mScribbleArea->setAllDirty();
131  }
132  }
133 }
134 
135 void PolylineTool::pointerMoveEvent(PointerEvent*)
136 {
137  Layer* layer = mEditor->layers()->currentLayer();
138  if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
139  {
140  drawPolyline(mPoints, getCurrentPoint());
141  }
142 }
143 
144 void PolylineTool::pointerReleaseEvent(PointerEvent *)
145 {}
146 
147 void PolylineTool::pointerDoubleClickEvent(PointerEvent*)
148 {
149  // include the current point before ending the line.
150  mPoints << getCurrentPoint();
151 
152  mEditor->backup(typeName());
153 
154  endPolyline(mPoints);
155  clearToolData();
156 }
157 
158 
159 bool PolylineTool::keyPressEvent(QKeyEvent* event)
160 {
161  switch (event->key())
162  {
163  case Qt::Key_Return:
164  if (mPoints.size() > 0)
165  {
166  endPolyline(mPoints);
167  clearToolData();
168  return true;
169  }
170  break;
171 
172  case Qt::Key_Escape:
173  if (mPoints.size() > 0)
174  {
175  cancelPolyline();
176  clearToolData();
177  return true;
178  }
179  break;
180 
181  default:
182  return false;
183  }
184 
185  return false;
186 }
187 
188 void PolylineTool::drawPolyline(QList<QPointF> points, QPointF endPoint)
189 {
190  if (points.size() > 0)
191  {
192  QPen pen(mEditor->color()->frontColor(),
193  properties.width,
195  Qt::RoundCap,
196  Qt::RoundJoin);
197  Layer* layer = mEditor->layers()->currentLayer();
198 
199  // Bitmap by default
200  QPainterPath tempPath;
201  if (properties.bezier_state)
202  {
203  tempPath = BezierCurve(points).getSimplePath();
204  }
205  else
206  {
207  tempPath = BezierCurve(points).getStraightPath();
208  }
209  tempPath.lineTo(endPoint);
210 
211  // Vector otherwise
212  if (layer->type() == Layer::VECTOR)
213  {
214  if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR)
215  {
216  tempPath = mEditor->view()->mapCanvasToScreen(tempPath);
217  if (mScribbleArea->makeInvisible() == true)
218  {
219  pen.setWidth(0);
220  pen.setStyle(Qt::DotLine);
221  }
222  else
223  {
224  pen.setWidth(properties.width * mEditor->view()->scaling());
225  }
226  }
227  }
228 
229  mScribbleArea->drawPolyline(tempPath, pen, properties.useAA);
230  }
231 }
232 
233 
234 void PolylineTool::cancelPolyline()
235 {
236  // Clear the in-progress polyline from the bitmap buffer.
237  mScribbleArea->clearBitmapBuffer();
238  mScribbleArea->updateCurrentFrame();
239 }
240 
241 void PolylineTool::endPolyline(QList<QPointF> points)
242 {
243  Layer* layer = mEditor->layers()->currentLayer();
244  mScribbleArea->clearBitmapBuffer();
245 
246  if (layer->type() == Layer::VECTOR)
247  {
248  BezierCurve curve = BezierCurve(points, properties.bezier_state);
249  if (mScribbleArea->makeInvisible() == true)
250  {
251  curve.setWidth(0);
252  }
253  else
254  {
255  curve.setWidth(properties.width);
256  }
257  curve.setColorNumber(mEditor->color()->frontColorNumber());
258  curve.setVariableWidth(false);
259  curve.setInvisibility(mScribbleArea->makeInvisible());
260 
261  VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
262  if (vectorImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
263  vectorImage->addCurve(curve, mEditor->view()->scaling());
264  }
265  if (layer->type() == Layer::BITMAP)
266  {
267  drawPolyline(points, points.last());
268  BitmapImage *bitmapImage = static_cast<LayerBitmap*>(layer)->getLastBitmapImageAtFrame(mEditor->currentFrame(), 0);
269  if (bitmapImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
270  bitmapImage->paste(mScribbleArea->mBufferImg);
271  }
272 
273  mScribbleArea->setAllDirty();
274  mScribbleArea->clearBitmapBuffer();
275  mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
276 }
void clear()
SolidLine
virtual bool isActive() override
Check if the tool is active.
LeftButton
void deselectAll()
VectorImage::deselectAll.
RoundCap
int size() const const
void handleDrawingOnEmptyFrame()
Call this when starting to use a paint tool.
void lineTo(const QPointF &endPoint)
bool isEmpty() const const
Definition: layer.h:39
void addCurve(BezierCurve &newCurve, qreal factor, bool interacts=true)
VectorImage::addCurve.
int key() const const
RoundJoin
T & last()
Qt::MouseButton button() const
Returns Qt::MouseButton()
Key_Return