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
buckettool.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 "buckettool.h"
18
19#include <QPixmap>
20#include <QPainter>
21#include <QSettings>
22#include "pointerevent.h"
23
24#include "layer.h"
25#include "layervector.h"
26#include "layerbitmap.h"
27#include "layercamera.h"
28#include "layermanager.h"
29#include "colormanager.h"
30#include "viewmanager.h"
31#include "vectorimage.h"
32#include "editor.h"
33#include "scribblearea.h"
34
35
36BucketTool::BucketTool(QObject* parent) : StrokeTool(parent)
37{
38}
39
40ToolType BucketTool::type()
41{
42 return BUCKET;
43}
44
45void BucketTool::loadSettings()
46{
47 mPropertyEnabled[TOLERANCE] = true;
48 mPropertyEnabled[WIDTH] = true;
49 mPropertyEnabled[FILL_MODE] = true;
50
51 QSettings settings(PENCIL2D, PENCIL2D);
52
53 properties.width = settings.value("fillThickness", 4.0).toDouble();
54 properties.feather = 10;
55 properties.stabilizerLevel = StabilizationLevel::NONE;
56 properties.useAA = DISABLED;
57 properties.tolerance = settings.value(SETTING_BUCKET_TOLERANCE, 32.0).toDouble();
58 properties.toleranceEnabled = settings.value(SETTING_BUCKET_TOLERANCE_ON, false).toBool();
59
60 properties.bucketFillExpand = settings.value(SETTING_BUCKET_FILL_EXPAND, 2.0).toInt();
61 properties.bucketFillExpandEnabled = settings.value(SETTING_BUCKET_FILL_EXPAND_ON, true).toBool();
62 properties.bucketFillReferenceMode = settings.value(SETTING_BUCKET_FILL_REFERENCE_MODE, 0).toInt();
63 properties.fillMode = settings.value(SETTING_FILL_MODE, 0).toInt();
64}
65
66void BucketTool::saveSettings()
67{
68 QSettings settings(PENCIL2D, PENCIL2D);
69
70 settings.setValue("fillThickness", properties.width);
71 settings.setValue(SETTING_BUCKET_TOLERANCE, properties.tolerance);
72 settings.setValue(SETTING_BUCKET_TOLERANCE_ON, properties.toleranceEnabled);
73 settings.setValue(SETTING_BUCKET_FILL_EXPAND, properties.bucketFillExpand);
74 settings.setValue(SETTING_BUCKET_FILL_EXPAND_ON, properties.bucketFillExpandEnabled);
75 settings.setValue(SETTING_BUCKET_FILL_REFERENCE_MODE, properties.bucketFillReferenceMode);
76 settings.setValue(SETTING_FILL_MODE, properties.fillMode);
77
78 settings.sync();
79}
80
81void BucketTool::resetToDefault()
82{
83 setWidth(4.0);
84 setTolerance(32.0);
85 setFillMode(0);
86 setFillExpand(2);
87 setFillExpandEnabled(true);
88 setToleranceEnabled(false);
89 setFillReferenceMode(0);
90}
91
92QCursor BucketTool::cursor()
93{
94 if (mEditor->preference()->isOn(SETTING::TOOL_CURSOR))
95 {
96 return QCursor(QPixmap(":icons/general/cursor-bucket.svg"), -1, 17);
97 }
98 else
99 {
100 return QCursor(QPixmap(":icons/general/cross.png"), 10, 10);
101 }
102}
103
104void BucketTool::setTolerance(const int tolerance)
105{
106 // Set current property
107 properties.tolerance = tolerance;
108}
109
115void BucketTool::setWidth(const qreal width)
116{
117 // Set current property
118 properties.width = width;
119}
120
121void BucketTool::setFillMode(int mode)
122{
123 // Set current property
124 properties.fillMode = mode;
125}
126
127void BucketTool::setToleranceEnabled(const bool enabled)
128{
129 properties.toleranceEnabled = enabled;
130
131}
132
133void BucketTool::setFillExpandEnabled(const bool enabled)
134{
135 properties.bucketFillExpandEnabled = enabled;
136
137}
138
139void BucketTool::setFillExpand(const int fillExpandValue)
140{
141 properties.bucketFillExpand = fillExpandValue;
142}
143
144void BucketTool::setFillReferenceMode(int referenceMode)
145{
146 properties.bucketFillReferenceMode = referenceMode;
147}
148
149void BucketTool::pointerPressEvent(PointerEvent* event)
150{
151 mInterpolator.pointerPressEvent(event);
152 startStroke(event->inputType());
153
154 Layer* targetLayer = mEditor->layers()->currentLayer();
155
156 if (targetLayer->type() != Layer::BITMAP) { return; }
157
158 LayerCamera* layerCam = mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex());
159
160 mBitmapBucket = BitmapBucket(mEditor,
161 mEditor->color()->frontColor(),
162 layerCam ? layerCam->getViewAtFrame(mEditor->currentFrame()).inverted().mapRect(layerCam->getViewRect()) : QRect(),
163 getCurrentPoint(),
164 properties);
165
166 // Because we can change layer to on the fly, but we do not act reactively
167 // on it, it's necessary to invalidate layer cache on press event.
168 // Otherwise, the cache will be drawn until a move event has been initiated.
169 mScribbleArea->invalidatePainterCaches();
170}
171
172void BucketTool::pointerMoveEvent(PointerEvent* event)
173{
174 mInterpolator.pointerMoveEvent(event);
175 if (event->buttons() & Qt::LeftButton && event->inputType() == mCurrentInputType)
176 {
177 Layer* layer = mEditor->layers()->currentLayer();
178 if (layer->type() == Layer::VECTOR)
179 {
180 drawStroke();
181 }
182 else if (layer->type() == Layer::BITMAP)
183 {
184 paintBitmap();
185 mFilledOnMove = true;
186 }
187 }
188}
189
190void BucketTool::pointerReleaseEvent(PointerEvent* event)
191{
192 mInterpolator.pointerReleaseEvent(event);
193 if (event->inputType() != mCurrentInputType) return;
194
195 Layer* layer = editor()->layers()->currentLayer();
196 if (layer == nullptr) { return; }
197
198 if (event->button() == Qt::LeftButton)
199 {
200 // Backup of bitmap image is more complicated now and has therefore been moved to bitmap code
201 if (layer->type() == Layer::VECTOR) {
202 mEditor->backup(typeName());
203 paintVector(layer);
204 }
205 else if (layer->type() == Layer::BITMAP && !mFilledOnMove)
206 {
207 paintBitmap();
208 }
209 }
210 mFilledOnMove = false;
211
212 endStroke();
213}
214
215void BucketTool::paintBitmap()
216{
217 mBitmapBucket.paint(getCurrentPoint(), [this](BucketState progress, int layerIndex, int frameIndex)
218 {
219 if (progress == BucketState::WillFillTarget)
220 {
221 mEditor->backup(layerIndex, frameIndex, typeName());
222 }
223 else if (progress == BucketState::DidFillTarget)
224 {
225 mEditor->setModified(layerIndex, frameIndex);
226 }
227 });
228}
229
230void BucketTool::paintVector(Layer* layer)
231{
232 mScribbleArea->clearDrawingBuffer();
233
234 VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
235 if (vectorImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
236
237 if (!vectorImage->isPathFilled())
238 {
239 vectorImage->fillSelectedPath(mEditor->color()->frontColorNumber());
240 }
241
242 vectorImage->applyWidthToSelection(properties.width);
243 vectorImage->applyColorToSelectedCurve(mEditor->color()->frontColorNumber());
244 vectorImage->applyColorToSelectedArea(mEditor->color()->frontColorNumber());
245
246 applyChanges();
247
248 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
249}
250
251void BucketTool::applyChanges()
252{
253 mScribbleArea->applyTransformedSelection();
254}
255
256void BucketTool::drawStroke()
257{
258 StrokeTool::drawStroke();
259
260 if (properties.stabilizerLevel != mInterpolator.getStabilizerLevel())
261 {
262 mInterpolator.setStabilizerLevel(properties.stabilizerLevel);
263 }
264
265 QList<QPointF> p = mInterpolator.interpolateStroke();
266
267 Layer* layer = mEditor->layers()->currentLayer();
268
269 if (layer->type() == Layer::VECTOR)
270 {
271 mCurrentWidth = 30;
272 QColor pathColor = qPremultiply(mEditor->color()->frontColor().rgba());
273
274 QPen pen(pathColor,
275 mCurrentWidth * mEditor->view()->scaling(),
276 Qt::NoPen,
277 Qt::RoundCap,
278 Qt::RoundJoin);
279
280 if (p.size() == 4)
281 {
282 QPainterPath path(p[0]);
283 path.cubicTo(p[1], p[2], p[3]);
284 mScribbleArea->drawPath(path, pen, Qt::NoBrush, QPainter::CompositionMode_Source);
285 }
286 }
287}
BitmapBucket
Definition: bitmapbucket.h:35
BitmapBucket::paint
void paint(const QPointF &updatedPoint, std::function< void(BucketState, int, int)> progress)
Will paint at the given point, given that it makes sense.
Definition: bitmapbucket.cpp:114
BucketTool::setWidth
void setWidth(const qreal width) override
BrushTool::setWidth.
Definition: buckettool.cpp:115
ColorManager::frontColor
QColor frontColor(bool useIndexedColor=true)
frontColor
Definition: colormanager.cpp:61
LayerCamera
Definition: layercamera.h:30
Layer
Definition: layer.h:33
LayerVector
Definition: layervector.h:26
PointerEvent
Definition: pointerevent.h:8
ScribbleArea::invalidatePainterCaches
void invalidatePainterCaches()
Invalidate the layer pixmap and camera painter caches.
Definition: scribblearea.cpp:283
StrokeTool
Definition: stroketool.h:34
VectorImage
Definition: vectorimage.h:32
VectorImage::applyColorToSelectedArea
void applyColorToSelectedArea(int colorNumber)
VectorImage::applyColorToSelectedArea.
Definition: vectorimage.cpp:1315
VectorImage::fillSelectedPath
void fillSelectedPath(int color)
VectorImage::fillSelectedPath.
Definition: vectorimage.cpp:1789
VectorImage::isPathFilled
bool isPathFilled()
VectorImage::isPathFilled.
Definition: vectorimage.cpp:705
VectorImage::applyColorToSelectedCurve
void applyColorToSelectedCurve(int colorNumber)
VectorImage::applyColorToSelectedCurve.
Definition: vectorimage.cpp:1302
VectorImage::applyWidthToSelection
void applyWidthToSelection(qreal width)
VectorImage::applyWidthToSelection.
Definition: vectorimage.cpp:1328
QColor
QColor::rgba
QRgb rgba() const const
QCursor
QList
QList::size
int size() const const
QObject
QObject::event
virtual bool event(QEvent *e)
QPainter::CompositionMode_Source
CompositionMode_Source
QPainterPath
QPen
QPixmap
QRect
QSettings
Qt::NoBrush
NoBrush
Qt::LeftButton
LeftButton
Qt::RoundCap
RoundCap
Qt::RoundJoin
RoundJoin
Qt::NoPen
NoPen
QTransform::inverted
QTransform inverted(bool *invertible) const const
QTransform::mapRect
QRect mapRect(const QRect &rectangle) const const
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39