18#include "scribblearea.h"
21#include <QGuiApplication>
23#include <QPixmapCache>
26#include "pointerevent.h"
27#include "beziercurve.h"
30#include "layerbitmap.h"
31#include "layervector.h"
32#include "layercamera.h"
33#include "bitmapimage.h"
34#include "vectorimage.h"
38#include "onionskinpainteroptions.h"
40#include "colormanager.h"
41#include "toolmanager.h"
42#include "layermanager.h"
43#include "playbackmanager.h"
44#include "viewmanager.h"
45#include "selectionmanager.h"
46#include "overlaymanager.h"
49 mCanvasPainter(mCanvas),
50 mCameraPainter(mCanvas)
52 setObjectName(
"ScribbleArea");
59ScribbleArea::~ScribbleArea()
63bool ScribbleArea::init()
65 mPrefs = mEditor->preference();
66 mDoubleClickTimer =
new QTimer(
this);
67 mMouseFilterTimer =
new QTimer(
this);
69 connect(mPrefs, &PreferenceManager::optionChanged,
this, &ScribbleArea::settingUpdated);
77 connect(mEditor->select(), &SelectionManager::needDeleteSelection,
this, &ScribbleArea::deleteSelection);
79 connect(&mTiledBuffer, &TiledBuffer::tileUpdated,
this, &ScribbleArea::onTileUpdated);
80 connect(&mTiledBuffer, &TiledBuffer::tileCreated,
this, &ScribbleArea::onTileCreated);
85 const int curveSmoothingLevel = mPrefs->getInt(SETTING::CURVE_SMOOTHING);
86 mCurveSmoothingLevel = curveSmoothingLevel / 20.0;
88 mMakeInvisible =
false;
90 mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION);
92 mLayerVisibility =
static_cast<LayerVisibility
>(mPrefs->getInt(SETTING::LAYER_VISIBILITY));
94 mDeltaFactor = mEditor->preference()->isOn(SETTING::INVERT_SCROLL_ZOOM_DIRECTION) ? -1 : 1;
97#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
104 mPixmapCacheKeys.
clear();
109void ScribbleArea::settingUpdated(SETTING setting)
113 case SETTING::CURVE_SMOOTHING:
114 setCurveSmoothing(mPrefs->getInt(SETTING::CURVE_SMOOTHING));
116 case SETTING::TOOL_CURSOR:
119 case SETTING::ONION_PREV_FRAMES_NUM:
120 case SETTING::ONION_NEXT_FRAMES_NUM:
121 case SETTING::ONION_MIN_OPACITY:
122 case SETTING::ONION_MAX_OPACITY:
125 case SETTING::ANTIALIAS:
127 case SETTING::GRID_SIZE_W:
128 case SETTING::GRID_SIZE_H:
129 case SETTING::OVERLAY_CENTER:
130 case SETTING::OVERLAY_THIRDS:
131 case SETTING::OVERLAY_GOLDEN:
132 case SETTING::OVERLAY_SAFE:
133 case SETTING::OVERLAY_PERSPECTIVE1:
134 case SETTING::OVERLAY_PERSPECTIVE2:
135 case SETTING::OVERLAY_PERSPECTIVE3:
136 case SETTING::ACTION_SAFE_ON:
137 case SETTING::ACTION_SAFE:
138 case SETTING::TITLE_SAFE_ON:
139 case SETTING::TITLE_SAFE:
140 case SETTING::OVERLAY_SAFE_HELPER_TEXT_ON:
141 case SETTING::PREV_ONION:
142 case SETTING::NEXT_ONION:
143 case SETTING::ONION_BLUE:
144 case SETTING::ONION_RED:
145 case SETTING::INVISIBLE_LINES:
146 case SETTING::OUTLINES:
147 case SETTING::ONION_TYPE:
148 case SETTING::ONION_WHILE_PLAYBACK:
151 case SETTING::MULTILAYER_ONION:
152 mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION);
155 case SETTING::LAYER_VISIBILITY_THRESHOLD:
156 case SETTING::LAYER_VISIBILITY:
157 setLayerVisibility(
static_cast<LayerVisibility
>(mPrefs->getInt(SETTING::LAYER_VISIBILITY)));
159 case SETTING::INVERT_SCROLL_ZOOM_DIRECTION:
160 mDeltaFactor = mEditor->preference()->isOn(SETTING::INVERT_SCROLL_ZOOM_DIRECTION) ? -1 : 1;
168void ScribbleArea::updateToolCursor()
173void ScribbleArea::setCurveSmoothing(
int newSmoothingLevel)
175 mCurveSmoothingLevel = newSmoothingLevel / 20.0;
179void ScribbleArea::setEffect(SETTING e,
bool isOn)
181 mPrefs->set(e, isOn);
190 Q_UNUSED(tiledBuffer);
197 Q_UNUSED(tiledBuffer)
204 if (currentTool()->isActive() && currentTool()->isDrawingTool()) {
213 Layer* currentLayer = mEditor->layers()->currentLayer();
224 if (frameNumber < 0) {
return; }
226 bool isOnionAbsolute = mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute";
227 Layer *layer = mEditor->layers()->currentLayer(0);
232 if (mPrefs->isOn(SETTING::PREV_ONION))
234 int onionFrameNumber = frameNumber;
237 onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber + 1,
true);
240 for(
int i = 1; i <= mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM); i++)
242 onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber, isOnionAbsolute);
243 if (onionFrameNumber < 0)
break;
249 if (mPrefs->isOn(SETTING::NEXT_ONION))
251 int onionFrameNumber = frameNumber;
253 for(
int i = 1; i <= mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM); i++)
255 onionFrameNumber = layer->getNextFrameNumber(onionFrameNumber, isOnionAbsolute);
256 if (onionFrameNumber < 0)
break;
265 if (currentTool()->isDrawingTool() && currentTool()->isActive()) {
return; }
268 mPixmapCacheKeys.
clear();
277 auto cacheKeyIter = mPixmapCacheKeys.
find(
static_cast<unsigned int>(frameNumber));
278 if (cacheKeyIter != mPixmapCacheKeys.
end())
281 unsigned int key = cacheKeyIter.key();
282 mPixmapCacheKeys.
remove(key);
288 mCameraPainter.resetCache();
289 mCanvasPainter.resetLayerCache();
297 case ToolPropertyType::CAMERAPATH:
307 int frame = mEditor->currentFrame();
309 prepCameraPainter(frame);
317 int currentFrame = mEditor->currentFrame();
318 if (mPrefs->isOn(SETTING::PREV_ONION) ||
319 mPrefs->isOn(SETTING::NEXT_ONION)) {
323 prepOverlays(currentFrame);
324 prepCameraPainter(currentFrame);
331 Q_UNUSED(frameNumber)
339 if (mPrefs->isOn(SETTING::PREV_ONION) || mPrefs->isOn(SETTING::NEXT_ONION)) {
347 if (mPrefs->isOn(SETTING::PREV_ONION) || mPrefs->isOn(SETTING::NEXT_ONION)) {
367 int currentFrame = mEditor->currentFrame();
382bool ScribbleArea::event(
QEvent *event)
384 bool processed =
false;
387 editor()->tools()->clearTemporaryTool();
391 processed = currentTool()->enterEvent(
static_cast<QEnterEvent*
>(event)) || processed;
394 processed = currentTool()->leaveEvent(event) || processed;
404void ScribbleArea::keyPressEvent(
QKeyEvent *event)
409 if (isPointerInUse()) {
return; }
411 if (currentTool()->keyPressEvent(event))
418 editor()->tools()->setTemporaryTool(ERASER, {},
event->modifiers()))
425 auto selectMan = mEditor->select();
426 bool isSomethingSelected = selectMan->somethingSelected();
427 if (isSomethingSelected)
429 keyEventForSelection(event);
437void ScribbleArea::keyEventForSelection(
QKeyEvent* event)
439 auto selectMan = mEditor->select();
440 switch (event->
key())
443 selectMan->translate(
QPointF(1, 0));
444 selectMan->calculateSelectionTransformation();
448 selectMan->translate(
QPointF(-1, 0));
449 selectMan->calculateSelectionTransformation();
453 selectMan->translate(
QPointF(0, -1));
454 selectMan->calculateSelectionTransformation();
458 selectMan->translate(
QPointF(0, 1));
459 selectMan->calculateSelectionTransformation();
463 applyTransformedSelection();
464 mEditor->deselectAll();
467 cancelTransformedSelection();
468 mEditor->deselectAll();
472 mEditor->deselectAll();
486void ScribbleArea::keyEvent(
QKeyEvent* event)
488 switch (event->
key())
491 mEditor->scrubForward();
494 mEditor->scrubBackward();
497 mEditor->layers()->gotoNextLayer();
500 mEditor->layers()->gotoPreviouslayer();
514void ScribbleArea::keyReleaseEvent(
QKeyEvent *event)
522 if (event->
key() == 0)
528 editor()->tools()->tryClearTemporaryTool(
static_cast<Qt::Key>(event->
key()));
531 if (isPointerInUse()) {
return; }
533 if (currentTool()->keyReleaseEvent(event))
545 if (isPointerInUse())
return;
548 const QPoint pixels =
event->pixelDelta();
549 const QPoint angle =
event->angleDelta();
550#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
551 const QPointF offset = mEditor->view()->mapScreenToCanvas(event->
position());
553 const QPointF offset = mEditor->view()->mapScreenToCanvas(event->
posF());
556 const qreal currentScale = mEditor->view()->scaling();
560 if (!isX11 && !pixels.
isNull())
570 const qreal newScale = currentScale * std::pow(100, (delta * mDeltaFactor) / (12.0 * 120));
571 mEditor->view()->scaleAtOffset(newScale, offset);
580#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
581 if (event.pointerType() == QPointingDevice::PointerType::Eraser)
586 editor()->tools()->tabletSwitchToEraser();
590 editor()->tools()->tabletRestorePrevTool();
593 if (event.eventType() == PointerEvent::Press)
598 mIsFirstClick =
false;
599 mDoubleClickTimer->
start();
600 pointerPressEvent(&event);
605 mTabletPressPos = e->
posF();
607 if (mDoubleClickMillis <= DOUBLE_CLICK_THRESHOLD && distance < 5.0) {
608 currentTool()->pointerDoubleClickEvent(&event);
613 pointerPressEvent(&event);
616 mTabletInUse =
event.isAccepted();
618 else if (event.eventType() == PointerEvent::Move)
622 pointerMoveEvent(&event);
625 else if (event.eventType() == PointerEvent::Release)
627 mTabletReleaseMillisAgo = 0;
628 mMouseFilterTimer->
start();
631 pointerReleaseEvent(&event);
632 mTabletInUse =
false;
636#if defined Q_OS_LINUX
652void ScribbleArea::pointerPressEvent(
PointerEvent* event)
654 bool isCameraLayer = mEditor->layers()->currentLayer()->type() == Layer::CAMERA;
657 Layer* layer = mEditor->layers()->currentLayer();
658 if (!layer->visible())
669 editor()->tools()->setTemporaryTool(HAND, event->
buttons()))
671 currentTool()->pointerPressEvent(event);
674 currentTool()->pointerPressEvent(event);
680 currentTool()->pointerMoveEvent(event);
683void ScribbleArea::pointerReleaseEvent(
PointerEvent* event)
685 currentTool()->pointerReleaseEvent(event);
687 editor()->tools()->tryClearTemporaryTool(event->
button());
690void ScribbleArea::handleDoubleClick()
692 mDoubleClickMillis += 100;
694 if (mDoubleClickMillis >= DOUBLE_CLICK_THRESHOLD)
696 mDoubleClickMillis = 0;
697 mIsFirstClick =
true;
698 mDoubleClickTimer->
stop();
702void ScribbleArea::tabletReleaseEventFired()
710 mTabletReleaseMillisAgo += 50;
712 if (mTabletReleaseMillisAgo >= MOUSE_FILTER_THRESHOLD) {
713 mTabletReleaseMillisAgo = 0;
714 mMouseFilterTimer->
stop();
720 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD))
727 pointerPressEvent(&event);
728 mMouseInUse =
event.isAccepted();
733 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD)) { e->
ignore();
return; }
736 pointerMoveEvent(&event);
739void ScribbleArea::mouseReleaseEvent(
QMouseEvent* e)
741 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD)) { e->
ignore();
return; }
744 pointerReleaseEvent(&event);
748void ScribbleArea::mouseDoubleClickEvent(
QMouseEvent* e)
750 if (mTabletInUse) { e->
ignore();
return; }
753 currentTool()->pointerDoubleClickEvent(&event);
762 mEditor->view()->setCanvasSize(
size());
766 mCanvasPainter.reset();
767 mCameraPainter.reset();
770void ScribbleArea::showLayerNotVisibleWarning()
773 tr(
"You are trying to modify a hidden layer! Please select another layer (or make the current layer visible)."),
778void ScribbleArea::paintBitmapBuffer()
782 Q_ASSERT(layer->type() == Layer::BITMAP);
784 int frameNumber = mEditor->currentFrame();
788 if (layer->getLastKeyFrameAtPosition(frameNumber) ==
nullptr)
794 BitmapImage* targetImage = currentBitmapImage(layer);
795 if (targetImage !=
nullptr)
798 switch (currentTool()->type())
806 if (currentTool()->properties.preserveAlpha)
814 targetImage->paste(&mTiledBuffer, cm);
817 QRect rect = mEditor->view()->mapCanvasToScreen(mTiledBuffer.bounds()).toRect();
821 layer->setModified(frameNumber,
true);
822 mTiledBuffer.
clear();
825void ScribbleArea::clearDrawingBuffer()
827 mTiledBuffer.
clear();
832 auto layer = mEditor->layers()->currentLayer();
834 if (!layer || !layer->isPaintable())
839 if (currentTool()->type() == ERASER) {
843 int frameNumber = mEditor->currentFrame();
844 if (layer->getKeyFrameAt(frameNumber)) {
return; }
847 int action = mPrefs->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION);
848 auto previousKeyFrame = layer->getLastKeyFrameAtPosition(frameNumber);
851 case KEEP_DRAWING_ON_PREVIOUS_KEY:
853 if (previousKeyFrame ==
nullptr) {
860 case DUPLICATE_PREVIOUS_KEY:
862 if (previousKeyFrame !=
nullptr) {
863 KeyFrame* dupKey = previousKeyFrame->clone();
865 mEditor->scrubTo(frameNumber);
876 drawCanvas(frameNumber, mCanvas.
rect());
885 int currentFrame = mEditor->currentFrame();
886 if (!currentTool()->isActive())
889 const int frameNumber = mEditor->layers()->lastFrameAtFrame(currentFrame);
893 drawCanvas(currentFrame, event->
rect());
897 auto cacheKeyIter = mPixmapCacheKeys.
find(
static_cast<unsigned>(frameNumber));
901 drawCanvas(currentFrame, event->
rect());
913 prepCanvas(currentFrame);
914 prepCameraPainter(currentFrame);
915 prepOverlays(currentFrame);
917 mCanvasPainter.paintCached(event->
rect());
918 mCameraPainter.paintCached(event->
rect());
921 if (currentTool()->type() == MOVE)
923 Layer* layer = mEditor->layers()->currentLayer();
925 if (layer->type() == Layer::VECTOR)
927 VectorImage* vectorImage = currentVectorImage(layer);
928 if (vectorImage !=
nullptr)
930 vectorImage->setModified(
true);
938 painter.setWorldMatrixEnabled(
false);
943 painter.setClipRect(event->
rect());
944 painter.drawPixmap(
QPointF(), mCanvas);
946 currentTool()->paint(painter, event->
rect());
948 if (!editor()->playback()->isPlaying())
950 Layer* layer = mEditor->layers()->currentLayer();
951 if (layer->type() == Layer::VECTOR)
953 VectorImage* vectorImage = currentVectorImage(layer);
954 if (vectorImage !=
nullptr)
956 switch (currentTool()->type())
961 auto selectMan = mEditor->select();
963 painter.setWorldMatrixEnabled(
false);
967 painter.setPen(pen2);
970 color =
QColor(200, 200, 200);
971 painter.setBrush(color);
973 for (
int k = 0; k < vectorSelection.curve.
size(); k++)
975 int curveNumber = vectorSelection.curve.
at(k);
977 for (
int vertexNumber = -1; vertexNumber < vectorImage->
getCurveSize(curveNumber); vertexNumber++)
980 QRectF rectangle(mEditor->view()->mapCanvasToScreen(vertexPoint) -
QPointF(3.0, 3.0),
QSizeF(7, 7));
981 if (
rect().contains(mEditor->view()->mapCanvasToScreen(vertexPoint).
toPoint()))
983 painter.drawRect(rectangle);
988 color =
QColor(100, 100, 255);
989 painter.setBrush(color);
990 for (
int k = 0; k < vectorSelection.vertex.
size(); k++)
992 VertexRef vertexRef = vectorSelection.vertex.
at(k);
995 painter.drawRect(rectangle0);
998 color =
QColor(255, 0, 0);
999 painter.setBrush(color);
1001 if (vectorSelection.curve.
size() > 0)
1003 for (
int k = 0; k < closestVertices.
size(); k++)
1009 painter.drawRect(rectangle);
1023 mOverlayPainter.paint(painter,
rect());
1026 if (mEditor->select()->somethingSelected())
1028 paintSelectionVisuals(painter);
1034 painter.setWorldMatrixEnabled(
false);
1043void ScribbleArea::paintSelectionVisuals(
QPainter &painter)
1045 Object*
object = mEditor->object();
1047 auto selectMan = mEditor->select();
1049 QRectF currentSelectionRect = selectMan->mySelectionRect();
1051 if (currentSelectionRect.
isEmpty()) {
return; }
1053 TransformParameters params = { currentSelectionRect, editor()->view()->getView(), selectMan->selectionTransform() };
1054 mSelectionPainter.paint(painter,
object, mEditor->currentLayerIndex(), currentTool(), params);
1055 emit selectionUpdated();
1060 Q_ASSERT(layer->type() == Layer::BITMAP);
1061 auto bitmapLayer =
static_cast<LayerBitmap*
>(layer);
1062 return bitmapLayer->getLastBitmapImageAtFrame(mEditor->currentFrame());
1067 Q_ASSERT(layer->type() == Layer::VECTOR);
1068 auto vectorLayer =
static_cast<LayerVector*
>(layer);
1069 return vectorLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
1072void ScribbleArea::prepCameraPainter(
int frame)
1074 Object*
object = mEditor->object();
1076 mCameraPainter.preparePainter(
object,
1077 mEditor->currentLayerIndex(),
1079 mEditor->view()->getView(),
1080 mEditor->playback()->isPlaying(),
1082 mPrefs->getFloat(SETTING::LAYER_VISIBILITY_THRESHOLD),
1083 mEditor->view()->getViewScaleInverse());
1086 onionSkinOptions.enabledWhilePlaying = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK);
1087 onionSkinOptions.isPlaying = mEditor->playback()->isPlaying();
1088 onionSkinOptions.isAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute");
1089 onionSkinOptions.skinPrevFrames = mPrefs->isOn(SETTING::PREV_ONION);
1090 onionSkinOptions.skinNextFrames = mPrefs->isOn(SETTING::NEXT_ONION);
1091 onionSkinOptions.colorizePrevFrames = mPrefs->isOn(SETTING::ONION_RED);
1092 onionSkinOptions.colorizeNextFrames = mPrefs->isOn(SETTING::ONION_BLUE);
1093 onionSkinOptions.framesToSkinPrev = mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM);
1094 onionSkinOptions.framesToSkinNext = mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
1095 onionSkinOptions.maxOpacity = mPrefs->getInt(SETTING::ONION_MAX_OPACITY);
1096 onionSkinOptions.minOpacity = mPrefs->getInt(SETTING::ONION_MIN_OPACITY);
1098 mCameraPainter.setOnionSkinPainterOptions(onionSkinOptions);
1101void ScribbleArea::prepCanvas(
int frame)
1103 Object*
object = mEditor->object();
1106 o.bAntiAlias = mPrefs->isOn(SETTING::ANTIALIAS);
1107 o.bThinLines = mPrefs->isOn(SETTING::INVISIBLE_LINES);
1108 o.bOutlines = mPrefs->isOn(SETTING::OUTLINES);
1109 o.eLayerVisibility = mLayerVisibility;
1110 o.fLayerVisibilityThreshold = mPrefs->getFloat(SETTING::LAYER_VISIBILITY_THRESHOLD);
1111 o.scaling = mEditor->view()->scaling();
1115 onionSkinOptions.enabledWhilePlaying = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK);
1116 onionSkinOptions.isPlaying = mEditor->playback()->isPlaying();
1117 onionSkinOptions.isAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute");
1118 onionSkinOptions.skinPrevFrames = mPrefs->isOn(SETTING::PREV_ONION);
1119 onionSkinOptions.skinNextFrames = mPrefs->isOn(SETTING::NEXT_ONION);
1120 onionSkinOptions.colorizePrevFrames = mPrefs->isOn(SETTING::ONION_RED);
1121 onionSkinOptions.colorizeNextFrames = mPrefs->isOn(SETTING::ONION_BLUE);
1122 onionSkinOptions.framesToSkinPrev = mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM);
1123 onionSkinOptions.framesToSkinNext = mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
1124 onionSkinOptions.maxOpacity = mPrefs->getInt(SETTING::ONION_MAX_OPACITY);
1125 onionSkinOptions.minOpacity = mPrefs->getInt(SETTING::ONION_MIN_OPACITY);
1127 mCanvasPainter.setOnionSkinOptions(onionSkinOptions);
1128 mCanvasPainter.setOptions(o);
1132 mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse());
1133 mCanvasPainter.setTransformedSelection(sm->mySelectionRect().
toRect(), sm->selectionTransform());
1135 mCanvasPainter.setPaintSettings(
object, mEditor->layers()->currentLayerIndex(), frame, &mTiledBuffer);
1138void ScribbleArea::drawCanvas(
int frame,
QRect rect)
1141 prepCameraPainter(frame);
1142 prepOverlays(frame);
1143 mCanvasPainter.paint(
rect);
1144 mCameraPainter.paint(
rect);
1147void ScribbleArea::setGaussianGradient(
QGradient &gradient,
QColor color, qreal opacity, qreal offset)
1149 if (offset < 0) { offset = 0; }
1150 if (offset > 100) { offset = 100; }
1152 int r = color.
red();
1153 int g = color.
green();
1154 int b = color.
blue();
1155 qreal a = color.
alphaF();
1157 int mainColorAlpha = qRound(a * 255 * opacity);
1160 int alphaAdded = qRound((mainColorAlpha * offset) / 100);
1164 gradient.
setColorAt(1.0 - (offset / 100.0),
QColor(r, g, b, mainColorAlpha - alphaAdded));
1169 mTiledBuffer.
drawPath(mEditor->view()->mapScreenToCanvas(path), pen, brush, cm, mPrefs->isOn(SETTING::ANTIALIAS));
1172void ScribbleArea::drawPen(
QPointF thePoint, qreal brushWidth,
QColor fillColor,
bool useAA)
1178void ScribbleArea::drawPencil(
QPointF thePoint, qreal brushWidth, qreal fixedBrushFeather,
QColor fillColor, qreal opacity)
1189 setGaussianGradient(radialGrad, fillColor, opacity, mOffset);
1205 blitRect.extend(mEditor->view()->mapCanvasToScreen(mTiledBuffer.bounds()).toRect());
1207 QRect updateRect = mEditor->view()->mapCanvasToScreen(path.
boundingRect()).toRect();
1209 blitRect.extend(updateRect);
1211 mTiledBuffer.
clear();
1218void ScribbleArea::endStroke()
1220 if (mEditor->layers()->currentLayer()->type() == Layer::BITMAP) {
1221 paintBitmapBuffer();
1227void ScribbleArea::flipSelection(
bool flipVertical)
1232void ScribbleArea::prepOverlays(
int frame)
1236 o.bGrid = mPrefs->isOn(SETTING::GRID);
1237 o.nGridSizeW = mPrefs->getInt(SETTING::GRID_SIZE_W);
1238 o.nGridSizeH = mPrefs->getInt(SETTING::GRID_SIZE_H);
1239 o.bCenter = mPrefs->isOn(SETTING::OVERLAY_CENTER);
1240 o.bThirds = mPrefs->isOn(SETTING::OVERLAY_THIRDS);
1241 o.bGoldenRatio = mPrefs->isOn(SETTING::OVERLAY_GOLDEN);
1242 o.bSafeArea = mPrefs->isOn(SETTING::OVERLAY_SAFE);
1243 o.bPerspective1 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE1);
1244 o.bPerspective2 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE2);
1245 o.bPerspective3 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE3);
1246 o.nOverlayAngle = mPrefs->getInt(SETTING::OVERLAY_ANGLE);
1247 o.bActionSafe = mPrefs->isOn(SETTING::ACTION_SAFE_ON);
1248 o.nActionSafe = mPrefs->getInt(SETTING::ACTION_SAFE);
1249 o.bShowSafeAreaHelperText = mPrefs->isOn(SETTING::OVERLAY_SAFE_HELPER_TEXT_ON);
1250 o.bTitleSafe = mPrefs->isOn(SETTING::TITLE_SAFE_ON);
1251 o.nTitleSafe = mPrefs->getInt(SETTING::TITLE_SAFE);
1252 o.nOverlayAngle = mPrefs->getInt(SETTING::OVERLAY_ANGLE);
1253 o.bShowHandle = mEditor->tools()->currentTool()->type() == MOVE && mEditor->layers()->currentLayer()->type() != Layer::CAMERA;
1255 o.mSinglePerspPoint = mEditor->overlays()->getSinglePerspectivePoint();
1256 o.mLeftPerspPoint = mEditor->overlays()->getLeftPerspectivePoint();
1257 o.mRightPerspPoint = mEditor->overlays()->getRightPerspectivePoint();
1258 o.mMiddlePerspPoint = mEditor->overlays()->getMiddlePerspectivePoint();
1260 o.nFrameIndex = frame;
1262 mOverlayPainter.setOptions(o);
1263 mOverlayPainter.preparePainter(mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex()),
palette());
1266 mOverlayPainter.setViewTransform(vm->getView());
1269void ScribbleArea::blurBrush(
BitmapImage *bmiSource_,
QPointF srcPoint_,
QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_)
1272 setGaussianGradient(radialGrad,
QColor(255, 255, 255, 127), opacity_, mOffset_);
1274 QRectF srcRect(srcPoint_.
x() - 0.5 * brushWidth_, srcPoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1275 QRectF trgRect(thePoint_.
x() - 0.5 * brushWidth_, thePoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1277 BitmapImage bmiSrcClip = bmiSource_->copy(srcRect.toAlignedRect());
1281 bmiSrcClip.bounds().
moveTo(trgRect.topLeft().toPoint());
1286void ScribbleArea::liquifyBrush(
BitmapImage *bmiSource_,
QPointF srcPoint_,
QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_)
1288 QPointF delta = (thePoint_ - srcPoint_);
1289 QRectF trgRect(thePoint_.
x() - 0.5 * brushWidth_, thePoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1292 setGaussianGradient(radialGrad,
QColor(255, 255, 255, 255), opacity_, mOffset_);
1299 qreal factor, factorGrad;
1301 for (
int yb = bmiTmpClip.top(); yb < bmiTmpClip.bottom(); yb++)
1303 for (
int xb = bmiTmpClip.left(); xb < bmiTmpClip.right(); xb++)
1306 color.
setRgba(bmiTmpClip.pixel(xb, yb));
1307 factorGrad = color.
alphaF();
1309 int xa = xb - factorGrad * delta.
x();
1310 int ya = yb - factorGrad * delta.
y();
1312 color.
setRgba(bmiSource_->pixel(xa, ya));
1327 bmiTmpClip.setPixel(xb, yb, color.
rgba());
1331 bmiTmpClip.setPixel(xb, yb, qRgba(255, 255, 255, 0));
1341QPointF ScribbleArea::getCentralPoint()
1346void ScribbleArea::applyTransformedSelection()
1348 mCanvasPainter.ignoreTransformedSelection();
1350 Layer* layer = mEditor->layers()->currentLayer();
1351 if (layer ==
nullptr) {
return; }
1353 auto selectMan = mEditor->select();
1354 if (selectMan->somethingSelected())
1356 if (selectMan->mySelectionRect().isEmpty() || selectMan->selectionTransform().isIdentity()) {
return; }
1358 if (layer->type() == Layer::BITMAP)
1361 BitmapImage* bitmapImage = currentBitmapImage(layer);
1362 if (bitmapImage ==
nullptr) {
return; }
1363 BitmapImage transformedImage = bitmapImage->transformed(selectMan->mySelectionRect().toRect(), selectMan->selectionTransform(),
true);
1366 bitmapImage->clear(selectMan->mySelectionRect());
1369 else if (layer->type() == Layer::VECTOR)
1374 VectorImage* vectorImage = currentVectorImage(layer);
1375 if (vectorImage ==
nullptr) {
return; }
1380 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1386void ScribbleArea::cancelTransformedSelection()
1388 mCanvasPainter.ignoreTransformedSelection();
1390 auto selectMan = mEditor->select();
1391 if (selectMan->somethingSelected())
1393 Layer* layer = mEditor->layers()->currentLayer();
1394 if (layer ==
nullptr) {
return; }
1396 if (layer->type() == Layer::VECTOR)
1398 VectorImage* vectorImage = currentVectorImage(layer);
1399 if (vectorImage !=
nullptr)
1405 mEditor->select()->setSelection(selectMan->mySelectionRect(),
false);
1407 selectMan->resetSelectionProperties();
1410 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1415void ScribbleArea::toggleThinLines()
1417 bool previousValue = mPrefs->isOn(SETTING::INVISIBLE_LINES);
1418 setEffect(SETTING::INVISIBLE_LINES, !previousValue);
1421void ScribbleArea::setLayerVisibility(LayerVisibility visibility)
1423 mLayerVisibility = visibility;
1424 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1429void ScribbleArea::increaseLayerVisibilityIndex()
1432 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1437void ScribbleArea::decreaseLayerVisibilityIndex()
1440 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1448BaseTool* ScribbleArea::currentTool()
const
1450 return editor()->tools()->currentTool();
1453void ScribbleArea::deleteSelection()
1455 auto selectMan = mEditor->select();
1456 if (selectMan->somethingSelected())
1458 Layer* layer = mEditor->layers()->currentLayer();
1459 if (layer ==
nullptr) {
return; }
1463 mEditor->backup(
tr(
"Delete Selection",
"Undo Step: clear the selection area."));
1465 selectMan->clearCurves();
1466 if (layer->type() == Layer::VECTOR)
1468 VectorImage* vectorImage = currentVectorImage(layer);
1469 Q_CHECK_PTR(vectorImage);
1472 else if (layer->type() == Layer::BITMAP)
1474 BitmapImage* bitmapImage = currentBitmapImage(layer);
1475 Q_CHECK_PTR(bitmapImage);
1476 bitmapImage->clear(selectMan->mySelectionRect());
1478 mEditor->setModified(mEditor->currentLayerIndex(), mEditor->currentFrame());
1482void ScribbleArea::clearImage()
1484 Layer* layer = mEditor->layers()->currentLayer();
1485 if (layer ==
nullptr) {
return; }
1487 if (layer->type() == Layer::VECTOR)
1489 mEditor->backup(
tr(
"Clear Image",
"Undo step text"));
1491 VectorImage* vectorImage = currentVectorImage(layer);
1492 if (vectorImage !=
nullptr)
1494 vectorImage->
clear();
1496 mEditor->select()->clearCurves();
1497 mEditor->select()->clearVertices();
1499 else if (layer->type() == Layer::BITMAP)
1501 mEditor->backup(
tr(
"Clear Image",
"Undo step text"));
1503 BitmapImage* bitmapImage = currentBitmapImage(layer);
1504 if (bitmapImage ==
nullptr)
return;
1505 bitmapImage->clear();
1511 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1514void ScribbleArea::paletteColorChanged(
QColor color)
1518 for (
int i = 0; i < mEditor->layers()->count(); i++)
1520 Layer* layer = mEditor->layers()->getLayer(i);
1521 if (layer->type() == Layer::VECTOR)
1523 VectorImage* vectorImage =
static_cast<LayerVector*
>(layer)->getVectorImageAtFrame(mEditor->currentFrame());
1524 if (vectorImage !=
nullptr)
1526 vectorImage->modification();
KeyFrame * addNewKey()
Attempts to create a new keyframe at the current frame and layer.
void frameModified(int frameNumber)
This should be emitted after modifying the frame content.
QList< int > dirtyFrames() const
Returns a list of dirty frame positions.
virtual bool addKeyFrame(int position, KeyFrame *pKeyFrame)
Adds a keyframe at the given position, unless one already exists.
void clearDirtyFrames()
Clear the list of dirty keyframes.
Qt::MouseButton button() const
Returns Qt::MouseButton()
Qt::MouseButtons buttons() const
Returns Qt::MouseButtons()
void onScrubbed(int frameNumber)
Frame scrubbed, invalidate relevant cache.
void onToolPropertyUpdated(ToolType, ToolPropertyType)
Tool property updated, invalidate cache and frame if needed.
void onViewChanged()
View updated, invalidate relevant cache.
void onObjectLoaded()
Object updated, invalidate all cache.
void invalidateCacheForDirtyFrames()
invalidate cache for dirty keyframes.
void updateFrame()
Update frame.
void handleDrawingOnEmptyFrame()
Call this when starting to use a paint tool.
void invalidatePainterCaches()
Invalidate the layer pixmap and camera painter caches.
void invalidateOnionSkinsCacheAround(int frame)
invalidate onion skin cache around frame
void onSelectionChanged()
Selection was changed, keep cache.
void onOnionSkinTypeChanged()
Onion skin type changed, all frames will be affected.
void onFramesModified()
Multiple frames modified, invalidate cache for affected frames.
void onToolChanged(ToolType)
Tool changed, invalidate cache and frame if needed.
void onPlayStateChanged()
Playstate changed, invalidate relevant cache.
void invalidateAllCache()
Invalidate all cache.
void invalidateCacheForFrame(int frameNumber)
Invalidate cache for the given frame.
void onLayerChanged()
Layer changed, invalidate relevant cache.
void onFrameModified(int frameNumber)
Frame modified, invalidate cache for frame if any.
void flipSelection(bool flipVertical)
ScribbleArea::flipSelection flip selection along the X or Y axis.
void drawPath(QPainterPath path, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing)
Draws a path with the specified parameters to the tiled buffer.
void clear()
Clears the content of the tiled buffer.
void drawImage(const QImage &image, const QRect &imageBounds, QPainter::CompositionMode cm, bool antialiasing)
Draws a image with the specified parameters to the tiled buffer.
void drawBrush(QPointF point, qreal brushWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing)
Draws a brush with the specified parameters to the tiled buffer.
QPointF getVertex(int curveNumber, int vertexNumber)
VectorImage::getVertex.
void clear()
VectorImage::clear.
void applySelectionTransformation()
VectorImage::applySelectionTransformation.
void setSelectionTransformation(QTransform transform)
VectorImage::setSelectionTransformation.
int getCurveSize(int curveNumber)
VectorImage::getCurveSize.
void deleteSelection()
VectorImage::deleteSelection.
qreal alphaF() const const
QEvent::Type type() const const
void setColorAt(qreal position, const QColor &color)
bool isAutoRepeat() const const
Qt::KeyboardModifiers modifiers() const const
qreal length() const const
const T & at(int i) const const
QMap::iterator find(const Key &key)
int remove(const Key &key)
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
const QPointF & localPos() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString tr(const char *sourceText, const char *disambiguation, int n)
qreal devicePixelRatioF() const const
QRectF boundingRect() const const
const QRect & rect() const const
void setDevicePixelRatio(qreal scaleFactor)
QPixmap * find(const QString &key)
bool insert(const QString &key, const QPixmap &pixmap)
void remove(const QString &key)
void setCacheLimit(int n)
bool isNull() const const
QPoint toPoint() const const
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
void moveTo(int x, int y)
bool isEmpty() const const
QRect toAlignedRect() const const
QRect toRect() const const
const QPointF & posF() const const
void setInterval(int msec)
bool isActive() const const
const QPointF & posF() const const
QPointF position() const const