Pencil2D  ff90c0872e88be3bf81c548cd60f01983012ec49
Pencil2D is an animation software for both bitmap and vector graphics. It is free, multi-platform, and open source.
 All Classes Functions
basetool.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 "basetool.h"
19 
20 #include <array>
21 #include "editor.h"
22 #include "toolmanager.h"
23 #include "scribblearea.h"
24 #include "strokemanager.h"
25 
26 
27 // ---- shared static variables ---- ( only one instance for all the tools )
28 ToolPropertyType BaseTool::assistedSettingType; // setting beeing changed
29 qreal BaseTool::OriginalSettingValue; // start value (width, feather ..)
30 bool BaseTool::isAdjusting = false;
31 
32 
33 QString BaseTool::TypeName( ToolType type )
34 {
35  static std::array< QString, TOOL_TYPE_COUNT > map;
36 
37  if ( map[ 0 ].isEmpty() )
38  {
39  map[ PENCIL ] = tr( "Pencil" );
40  map[ ERASER ] = tr( "Eraser" );
41  map[ SELECT ] = tr( "Select" );
42  map[ MOVE ] = tr( "Move" );
43  map[ HAND ] = tr( "Hand" );
44  map[ SMUDGE ] = tr( "Smudge" );
45  map[ PEN ] = tr( "Pen" );
46  map[ POLYLINE ] = tr( "Polyline" );
47  map[ BUCKET ] = tr( "Bucket" );
48  map[ EYEDROPPER ] = tr( "Eyedropper" );
49  map[ BRUSH ] = tr( "Brush" );
50  }
51 
52  return map.at( type );
53 }
54 
55 BaseTool::BaseTool( QObject *parent ) : QObject( parent )
56 {
57  m_enabledProperties.insert( WIDTH, false );
58  m_enabledProperties.insert( FEATHER, false );
59  m_enabledProperties.insert( USEFEATHER, false );
60  m_enabledProperties.insert( PRESSURE, false );
61  m_enabledProperties.insert( INVISIBILITY, false );
62  m_enabledProperties.insert( PRESERVEALPHA, false );
63  m_enabledProperties.insert( BEZIER, false );
64  m_enabledProperties.insert( ANTI_ALIASING, false );
65  m_enabledProperties.insert( INTERPOLATION, false );
66 }
67 
68 QCursor BaseTool::cursor()
69 {
70  return Qt::ArrowCursor;
71 }
72 
73 void BaseTool::initialize( Editor* editor )
74 {
75  Q_ASSERT( editor );
76 
77  if ( editor == NULL )
78  {
79  qCritical( "ERROR: editor is null!" );
80  }
81  mEditor = editor;
82  mScribbleArea = editor->getScribbleArea();
83 
84 
85  Q_ASSERT( mScribbleArea );
86 
87  if ( mScribbleArea == NULL )
88  {
89  qCritical( "ERROR: mScribbleArea is null in editor!" );
90  }
91 
92 
93  m_pStrokeManager = mEditor->getScribbleArea()->getStrokeManager();
94 
95  loadSettings();
96 }
97 
98 /*
99 void BaseTool::mousePressEvent( QMouseEvent* )
100 {
101 }
102 
103 void BaseTool::mouseMoveEvent( QMouseEvent* )
104 {
105 }
106 
107 void BaseTool::mouseReleaseEvent( QMouseEvent* )
108 {
109 }
110 */
111 
112 void BaseTool::mouseDoubleClickEvent( QMouseEvent *event )
113 {
114  mousePressEvent( event );
115 }
116 
121 QPixmap BaseTool::canvasCursor() // Todo: only one instance required: make fn static?
122 {
123  Q_ASSERT( mEditor->getScribbleArea() );
124 
125  propWidth = properties.width;
126  propFeather = properties.feather;
127  cursorWidth = propWidth + 0.5 * propFeather;
128 
129  if ( cursorWidth < 1 ) { cursorWidth = 1; }
130  radius = cursorWidth / 2;
131  xyA = 1 + propFeather / 2;
132  xyB = 1 + propFeather / 8;
133  whA = qMax( 0, propWidth - xyA - 1 );
134  whB = qMax( 0, cursorWidth - propFeather / 4 - 2 );
135  cursorPixmap = QPixmap( cursorWidth, cursorWidth );
136  if ( !cursorPixmap.isNull() )
137  {
138  cursorPixmap.fill( QColor( 255, 255, 255, 0 ) );
139  QPainter cursorPainter( &cursorPixmap );
140  cursorPen = cursorPainter.pen();
141  cursorPainter.translate(-1,-1); // cursor is slightly offset
142 
143  // Draw cross in center
144  cursorPen.setStyle( Qt::SolidLine );
145  cursorPen.setColor( QColor( 0, 0, 0, 127 ) );
146  cursorPainter.setPen(cursorPen);
147  cursorPainter.drawLine( QPointF( radius - 2, radius ), QPointF( radius + 2, radius ) );
148  cursorPainter.drawLine( QPointF( radius, radius - 2 ), QPointF( radius, radius + 2 ) );
149 
150  // Draw outer circle
151  cursorPen.setStyle( Qt::DotLine );
152  cursorPen.setColor( QColor( 0, 0, 0, 255 ) );
153  cursorPainter.setPen(cursorPen);
154  cursorPainter.drawEllipse( QRectF( xyB, xyB, whB, whB ) );
155  cursorPen.setDashOffset( 4 );
156  cursorPen.setColor( QColor( 255, 255, 255, 255 ) );
157  cursorPainter.setPen(cursorPen);
158  cursorPainter.drawEllipse( QRectF( xyB, xyB, whB, whB ) );
159 
160  // Draw inner circle
161  cursorPen.setStyle( Qt::DotLine );
162  cursorPen.setColor( QColor( 0, 0, 0, 255 ) );
163  cursorPainter.setPen(cursorPen);
164  cursorPainter.drawEllipse( QRectF( xyA, xyA, whA, whA ) );
165  cursorPen.setDashOffset( 4 );
166  cursorPen.setColor( QColor( 255, 255, 255, 255 ) );
167  cursorPainter.setPen(cursorPen);
168  cursorPainter.drawEllipse( QRectF( xyA, xyA, whA, whA ) );
169 
170  cursorPainter.end();
171  }
172  return cursorPixmap;
173 }
174 
179 QPixmap BaseTool::quickSizeCursor() // Todo: only one instance required: make fn static?
180 {
181  Q_ASSERT( mEditor->getScribbleArea() );
182 
183  propWidth = properties.width;
184  propFeather = properties.feather;
185  cursorWidth = propWidth + 0.5 * propFeather;
186 
187  if ( cursorWidth < 1 ) { cursorWidth = 1; }
188  radius = cursorWidth / 2;
189  xyA = 1 + propFeather / 2;
190  xyB = 1 + propFeather / 8;
191  whA = qMax( 0, propWidth - xyA - 1 );
192  whB = qMax( 0, cursorWidth - propFeather / 4 - 2 );
193  cursorPixmap = QPixmap( cursorWidth, cursorWidth );
194  if ( !cursorPixmap.isNull() )
195  {
196  cursorPixmap.fill( QColor( 255, 255, 255, 0 ) );
197  QPainter cursorPainter( &cursorPixmap );
198  cursorPainter.setPen( QColor( 0, 0, 0, 255 ) );
199  cursorPainter.drawLine( QPointF( radius - 2, radius ), QPointF( radius + 2, radius ) );
200  cursorPainter.drawLine( QPointF( radius, radius - 2 ), QPointF( radius, radius + 2 ) );
201  cursorPainter.setRenderHints( QPainter::Antialiasing, true );
202  cursorPainter.setPen( QColor( 0, 0, 0, 0 ) );
203  cursorPainter.setBrush( QColor( 0, 255, 127, 64 ) );
204  cursorPainter.setCompositionMode( QPainter::CompositionMode_Exclusion );
205  cursorPainter.drawEllipse( QRectF( xyB, xyB, whB, whB ) ); // outside circle
206  cursorPainter.setBrush( QColor( 255, 64, 0, 255 ) );
207  cursorPainter.drawEllipse( QRectF( xyA, xyA, whA, whA ) ); // inside circle
208  cursorPainter.end();
209  }
210  return cursorPixmap;
211 }
212 
213 void BaseTool::startAdjusting( ToolPropertyType argSettingType, qreal argStep )
214 {
215  isAdjusting = true;
216  assistedSettingType = argSettingType;
217  mAdjustmentStep = argStep;
218  if ( argSettingType == WIDTH )
219  {
220  OriginalSettingValue = properties.width;
221  }
222  else if ( argSettingType == FEATHER )
223  {
224  OriginalSettingValue = properties.feather;
225  }
226  mEditor->getScribbleArea()->updateCanvasCursor();
227 }
228 
229 void BaseTool::stopAdjusting()
230 {
231  isAdjusting = false;
232  mAdjustmentStep = 0;
233  OriginalSettingValue = 0;
234  mEditor->getScribbleArea()->updateCanvasCursor();
235 }
236 
237 void BaseTool::adjustCursor( qreal argOffsetX, ToolPropertyType type ) //offsetx x-lastx ...
238 {
239  qreal inc = pow( OriginalSettingValue * 100, 0.5 );
240  qreal newValue = inc + argOffsetX;
241  int max = type == FEATHER ? 64 : 200;
242  int min = type == FEATHER ? 2 : 1;
243 
244  if ( newValue < 0 )
245  {
246  newValue = 0;
247  }
248 
249  newValue = pow( newValue, 2 ) / 100;
250  if ( mAdjustmentStep > 0 )
251  {
252  int tempValue = ( int )( newValue / mAdjustmentStep ); // + 0.5 ?
253  newValue = tempValue * mAdjustmentStep;
254  }
255  if ( newValue < min ) // can be optimized for size: min(200,max(0.2,newValueX))
256  {
257  newValue = min;
258  }
259  else if ( newValue > max )
260  {
261  newValue = max;
262  }
263 
264  switch (type){
265  case FEATHER:
266  if ( ( this->type() == BRUSH ) || ( this->type() == ERASER ) || ( this->type() == SMUDGE ) )
267  {
268  mEditor->tools()->setFeather( newValue );
269  }
270  break;
271  case WIDTH:
272  mEditor->tools()->setWidth( newValue );
273  break;
274  default:
275  break;
276  };
277 }
278 
279 void BaseTool::adjustPressureSensitiveProperties( qreal pressure, bool mouseDevice )
280 {
281  Q_UNUSED( pressure );
282  Q_UNUSED( mouseDevice );
283 }
284 
285 QPointF BaseTool::getCurrentPixel()
286 {
287  return m_pStrokeManager->getCurrentPixel();
288 }
289 
290 QPointF BaseTool::getCurrentPoint()
291 {
292  return mEditor->view()->mapScreenToCanvas( getCurrentPixel() );
293 }
294 
295 QPointF BaseTool::getLastPixel()
296 {
297  return m_pStrokeManager->getLastPixel();
298 }
299 
300 QPointF BaseTool::getLastPoint()
301 {
302  return mEditor->view()->mapScreenToCanvas( getLastPixel() );
303 }
304 
305 QPointF BaseTool::getLastPressPixel()
306 {
307  return m_pStrokeManager->getLastPressPixel();
308 }
309 
310 QPointF BaseTool::getLastPressPoint()
311 {
312  return mEditor->view()->mapScreenToCanvas( getLastPressPixel() );
313 }
314 
315 void BaseTool::setWidth( const qreal width )
316 {
317  properties.width = width;
318 }
319 
320 void BaseTool::setFeather( const qreal feather )
321 {
322  properties.feather = feather;
323 }
324 
325 void BaseTool::setUseFeather( const bool usingFeather )
326 {
327  properties.useFeather = usingFeather;
328 }
329 
330 void BaseTool::setInvisibility( const bool invisibility )
331 {
332  properties.invisibility = invisibility;
333 }
334 
335 void BaseTool::setBezier( const bool _bezier_state )
336 {
337  properties.bezier_state = _bezier_state;
338 }
339 
340 void BaseTool::setPressure( const bool pressure )
341 {
342  properties.pressure = pressure;
343 }
344 
345 void BaseTool::setPreserveAlpha( const bool preserveAlpha )
346 {
347  properties.preserveAlpha = preserveAlpha;
348 }
349 
350 void BaseTool::setVectorMergeEnabled(const bool vectorMergeEnabled)
351 {
352  properties.vectorMergeEnabled = vectorMergeEnabled;
353 }
354 
355 void BaseTool::setAA(const int useAA)
356 {
357  properties.useAA = useAA;
358 }
359 
360 void BaseTool::setInpolLevel(const int level)
361 {
362  properties.inpolLevel = level;
363 }
364 
365 void BaseTool::setTolerance(const int tolerance)
366 {
367  properties.tolerance = tolerance;
368 }
369 
370 void BaseTool::setUseFillContour(const bool useFillContour)
371 {
372  properties.useFillContour = useFillContour;
373 }
QPixmap quickSizeCursor()
precision circular cursor: used for drawing stroke size while adjusting
Definition: basetool.cpp:179
QPixmap canvasCursor()
precision circular cursor: used for drawing a cursor within scribble area.
Definition: basetool.cpp:121
Definition: editor.h:45