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
erasertool.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#include "erasertool.h"
18
19#include <QSettings>
20#include <QPixmap>
21#include <QPainter>
22
23#include "editor.h"
24#include "blitrect.h"
25#include "scribblearea.h"
26#include "layermanager.h"
27#include "viewmanager.h"
28#include "undoredomanager.h"
29#include "layervector.h"
30#include "vectorimage.h"
31#include "pointerevent.h"
32
33
34EraserTool::EraserTool(QObject* parent) : StrokeTool(parent)
35{
36}
37
38ToolType EraserTool::type()
39{
40 return ERASER;
41}
42
43void EraserTool::loadSettings()
44{
45 StrokeTool::loadSettings();
46
47 mPropertyEnabled[WIDTH] = true;
48 mPropertyEnabled[USEFEATHER] = true;
49 mPropertyEnabled[FEATHER] = true;
50 mPropertyEnabled[USEFEATHER] = true;
51 mPropertyEnabled[PRESSURE] = true;
52 mPropertyEnabled[STABILIZATION] = true;
53 mPropertyEnabled[ANTI_ALIASING] = true;
54
55 QSettings settings(PENCIL2D, PENCIL2D);
56
57 properties.width = settings.value("eraserWidth", 24.0).toDouble();
58 properties.feather = settings.value("eraserFeather", 48.0).toDouble();
59 properties.useFeather = settings.value("eraserUseFeather", true).toBool();
60 properties.pressure = settings.value("eraserPressure", true).toBool();
61 properties.invisibility = DISABLED;
62 properties.preserveAlpha = OFF;
63 properties.stabilizerLevel = settings.value("stabilizerLevel", StabilizationLevel::NONE).toInt();
64 properties.useAA = settings.value("eraserAA", 1).toInt();
65
66 if (properties.useFeather) { properties.useAA = -1; }
67
68 mQuickSizingProperties.insert(Qt::ShiftModifier, WIDTH);
69 mQuickSizingProperties.insert(Qt::ControlModifier, FEATHER);
70}
71
72void EraserTool::saveSettings()
73{
74 QSettings settings(PENCIL2D, PENCIL2D);
75
76 settings.setValue("eraserWidth", properties.width);
77 settings.setValue("eraserFeather", properties.feather);
78 settings.setValue("eraserUseFeather", properties.useFeather);
79 settings.setValue("eraserPressure", properties.pressure);
80 settings.setValue("eraserAA", properties.useAA);
81 settings.setValue("stabilizerLevel", properties.stabilizerLevel);
82
83 settings.sync();
84}
85
86void EraserTool::resetToDefault()
87{
88 setWidth(24.0);
89 setFeather(48.0);
90 setUseFeather(true);
91 setPressure(true);
92 setAA(true);
93 setStabilizerLevel(StabilizationLevel::NONE);
94}
95
96void EraserTool::setWidth(const qreal width)
97{
98 // Set current property
99 properties.width = width;
100}
101
102void EraserTool::setUseFeather(const bool usingFeather)
103{
104 // Set current property
105 properties.useFeather = usingFeather;
106}
107
108void EraserTool::setFeather(const qreal feather)
109{
110 // Set current property
111 properties.feather = feather;
112}
113
114void EraserTool::setPressure(const bool pressure)
115{
116 // Set current property
117 properties.pressure = pressure;
118}
119
120void EraserTool::setAA(const int AA)
121{
122 // Set current property
123 properties.useAA = AA;
124}
125
126void EraserTool::setStabilizerLevel(const int level)
127{
128 properties.stabilizerLevel = level;
129}
130
131
132QCursor EraserTool::cursor()
133{
134 return QCursor(QPixmap(":icons/general/cross.png"), 10, 10);
135}
136
137void EraserTool::pointerPressEvent(PointerEvent *event)
138{
139 mInterpolator.pointerPressEvent(event);
140 if (handleQuickSizing(event)) {
141 return;
142 }
143
144 startStroke(event->inputType());
145 mLastBrushPoint = getCurrentPoint();
146 mMouseDownPoint = getCurrentPoint();
147
148 StrokeTool::pointerPressEvent(event);
149}
150
151void EraserTool::pointerMoveEvent(PointerEvent* event)
152{
153 mInterpolator.pointerMoveEvent(event);
154 if (handleQuickSizing(event)) {
155 return;
156 }
157
158 if (event->buttons() & Qt::LeftButton && event->inputType() == mCurrentInputType)
159 {
160 mCurrentPressure = mInterpolator.getPressure();
161 updateStrokes();
162 if (properties.stabilizerLevel != mInterpolator.getStabilizerLevel())
163 {
164 mInterpolator.setStabilizerLevel(properties.stabilizerLevel);
165 }
166 }
167
168 StrokeTool::pointerMoveEvent(event);
169}
170
171void EraserTool::pointerReleaseEvent(PointerEvent *event)
172{
173 mInterpolator.pointerReleaseEvent(event);
174 if (handleQuickSizing(event)) {
175 return;
176 }
177
178 if (event->inputType() != mCurrentInputType) return;
179
180 mEditor->backup(typeName());
181
182 qreal distance = QLineF(getCurrentPoint(), mMouseDownPoint).length();
183 if (distance < 1)
184 {
185 paintAt(mMouseDownPoint);
186 }
187 else
188 {
189 drawStroke();
190 }
191
192 removeVectorPaint();
193 endStroke();
194
195 StrokeTool::pointerReleaseEvent(event);
196}
197
198// draw a single paint dab at the given location
199void EraserTool::paintAt(QPointF point)
200{
201 Layer* layer = mEditor->layers()->currentLayer();
202 if (layer->type() == Layer::BITMAP)
203 {
204 qreal pressure = (properties.pressure) ? mCurrentPressure : 1.0;
205 qreal opacity = (properties.pressure) ? (mCurrentPressure * 0.5) : 1.0;
206 qreal brushWidth = properties.width * pressure;
207 mCurrentWidth = brushWidth;
208
209 mScribbleArea->drawBrush(point,
210 brushWidth,
211 properties.feather,
212 QColor(255, 255, 255, 255),
213 QPainter::CompositionMode_SourceOver,
214 opacity,
215 properties.useFeather,
216 properties.useAA == ON);
217 }
218}
219
220void EraserTool::drawStroke()
221{
222 StrokeTool::drawStroke();
223 QList<QPointF> p = mInterpolator.interpolateStroke();
224
225 Layer* layer = mEditor->layers()->currentLayer();
226
227 if (layer->type() == Layer::BITMAP)
228 {
229 qreal pressure = (properties.pressure) ? mCurrentPressure : 1.0;
230 qreal opacity = (properties.pressure) ? (mCurrentPressure * 0.5) : 1.0;
231 qreal brushWidth = properties.width * pressure;
232 mCurrentWidth = brushWidth;
233
234 qreal brushStep = (0.5 * brushWidth);
235 brushStep = qMax(1.0, brushStep);
236
237 BlitRect rect;
238
239 QPointF a = mLastBrushPoint;
240 QPointF b = getCurrentPoint();
241
242 qreal distance = 4 * QLineF(b, a).length();
243 int steps = qRound(distance / brushStep);
244
245 for (int i = 0; i < steps; i++)
246 {
247 QPointF point = mLastBrushPoint + (i + 1) * brushStep * (getCurrentPoint() - mLastBrushPoint) / distance;
248
249 mScribbleArea->drawBrush(point,
250 brushWidth,
251 properties.feather,
252 Qt::white,
253 QPainter::CompositionMode_SourceOver,
254 opacity,
255 properties.useFeather,
256 properties.useAA == ON);
257 if (i == (steps - 1))
258 {
259 mLastBrushPoint = getCurrentPoint();
260 }
261 }
262 }
263 else if (layer->type() == Layer::VECTOR)
264 {
265 mCurrentWidth = properties.width;
266 if (properties.pressure)
267 {
268 mCurrentWidth = (mCurrentWidth + (mInterpolator.getPressure() * mCurrentWidth)) * 0.5;
269 }
270 qreal brushWidth = mCurrentWidth;
271
272 QPen pen(Qt::white, brushWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
273
274 if (p.size() == 4)
275 {
276 QPainterPath path(p[0]);
277 path.cubicTo(p[1],
278 p[2],
279 p[3]);
280 mScribbleArea->drawPath(path, pen, Qt::NoBrush, QPainter::CompositionMode_Source);
281 }
282 }
283}
284
285void EraserTool::removeVectorPaint()
286{
287 Layer* layer = mEditor->layers()->currentLayer();
288 if (layer->type() == Layer::VECTOR)
289 {
290 mScribbleArea->clearDrawingBuffer();
291 VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
292 if (vectorImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
293 // Clear the area containing the last point
294 //vectorImage->removeArea(lastPoint);
295 // Clear the temporary pixel path
296 vectorImage->deleteSelectedPoints();
297
298 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
299 }
300}
301
302void EraserTool::updateStrokes()
303{
304 Layer* layer = mEditor->layers()->currentLayer();
305 if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
306 {
307 drawStroke();
308 }
309
310 if (layer->type() == Layer::VECTOR)
311 {
312 qreal radius = properties.width / 2;
313
314 VectorImage* currKey = static_cast<VectorImage*>(layer->getLastKeyFrameAtPosition(mEditor->currentFrame()));
315 QList<VertexRef> nearbyVertices = currKey->getVerticesCloseTo(getCurrentPoint(), radius);
316 for (auto nearbyVertice : nearbyVertices)
317 {
318 currKey->setSelected(nearbyVertice, true);
319 }
320 }
321}
BlitRect
Definition: blitrect.h:25
Layer
Definition: layer.h:33
LayerVector
Definition: layervector.h:26
PointerEvent
Definition: pointerevent.h:8
StrokeTool
Definition: stroketool.h:34
StrokeTool::loadSettings
void loadSettings() override
Definition: stroketool.cpp:58
VectorImage
Definition: vectorimage.h:32
VectorImage::setSelected
void setSelected(int curveNumber, bool YesOrNo)
VectorImage::setSelected.
Definition: vectorimage.cpp:616
VectorImage::deleteSelectedPoints
void deleteSelectedPoints()
VectorImage::deleteSelectedPoints.
Definition: vectorimage.cpp:1030
VectorImage::getVerticesCloseTo
QList< VertexRef > getVerticesCloseTo(QPointF thisPoint, qreal maxDistance)
VectorImage::getVerticesCloseTo.
Definition: vectorimage.cpp:1458
QColor
QCursor
QHash::insert
QHash::iterator insert(const Key &key, const T &value)
QLineF
QLineF::length
qreal length() const const
QList
QList::size
int size() const const
QObject
QObject::event
virtual bool event(QEvent *e)
QPainter::CompositionMode_SourceOver
CompositionMode_SourceOver
QPainterPath
QPen
QPixmap
QPointF
QSettings
Qt::NoBrush
NoBrush
Qt::white
white
Qt::ShiftModifier
ShiftModifier
Qt::LeftButton
LeftButton
Qt::RoundCap
RoundCap
Qt::RoundJoin
RoundJoin
Qt::SolidLine
SolidLine
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39