Pencil2D  ff90c0872e88be3bf81c548cd60f01983012ec49
Pencil2D is an animation software for both bitmap and vector graphics. It is free, multi-platform, and open source.
 All Classes Functions
erasertool.cpp
1 /*
2 
3 Pencil - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2017 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 
18 #include <QSettings>
19 #include <QPixmap>
20 #include <QPainter>
21 
22 #include "scribblearea.h"
23 
24 #include "pencilsettings.h"
25 #include "strokemanager.h"
26 #include "layermanager.h"
27 #include "editor.h"
28 #include "blitrect.h"
29 #include "layervector.h"
30 #include "erasertool.h"
31 
32 
33 EraserTool::EraserTool( QObject *parent )
34  : StrokeTool( parent )
35 {
36 }
37 
38 ToolType EraserTool::type()
39 {
40  return ERASER;
41 }
42 
43 void EraserTool::loadSettings()
44 {
45  m_enabledProperties[WIDTH] = true;
46  m_enabledProperties[FEATHER] = true;
47  m_enabledProperties[PRESSURE] = true;
48  m_enabledProperties[INTERPOLATION] = true;
49 
50 
51  QSettings settings( PENCIL2D, PENCIL2D );
52 
53  properties.width = settings.value( "eraserWidth" ).toDouble();
54  properties.feather = settings.value( "eraserFeather" ).toDouble();
55 
56  properties.pressure = settings.value( "eraserPressure" ).toBool();
57  properties.invisibility = DISABLED;
58  properties.preserveAlpha = OFF;
59  properties.inpolLevel = 0;
60 
61  // First run
62  if ( properties.width <= 0 )
63  {
64  setWidth(25);
65  setFeather(50);
66  setPressure(1);
67  }
68 }
69 
70 void EraserTool::setWidth(const qreal width)
71 {
72  // Set current property
73  properties.width = width;
74 
75  // Update settings
76  QSettings settings( PENCIL2D, PENCIL2D );
77  settings.setValue("eraserWidth", width);
78  settings.sync();
79 }
80 
81 void EraserTool::setFeather( const qreal feather )
82 {
83  // Set current property
84  properties.feather = feather;
85 
86  // Update settings
87  QSettings settings( PENCIL2D, PENCIL2D );
88  settings.setValue("eraserFeather", feather);
89  settings.sync();
90 }
91 
92 void EraserTool::setPressure( const bool pressure )
93 {
94  // Set current property
95  properties.pressure = pressure;
96 
97  // Update settings
98  QSettings settings( PENCIL2D, PENCIL2D );
99  settings.setValue("eraserPressure", pressure);
100  settings.sync();
101 }
102 
103 void EraserTool::setInpolLevel(const int level)
104 {
105  properties.inpolLevel = level;
106 
107  QSettings settings( PENCIL2D, PENCIL2D);
108  settings.setValue("lineInpol", level);
109  settings.sync();
110 }
111 
112 
113 QCursor EraserTool::cursor()
114 {
115  return Qt::CrossCursor;
116 }
117 
118 void EraserTool::adjustPressureSensitiveProperties( qreal pressure, bool mouseDevice )
119 {
120  if ( properties.pressure && !mouseDevice )
121  {
122  mCurrentPressure = pressure;
123  }
124  else
125  {
126  mCurrentPressure = 1.0;
127  }
128 }
129 
130 void EraserTool::mousePressEvent( QMouseEvent *event )
131 {
132  if ( event->button() == Qt::LeftButton )
133  {
134  mEditor->backup( typeName() );
135  mScribbleArea->setAllDirty();
136  }
137 
138  startStroke();
139  mLastBrushPoint = getCurrentPoint();
140 }
141 
142 void EraserTool::mouseReleaseEvent( QMouseEvent *event )
143 {
144 
145  if ( event->button() == Qt::LeftButton )
146  {
147  if ( mScribbleArea->isLayerPaintable() )
148  {
149  drawStroke();
150  }
151 
152  removeVectorPaint();
153  }
154 
155  endStroke();
156 }
157 
158 void EraserTool::mouseMoveEvent( QMouseEvent *event )
159 {
160 
161  if ( event->buttons() & Qt::LeftButton )
162  {
163  if ( mScribbleArea->isLayerPaintable() )
164  {
165  updateStrokes();
166  if (properties.inpolLevel != m_pStrokeManager->getInpolLevel()) {
167  m_pStrokeManager->setInpolLevel(properties.inpolLevel);
168  }
169  }
170  }
171 }
172 
173 // draw a single paint dab at the given location
174 void EraserTool::paintAt( QPointF )
175 {
176 }
177 
178 void EraserTool::drawStroke()
179 {
180  StrokeTool::drawStroke();
181  QList<QPointF> p = m_pStrokeManager->interpolateStroke();
182 
183  Layer* layer = mEditor->layers()->currentLayer();
184 
185  if ( layer->type() == Layer::BITMAP )
186  {
187  for ( int i = 0; i < p.size(); i++ )
188  {
189  p[ i ] = mEditor->view()->mapScreenToCanvas( p[ i ] );
190  }
191 
192  qreal opacity = m_pStrokeManager->getPressure();
193  mCurrentWidth = properties.width;
194 
195  qreal brushWidth = (mCurrentWidth + ( m_pStrokeManager->getPressure() * mCurrentWidth)) * 0.5;
196  qreal brushStep = (0.5 * brushWidth) - ((properties.feather/100.0) * brushWidth * 0.5);
197  brushStep = qMax( 1.0, brushStep );
198 
199  BlitRect rect;
200 
201  QPointF a = mLastBrushPoint;
202  QPointF b = getCurrentPoint();
203 
204  qreal distance = 4 * QLineF( b, a ).length();
205  int steps = qRound( distance ) / brushStep;
206 
207  for ( int i = 0; i < steps; i++ )
208  {
209  QPointF point = mLastBrushPoint + ( i + 1 ) * ( brushStep )* ( b - mLastBrushPoint ) / distance;
210  rect.extend( point.toPoint() );
211  mScribbleArea->drawBrush( point,
212  brushWidth,
213  properties.feather,
214  QColor(255, 255, 255, 255),
215  opacity );
216 
217  if ( i == ( steps - 1 ) )
218  {
219  mLastBrushPoint = point;
220  }
221  }
222 
223  int rad = qRound( brushWidth ) / 2 + 2;
224 
225  //continously update buffer to update stroke behind grid.
226  mScribbleArea->paintBitmapBufferRect(rect);
227 
228  mScribbleArea->refreshBitmap( rect, rad );
229  }
230  else if ( layer->type() == Layer::VECTOR )
231  {
232  qreal brushWidth = 0;
233  if (properties.pressure ) {
234  brushWidth = properties.width * m_pStrokeManager->getPressure();
235  }
236  else {
237  brushWidth = properties.width;
238  }
239 
240  QPen pen( Qt::white, brushWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin );
241  int rad = qRound( ( brushWidth / 2 + 2 ) * mEditor->view()->scaling() );
242 
243  if ( p.size() == 4 ) {
244  QSizeF size( 2, 2 );
245  QPainterPath path( p[ 0 ] );
246  path.cubicTo( p[ 1 ],
247  p[ 2 ],
248  p[ 3 ] );
249  qDebug() << path;
250  mScribbleArea->drawPath( path, pen, Qt::NoBrush, QPainter::CompositionMode_Source );
251  mScribbleArea->refreshVector( path.boundingRect().toRect(), rad );
252  }
253  }
254 }
255 
256 void EraserTool::removeVectorPaint()
257 {
258  Layer* layer = mEditor->layers()->currentLayer();
259  if ( layer->type() == Layer::BITMAP )
260  {
261  mScribbleArea->paintBitmapBuffer();
262  mScribbleArea->setAllDirty();
263  mScribbleArea->clearBitmapBuffer();
264  }
265  else if ( layer->type() == Layer::VECTOR )
266  {
267  VectorImage *vectorImage = ( ( LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
268  // Clear the area containing the last point
269  //vectorImage->removeArea(lastPoint);
270  // Clear the temporary pixel path
271  mScribbleArea->clearBitmapBuffer();
272  vectorImage->deleteSelectedPoints();
273  //update();
274  mScribbleArea->setModified( mEditor->layers()->currentLayerIndex(), mEditor->currentFrame() );
275  mScribbleArea->setAllDirty();
276  }
277 }
278 
279 void EraserTool::updateStrokes()
280 {
281  Layer* layer = mEditor->layers()->currentLayer();
282  if ( layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR )
283  {
284  drawStroke();
285  }
286 
287  if ( layer->type() == Layer::VECTOR )
288  {
289  qreal radius = ( properties.width / 2 ) / mEditor->view()->scaling();
290  QList<VertexRef> nearbyVertices = ( ( LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 )
291  ->getVerticesCloseTo( getCurrentPoint(), radius );
292  for ( int i = 0; i < nearbyVertices.size(); i++ )
293  {
294  ( ( LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 )->setSelected( nearbyVertices.at( i ), true );
295  }
296  //update();
297  mScribbleArea->setAllDirty();
298  }
299 }
Definition: layer.h:32