Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • core_lib
  • src
  • tool
polylinetool.cpp
1/*
2
3Pencil2D - Traditional Animation Software
4Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5Copyright (C) 2012-2020 Matthew Chiawen Chang
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation; version 2 of the License.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU 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 "layermanager.h"
25#include "colormanager.h"
26#include "viewmanager.h"
27#include "undoredomanager.h"
28#include "pointerevent.h"
29#include "layervector.h"
30#include "layerbitmap.h"
31#include "vectorimage.h"
32
33
34PolylineTool::PolylineTool(QObject* parent) : StrokeTool(parent)
35{
36}
37
38ToolType PolylineTool::type()
39{
40 return POLYLINE;
41}
42
43void PolylineTool::loadSettings()
44{
45 StrokeTool::loadSettings();
46
47 mPropertyEnabled[WIDTH] = true;
48 mPropertyEnabled[BEZIER] = true;
49 mPropertyEnabled[CLOSEDPATH] = true;
50 mPropertyEnabled[ANTI_ALIASING] = true;
51
52 QSettings settings(PENCIL2D, PENCIL2D);
53
54 properties.width = settings.value("polyLineWidth", 8.0).toDouble();
55 properties.feather = -1;
56 properties.pressure = false;
57 properties.invisibility = OFF;
58 properties.preserveAlpha = OFF;
59 properties.closedPolylinePath = settings.value("closedPolylinePath").toBool();
60 properties.useAA = settings.value("brushAA").toBool();
61 properties.stabilizerLevel = -1;
62
63 mQuickSizingProperties.insert(Qt::ShiftModifier, WIDTH);
64}
65
66void PolylineTool::saveSettings()
67{
68 QSettings settings(PENCIL2D, PENCIL2D);
69
70 settings.setValue("polyLineWidth", properties.width);
71 settings.setValue("brushAA", properties.useAA);
72 settings.setValue("closedPolylinePath", properties.closedPolylinePath);
73
74 settings.sync();
75}
76
77void PolylineTool::resetToDefault()
78{
79 setWidth(8.0);
80 setBezier(false);
81 setClosedPath(false);
82}
83
84void PolylineTool::setWidth(const qreal width)
85{
86 // Set current property
87 properties.width = width;
88}
89
90void PolylineTool::setFeather(const qreal feather)
91{
92 Q_UNUSED(feather);
93 properties.feather = -1;
94}
95
96void PolylineTool::setAA(const int AA)
97{
98 // Set current property
99 properties.useAA = AA;
100}
101
102void PolylineTool::setClosedPath(const bool closed)
103{
104 BaseTool::setClosedPath(closed);
105}
106
107bool PolylineTool::leavingThisTool()
108{
109 StrokeTool::leavingThisTool();
110 if (mPoints.size() > 0)
111 {
112 cancelPolyline();
113 }
114 return true;
115}
116
117bool PolylineTool::isActive() const
118{
119 return !mPoints.isEmpty();
120}
121
122QCursor PolylineTool::cursor()
123{
124 return QCursor(QPixmap(":icons/general/cross.png"), 10, 10);
125}
126
127void PolylineTool::clearToolData()
128{
129 if (mPoints.empty()) {
130 return;
131 }
132
133 mPoints.clear();
134 emit isActiveChanged(POLYLINE, false);
135
136 // Clear the in-progress polyline from the bitmap buffer.
137 mScribbleArea->clearDrawingBuffer();
138 mScribbleArea->updateFrame();
139}
140
141void PolylineTool::pointerPressEvent(PointerEvent* event)
142{
143 mInterpolator.pointerPressEvent(event);
144 if (handleQuickSizing(event)) {
145 return;
146 }
147
148 Layer* layer = mEditor->layers()->currentLayer();
149
150 if (event->button() == Qt::LeftButton)
151 {
152 if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
153 {
154 mScribbleArea->handleDrawingOnEmptyFrame();
155
156 if (layer->type() == Layer::VECTOR)
157 {
158 VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
159 Q_CHECK_PTR(vectorImage);
160 vectorImage->deselectAll();
161 if (mScribbleArea->makeInvisible() && !mEditor->preference()->isOn(SETTING::INVISIBLE_LINES))
162 {
163 mScribbleArea->toggleThinLines();
164 }
165 }
166 mPoints << getCurrentPoint();
167 emit isActiveChanged(POLYLINE, true);
168 }
169 }
170
171 StrokeTool::pointerPressEvent(event);
172}
173
174void PolylineTool::pointerMoveEvent(PointerEvent* event)
175{
176 mInterpolator.pointerMoveEvent(event);
177 if (handleQuickSizing(event)) {
178 return;
179 }
180
181 Layer* layer = mEditor->layers()->currentLayer();
182 if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
183 {
184 drawPolyline(mPoints, getCurrentPoint());
185 }
186
187 StrokeTool::pointerMoveEvent(event);
188}
189
190void PolylineTool::pointerReleaseEvent(PointerEvent* event)
191{
192 mInterpolator.pointerReleaseEvent(event);
193 if (handleQuickSizing(event)) {
194 return;
195 }
196
197 StrokeTool::pointerReleaseEvent(event);
198}
199
200void PolylineTool::pointerDoubleClickEvent(PointerEvent* event)
201{
202 mInterpolator.pointerPressEvent(event);
203 // include the current point before ending the line.
204 mPoints << getCurrentPoint();
205
206 const UndoSaveState* saveState = mEditor->undoRedo()->state(UndoRedoRecordType::KEYFRAME_MODIFY);
207 mEditor->backup(typeName());
208
209 endPolyline(mPoints);
210 mEditor->undoRedo()->record(saveState, typeName());
211}
212
213void PolylineTool::removeLastPolylineSegment()
214{
215 if (mPoints.size() > 1)
216 {
217 mPoints.removeLast();
218 drawPolyline(mPoints, getCurrentPoint());
219 }
220 else if (mPoints.size() == 1)
221 {
222 cancelPolyline();
223 clearToolData();
224 }
225}
226
227bool PolylineTool::keyPressEvent(QKeyEvent* event)
228{
229 switch (event->key())
230 {
231 case Qt::Key_Control:
232 mClosedPathOverrideEnabled = true;
233 drawPolyline(mPoints, getCurrentPoint());
234 return true;
235 break;
236
237 case Qt::Key_Return:
238 if (mPoints.size() > 0)
239 {
240 const UndoSaveState* saveState = mEditor->undoRedo()->state(UndoRedoRecordType::KEYFRAME_MODIFY);
241 endPolyline(mPoints);
242 mEditor->undoRedo()->record(saveState, typeName());
243 return true;
244 }
245 break;
246 case Qt::Key_Backspace:
247 if (mPoints.size() > 0)
248 {
249 removeLastPolylineSegment();
250 return true;
251 }
252 case Qt::Key_Escape:
253 if (mPoints.size() > 0)
254 {
255 cancelPolyline();
256 return true;
257 }
258 break;
259
260 default:
261 break;
262 }
263
264 return BaseTool::keyPressEvent(event);
265}
266
267bool PolylineTool::keyReleaseEvent(QKeyEvent* event)
268{
269 switch (event->key())
270 {
271 case Qt::Key_Control:
272 mClosedPathOverrideEnabled = false;
273 drawPolyline(mPoints, getCurrentPoint());
274 return true;
275 break;
276
277 default:
278 break;
279 }
280
281 return BaseTool::keyReleaseEvent(event);
282}
283
284void PolylineTool::drawPolyline(QList<QPointF> points, QPointF endPoint)
285{
286 if (points.size() > 0)
287 {
288 QPen pen(mEditor->color()->frontColor(),
289 properties.width,
290 Qt::SolidLine,
291 Qt::RoundCap,
292 Qt::RoundJoin);
293 Layer* layer = mEditor->layers()->currentLayer();
294
295 // Bitmap by default
296 QPainterPath tempPath;
297 if (properties.bezier_state)
298 {
299 tempPath = BezierCurve(points).getSimplePath();
300 }
301 else
302 {
303 tempPath = BezierCurve(points).getStraightPath();
304 }
305 tempPath.lineTo(endPoint);
306
307 // Ctrl key inverts closed behavior while held (XOR)
308 if ((properties.closedPolylinePath == !mClosedPathOverrideEnabled) && points.size() > 1)
309 {
310 tempPath.closeSubpath();
311 }
312
313 // Vector otherwise
314 if (layer->type() == Layer::VECTOR)
315 {
316 if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR)
317 {
318 if (mScribbleArea->makeInvisible() == true)
319 {
320 pen.setWidth(0);
321 pen.setStyle(Qt::DotLine);
322 }
323 else
324 {
325 pen.setWidth(properties.width);
326 }
327 }
328 }
329
330 mScribbleArea->drawPolyline(tempPath, pen, properties.useAA);
331 }
332}
333
334
335void PolylineTool::cancelPolyline()
336{
337 clearToolData();
338}
339
340void PolylineTool::endPolyline(QList<QPointF> points)
341{
342 Layer* layer = mEditor->layers()->currentLayer();
343
344 if (layer->type() == Layer::VECTOR)
345 {
346 BezierCurve curve = BezierCurve(points, properties.bezier_state);
347 if (mScribbleArea->makeInvisible() == true)
348 {
349 curve.setWidth(0);
350 }
351 else
352 {
353 curve.setWidth(properties.width);
354 }
355 curve.setColorNumber(mEditor->color()->frontColorNumber());
356 curve.setVariableWidth(false);
357 curve.setInvisibility(mScribbleArea->makeInvisible());
358
359 VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
360 if (vectorImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
361 vectorImage->addCurve(curve, mEditor->view()->scaling());
362 }
363 if (layer->type() == Layer::BITMAP)
364 {
365 drawPolyline(points, points.last());
366 }
367
368 mScribbleArea->endStroke();
369 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
370
371 clearToolData();
372}
BezierCurve
Definition: beziercurve.h:34
ColorManager::frontColor
QColor frontColor(bool useIndexedColor=true)
frontColor
Definition: colormanager.cpp:61
Layer
Definition: layer.h:33
LayerVector
Definition: layervector.h:26
PointerEvent
Definition: pointerevent.h:8
PolylineTool::isActive
bool isActive() const override
Check if the tool is active.
Definition: polylinetool.cpp:117
PolylineTool::leavingThisTool
bool leavingThisTool() override
Will clean up active connections.
Definition: polylinetool.cpp:107
ScribbleArea::updateFrame
void updateFrame()
Update frame.
Definition: scribblearea.cpp:199
ScribbleArea::handleDrawingOnEmptyFrame
void handleDrawingOnEmptyFrame()
Call this when starting to use a paint tool.
Definition: scribblearea.cpp:827
StrokeTool
Definition: stroketool.h:34
StrokeTool::leavingThisTool
bool leavingThisTool() override
Will clean up active connections.
Definition: stroketool.cpp:74
StrokeTool::loadSettings
void loadSettings() override
Definition: stroketool.cpp:58
UndoRedoManager::record
void record(const UndoSaveState *&undoState, const QString &description)
Records the given save state.
Definition: undoredomanager.cpp:95
UndoRedoManager::state
const UndoSaveState * state(UndoRedoRecordType recordType) const
Prepares and returns a save state with the given scope.
Definition: undoredomanager.cpp:199
VectorImage
Definition: vectorimage.h:32
VectorImage::deselectAll
void deselectAll()
VectorImage::deselectAll.
Definition: vectorimage.cpp:839
VectorImage::addCurve
void addCurve(BezierCurve &newCurve, qreal factor, bool interacts=true)
VectorImage::addCurve.
Definition: vectorimage.cpp:341
QCursor
QHash::insert
QHash::iterator insert(const Key &key, const T &value)
QKeyEvent
QList
QList::clear
void clear()
QList::empty
bool empty() const const
QList::isEmpty
bool isEmpty() const const
QList::last
T & last()
QList::removeLast
void removeLast()
QList::size
int size() const const
QObject
QObject::event
virtual bool event(QEvent *e)
QPainterPath
QPainterPath::closeSubpath
void closeSubpath()
QPainterPath::lineTo
void lineTo(const QPointF &endPoint)
QPen
QPixmap
QPointF
QSettings
Qt::Key_Control
Key_Control
Qt::ShiftModifier
ShiftModifier
Qt::LeftButton
LeftButton
Qt::RoundCap
RoundCap
Qt::RoundJoin
RoundJoin
Qt::SolidLine
SolidLine
UndoSaveState
This is the main undo/redo state structure which is meant to populate whatever states that needs to b...
Definition: undoredomanager.h:80
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39