All Classes Namespaces Functions Variables Enumerations Properties Pages
buckettool.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 #include "buckettool.h"
18 
19 #include <QPixmap>
20 #include <QPainter>
21 #include <QtMath>
22 #include <QSettings>
23 #include "pointerevent.h"
24 
25 #include "layer.h"
26 #include "layervector.h"
27 #include "layerbitmap.h"
28 #include "layermanager.h"
29 #include "colormanager.h"
30 #include "strokemanager.h"
31 #include "viewmanager.h"
32 #include "vectorimage.h"
33 #include "editor.h"
34 #include "scribblearea.h"
35 
36 
37 BucketTool::BucketTool(QObject* parent) : StrokeTool(parent)
38 {
39 }
40 
41 ToolType BucketTool::type()
42 {
43  return BUCKET;
44 }
45 
46 void BucketTool::loadSettings()
47 {
48  mPropertyEnabled[TOLERANCE] = true;
49  mPropertyEnabled[WIDTH] = 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("tolerance", 32.0).toDouble();
58 }
59 
60 void BucketTool::resetToDefault()
61 {
62  setWidth(4.0);
63  setTolerance(32.0);
64 }
65 
66 QCursor BucketTool::cursor()
67 {
68  if (mEditor->preference()->isOn(SETTING::TOOL_CURSOR))
69  {
70  QPixmap pixmap(":icons/bucketTool.png");
71  QPainter painter(&pixmap);
72  painter.end();
73 
74  return QCursor(pixmap, 4, 20);
75  }
76  else
77  {
78  return QCursor(QPixmap(":icons/cross.png"), 10, 10);
79  }
80 }
81 
87 void BucketTool::setWidth(const qreal width)
88 {
89  // Set current property
90  properties.width = width;
91 
92  // Update settings
93  QSettings settings(PENCIL2D, PENCIL2D);
94  settings.setValue("fillThickness", width);
95  settings.sync();
96 }
97 
98 void BucketTool::setTolerance(const int tolerance)
99 {
100  // Set current property
101  properties.tolerance = tolerance;
102 
103  // Update settings
104  QSettings settings(PENCIL2D, PENCIL2D);
105  settings.setValue("tolerance", tolerance);
106  settings.sync();
107 }
108 
109 void BucketTool::pointerPressEvent(PointerEvent* event)
110 {
111  startStroke(event->inputType());
112  if (event->button() == Qt::LeftButton)
113  {
114  mScribbleArea->setAllDirty();
115  }
116 }
117 
118 void BucketTool::pointerMoveEvent(PointerEvent* event)
119 {
120  if (event->buttons() & Qt::LeftButton && event->inputType() == mCurrentInputType)
121  {
122  Layer* layer = mEditor->layers()->currentLayer();
123  if (layer->type() == Layer::VECTOR)
124  {
125  drawStroke();
126  }
127  }
128 }
129 
130 void BucketTool::pointerReleaseEvent(PointerEvent* event)
131 {
132  if (event->inputType() != mCurrentInputType) return;
133 
134  Layer* layer = editor()->layers()->currentLayer();
135  if (layer == nullptr) { return; }
136 
137  if (event->button() == Qt::LeftButton)
138  {
139  mEditor->backup(typeName());
140 
141  switch (layer->type())
142  {
143  case Layer::BITMAP: paintBitmap(layer); break;
144  case Layer::VECTOR: paintVector(layer); break;
145  default:
146  break;
147  }
148  }
149  endStroke();
150 }
151 
152 bool BucketTool::startAdjusting(Qt::KeyboardModifiers modifiers, qreal argStep)
153 {
154  mQuickSizingProperties.clear();
155  if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR)
156  {
157  mQuickSizingProperties.insert(Qt::ShiftModifier, WIDTH);
158  }
159  else
160  {
161  mQuickSizingProperties.insert(Qt::ControlModifier, TOLERANCE);
162  }
163  return BaseTool::startAdjusting(modifiers, argStep);
164 }
165 
166 void BucketTool::paintBitmap(Layer* layer)
167 {
168  Layer* targetLayer = layer; // by default
169  int layerNumber = editor()->layers()->currentLayerIndex(); // by default
170 
171  BitmapImage* targetImage = static_cast<LayerBitmap*>(targetLayer)->getLastBitmapImageAtFrame(editor()->currentFrame(), 0);
172  if (targetImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
173 
174  QPoint point = QPoint(qFloor(getLastPoint().x()), qFloor(getLastPoint().y()));
175  QRect cameraRect = mScribbleArea->getCameraRect().toRect();
176  BitmapImage::floodFill(targetImage,
177  cameraRect,
178  point,
179  qPremultiply(mEditor->color()->frontColor().rgba()),
180  properties.tolerance);
181 
182  mScribbleArea->setModified(layerNumber, mEditor->currentFrame());
183  mScribbleArea->setAllDirty();
184 }
185 
186 void BucketTool::paintVector(Layer* layer)
187 {
188  mScribbleArea->clearBitmapBuffer();
189 
190  VectorImage* vectorImage = static_cast<LayerVector*>(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
191  if (vectorImage == nullptr) { return; } // Can happen if the first frame is deleted while drawing
192 
193  if (!vectorImage->isPathFilled())
194  {
195  vectorImage->fillSelectedPath(mEditor->color()->frontColorNumber());
196  }
197 
198  vectorImage->applyWidthToSelection(properties.width);
199  vectorImage->applyColorToSelectedCurve(mEditor->color()->frontColorNumber());
200  vectorImage->applyColorToSelectedArea(mEditor->color()->frontColorNumber());
201 
202  applyChanges();
203 
204  mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
205  mScribbleArea->setAllDirty();
206 }
207 
208 void BucketTool::applyChanges()
209 {
210  mScribbleArea->applyTransformedSelection();
211 }
212 
213 void BucketTool::drawStroke()
214 {
215  StrokeTool::drawStroke();
216 
217  if (properties.stabilizerLevel != strokeManager()->getStabilizerLevel())
218  {
219  strokeManager()->setStabilizerLevel(properties.stabilizerLevel);
220  }
221 
222  QList<QPointF> p = strokeManager()->interpolateStroke();
223 
224  Layer* layer = mEditor->layers()->currentLayer();
225 
226  if (layer->type() == Layer::VECTOR)
227  {
228  mCurrentWidth = 30;
229  int rad = qRound((mCurrentWidth / 2 + 2) * mEditor->view()->scaling());
230 
231  QColor pathColor = qPremultiply(mEditor->color()->frontColor().rgba());
232  //pathColor.setAlpha(255);
233 
234  QPen pen(pathColor,
235  mCurrentWidth * mEditor->view()->scaling(),
236  Qt::NoPen,
237  Qt::RoundCap,
238  Qt::RoundJoin);
239 
240  if (p.size() == 4)
241  {
242  QPainterPath path(p[0]);
243  path.cubicTo(p[1], p[2], p[3]);
244  mScribbleArea->drawPath(path, pen, Qt::NoBrush, QPainter::CompositionMode_Source);
245  mScribbleArea->refreshVector(path.boundingRect().toRect(), rad);
246  }
247  }
248 }
void setWidth(const qreal width) override
BrushTool::setWidth.
Definition: buckettool.cpp:87
typedef KeyboardModifiers
QHash::iterator insert(const Key &key, const T &value)
void sync()
void applyColorToSelectedArea(int colorNumber)
VectorImage::applyColorToSelectedArea.
QRect toRect() const const
bool isPathFilled()
VectorImage::isPathFilled.
void fillSelectedPath(int color)
VectorImage::fillSelectedPath.
LeftButton
RoundCap
int size() const const
void setValue(const QString &key, const QVariant &value)
Definition: layer.h:39
void applyWidthToSelection(qreal width)
VectorImage::applyWidthToSelection.
Qt::MouseButtons buttons() const
Returns Qt::MouseButtons()
void clear()
CompositionMode_Source
RoundJoin
void applyColorToSelectedCurve(int colorNumber)
VectorImage::applyColorToSelectedCurve.
Qt::MouseButton button() const
Returns Qt::MouseButton()
QRgb rgba() const const