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 
94 bool PolylineTool::leavingThisTool()
95 {
96  if (mPoints.size() > 0)
97  {
98  cancelPolyline();
99  clearToolData();
100  }
101  return true;
102 }
103 
105 {
106  return !mPoints.isEmpty();
107 }
108 
109 QCursor PolylineTool::cursor()
110 {
111  return QCursor(QPixmap(":icons/cross.png"), 10, 10);
112 }
113 
114 void PolylineTool::clearToolData()
115 {
116  mPoints.clear();
117  emit isActiveChanged(POLYLINE, false);
118 }
119 
120 void PolylineTool::pointerPressEvent(PointerEvent* event)
121 {
122  Layer* layer = mEditor->layers()->currentLayer();
123 
124  if (event->button() == Qt::LeftButton)
125  {
126  if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
127  {
128  mScribbleArea->handleDrawingOnEmptyFrame();
129 
130  if (layer->type() == Layer::VECTOR)
131  {
132  VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
133  Q_CHECK_PTR(vectorImage);
134  vectorImage->deselectAll();
135  if (mScribbleArea->makeInvisible() && !mEditor->preference()->isOn(SETTING::INVISIBLE_LINES))
136  {
137  mScribbleArea->toggleThinLines();
138  }
139  }
140  mPoints << getCurrentPoint();
141  emit isActiveChanged(POLYLINE, true);
142  }
143  }
144 }
145 
146 void PolylineTool::pointerMoveEvent(PointerEvent*)
147 {
148  Layer* layer = mEditor->layers()->currentLayer();
149  if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
150  {
151  drawPolyline(mPoints, getCurrentPoint());
152  }
153 }
154 
155 void PolylineTool::pointerReleaseEvent(PointerEvent *)
156 {}
157 
158 void PolylineTool::pointerDoubleClickEvent(PointerEvent*)
159 {
160  // include the current point before ending the line.
161  mPoints << getCurrentPoint();
162 
163  mEditor->backup(typeName());
164 
165  endPolyline(mPoints);
166  clearToolData();
167 }
168 
169 
170 bool PolylineTool::keyPressEvent(QKeyEvent* event)
171 {
172  switch (event->key())
173  {
174  case Qt::Key_Return:
175  if (mPoints.size() > 0)
176  {
177  endPolyline(mPoints);
178  clearToolData();
179  return true;
180  }
181  break;
182 
183  case Qt::Key_Escape:
184  if (mPoints.size() > 0)
185  {
186  cancelPolyline();
187  clearToolData();
188  return true;
189  }
190  break;
191 
192  default:
193  break;
194  }
195 
196  return BaseTool::keyPressEvent(event);
197 }
198 
199 void PolylineTool::drawPolyline(QList<QPointF> points, QPointF endPoint)
200 {
201  if (points.size() > 0)
202  {
203  QPen pen(mEditor->color()->frontColor(),
204  properties.width,
206  Qt::RoundCap,
207  Qt::RoundJoin);
208  Layer* layer = mEditor->layers()->currentLayer();
209 
210  // Bitmap by default
211  QPainterPath tempPath;
212  if (properties.bezier_state)
213  {
214  tempPath = BezierCurve(points).getSimplePath();
215  }
216  else
217  {
218  tempPath = BezierCurve(points).getStraightPath();
219  }
220  tempPath.lineTo(endPoint);
221 
222  // Vector otherwise
223  if (layer->type() == Layer::VECTOR)
224  {
225  if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR)
226  {
227  tempPath = mEditor->view()->mapCanvasToScreen(tempPath);
228  if (mScribbleArea->makeInvisible() == true)
229  {
230  pen.setWidth(0);
231  pen.setStyle(Qt::DotLine);
232  }
233  else
234  {
235  pen.setWidth(properties.width * mEditor->view()->scaling());
236  }
237  }
238  }
239 
240  mScribbleArea->drawPolyline(tempPath, pen, properties.useAA);
241  }
242 }
243 
244 
245 void PolylineTool::cancelPolyline()
246 {
247  // Clear the in-progress polyline from the bitmap buffer.
248  mScribbleArea->clearBitmapBuffer();
249  mScribbleArea->updateCurrentFrame();
250 }
251 
252 void PolylineTool::endPolyline(QList<QPointF> points)
253 {
254  Layer* layer = mEditor->layers()->currentLayer();
255  mScribbleArea->clearBitmapBuffer();
256 
257  if (layer->type() == Layer::VECTOR)
258  {
259  BezierCurve curve = BezierCurve(points, properties.bezier_state);
260  if (mScribbleArea->makeInvisible() == true)
261  {
262  curve.setWidth(0);
263  }
264  else
265  {
266  curve.setWidth(properties.width);
267  }
268  curve.setColorNumber(mEditor->color()->frontColorNumber());
269  curve.setVariableWidth(false);
270  curve.setInvisibility(mScribbleArea->makeInvisible());
271 
272  VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
273  if (vectorImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
274  vectorImage->addCurve(curve, mEditor->view()->scaling());
275  }
276  if (layer->type() == Layer::BITMAP)
277  {
278  drawPolyline(points, points.last());
279  BitmapImage *bitmapImage = static_cast<LayerBitmap*>(layer)->getLastBitmapImageAtFrame(mEditor->currentFrame(), 0);
280  if (bitmapImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
281  bitmapImage->paste(mScribbleArea->mBufferImg);
282  }
283 
284  mScribbleArea->clearBitmapBuffer();
285  mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
286 }
void clear()
SolidLine
virtual bool isActive() override
Check if the tool is active.
LeftButton
void setModified(int layerNumber, int frameNumber)
Set frame on layer to modified and invalidate current frame cache.
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:38
void addCurve(BezierCurve &newCurve, qreal factor, bool interacts=true)
VectorImage::addCurve.
int key() const const
RoundJoin
QColor frontColor(bool useIndexedColor=true)
frontColor
T & last()
Qt::MouseButton button() const
Returns Qt::MouseButton()
void updateCurrentFrame()
Update current frame.
Key_Return