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 "toolmanager.h"
31#include "viewmanager.h"
32#include "vectorimage.h"
33#include "editor.h"
34#include "scribblearea.h"
35
36
37BucketTool::BucketTool(QObject* parent) : BaseTool(parent)
38{
39}
40
41void BucketTool::loadSettings()
42{
43 mPropertyUsed[BucketToolProperties::FILLTHICKNESS_VALUE] = { Layer::VECTOR };
44 mPropertyUsed[BucketToolProperties::COLORTOLERANCE_VALUE] = { Layer::BITMAP };
45 mPropertyUsed[BucketToolProperties::COLORTOLERANCE_ENABLED] = { Layer::BITMAP };
46 mPropertyUsed[BucketToolProperties::FILLEXPAND_VALUE] = { Layer::BITMAP };
47 mPropertyUsed[BucketToolProperties::FILLEXPAND_ENABLED] = { Layer::BITMAP };
48 mPropertyUsed[BucketToolProperties::FILLLAYERREFERENCEMODE_VALUE] = { Layer::BITMAP };
49 mPropertyUsed[BucketToolProperties::FILLMODE_VALUE] = { Layer::BITMAP };
50
51 QSettings pencilSettings(PENCIL2D, PENCIL2D);
52
53 QHash<int, PropertyInfo> info;
54
55 info[BucketToolProperties::FILLTHICKNESS_VALUE] = { 1.0, 100.0, 4.0 };
56 info[BucketToolProperties::COLORTOLERANCE_VALUE] = { 1, 100, 32 };
57 info[BucketToolProperties::COLORTOLERANCE_ENABLED] = false;
58 info[BucketToolProperties::FILLEXPAND_VALUE] = { 1, 25, 2 };
59 info[BucketToolProperties::FILLEXPAND_ENABLED] = true;
60 info[BucketToolProperties::FILLLAYERREFERENCEMODE_VALUE] = { 0, 1, 0 };
61 info[BucketToolProperties::FILLMODE_VALUE] = { 0, 2, 0 };
62
63 toolProperties().insertProperties(info);
64 toolProperties().loadFrom(typeName(), pencilSettings);
65
66 if (toolProperties().requireMigration(pencilSettings, ToolProperties::VERSION_1)) {
67 toolProperties().setBaseValue(BucketToolProperties::FILLTHICKNESS_VALUE, pencilSettings.value("fillThickness", 4.0).toReal());
68 toolProperties().setBaseValue(BucketToolProperties::COLORTOLERANCE_VALUE, pencilSettings.value("Tolerance", 32).toInt());
69 toolProperties().setBaseValue(BucketToolProperties::COLORTOLERANCE_ENABLED, pencilSettings.value("BucketToleranceEnabled", false).toBool());
70 toolProperties().setBaseValue(BucketToolProperties::FILLEXPAND_VALUE, pencilSettings.value("BucketFillExpand", 2).toInt());
71 toolProperties().setBaseValue(BucketToolProperties::FILLEXPAND_ENABLED, pencilSettings.value("BucketFillExpandEnabled", true).toBool());
72 toolProperties().setBaseValue(BucketToolProperties::FILLLAYERREFERENCEMODE_VALUE, pencilSettings.value("BucketFillReferenceMode", 0).toInt());
73 toolProperties().setBaseValue(BucketToolProperties::FILLMODE_VALUE, pencilSettings.value("FillMode", 0).toInt());
74
75 pencilSettings.remove("fillThickness");
76 pencilSettings.remove("Tolerance");
77 pencilSettings.remove("BucketToleranceEnabled");
78 pencilSettings.remove("BucketFillExpand");
79 pencilSettings.remove("BucketFillExpandEnabled");
80 pencilSettings.remove("BucketFillReferenceMode");
81 pencilSettings.remove("FillMode");
82 }
83}
84
85QCursor BucketTool::cursor()
86{
87 if (mEditor->preference()->isOn(SETTING::TOOL_CURSOR))
88 {
89 return QCursor(QPixmap(":icons/general/cursor-bucket.svg"), -1, 17);
90 }
91 else
92 {
93 return QCursor(QPixmap(":icons/general/cross.png"), 10, 10);
94 }
95}
96
97void BucketTool::pointerPressEvent(PointerEvent* event)
98{
99 mInterpolator.pointerPressEvent(event);
100
101 Layer* targetLayer = mEditor->layers()->currentLayer();
102
103 if (targetLayer->type() != Layer::BITMAP) { return; }
104
105 LayerCamera* layerCam = mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex());
106
107 mUndoSaveState = mEditor->undoRedo()->state(UndoRedoRecordType::KEYFRAME_MODIFY);
108 mBitmapBucket = BitmapBucket(mEditor,
109 mEditor->color()->frontColor(),
110 layerCam ? layerCam->getViewAtFrame(mEditor->currentFrame()).inverted().mapRect(layerCam->getViewRect()) : QRect(),
111 getCurrentPoint(),
112 mSettings);
113
114 // Because we can change layer to on the fly, but we do not act reactively
115 // on it, it's necessary to invalidate layer cache on press event.
116 // Otherwise, the cache will be drawn until a move event has been initiated.
117 mScribbleArea->invalidatePainterCaches();
118}
119
120void BucketTool::pointerMoveEvent(PointerEvent* event)
121{
122 mInterpolator.pointerMoveEvent(event);
123 if (event->buttons() & Qt::LeftButton)
124 {
125 Layer* layer = mEditor->layers()->currentLayer();
126 if (layer->type() == Layer::BITMAP)
127 {
128 paintBitmap();
129 mFilledOnMove = true;
130 }
131 }
132}
133
134void BucketTool::pointerReleaseEvent(PointerEvent* event)
135{
136 mInterpolator.pointerReleaseEvent(event);
137
138 Layer* layer = editor()->layers()->currentLayer();
139 if (layer == nullptr) { return; }
140
141 if (event->button() == Qt::LeftButton)
142 {
143 // Backup of bitmap image is more complicated now and has therefore been moved to bitmap code
144 if (layer->type() == Layer::VECTOR) {
145 mEditor->backup(typeName());
146 paintVector(layer);
147 }
148 else if (layer->type() == Layer::BITMAP && !mFilledOnMove)
149 {
150 paintBitmap();
151 }
152 }
153 mFilledOnMove = false;
154}
155
156void BucketTool::paintBitmap()
157{
158 mBitmapBucket.paint(getCurrentPoint(), [this](BucketState progress, int layerIndex, int frameIndex)
159 {
160 if (progress == BucketState::WillFillTarget)
161 {
162 mEditor->backup(layerIndex, frameIndex, typeName());
163 }
164 else if (progress == BucketState::DidFillTarget)
165 {
166 mEditor->undoRedo()->record(mUndoSaveState, typeName());
167 mEditor->setModified(layerIndex, frameIndex);
168 }
169 });
170}
171
172void BucketTool::paintVector(Layer* layer)
173{
174 mScribbleArea->clearDrawingBuffer();
175
176 VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
177 if (vectorImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
178
179 if (!vectorImage->isPathFilled())
180 {
181 vectorImage->fillSelectedPath(mEditor->color()->frontColorNumber());
182 }
183
184 vectorImage->applyWidthToSelection(mSettings.fillThickness());
185 vectorImage->applyColorToSelectedCurve(mEditor->color()->frontColorNumber());
186 vectorImage->applyColorToSelectedArea(mEditor->color()->frontColorNumber());
187
188 applyChanges();
189
190 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
191}
192
193void BucketTool::applyChanges()
194{
195 mScribbleArea->applyTransformedSelection();
196}
197
198void BucketTool::setStrokeThickness(qreal width)
199{
200 toolProperties().setBaseValue(BucketToolProperties::FILLTHICKNESS_VALUE, width);
201 emit strokeThicknessChanged(width);
202}
203
204void BucketTool::setColorTolerance(int tolerance)
205{
206 toolProperties().setBaseValue(BucketToolProperties::COLORTOLERANCE_VALUE, tolerance);
207 emit toleranceChanged(tolerance);
208}
209
210void BucketTool::setColorToleranceEnabled(bool enabled)
211{
212 toolProperties().setBaseValue(BucketToolProperties::COLORTOLERANCE_ENABLED, enabled);
213 emit toleranceEnabledChanged(enabled);
214}
215
216void BucketTool::setFillExpand(int fillExpandValue)
217{
218 toolProperties().setBaseValue(BucketToolProperties::FILLEXPAND_VALUE, fillExpandValue);
219 emit fillExpandChanged(fillExpandValue);
220}
221
222void BucketTool::setFillExpandEnabled(bool enabled)
223{
224 toolProperties().setBaseValue(BucketToolProperties::FILLEXPAND_ENABLED, enabled);
225 emit fillExpandEnabledChanged(enabled);
226}
227
228void BucketTool::setFillReferenceMode(int referenceMode)
229{
230 toolProperties().setBaseValue(BucketToolProperties::FILLLAYERREFERENCEMODE_VALUE, referenceMode);
231 emit fillReferenceModeChanged(referenceMode);
232}
233
234void BucketTool::setFillMode(int mode)
235{
236 toolProperties().setBaseValue(BucketToolProperties::FILLMODE_VALUE, mode);
237 emit fillModeChanged(mode);
238}
239
240QPointF BucketTool::getCurrentPoint() const
241{
242 return mEditor->view()->mapScreenToCanvas(getCurrentPixel());
243}
244
245QPointF BucketTool::getCurrentPixel() const
246{
247 return mInterpolator.getCurrentPixel();
248}
249
BaseTool
Definition: basetool.h:47
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
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:284
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::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
QCursor
QHash
QObject
QObject::event
virtual bool event(QEvent *e)
QPixmap
QPointF
QRect
QSettings
QSettings::remove
void remove(const QString &key)
QSettings::value
QVariant value(const QString &key, const QVariant &defaultValue) const const
Qt::LeftButton
LeftButton
QTransform::inverted
QTransform inverted(bool *invertible) const const
QTransform::mapRect
QRect mapRect(const QRect &rectangle) const const
QVariant::toBool
bool toBool() const const
QVariant::toInt
int toInt(bool *ok) const const
QVariant::toReal
qreal toReal(bool *ok) const const
Generated on Tue Jan 6 2026 11:38:51 for Pencil2D by doxygen 1.9.6 based on revision f91a96748ec6712509b9b0ff47979db9c34d556f