18 #include "scribblearea.h"
21 #include <QScopedPointer>
22 #include <QMessageBox>
23 #include <QPixmapCache>
25 #include "beziercurve.h"
28 #include "layerbitmap.h"
29 #include "layervector.h"
30 #include "layercamera.h"
31 #include "bitmapimage.h"
32 #include "pencilsettings.h"
33 #include "toolmanager.h"
34 #include "strokemanager.h"
35 #include "layermanager.h"
36 #include "playbackmanager.h"
38 #define round(f) ((int)(f + 0.5))
41 ScribbleArea::ScribbleArea( QWidget* parent ) : QWidget( parent ),
42 mLog(
"ScribbleArea" )
44 setObjectName(
"ScribbleArea" );
48 setAttribute( Qt::WA_StaticContents );
53 ScribbleArea::~ScribbleArea()
58 bool ScribbleArea::init()
60 mPrefs = mEditor->preference();
62 connect( mPrefs, &PreferenceManager::optionChanged,
this, &ScribbleArea::settingUpdated );
64 int curveSmoothingLevel = mPrefs->getInt(SETTING::CURVE_SMOOTHING);
65 mCurveSmoothingLevel = curveSmoothingLevel / 20.0;
67 mQuickSizing = mPrefs->isOn( SETTING::QUICK_SIZING );
68 mMakeInvisible =
false;
69 somethingSelected =
false;
71 mIsSimplified = mPrefs->isOn( SETTING::OUTLINES );
72 mMultiLayerOnionSkin = mPrefs->isOn( SETTING::MULTILAYER_ONION );
78 QRect newSelection( QPoint( 0, 0 ), QSize( 0, 0 ) );
79 mySelection = newSelection;
80 myTransformedSelection = newSelection;
81 myTempTransformedSelection = newSelection;
84 selectionTransformation.reset();
90 setMouseTracking(
true );
92 mDebugRect = QRectF( 0, 0, 0, 0 );
94 setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ) );
96 QPixmapCache::setCacheLimit( 100 * 1024 );
98 int nLength = mEditor->layers()->projectLength();
99 mPixmapCacheKeys.resize( std::max( nLength, 240 ) );
101 mNeedUpdateAll =
false;
106 void ScribbleArea::settingUpdated(SETTING setting)
110 case SETTING::CURVE_SMOOTHING:
111 setCurveSmoothing(mPrefs->getInt(SETTING::CURVE_SMOOTHING));
113 case SETTING::TOOL_CURSOR:
116 case SETTING::ONION_PREV_FRAMES_NUM:
117 case SETTING::ONION_NEXT_FRAMES_NUM:
118 case SETTING::ONION_MIN_OPACITY:
119 case SETTING::ONION_MAX_OPACITY:
120 case SETTING::ANTIALIAS:
122 case SETTING::GRID_SIZE:
123 case SETTING::PREV_ONION:
124 case SETTING::NEXT_ONION:
125 case SETTING::ONION_BLUE:
126 case SETTING::ONION_RED:
127 case SETTING::INVISIBLE_LINES:
128 case SETTING::OUTLINES:
131 case SETTING::QUICK_SIZING:
132 mQuickSizing = mPrefs->isOn( SETTING::QUICK_SIZING );
134 case SETTING::MULTILAYER_ONION:
135 mMultiLayerOnionSkin = mPrefs->isOn( SETTING::MULTILAYER_ONION );
143 void ScribbleArea::updateToolCursor()
145 setCursor( currentTool()->cursor() );
146 updateCanvasCursor();
150 void ScribbleArea::setCurveSmoothing(
int newSmoothingLevel )
152 mCurveSmoothingLevel = newSmoothingLevel / 20.0;
156 void ScribbleArea::setEffect( SETTING e,
bool isOn )
158 mPrefs->set(e, isOn);
165 void ScribbleArea::updateCurrentFrame()
167 updateFrame( mEditor->currentFrame() );
170 void ScribbleArea::updateFrame(
int frame )
172 int frameNumber = mEditor->layers()->LastFrameAtFrame( frame );
174 Q_ASSERT( frame >= 0 );
175 if ( mPixmapCacheKeys.size() <=
static_cast< unsigned >( frame ) )
177 mPixmapCacheKeys.resize( frame + 10 );
180 QPixmapCache::remove( mPixmapCacheKeys[ frameNumber ] );
181 mPixmapCacheKeys[ frameNumber] = QPixmapCache::Key();
186 void ScribbleArea::updateAllFrames()
188 QPixmapCache::clear();
189 std::fill( mPixmapCacheKeys.begin(), mPixmapCacheKeys.end(), QPixmapCache::Key() );
192 mNeedUpdateAll =
false;
195 void ScribbleArea::updateAllVectorLayersAtCurrentFrame()
197 updateAllVectorLayersAt( mEditor->currentFrame() );
200 void ScribbleArea::updateAllVectorLayersAt(
int frameNumber )
202 for (
int i = 0; i < mEditor->object()->getLayerCount(); i++ )
204 Layer *layer = mEditor->object()->getLayer( i );
205 if ( layer->type() == Layer::VECTOR )
207 auto vecLayer =
static_cast< LayerVector*
>( layer );
208 vecLayer->getLastVectorImageAtFrame( frameNumber, 0 )->modification();
211 updateFrame( mEditor->currentFrame() );
214 void ScribbleArea::updateAllVectorLayers()
216 for (
int i = 0; i < mEditor->object()->getLayerCount(); i++ )
218 Layer *layer = mEditor->object()->getLayer( i );
219 if ( layer->type() == Layer::VECTOR )
227 void ScribbleArea::setModified(
int layerNumber,
int frameNumber )
229 Layer *layer = mEditor->object()->getLayer( layerNumber );
230 if ( layer->type() == Layer::VECTOR )
232 layer->setModified( frameNumber,
true );
234 else if ( layer->type() == Layer::BITMAP )
236 layer->setModified( frameNumber,
true );
239 emit modification( layerNumber );
248 void ScribbleArea::keyPressEvent( QKeyEvent *event )
252 if (event->isAutoRepeat()) {
256 mKeyboardInUse =
true;
258 if ( mMouseInUse ){
return; }
260 if ( instantTool ){
return; }
263 if ( currentTool()->keyPressEvent( event ) )
270 if ( event->modifiers() == ( Qt::ControlModifier | Qt::ShiftModifier ) )
272 setTemporaryTool( ERASER );
277 switch ( event->key() )
280 if ( somethingSelected )
282 myTempTransformedSelection.translate( 1, 0 );
283 myTransformedSelection = myTempTransformedSelection;
284 calculateSelectionTransformation();
285 paintTransformedSelection();
289 mEditor->scrubForward();
294 if ( somethingSelected )
296 myTempTransformedSelection.translate( -1, 0 );
297 myTransformedSelection = myTempTransformedSelection;
298 calculateSelectionTransformation();
299 paintTransformedSelection();
303 mEditor->scrubBackward();
308 if ( somethingSelected )
310 myTempTransformedSelection.translate( 0, -1 );
311 myTransformedSelection = myTempTransformedSelection;
312 calculateSelectionTransformation();
313 paintTransformedSelection();
317 mEditor->layers()->gotoPreviouslayer();
322 if ( somethingSelected )
324 myTempTransformedSelection.translate( 0, 1 );
325 myTransformedSelection = myTempTransformedSelection;
326 calculateSelectionTransformation();
327 paintTransformedSelection();
331 mEditor->layers()->gotoNextLayer();
336 if ( somethingSelected )
338 applyTransformedSelection();
339 paintTransformedSelection();
348 if ( somethingSelected )
351 applyTransformedSelection();
354 case Qt::Key_Backspace:
355 if ( somethingSelected )
362 setTemporaryTool( HAND );
369 void ScribbleArea::keyReleaseEvent( QKeyEvent *event )
373 if (event->isAutoRepeat()) {
377 mKeyboardInUse =
false;
379 if ( mMouseInUse ) {
return; }
383 currentTool()->keyReleaseEvent( event );
387 if ( currentTool()->keyReleaseEvent( event ) )
396 void ScribbleArea::wheelEvent( QWheelEvent* event )
398 QPoint pixels =
event->pixelDelta();
399 QPoint angle =
event->angleDelta();
400 if ( !pixels.isNull() )
402 float delta = pixels.y();
405 mEditor->view()->scaleDown();
409 mEditor->view()->scaleUp();
412 else if ( !angle.isNull() )
414 float delta = angle.y();
417 mEditor->view()->scaleDown();
421 mEditor->view()->scaleUp();
427 void ScribbleArea::tabletEvent( QTabletEvent *event )
430 mStrokeManager->tabletEvent( event );
433 if (event->device() == QTabletEvent::NoDevice) {
434 currentTool()->adjustPressureSensitiveProperties( mStrokeManager->getPressure(),
437 currentTool()->adjustPressureSensitiveProperties( mStrokeManager->getPressure(),
438 event->pointerType() == QTabletEvent::Cursor );
441 if ( event->pointerType() == QTabletEvent::Eraser )
443 editor()->tools()->tabletSwitchToEraser();
446 editor()->tools()->tabletRestorePrevTool();
451 bool ScribbleArea::isLayerPaintable()
const
453 if ( !areLayersSane() )
456 Layer* layer = mEditor->layers()->currentLayer();
457 return layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR;
460 bool ScribbleArea::areLayersSane()
const
462 Layer* layer = mEditor->layers()->currentLayer();
464 if ( layer == NULL ) {
return false; }
465 if ( layer->type() == Layer::VECTOR )
467 VectorImage *vectorImage = ( (
LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
468 if ( vectorImage == NULL ) {
return false; }
470 if ( layer->type() == Layer::BITMAP )
472 BitmapImage *bitmapImage = ( (
LayerBitmap * )layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 );
473 if ( bitmapImage == NULL ) {
return false; }
480 void ScribbleArea::mousePressEvent( QMouseEvent* event )
484 mStrokeManager->mousePressEvent( event );
486 mUsePressure = currentTool()->properties.pressure;
488 if ( !( mStrokeManager->isTabletInUse() && currentTool()->properties.pressure ) )
490 mStrokeManager->setPressure( 1.0 );
491 currentTool()->adjustPressureSensitiveProperties( 1.0,
true );
495 if ( event->buttons() & Qt::MidButton )
498 mPrevTemporalToolType = currentTool()->type();
499 editor()->tools()->setCurrentTool( HAND );
501 else if ( event->button() == Qt::LeftButton )
503 mLastPixel = mStrokeManager->getLastPressPixel();
504 mLastPoint = mEditor->view()->mapScreenToCanvas( mLastPixel );
508 if ( event->button() == Qt::LeftButton && mQuickSizing)
510 if ( ( event->modifiers() == Qt::ShiftModifier ) && ( currentTool()->properties.width > -1 ) )
513 currentTool()->startAdjusting( WIDTH, 1 );
516 if ( ( event->modifiers() == Qt::ControlModifier ) && ( currentTool()->properties.feather > -1 ) )
519 currentTool()->startAdjusting( FEATHER, 1 );
522 if ( ( event->modifiers() == ( Qt::ShiftModifier | Qt::AltModifier ) ) && ( currentTool()->properties.width > -1 ) )
528 if ( ( event->modifiers() == ( Qt::ControlModifier | Qt::AltModifier ) ) && ( currentTool()->properties.feather > -1 ) )
531 currentTool()->startAdjusting( FEATHER, 0 );
537 Layer* layer = mEditor->layers()->currentLayer();
538 Q_ASSUME( layer !=
nullptr );
540 if ( layer->type() == Layer::VECTOR )
542 auto pLayerVector =
static_cast< LayerVector*
>( layer );
543 VectorImage* vectorImage = pLayerVector->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
544 Q_CHECK_PTR( vectorImage );
546 else if ( layer->type() == Layer::BITMAP )
548 auto pLayerBitmap =
static_cast< LayerBitmap*
>( layer );
549 BitmapImage* bitmapImage = pLayerBitmap->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 );
550 Q_CHECK_PTR( bitmapImage );
553 if ( !layer->mVisible && currentTool()->type() != HAND && ( event->button() != Qt::RightButton ) )
555 QMessageBox::warning(
this, tr(
"Warning" ),
556 tr(
"You are drawing on a hidden layer! Please select another layer (or make the current layer visible)." ),
563 mCurrentPixel = mStrokeManager->getCurrentPixel();
564 mCurrentPoint = mEditor->view()->mapScreenToCanvas( mCurrentPixel );
569 if ( event->buttons() & Qt::LeftButton ||
event->buttons() & Qt::RightButton )
571 mOffset = mCurrentPoint - mLastPoint;
574 if ( event->button() == Qt::RightButton )
576 mMouseRightButtonInUse =
true;
577 getTool( HAND )->mousePressEvent( event );
581 currentTool()->mousePressEvent( event );
584 void ScribbleArea::mouseMoveEvent( QMouseEvent *event )
586 if ( !areLayersSane() )
591 Q_EMIT refreshPreview();
593 mStrokeManager->mouseMoveEvent( event );
594 mCurrentPixel = mStrokeManager->getCurrentPixel();
595 mCurrentPoint = mEditor->view()->mapScreenToCanvas( mCurrentPixel );
598 if ( event->buttons() & Qt::LeftButton ||
event->buttons() & Qt::RightButton )
600 mOffset = mCurrentPoint - mLastPoint;
602 if ( currentTool()->isAdjusting )
604 ToolPropertyType tool_type;
605 tool_type =
event->modifiers() & Qt::ControlModifier ? FEATHER : WIDTH;
606 currentTool()->adjustCursor( mOffset.x(), tool_type );
607 updateCanvasCursor();
612 if ( event->buttons() == Qt::RightButton )
614 getTool( HAND )->mouseMoveEvent( event );
618 currentTool()->mouseMoveEvent( event );
622 clock_t curTime = clock();
623 mDebugTimeQue.push_back( curTime );
625 while ( mDebugTimeQue.size() > 100 )
627 mDebugTimeQue.pop_front();
630 if ( mDebugTimeQue.size() > 2 )
632 clock_t interval = mDebugTimeQue.back() - mDebugTimeQue.front();
633 double fps = mDebugTimeQue.size() / ( ( double )interval ) * CLOCKS_PER_SEC;
639 void ScribbleArea::mouseReleaseEvent( QMouseEvent *event )
644 if ( currentTool()->isAdjusting )
646 currentTool()->stopAdjusting();
647 mEditor->tools()->setWidth( currentTool()->properties.width );
651 mStrokeManager->mouseReleaseEvent( event );
653 if ( event->button() == Qt::RightButton )
655 getTool( HAND )->mouseReleaseEvent( event );
656 mMouseRightButtonInUse =
false;
660 currentTool()->mouseReleaseEvent( event );
662 if ( currentTool()->type() == EYEDROPPER )
664 setCurrentTool( mPrevToolType );
668 if ( instantTool && !mKeyboardInUse )
674 void ScribbleArea::mouseDoubleClickEvent( QMouseEvent *event )
676 currentTool()->mouseDoubleClickEvent( event );
679 void ScribbleArea::resizeEvent( QResizeEvent *event )
681 QWidget::resizeEvent( event );
682 mCanvas = QPixmap( size() );
683 mCanvas.fill(Qt::transparent);
685 this->setStyleSheet(
"background-color:yellow;");
687 mEditor->view()->setCanvasSize( size() );
694 void ScribbleArea::paintBitmapBuffer( )
696 Layer* layer = mEditor->layers()->currentLayer();
700 if ( layer == NULL ) {
return; }
704 BitmapImage *targetImage = ( (
LayerBitmap * )layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 );
705 if ( targetImage != NULL )
707 QPainter::CompositionMode cm = QPainter::CompositionMode_SourceOver;
708 switch ( currentTool()->type() )
711 cm = QPainter::CompositionMode_DestinationOut;
716 if ( getTool( currentTool()->type() )->properties.preserveAlpha )
718 cm = QPainter::CompositionMode_SourceAtop;
724 targetImage->paste( mBufferImg, cm );
729 QRect rect = mEditor->view()->getView().mapRect( mBufferImg->bounds() );
734 layer->setModified( mEditor->currentFrame(), true );
737 int frameNumber = mEditor->currentFrame();
738 QPixmapCache::remove( mPixmapCacheKeys[frameNumber] );
739 mPixmapCacheKeys[frameNumber] = QPixmapCache::Key();
741 drawCanvas( mEditor->currentFrame(), rect.adjusted( -1, -1, 1, 1 ) );
745 void ScribbleArea::paintBitmapBufferRect( QRect rect )
747 if ( currentTool()->type() == SMUDGE || currentTool()->type() == BRUSH || mEditor->playback()->isPlaying() ) {
748 Layer* layer = mEditor->layers()->currentLayer();
752 if ( layer == NULL ) {
return; }
754 BitmapImage *targetImage = ( (
LayerBitmap * )layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 );
756 if ( targetImage != NULL )
758 QPainter::CompositionMode cm = QPainter::CompositionMode_SourceOver;
759 switch ( currentTool()->type() )
762 cm = QPainter::CompositionMode_DestinationOut;
767 if ( getTool( currentTool()->type() )->properties.preserveAlpha )
769 cm = QPainter::CompositionMode_SourceAtop;
775 targetImage->paste( mBufferImg, cm );
783 layer->setModified( mEditor->currentFrame(), true );
786 int frameNumber = mEditor->currentFrame();
787 QPixmapCache::remove( mPixmapCacheKeys[frameNumber] );
788 mPixmapCacheKeys[frameNumber] = QPixmapCache::Key();
790 drawCanvas( mEditor->currentFrame(), rect.adjusted( -1, -1, 1, 1 ) );
795 void ScribbleArea::clearBitmapBuffer()
800 void ScribbleArea::drawLine( QPointF P1, QPointF P2, QPen pen, QPainter::CompositionMode cm )
802 mBufferImg->drawLine( P1, P2, pen, cm, mPrefs->isOn( SETTING::ANTIALIAS ) );
805 void ScribbleArea::drawPath( QPainterPath path, QPen pen, QBrush brush, QPainter::CompositionMode cm )
807 mBufferImg->drawPath( path, pen, brush, cm, mPrefs->isOn( SETTING::ANTIALIAS ) );
810 void ScribbleArea::refreshBitmap(
const QRectF& rect,
int rad )
812 QRectF updatedRect = mEditor->view()->mapCanvasToScreen( rect.normalized().adjusted( -rad, -rad, +rad, +rad ) );
813 update( updatedRect.toRect() );
816 void ScribbleArea::refreshVector(
const QRectF& rect,
int rad )
820 update( rect.normalized().adjusted( -rad, -rad, +rad, +rad ).toRect() );
827 void ScribbleArea::paintCanvasCursor( QPainter& painter )
829 Layer* layer = mEditor->layers()->currentLayer();
831 QTransform view = mEditor->view()->getView();
832 QPoint mousePos = currentTool()->getCurrentPoint().toPoint();
833 QPoint transformedPos = view.map( mousePos );
834 QPixmap transCursorImg = mCursorImg.transformed(view);
835 int centerCal = mCursorImg.width() / 2;
836 center.setX( centerCal );
837 center.setY( centerCal );
838 if ( layer->type() == Layer::VECTOR )
840 painter.setTransform( view );
842 painter.drawPixmap( QPoint( mousePos.x() - center.x(),
843 mousePos.y() - center.y() ),
847 centerCal = transCursorImg.width() / 2;
848 center.setX( centerCal );
849 center.setY( centerCal );
852 update( transCursorImg.rect().adjusted( -3, -3, 3, 3 )
853 .translated( transformedPos.x() - center.x(),
854 transformedPos.y() - center.y() ) );
857 void ScribbleArea::updateCanvasCursor()
859 if ( currentTool()->isAdjusting )
863 else if ( mEditor->preference()->isOn( SETTING::DOTTED_CURSOR ) )
869 mCursorImg = QPixmap();
873 void ScribbleArea::paintEvent( QPaintEvent* event )
875 if ( !mMouseInUse || currentTool()->type() == MOVE || currentTool()->type() == HAND || mMouseRightButtonInUse)
878 int curIndex = mEditor->currentFrame();
879 int frameNumber = mEditor->layers()->LastFrameAtFrame( curIndex );
881 QPixmapCache::Key cachedKey = mPixmapCacheKeys[frameNumber];
883 if ( !QPixmapCache::find( cachedKey, &mCanvas ) )
885 drawCanvas( mEditor->currentFrame(),
event->rect() );
887 mPixmapCacheKeys[frameNumber] = QPixmapCache::insert( mCanvas );
892 if ( currentTool()->type() == MOVE )
894 Layer* layer = mEditor->layers()->currentLayer();
895 Q_CHECK_PTR( layer );
896 if ( layer->type() == Layer::VECTOR )
898 auto vecLayer =
static_cast< LayerVector*
>( layer );
899 vecLayer->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 )->setModified(
true );
903 QPainter painter(
this );
906 painter.setWorldMatrixEnabled(
false );
909 painter.drawPixmap( QPoint( 0, 0 ), mCanvas );
911 Layer* layer = mEditor->layers()->currentLayer();
913 if ( !editor()->playback()->isPlaying() )
915 if ( layer->type() == Layer::VECTOR )
917 VectorImage *vectorImage = ( (
LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
919 switch ( currentTool()->type() )
925 painter.setWorldMatrixEnabled(
false );
926 painter.setRenderHint( QPainter::Antialiasing,
false );
928 QPen pen2( Qt::black, 0.5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin );
929 painter.setPen( pen2 );
932 colour = QColor( 200, 200, 200 );
933 painter.setBrush( colour );
934 for (
int k = 0; k < vectorSelection.curve.size(); k++ )
936 int curveNumber = vectorSelection.curve.at( k );
938 for (
int vertexNumber = -1; vertexNumber < vectorImage->getCurveSize( curveNumber ); vertexNumber++ )
940 QPointF vertexPoint = vectorImage->getVertex( curveNumber, vertexNumber );
941 QRectF rectangle( mEditor->view()->mapCanvasToScreen( vertexPoint ) - QPointF( 3.0, 3.0 ), QSizeF( 7, 7 ) );
942 if ( rect().contains( mEditor->view()->mapCanvasToScreen( vertexPoint ).toPoint() ) )
944 painter.drawRect( rectangle );
949 colour = QColor( 100, 100, 255 );
950 painter.setBrush( colour );
951 for (
int k = 0; k < vectorSelection.vertex.size(); k++ )
953 VertexRef vertexRef = vectorSelection.vertex.at( k );
954 QPointF vertexPoint = vectorImage->getVertex( vertexRef );
955 QRectF rectangle0 = QRectF( mEditor->view()->mapCanvasToScreen( vertexPoint ) - QPointF( 3.0, 3.0 ), QSizeF( 7, 7 ) );
956 painter.drawRect( rectangle0 );
959 colour = QColor( 255, 0, 0 );
960 painter.setBrush( colour );
961 if ( vectorSelection.curve.size() > 0 )
963 for (
int k = 0; k < mClosestVertices.size(); k++ )
965 VertexRef vertexRef = mClosestVertices.at( k );
966 QPointF vertexPoint = vectorImage->getVertex( vertexRef );
968 QRectF rectangle = QRectF( mEditor->view()->mapCanvasToScreen( vertexPoint ) - QPointF( 3.0, 3.0 ), QSizeF( 7, 7 ) );
969 painter.drawRect( rectangle );
980 QColor colour = QColor( 100, 100, 255, 50 );
981 QPen pen2( colour, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin );
984 for (
int k = 0; k < mClosestCurves.size(); k++ )
986 float scale = mEditor->view()->scaling();
988 int idx = mClosestCurves[ k ];
989 if ( vectorImage->m_curves.size() <= idx )
994 BezierCurve myCurve = vectorImage->m_curves[ mClosestCurves[ k ] ];
995 if ( myCurve.isPartlySelected() )
997 myCurve.transform( selectionTransformation );
999 QPainterPath path = myCurve.getStrokedPath( 1.2 / scale,
false );
1000 mBufferImg->drawPath( mEditor->view()->mapCanvasToScreen( path ),
1003 QPainter::CompositionMode_SourceOver,
1004 mPrefs->isOn( SETTING::ANTIALIAS ) );
1017 if ( mEditor->layers()->currentLayer() != NULL )
1019 painter.setOpacity( 1.0 );
1020 if ( mEditor->layers()->currentLayer()->type() == Layer::BITMAP )
1022 painter.setWorldMatrixEnabled(
true );
1023 painter.setTransform( mEditor->view()->getView() );
1025 else if ( mEditor->layers()->currentLayer()->type() == Layer::VECTOR )
1027 painter.setWorldMatrixEnabled(
false );
1031 mBufferImg->paintImage( painter );
1033 paintCanvasCursor( painter );
1036 mCanvasRenderer.renderGrid(painter);
1039 if ( somethingSelected && ( myTempTransformedSelection.isValid() || mMoveMode == ROTATION ) )
1042 painter.setWorldMatrixEnabled(
false );
1043 painter.setOpacity( 1.0 );
1044 QPolygon tempRect = mEditor->view()->getView().mapToPolygon( myTempTransformedSelection.normalized().toRect() );
1046 Layer* layer = mEditor->layers()->currentLayer();
1047 if ( layer != NULL )
1049 if ( layer->type() == Layer::BITMAP )
1051 painter.setBrush( Qt::NoBrush );
1052 painter.setPen( Qt::DashLine );
1054 if ( layer->type() == Layer::VECTOR )
1056 painter.setBrush( QColor( 0, 0, 0, 20 ) );
1057 painter.setPen( Qt::gray );
1059 painter.drawPolygon( tempRect );
1061 if ( layer->type() != Layer::VECTOR || currentTool()->type() != SELECT )
1063 painter.setPen( Qt::SolidLine );
1064 painter.setBrush( QBrush( Qt::gray ) );
1065 painter.drawRect( tempRect.point( 0 ).x() - 3, tempRect.point( 0 ).y() - 3, 6, 6 );
1066 painter.drawRect( tempRect.point( 1 ).x() - 3, tempRect.point( 1 ).y() - 3, 6, 6 );
1067 painter.drawRect( tempRect.point( 2 ).x() - 3, tempRect.point( 2 ).y() - 3, 6, 6 );
1068 painter.drawRect( tempRect.point( 3 ).x() - 3, tempRect.point( 3 ).y() - 3, 6, 6 );
1076 painter.setWorldMatrixEnabled(
false );
1077 painter.setPen( QPen( Qt::gray, 2 ) );
1078 painter.setBrush( Qt::NoBrush );
1079 painter.drawRect( QRect( 0, 0, width(), height() ) );
1085 void ScribbleArea::drawCanvas(
int frame, QRect rect )
1087 Object*
object = mEditor->object();
1090 options.bPrevOnionSkin = mPrefs->isOn( SETTING::PREV_ONION );
1091 options.bNextOnionSkin = mPrefs->isOn( SETTING::NEXT_ONION );
1092 options.bColorizePrevOnion = mPrefs->isOn(SETTING::ONION_RED);
1093 options.bColorizeNextOnion = mPrefs->isOn(SETTING::ONION_BLUE);
1094 options.nPrevOnionSkinCount = mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM);
1095 options.nNextOnionSkinCount = mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
1096 options.fOnionSkinMaxOpacity = mPrefs->getInt(SETTING::ONION_MAX_OPACITY);
1097 options.fOnionSkinMinOpacity = mPrefs->getInt(SETTING::ONION_MIN_OPACITY);
1098 options.bAntiAlias = mPrefs->isOn( SETTING::ANTIALIAS );
1099 options.bGrid = mPrefs->isOn( SETTING::GRID );
1100 options.nGridSize = mPrefs->getInt( SETTING::GRID_SIZE );
1101 options.bAxis = mPrefs->isOn( SETTING::AXIS );
1102 options.bThinLines = mPrefs->isOn( SETTING::INVISIBLE_LINES );
1103 options.bOutlines = mPrefs->isOn( SETTING::OUTLINES );
1104 options.nShowAllLayers = mShowAllLayers;
1105 options.bIsOnionAbsolute = (mPrefs->getString( SETTING::ONION_TYPE ) ==
"absolute");
1107 mCanvasRenderer.setOptions( options );
1111 mCanvasRenderer.setCanvas( &mCanvas );
1112 mCanvasRenderer.setViewTransform( mEditor->view()->getView() );
1113 mCanvasRenderer.paint(
object, mEditor->layers()->currentLayerIndex(), frame, rect );
1118 void ScribbleArea::setGaussianGradient( QGradient &gradient, QColor colour, qreal opacity, qreal mOffset )
1123 if (mOffset > 100) {
1126 int r = colour.red();
1127 int g = colour.green();
1128 int b = colour.blue();
1129 qreal a = colour.alphaF();
1131 int mainColorAlpha = qRound( a * 255 * opacity );
1135 int alphaAdded = qRound((mainColorAlpha * mOffset) / 100);
1137 gradient.setColorAt( 0.0, QColor( r, g, b, mainColorAlpha - alphaAdded ) );
1138 gradient.setColorAt( 1.0, QColor( r, g, b, 0 ) );
1139 gradient.setColorAt( 1.0 - (mOffset/100.0), QColor( r, g, b, mainColorAlpha - alphaAdded ) );
1142 void ScribbleArea::drawPen( QPointF thePoint, qreal brushWidth, QColor fillColour,
bool useAA )
1144 QRectF rectangle( thePoint.x() - 0.5 * brushWidth, thePoint.y() - 0.5 * brushWidth, brushWidth, brushWidth );
1146 mBufferImg->drawEllipse( rectangle, Qt::NoPen, QBrush(fillColour, Qt::SolidPattern),
1147 QPainter::CompositionMode_Source, useAA );
1150 void ScribbleArea::drawPencil( QPointF thePoint, qreal brushWidth, QColor fillColour, qreal opacity )
1152 drawBrush(thePoint, brushWidth, 50, fillColour, opacity,
true);
1155 void ScribbleArea::drawBrush( QPointF thePoint, qreal brushWidth, qreal mOffset, QColor fillColour, qreal opacity,
bool usingFeather,
int useAA )
1157 QRectF rectangle( thePoint.x() - 0.5 * brushWidth, thePoint.y() - 0.5 * brushWidth, brushWidth, brushWidth );
1160 if (usingFeather==
true)
1162 QRadialGradient radialGrad( thePoint, 0.5 * brushWidth );
1163 setGaussianGradient( radialGrad, fillColour, opacity, mOffset );
1165 gradientImg.drawEllipse( rectangle, Qt::NoPen, radialGrad,
1166 QPainter::CompositionMode_SourceOver,
false );
1170 mBufferImg->drawEllipse( rectangle, Qt::NoPen, QBrush(fillColour, Qt::SolidPattern),
1171 QPainter::CompositionMode_SourceOver, useAA );
1173 mBufferImg->paste( &gradientImg );
1182 int scaleX = myTempTransformedSelection.width() / mySelection.width();
1183 int scaleY = myTempTransformedSelection.height() / mySelection.height();
1186 QTransform translate = QTransform::fromTranslate( centerPoints[0].x(), centerPoints[0].y() );
1187 QTransform _translate = QTransform::fromTranslate( -centerPoints[1].x(), -centerPoints[1].y() );
1188 QTransform scale = QTransform::fromScale( -scaleX, scaleY );
1190 if (flipVertical ==
true)
1192 scale = QTransform::fromScale( scaleX, -scaleY );
1196 selectionTransformation.reset();
1197 selectionTransformation *= _translate *
1201 paintTransformedSelection();
1202 applyTransformedSelection();
1205 void ScribbleArea::blurBrush(
BitmapImage *bmiSource_, QPointF srcPoint_, QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_ )
1207 QRadialGradient radialGrad( thePoint_, 0.5 * brushWidth_ );
1208 setGaussianGradient( radialGrad, QColor( 255, 255, 255, 127 ), opacity_, mOffset_ );
1210 QRectF srcRect( srcPoint_.x() - 0.5 * brushWidth_, srcPoint_.y() - 0.5 * brushWidth_, brushWidth_, brushWidth_ );
1211 QRectF trgRect( thePoint_.x() - 0.5 * brushWidth_, thePoint_.y() - 0.5 * brushWidth_, brushWidth_, brushWidth_ );
1213 BitmapImage bmiSrcClip = bmiSource_->copy( srcRect.toRect() );
1216 bmiTmpClip.drawRect( srcRect, Qt::NoPen, radialGrad, QPainter::CompositionMode_Source, mPrefs->isOn( SETTING::ANTIALIAS ) );
1217 bmiSrcClip.bounds().moveTo( trgRect.topLeft().toPoint() );
1218 bmiTmpClip.paste( &bmiSrcClip, QPainter::CompositionMode_SourceAtop );
1219 mBufferImg->paste( &bmiTmpClip );
1222 void ScribbleArea::liquifyBrush(
BitmapImage *bmiSource_, QPointF srcPoint_, QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_ )
1224 QPointF delta = ( thePoint_ - srcPoint_ );
1225 QRectF trgRect( thePoint_.x() - 0.5 * brushWidth_, thePoint_.y() - 0.5 * brushWidth_, brushWidth_, brushWidth_ );
1227 QRadialGradient radialGrad( thePoint_, 0.5 * brushWidth_ );
1228 setGaussianGradient( radialGrad, QColor( 255, 255, 255, 255 ), opacity_, mOffset_ );
1232 bmiTmpClip->drawRect( trgRect, Qt::NoPen, radialGrad, QPainter::CompositionMode_Source, mPrefs->isOn( SETTING::ANTIALIAS ) );
1235 qreal factor, factorGrad;
1238 for ( yb = bmiTmpClip->bounds().top(); yb < bmiTmpClip->bounds().bottom(); yb++ )
1240 for ( xb = bmiTmpClip->bounds().left(); xb < bmiTmpClip->bounds().right(); xb++ )
1243 color.setRgba( bmiTmpClip->pixel( xb, yb ) );
1244 factorGrad = color.alphaF();
1246 xa = xb - factorGrad*delta.x();
1247 ya = yb - factorGrad*delta.y();
1249 color.setRgba( bmiSource_->pixel( xa, ya ) );
1250 factor = color.alphaF();
1254 color.setRed( color.red() / factor );
1255 color.setGreen( color.green() / factor );
1256 color.setBlue( color.blue() / factor );
1257 color.setAlpha( 255 );
1259 color.setRed( color.red()*factorGrad );
1260 color.setGreen( color.green()*factorGrad );
1261 color.setBlue( color.blue()*factorGrad );
1262 color.setAlpha( 255 * factorGrad );
1264 bmiTmpClip->setPixel( xb, yb, color.rgba() );
1267 bmiTmpClip->setPixel( xb, yb, qRgba( 255, 255, 255, 255 ) );
1271 mBufferImg->paste( bmiTmpClip );
1275 void ScribbleArea::drawPolyline(QPainterPath path, QPen pen,
bool useAA)
1277 QRectF updateRect = mEditor->view()->mapCanvasToScreen( path.boundingRect().toRect() ).adjusted( -1, -1, 1, 1);
1280 QRectF boundingRect = updateRect.adjusted(-width(),-height(), width(),height());
1281 mBufferImg->clear();
1282 mBufferImg->drawPath( path, pen, Qt::NoBrush, QPainter::CompositionMode_SourceOver, useAA);
1283 update( boundingRect.toRect());
1290 QTransform ScribbleArea::getView()
1292 Layer* layer = mEditor->layers()->currentLayer();
1293 if ( layer == NULL )
1296 return QTransform();
1299 if ( layer->type() == Layer::CAMERA )
1301 return ( (
LayerCamera * )layer )->getViewAtFrame( mEditor->currentFrame() );
1305 return mEditor->view()->getView();
1309 QRectF ScribbleArea::getViewRect()
1311 QRectF rect = QRectF( -width() / 2, -height() / 2, width(), height() );
1312 Layer* layer = mEditor->layers()->currentLayer();
1313 if ( layer == NULL ) {
return rect; }
1314 if ( layer->type() == Layer::CAMERA )
1324 QRectF ScribbleArea::getCameraRect()
1326 return mCanvasRenderer.getCameraRect();
1329 QPointF ScribbleArea::getCentralPoint()
1331 return mEditor->view()->mapScreenToCanvas( QPointF( width() / 2, height() / 2 ) );
1337 void ScribbleArea::calculateSelectionRect()
1339 selectionTransformation.reset();
1340 Layer* layer = mEditor->layers()->currentLayer();
1341 if ( layer == NULL ) {
return; }
1342 if ( layer->type() == Layer::VECTOR )
1344 VectorImage *vectorImage = ( (
LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
1345 vectorImage->calculateSelectionRect();
1346 setSelection( vectorImage->getSelectionRect(), true );
1356 QVector<QPoint> centerPoints;
1357 float selectionCenterX,
1359 tempSelectionCenterX,
1360 tempSelectionCenterY;
1362 tempSelectionCenterX = 0.5 * ( myTempTransformedSelection.left() +
1363 myTempTransformedSelection.right() );
1364 tempSelectionCenterY = 0.5 * ( myTempTransformedSelection.top() +
1365 myTempTransformedSelection.bottom() );
1366 selectionCenterX = 0.5 * ( mySelection.left() + mySelection.right() );
1367 selectionCenterY = 0.5 * ( mySelection.top() + mySelection.bottom() );
1368 centerPoints.append( QPoint( tempSelectionCenterX, tempSelectionCenterY ) );
1369 centerPoints.append( QPoint( selectionCenterX, selectionCenterY ) );
1370 return centerPoints;
1373 void ScribbleArea::calculateSelectionTransformation()
1375 float scaleX, scaleY;
1378 if ( mySelection.width() == 0 )
1384 scaleX = myTempTransformedSelection.width() / mySelection.width();
1387 if ( mySelection.height() == 0 )
1393 scaleY = myTempTransformedSelection.height() / mySelection.height();
1396 selectionTransformation.reset();
1398 selectionTransformation.translate( centerPoints[0].x(), centerPoints[0].y() );
1399 selectionTransformation.rotate(myRotatedAngle);
1400 selectionTransformation.scale( scaleX, scaleY );
1401 selectionTransformation.translate( -centerPoints[1].x(), -centerPoints[1].y() );
1407 void ScribbleArea::paintTransformedSelection()
1409 Layer* layer = mEditor->layers()->currentLayer();
1410 if ( layer == NULL )
1415 if ( somethingSelected )
1417 if ( layer->type() == Layer::BITMAP )
1419 mCanvasRenderer.setTransformedSelection(mySelection.toRect(), selectionTransformation);
1421 else if ( layer->type() == Layer::VECTOR )
1425 VectorImage *vectorImage = layerVector->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
1426 vectorImage->setSelectionTransformation( selectionTransformation );
1429 setModified( mEditor->layers()->currentLayerIndex(), mEditor->currentFrame() );
1434 void ScribbleArea::applyTransformedSelection()
1436 mCanvasRenderer.ignoreTransformedSelection();
1438 Layer* layer = mEditor->layers()->currentLayer();
1439 if ( layer == NULL )
1444 if ( somethingSelected )
1446 if ( layer->type() == Layer::BITMAP )
1448 BitmapImage* bitmapImage =
dynamic_cast< LayerBitmap*
>( layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 );
1450 BitmapImage* transformedImage =
new BitmapImage(bitmapImage->transformed(mySelection.toRect(), selectionTransformation, mPrefs->isOn(SETTING::ANTIALIAS)));
1452 bitmapImage->clear(mySelection);
1453 bitmapImage->paste(transformedImage, QPainter::CompositionMode_SourceOver);
1455 delete transformedImage;
1457 else if ( layer->type() == Layer::VECTOR )
1460 VectorImage *vectorImage = ((
LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
1461 vectorImage->applySelectionTransformation();
1465 setModified( mEditor->layers()->currentLayerIndex(), mEditor->currentFrame() );
1468 updateCurrentFrame();
1471 void ScribbleArea::cancelTransformedSelection()
1473 mCanvasRenderer.ignoreTransformedSelection();
1475 if (somethingSelected) {
1477 Layer* layer = mEditor->layers()->currentLayer();
1478 if ( layer == NULL )
1483 if ( layer->type() == Layer::VECTOR ) {
1485 VectorImage *vectorImage = ((
LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
1486 vectorImage->setSelectionTransformation( QTransform() );
1489 setSelection( mySelection,
true );
1491 selectionTransformation.reset();
1496 updateCurrentFrame();
1500 void ScribbleArea::setSelection( QRectF rect,
bool trueOrFalse )
1504 myTransformedSelection = rect;
1505 myTempTransformedSelection = rect;
1506 somethingSelected = trueOrFalse;
1514 void ScribbleArea::displaySelectionProperties()
1516 Layer* layer = mEditor->layers()->currentLayer();
1517 if ( layer == NULL ) {
return; }
1518 if ( layer->type() == Layer::VECTOR )
1521 VectorImage *vectorImage = layerVector->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
1523 if ( currentTool()->type() == MOVE )
1525 int selectedCurve = vectorImage->getFirstSelectedCurve();
1526 if ( selectedCurve != -1 )
1528 mEditor->tools()->setWidth( vectorImage->m_curves[ selectedCurve ].getWidth() );
1529 mEditor->tools()->setFeather( vectorImage->m_curves[ selectedCurve ].getFeather() );
1530 mEditor->tools()->setInvisibility( vectorImage->m_curves[ selectedCurve ].isInvisible() );
1531 mEditor->tools()->setPressure( vectorImage->m_curves[ selectedCurve ].getVariableWidth() );
1532 mEditor->color()->setColorNumber( vectorImage->m_curves[ selectedCurve ].getColourNumber() );
1535 int selectedArea = vectorImage->getFirstSelectedArea();
1536 if ( selectedArea != -1 )
1538 mEditor->color()->setColorNumber( vectorImage->area[ selectedArea ].mColourNumber );
1544 void ScribbleArea::selectAll()
1548 Layer* layer = mEditor->layers()->currentLayer();
1551 if ( layer == NULL ) {
return; }
1553 if ( layer->type() == Layer::BITMAP )
1561 BitmapImage *bitmapImage = ( (
LayerBitmap * )layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 );
1562 setSelection(bitmapImage->bounds(),
true);
1566 else if ( layer->type() == Layer::VECTOR )
1568 VectorImage *vectorImage = ( (
LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 );
1569 vectorImage->selectAll();
1570 setSelection( vectorImage->getSelectionRect(), true );
1572 updateCurrentFrame();
1582 mOffset = QPoint(0,0);
1584 selectionTransformation.reset();
1587 void ScribbleArea::deselectAll()
1590 mySelection.setRect( 10, 10, 20, 20 );
1591 myTransformedSelection.setRect( 10, 10, 20, 20 );
1592 myTempTransformedSelection.setRect( 10, 10, 20, 20 );
1594 Layer* layer = mEditor->layers()->currentLayer();
1595 if ( layer == NULL ) {
return; }
1596 if ( layer->type() == Layer::VECTOR )
1598 ( (
LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 )->deselectAll();
1600 somethingSelected =
false;
1601 isTransforming =
false;
1603 mBufferImg->clear();
1606 vectorSelection.clear();
1609 editor()->tools()->cleanupAllToolsData();
1611 updateCurrentFrame();
1614 void ScribbleArea::toggleThinLines()
1616 bool previousValue = mPrefs->isOn(SETTING::INVISIBLE_LINES);
1617 setEffect( SETTING::INVISIBLE_LINES, !previousValue );
1620 void ScribbleArea::toggleOutlines()
1622 mIsSimplified = !mIsSimplified;
1623 setEffect( SETTING::OUTLINES, mIsSimplified );
1626 void ScribbleArea::toggleShowAllLayers()
1629 if ( mShowAllLayers == 3 )
1639 BaseTool* ScribbleArea::currentTool()
1641 return editor()->tools()->currentTool();
1644 BaseTool* ScribbleArea::getTool( ToolType eToolType )
1646 return editor()->tools()->getTool( eToolType );
1650 void ScribbleArea::setCurrentTool( ToolType eToolMode )
1652 if ( currentTool() != NULL && eToolMode != currentTool()->type() )
1654 qDebug() <<
"Set Current Tool" << BaseTool::TypeName( eToolMode );
1655 if ( BaseTool::TypeName( eToolMode ) ==
"" )
1662 if ( currentTool()->type() == MOVE )
1664 paintTransformedSelection();
1667 else if ( currentTool()->type() == POLYLINE )
1673 mPrevToolType = currentTool()->type();
1676 setCursor( currentTool()->cursor() );
1677 updateCanvasCursor();
1678 qDebug() <<
"fn: setCurrentTool " <<
"call: setCursor()" <<
"current tool" << currentTool()->typeName();
1681 void ScribbleArea::setTemporaryTool( ToolType eToolMode )
1686 if (!instantTool && currentTool()->type() != eToolMode) {
1689 mPrevTemporalToolType = currentTool()->type();
1690 editor()->tools()->setCurrentTool( eToolMode );
1694 void ScribbleArea::deleteSelection()
1696 if ( somethingSelected )
1698 Layer* layer = mEditor->layers()->currentLayer();
1699 if ( layer == NULL ) {
return; }
1700 mEditor->backup( tr(
"Delete Selection" ) );
1701 mClosestCurves.clear();
1702 if ( layer->type() == Layer::VECTOR ) { ( (
LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 )->deleteSelection(); }
1703 if ( layer->type() == Layer::BITMAP ) { ( (
LayerBitmap * )layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 )->clear( mySelection ); }
1708 void ScribbleArea::clearImage()
1710 Layer* layer = mEditor->layers()->currentLayer();
1711 if ( layer == NULL ) {
return; }
1712 if ( layer->type() == Layer::VECTOR )
1714 mEditor->backup( tr(
"Clear Image" ) );
1715 ( (
LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 )->clear();
1716 mClosestCurves.clear();
1717 mClosestVertices.clear();
1719 else if ( layer->type() == Layer::BITMAP )
1721 mEditor->backup( tr(
"Clear Image" ) );
1722 ( (
LayerBitmap * )layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 )->clear();
1729 setModified( mEditor->layers()->currentLayerIndex(), mEditor->currentFrame() );
1732 void ScribbleArea::setPrevTool()
1734 editor()->tools()->setCurrentTool( mPrevTemporalToolType );
1735 instantTool =
false;
1740 void ScribbleArea::paletteColorChanged(QColor color)
1743 updateAllVectorLayersAtCurrentFrame();
1747 void ScribbleArea::floodFillError(
int errorType )
1749 QString message, error;
1750 if ( errorType == 1 ) { message = tr(
"There is a gap in your drawing (or maybe you have zoomed too much)." ); }
1751 if ( errorType == 2 || errorType == 3 ) message = tr(
"Sorry! This doesn't always work."
1752 "Please try again (zoom a bit, click at another location... )<br>"
1753 "if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.)." );
1755 if ( errorType == 1 ) { error = tr(
"Out of bound." ); }
1756 if ( errorType == 2 ) { error = tr(
"Could not find a closed path." ); }
1757 if ( errorType == 3 ) { error = tr(
"Could not find the root index." ); }
1758 QMessageBox::warning(
this, tr(
"Flood fill error" ), tr(
"%1<br><br>Error: %2").arg(message).arg(error), QMessageBox::Ok, QMessageBox::Ok );
void resetSelectionProperties()
ScribbleArea::resetSelectionProperties should be used whenever translate, rotate, transform...
QVector< QPoint > calcSelectionCenterPoints()
ScribbleArea::calculateSelectionCenter.
void flipSelection(bool flipVertical)
ScribbleArea::flipSelection flip selection along the X or Y axis.