18#include "scribblearea.h"
21#include <QGuiApplication>
23#include <QPixmapCache>
25#include "pointerevent.h"
26#include "beziercurve.h"
29#include "layerbitmap.h"
30#include "layervector.h"
31#include "layercamera.h"
32#include "bitmapimage.h"
33#include "vectorimage.h"
36#include "onionskinpainteroptions.h"
38#include "colormanager.h"
39#include "toolmanager.h"
40#include "strokemanager.h"
41#include "layermanager.h"
42#include "playbackmanager.h"
43#include "viewmanager.h"
44#include "selectionmanager.h"
45#include "overlaymanager.h"
47ScribbleArea::ScribbleArea(
QWidget* parent) :
QWidget(parent), mCanvasPainter(mCanvas)
49 setObjectName(
"ScribbleArea");
58ScribbleArea::~ScribbleArea()
62bool ScribbleArea::init()
64 mPrefs = mEditor->preference();
65 mDoubleClickTimer =
new QTimer(
this);
66 mMouseFilterTimer =
new QTimer(
this);
68 connect(mPrefs, &PreferenceManager::optionChanged,
this, &ScribbleArea::settingUpdated);
76 connect(mEditor->select(), &SelectionManager::needDeleteSelection,
this, &ScribbleArea::deleteSelection);
81 const int curveSmoothingLevel = mPrefs->getInt(SETTING::CURVE_SMOOTHING);
82 mCurveSmoothingLevel = curveSmoothingLevel / 20.0;
84 mQuickSizing = mPrefs->isOn(SETTING::QUICK_SIZING);
85 mMakeInvisible =
false;
87 mIsSimplified = mPrefs->isOn(SETTING::OUTLINES);
88 mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION);
90 mLayerVisibility =
static_cast<LayerVisibility
>(mPrefs->getInt(SETTING::LAYER_VISIBILITY));
95#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
102 mPixmapCacheKeys.
clear();
107void ScribbleArea::settingUpdated(SETTING setting)
111 case SETTING::CURVE_SMOOTHING:
112 setCurveSmoothing(mPrefs->getInt(SETTING::CURVE_SMOOTHING));
114 case SETTING::TOOL_CURSOR:
117 case SETTING::ONION_PREV_FRAMES_NUM:
118 case SETTING::ONION_NEXT_FRAMES_NUM:
119 case SETTING::ONION_MIN_OPACITY:
120 case SETTING::ONION_MAX_OPACITY:
123 case SETTING::ANTIALIAS:
125 case SETTING::GRID_SIZE_W:
126 case SETTING::GRID_SIZE_H:
127 case SETTING::OVERLAY_CENTER:
128 case SETTING::OVERLAY_THIRDS:
129 case SETTING::OVERLAY_GOLDEN:
130 case SETTING::OVERLAY_SAFE:
131 case SETTING::OVERLAY_PERSPECTIVE1:
132 case SETTING::OVERLAY_PERSPECTIVE2:
133 case SETTING::OVERLAY_PERSPECTIVE3:
134 case SETTING::ACTION_SAFE_ON:
135 case SETTING::ACTION_SAFE:
136 case SETTING::TITLE_SAFE_ON:
137 case SETTING::TITLE_SAFE:
138 case SETTING::OVERLAY_SAFE_HELPER_TEXT_ON:
139 case SETTING::PREV_ONION:
140 case SETTING::NEXT_ONION:
141 case SETTING::ONION_BLUE:
142 case SETTING::ONION_RED:
143 case SETTING::INVISIBLE_LINES:
144 case SETTING::OUTLINES:
145 case SETTING::ONION_TYPE:
146 case SETTING::ONION_WHILE_PLAYBACK:
149 case SETTING::QUICK_SIZING:
150 mQuickSizing = mPrefs->isOn(SETTING::QUICK_SIZING);
152 case SETTING::MULTILAYER_ONION:
153 mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION);
156 case SETTING::LAYER_VISIBILITY_THRESHOLD:
157 case SETTING::LAYER_VISIBILITY:
158 setLayerVisibility(
static_cast<LayerVisibility
>(mPrefs->getInt(SETTING::LAYER_VISIBILITY)));
166void ScribbleArea::updateToolCursor()
169 updateCanvasCursor();
172void ScribbleArea::setCurveSmoothing(
int newSmoothingLevel)
174 mCurveSmoothingLevel = newSmoothingLevel / 20.0;
178void ScribbleArea::setEffect(SETTING e,
bool isOn)
180 mPrefs->set(e, isOn);
194 Q_ASSERT(frame >= 0);
200 Layer* currentLayer = mEditor->layers()->currentLayer();
211 if (frameNumber < 0) {
return; }
213 bool isOnionAbsolute = mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute";
214 Layer *layer = mEditor->layers()->currentLayer(0);
219 if (mPrefs->isOn(SETTING::PREV_ONION))
221 int onionFrameNumber = frameNumber;
224 onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber + 1,
true);
227 for(
int i = 1; i <= mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM); i++)
229 onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber, isOnionAbsolute);
230 if (onionFrameNumber < 0)
break;
236 if (mPrefs->isOn(SETTING::NEXT_ONION))
238 int onionFrameNumber = frameNumber;
240 for(
int i = 1; i <= mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM); i++)
242 onionFrameNumber = layer->getNextFrameNumber(onionFrameNumber, isOnionAbsolute);
243 if (onionFrameNumber < 0)
break;
253 mPixmapCacheKeys.
clear();
262 auto cacheKeyIter = mPixmapCacheKeys.
find(
static_cast<unsigned int>(frameNumber));
263 if (cacheKeyIter != mPixmapCacheKeys.
end())
266 unsigned int key = cacheKeyIter.key();
267 mPixmapCacheKeys.
remove(key);
273 mCameraPainter.resetCache();
274 mCanvasPainter.resetLayerCache();
282 case ToolPropertyType::CAMERAPATH:
292 int frame = mEditor->currentFrame();
294 prepCameraPainter(frame);
302 int currentFrame = mEditor->currentFrame();
303 if (mPrefs->isOn(SETTING::PREV_ONION) ||
304 mPrefs->isOn(SETTING::NEXT_ONION)) {
308 prepOverlays(currentFrame);
309 prepCameraPainter(currentFrame);
323 if (mPrefs->isOn(SETTING::PREV_ONION) || mPrefs->isOn(SETTING::NEXT_ONION)) {
331 if (mPrefs->isOn(SETTING::PREV_ONION) || mPrefs->isOn(SETTING::NEXT_ONION)) {
351 int currentFrame = mEditor->currentFrame();
366bool ScribbleArea::event(
QEvent *event)
370 editor()->tools()->clearTemporaryTool();
379void ScribbleArea::keyPressEvent(
QKeyEvent *event)
384 mKeyboardInUse =
true;
386 if (isPointerInUse()) {
return; }
388 if (currentTool()->keyPressEvent(event))
395 editor()->tools()->setTemporaryTool(ERASER, {},
event->modifiers()))
402 auto selectMan = mEditor->select();
403 bool isSomethingSelected = selectMan->somethingSelected();
404 if (isSomethingSelected)
406 keyEventForSelection(event);
414void ScribbleArea::keyEventForSelection(
QKeyEvent* event)
416 auto selectMan = mEditor->select();
417 switch (event->
key())
420 selectMan->translate(
QPointF(1, 0));
421 selectMan->calculateSelectionTransformation();
425 selectMan->translate(
QPointF(-1, 0));
426 selectMan->calculateSelectionTransformation();
430 selectMan->translate(
QPointF(0, -1));
431 selectMan->calculateSelectionTransformation();
435 selectMan->translate(
QPointF(0, 1));
436 selectMan->calculateSelectionTransformation();
440 applyTransformedSelection();
441 mEditor->deselectAll();
444 cancelTransformedSelection();
445 mEditor->deselectAll();
449 mEditor->deselectAll();
463void ScribbleArea::keyEvent(
QKeyEvent* event)
465 switch (event->
key())
468 mEditor->scrubForward();
471 mEditor->scrubBackward();
474 mEditor->layers()->gotoNextLayer();
477 mEditor->layers()->gotoPreviouslayer();
491void ScribbleArea::keyReleaseEvent(
QKeyEvent *event)
499 mKeyboardInUse =
false;
501 if (event->
key() == 0)
507 editor()->tools()->tryClearTemporaryTool(
static_cast<Qt::Key>(event->
key()));
510 if (isPointerInUse()) {
return; }
512 if (currentTool()->keyReleaseEvent(event))
524 if (isPointerInUse())
return;
527 const QPoint pixels =
event->pixelDelta();
528 const QPoint angle =
event->angleDelta();
529 const QPointF offset = mEditor->view()->mapScreenToCanvas(event->
posF());
531 const qreal currentScale = mEditor->view()->scaling();
533 if (!isX11 && !pixels.
isNull())
538 const int delta = pixels.
y();
539 const qreal newScale = currentScale * (1 + (delta * 0.01));
540 mEditor->view()->scaleAtOffset(newScale, offset);
544 const int delta = angle.
y();
546 const qreal newScale = currentScale * std::pow(100, delta / (12.0 * 120));
547 mEditor->view()->scaleAtOffset(newScale, offset);
549 updateCanvasCursor();
559 editor()->tools()->tabletSwitchToEraser();
563 editor()->tools()->tabletRestorePrevTool();
569 mStrokeManager->pointerPressEvent(&event);
570 mStrokeManager->setTabletInUse(
true);
573 mIsFirstClick =
false;
574 mDoubleClickTimer->
start();
575 pointerPressEvent(&event);
579 qreal distance =
QLineF(currentTool()->getCurrentPressPoint(), currentTool()->getLastPressPoint()).
length();
581 if (mDoubleClickMillis <= DOUBLE_CLICK_THRESHOLD && distance < 5.0) {
582 currentTool()->pointerDoubleClickEvent(&event);
587 pointerPressEvent(&event);
590 mTabletInUse =
event.isAccepted();
596 mStrokeManager->pointerMoveEvent(&event);
597 pointerMoveEvent(&event);
602 mTabletReleaseMillisAgo = 0;
603 mMouseFilterTimer->
start();
606 mStrokeManager->pointerReleaseEvent(&event);
607 pointerReleaseEvent(&event);
608 mStrokeManager->setTabletInUse(
false);
609 mTabletInUse =
false;
613#if defined Q_OS_LINUX
629void ScribbleArea::pointerPressEvent(
PointerEvent* event)
631 bool isCameraLayer = mEditor->layers()->currentLayer()->type() == Layer::CAMERA;
634 Layer* layer = mEditor->layers()->currentLayer();
635 if (!layer->visible())
646 editor()->tools()->setTemporaryTool(HAND, event->
buttons()))
648 currentTool()->pointerPressEvent(event);
652 if (isPressed && mQuickSizing)
655 if (currentTool()->startAdjusting(event->
modifiers(), 1))
663 currentTool()->pointerPressEvent(event);
669 updateCanvasCursor();
675 if (currentTool()->isAdjusting())
677 currentTool()->adjustCursor(event->
modifiers());
682 currentTool()->pointerMoveEvent(event);
685void ScribbleArea::pointerReleaseEvent(
PointerEvent* event)
687 if (currentTool()->isAdjusting())
689 currentTool()->stopAdjusting();
690 mEditor->tools()->setWidth(
static_cast<float>(currentTool()->properties.width));
696 mMouseRightButtonInUse =
false;
701 currentTool()->pointerReleaseEvent(event);
703 editor()->tools()->tryClearTemporaryTool(event->
button());
706void ScribbleArea::handleDoubleClick()
708 mDoubleClickMillis += 100;
710 if (mDoubleClickMillis >= DOUBLE_CLICK_THRESHOLD)
712 mDoubleClickMillis = 0;
713 mIsFirstClick =
true;
714 mDoubleClickTimer->
stop();
718void ScribbleArea::tabletReleaseEventFired()
726 mTabletReleaseMillisAgo += 50;
728 if (mTabletReleaseMillisAgo >= MOUSE_FILTER_THRESHOLD) {
729 mTabletReleaseMillisAgo = 0;
730 mMouseFilterTimer->
stop();
734bool ScribbleArea::isLayerPaintable()
const
736 Layer* layer = mEditor->layers()->currentLayer();
737 if (layer ==
nullptr) {
return false; }
739 return layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR;
744 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD))
752 mStrokeManager->pointerPressEvent(&event);
754 pointerPressEvent(&event);
755 mMouseInUse =
event.isAccepted();
760 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD)) { e->
ignore();
return; }
763 mStrokeManager->pointerMoveEvent(&event);
765 pointerMoveEvent(&event);
768void ScribbleArea::mouseReleaseEvent(
QMouseEvent* e)
770 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD)) { e->
ignore();
return; }
773 mStrokeManager->pointerReleaseEvent(&event);
775 pointerReleaseEvent(&event);
779void ScribbleArea::mouseDoubleClickEvent(
QMouseEvent* e)
781 if (mStrokeManager->isTabletInUse()) { e->
ignore();
return; }
783 mStrokeManager->pointerPressEvent(&event);
785 currentTool()->pointerDoubleClickEvent(&event);
794 mEditor->view()->setCanvasSize(
size());
798 mCanvasPainter.reset();
801void ScribbleArea::showLayerNotVisibleWarning()
804 tr(
"You are trying to modify a hidden layer! Please select another layer (or make the current layer visible)."),
809void ScribbleArea::paintBitmapBuffer()
813 Q_ASSERT(layer->type() == Layer::BITMAP);
815 int frameNumber = mEditor->currentFrame();
819 if (layer->getLastKeyFrameAtPosition(frameNumber) ==
nullptr)
826 BitmapImage* targetImage = currentBitmapImage(layer);
827 if (targetImage !=
nullptr)
830 switch (currentTool()->type())
838 if (getTool(currentTool()->type())->properties.preserveAlpha)
846 targetImage->paste(&mBufferImg, cm);
849 QRect rect = mEditor->view()->mapCanvasToScreen(mBufferImg.bounds()).toRect();
851 drawCanvas(frameNumber,
rect.adjusted(-1, -1, 1, 1));
856 layer->setModified(frameNumber,
true);
861void ScribbleArea::clearBitmapBuffer()
868 mBufferImg.drawLine(P1, P2, pen, cm, mPrefs->isOn(SETTING::ANTIALIAS));
873 mBufferImg.drawPath(mEditor->view()->mapScreenToCanvas(path), pen, brush, cm, mPrefs->isOn(SETTING::ANTIALIAS));
874 update(mEditor->view()->mapCanvasToScreen(mBufferImg.bounds()).toRect().adjusted(-1, -1, 1, 1));
877void ScribbleArea::paintCanvasCursor(
QPainter& painter)
880 QPointF mousePos = currentTool()->isAdjusting() ? currentTool()->getCurrentPressPoint() : currentTool()->getCurrentPoint();
881 int centerCal = mCursorImg.
width() / 2;
883 mTransformedCursorPos = view.
map(mousePos);
889 mCursorCenterPos.
setX(centerCal);
890 mCursorCenterPos.
setY(centerCal);
892 painter.
drawPixmap(
QPoint(
static_cast<int>(mTransformedCursorPos.
x() - mCursorCenterPos.
x()),
893 static_cast<int>(mTransformedCursorPos.
y() - mCursorCenterPos.
y())),
899 mCursorCenterPos.
setX(centerCal);
900 mCursorCenterPos.
setY(centerCal);
903void ScribbleArea::updateCanvasCursor()
905 float scalingFac = mEditor->view()->scaling();
906 qreal brushWidth = currentTool()->properties.width;
907 qreal brushFeather = currentTool()->properties.feather;
908 if (currentTool()->isAdjusting())
912 else if (mEditor->preference()->isOn(SETTING::DOTTED_CURSOR))
914 bool useFeather = currentTool()->properties.useFeather;
915 mCursorImg = currentTool()->
canvasCursor(
static_cast<float>(brushWidth),
static_cast<float>(brushFeather), useFeather, scalingFac,
width());
923 QPoint translatedPos =
QPoint(
static_cast<int>(mTransformedCursorPos.
x() - mCursorCenterPos.
x()),
924 static_cast<int>(mTransformedCursorPos.
y() - mCursorCenterPos.
y()));
933 auto layer = mEditor->layers()->currentLayer();
935 if (!layer || !layer->isPaintable())
940 if (currentTool()->type() == ERASER) {
944 int frameNumber = mEditor->currentFrame();
945 if (layer->getKeyFrameAt(frameNumber)) {
return; }
948 int action = mPrefs->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION);
949 auto previousKeyFrame = layer->getLastKeyFrameAtPosition(frameNumber);
952 case KEEP_DRAWING_ON_PREVIOUS_KEY:
954 if (previousKeyFrame ==
nullptr) {
955 mEditor->addNewKey();
961 case DUPLICATE_PREVIOUS_KEY:
963 if (previousKeyFrame !=
nullptr) {
964 KeyFrame* dupKey = previousKeyFrame->clone();
965 layer->addKeyFrame(frameNumber, dupKey);
966 mEditor->scrubTo(frameNumber);
974 mEditor->addNewKey();
977 drawCanvas(frameNumber, mCanvas.
rect());
986 int currentFrame = mEditor->currentFrame();
987 if (!currentTool()->isActive())
990 const int frameNumber = mEditor->layers()->lastFrameAtFrame(currentFrame);
994 drawCanvas(currentFrame, event->
rect());
998 auto cacheKeyIter = mPixmapCacheKeys.
find(
static_cast<unsigned>(frameNumber));
1002 drawCanvas(currentFrame, event->
rect());
1014 prepCanvas(currentFrame, event->
rect());
1015 prepCameraPainter(currentFrame);
1016 prepOverlays(currentFrame);
1018 mCanvasPainter.paintCached(event->
rect());
1019 mCameraPainter.paintCached();
1022 if (currentTool()->type() == MOVE)
1024 Layer* layer = mEditor->layers()->currentLayer();
1026 if (layer->type() == Layer::VECTOR)
1028 VectorImage* vectorImage = currentVectorImage(layer);
1029 if (vectorImage !=
nullptr)
1031 vectorImage->setModified(
true);
1042 currentTool()->paint(painter);
1044 Layer* layer = mEditor->layers()->currentLayer();
1046 if (!editor()->playback()->isPlaying())
1048 if (layer->type() == Layer::VECTOR)
1050 VectorImage* vectorImage = currentVectorImage(layer);
1051 if (vectorImage !=
nullptr)
1053 switch (currentTool()->type())
1058 auto selectMan = mEditor->select();
1067 color =
QColor(200, 200, 200);
1070 for (
int k = 0; k < vectorSelection.curve.
size(); k++)
1072 int curveNumber = vectorSelection.curve.
at(k);
1074 for (
int vertexNumber = -1; vertexNumber < vectorImage->
getCurveSize(curveNumber); vertexNumber++)
1077 QRectF rectangle(mEditor->view()->mapCanvasToScreen(vertexPoint) -
QPointF(3.0, 3.0),
QSizeF(7, 7));
1078 if (
rect().contains(mEditor->view()->mapCanvasToScreen(vertexPoint).
toPoint()))
1085 color =
QColor(100, 100, 255);
1087 for (
int k = 0; k < vectorSelection.vertex.
size(); k++)
1089 VertexRef vertexRef = vectorSelection.vertex.
at(k);
1095 color =
QColor(255, 0, 0);
1098 if (vectorSelection.curve.
size() > 0)
1100 for (
int k = 0; k < closestVertices.
size(); k++)
1120 paintCanvasCursor(painter);
1122 mOverlayPainter.paint(painter);
1126 if (mEditor->select()->somethingSelected())
1128 paintSelectionVisuals(painter);
1143void ScribbleArea::paintSelectionVisuals(
QPainter &painter)
1145 Object*
object = mEditor->object();
1147 auto selectMan = mEditor->select();
1149 QRectF currentSelectionRect = selectMan->mySelectionRect();
1151 if (currentSelectionRect.
isEmpty()) {
return; }
1153 TransformParameters params = { currentSelectionRect, editor()->view()->getView(), selectMan->selectionTransform() };
1154 mSelectionPainter.paint(painter,
object, mEditor->currentLayerIndex(), currentTool(), params);
1155 emit selectionUpdated();
1160 Q_ASSERT(layer->type() == Layer::BITMAP);
1161 auto bitmapLayer =
static_cast<LayerBitmap*
>(layer);
1162 return bitmapLayer->getLastBitmapImageAtFrame(mEditor->currentFrame());
1167 Q_ASSERT(layer->type() == Layer::VECTOR);
1168 auto vectorLayer =
static_cast<LayerVector*
>(layer);
1169 return vectorLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
1172void ScribbleArea::prepCameraPainter(
int frame)
1174 Object*
object = mEditor->object();
1176 mCameraPainter.preparePainter(
object,
1177 mEditor->currentLayerIndex(),
1179 mEditor->view()->getView(),
1180 mEditor->playback()->isPlaying(),
1182 mPrefs->getFloat(SETTING::LAYER_VISIBILITY_THRESHOLD),
1183 mEditor->view()->getViewScaleInverse());
1186 onionSkinOptions.enabledWhilePlaying = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK);
1187 onionSkinOptions.isPlaying = mEditor->playback()->isPlaying();
1188 onionSkinOptions.isAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute");
1189 onionSkinOptions.skinPrevFrames = mPrefs->isOn(SETTING::PREV_ONION);
1190 onionSkinOptions.skinNextFrames = mPrefs->isOn(SETTING::NEXT_ONION);
1191 onionSkinOptions.colorizePrevFrames = mPrefs->isOn(SETTING::ONION_RED);
1192 onionSkinOptions.colorizeNextFrames = mPrefs->isOn(SETTING::ONION_BLUE);
1193 onionSkinOptions.framesToSkinPrev = mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM);
1194 onionSkinOptions.framesToSkinNext = mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
1195 onionSkinOptions.maxOpacity = mPrefs->getInt(SETTING::ONION_MAX_OPACITY);
1196 onionSkinOptions.minOpacity = mPrefs->getInt(SETTING::ONION_MIN_OPACITY);
1198 mCameraPainter.setOnionSkinPainterOptions(onionSkinOptions);
1199 mCameraPainter.setCanvas(&mCanvas);
1202void ScribbleArea::prepCanvas(
int frame,
QRect rect)
1204 Object*
object = mEditor->object();
1207 o.bAntiAlias = mPrefs->isOn(SETTING::ANTIALIAS);
1208 o.bThinLines = mPrefs->isOn(SETTING::INVISIBLE_LINES);
1209 o.bOutlines = mPrefs->isOn(SETTING::OUTLINES);
1210 o.eLayerVisibility = mLayerVisibility;
1211 o.fLayerVisibilityThreshold = mPrefs->getFloat(SETTING::LAYER_VISIBILITY_THRESHOLD);
1212 o.scaling = mEditor->view()->scaling();
1216 onionSkinOptions.enabledWhilePlaying = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK);
1217 onionSkinOptions.isPlaying = mEditor->playback()->isPlaying();
1218 onionSkinOptions.isAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute");
1219 onionSkinOptions.skinPrevFrames = mPrefs->isOn(SETTING::PREV_ONION);
1220 onionSkinOptions.skinNextFrames = mPrefs->isOn(SETTING::NEXT_ONION);
1221 onionSkinOptions.colorizePrevFrames = mPrefs->isOn(SETTING::ONION_RED);
1222 onionSkinOptions.colorizeNextFrames = mPrefs->isOn(SETTING::ONION_BLUE);
1223 onionSkinOptions.framesToSkinPrev = mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM);
1224 onionSkinOptions.framesToSkinNext = mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
1225 onionSkinOptions.maxOpacity = mPrefs->getInt(SETTING::ONION_MAX_OPACITY);
1226 onionSkinOptions.minOpacity = mPrefs->getInt(SETTING::ONION_MIN_OPACITY);
1228 mCanvasPainter.setOnionSkinOptions(onionSkinOptions);
1229 mCanvasPainter.setOptions(o);
1233 mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse());
1234 mCanvasPainter.setTransformedSelection(sm->mySelectionRect().
toRect(), sm->selectionTransform());
1236 mCanvasPainter.setPaintSettings(
object, mEditor->layers()->currentLayerIndex(), frame,
rect, &mBufferImg);
1239void ScribbleArea::drawCanvas(
int frame,
QRect rect)
1242 prepCanvas(frame,
rect);
1243 prepCameraPainter(frame);
1244 prepOverlays(frame);
1245 mCanvasPainter.paint(
rect);
1246 mCameraPainter.paint();
1249void ScribbleArea::setGaussianGradient(
QGradient &gradient,
QColor color, qreal opacity, qreal offset)
1251 if (offset < 0) { offset = 0; }
1252 if (offset > 100) { offset = 100; }
1254 int r = color.
red();
1255 int g = color.
green();
1256 int b = color.
blue();
1257 qreal a = color.
alphaF();
1259 int mainColorAlpha = qRound(a * 255 * opacity);
1262 int alphaAdded = qRound((mainColorAlpha * offset) / 100);
1266 gradient.
setColorAt(1.0 - (offset / 100.0),
QColor(r, g, b, mainColorAlpha - alphaAdded));
1269void ScribbleArea::drawPen(
QPointF thePoint, qreal brushWidth,
QColor fillColor,
bool useAA)
1271 QRectF rectangle(thePoint.
x() - 0.5 * brushWidth, thePoint.
y() - 0.5 * brushWidth, brushWidth, brushWidth);
1275 update(mEditor->view()->mapCanvasToScreen(mBufferImg.bounds()).toRect().adjusted(-1, -1, 1, 1));
1278void ScribbleArea::drawPencil(
QPointF thePoint, qreal brushWidth, qreal fixedBrushFeather,
QColor fillColor, qreal opacity)
1280 drawBrush(thePoint, brushWidth, fixedBrushFeather, fillColor, opacity,
true);
1283void ScribbleArea::drawBrush(
QPointF thePoint, qreal brushWidth, qreal mOffset,
QColor fillColor, qreal opacity,
bool usingFeather,
bool useAA)
1285 QRectF rectangle(thePoint.
x() - 0.5 * brushWidth, thePoint.
y() - 0.5 * brushWidth, brushWidth, brushWidth);
1290 setGaussianGradient(radialGrad, fillColor, opacity, mOffset);
1292 mBufferImg.drawEllipse(rectangle,
Qt::NoPen, radialGrad,
1301 update(mEditor->view()->mapCanvasToScreen(mBufferImg.bounds()).toRect().adjusted(-1, -1, 1, 1));
1304void ScribbleArea::flipSelection(
bool flipVertical)
1309void ScribbleArea::prepOverlays(
int frame)
1313 o.bGrid = mPrefs->isOn(SETTING::GRID);
1314 o.nGridSizeW = mPrefs->getInt(SETTING::GRID_SIZE_W);
1315 o.nGridSizeH = mPrefs->getInt(SETTING::GRID_SIZE_H);
1316 o.bCenter = mPrefs->isOn(SETTING::OVERLAY_CENTER);
1317 o.bThirds = mPrefs->isOn(SETTING::OVERLAY_THIRDS);
1318 o.bGoldenRatio = mPrefs->isOn(SETTING::OVERLAY_GOLDEN);
1319 o.bSafeArea = mPrefs->isOn(SETTING::OVERLAY_SAFE);
1320 o.bPerspective1 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE1);
1321 o.bPerspective2 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE2);
1322 o.bPerspective3 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE3);
1323 o.nOverlayAngle = mPrefs->getInt(SETTING::OVERLAY_ANGLE);
1324 o.bActionSafe = mPrefs->isOn(SETTING::ACTION_SAFE_ON);
1325 o.nActionSafe = mPrefs->getInt(SETTING::ACTION_SAFE);
1326 o.bShowSafeAreaHelperText = mPrefs->isOn(SETTING::OVERLAY_SAFE_HELPER_TEXT_ON);
1327 o.bTitleSafe = mPrefs->isOn(SETTING::TITLE_SAFE_ON);
1328 o.nTitleSafe = mPrefs->getInt(SETTING::TITLE_SAFE);
1329 o.nOverlayAngle = mPrefs->getInt(SETTING::OVERLAY_ANGLE);
1330 o.bShowHandle = mEditor->tools()->currentTool()->type() == MOVE && mEditor->layers()->currentLayer()->type() != Layer::CAMERA;
1332 o.mSinglePerspPoint = mEditor->overlays()->getSinglePerspectivePoint();
1333 o.mLeftPerspPoint = mEditor->overlays()->getLeftPerspectivePoint();
1334 o.mRightPerspPoint = mEditor->overlays()->getRightPerspectivePoint();
1335 o.mMiddlePerspPoint = mEditor->overlays()->getMiddlePerspectivePoint();
1337 o.nFrameIndex = frame;
1339 mOverlayPainter.setOptions(o);
1340 mOverlayPainter.preparePainter(mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex()),
palette());
1343 mOverlayPainter.setViewTransform(vm->getView());
1346void ScribbleArea::blurBrush(
BitmapImage *bmiSource_,
QPointF srcPoint_,
QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_)
1349 setGaussianGradient(radialGrad,
QColor(255, 255, 255, 127), opacity_, mOffset_);
1351 QRectF srcRect(srcPoint_.
x() - 0.5 * brushWidth_, srcPoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1352 QRectF trgRect(thePoint_.
x() - 0.5 * brushWidth_, thePoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1354 BitmapImage bmiSrcClip = bmiSource_->copy(srcRect.toAlignedRect());
1358 bmiSrcClip.bounds().
moveTo(trgRect.topLeft().toPoint());
1360 mBufferImg.paste(&bmiTmpClip);
1362 update(mEditor->view()->mapCanvasToScreen(mBufferImg.bounds()).toRect().adjusted(-1, -1, 1, 1));
1365void ScribbleArea::liquifyBrush(
BitmapImage *bmiSource_,
QPointF srcPoint_,
QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_)
1367 QPointF delta = (thePoint_ - srcPoint_);
1368 QRectF trgRect(thePoint_.
x() - 0.5 * brushWidth_, thePoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1371 setGaussianGradient(radialGrad,
QColor(255, 255, 255, 255), opacity_, mOffset_);
1378 qreal factor, factorGrad;
1380 for (
int yb = bmiTmpClip.top(); yb < bmiTmpClip.bottom(); yb++)
1382 for (
int xb = bmiTmpClip.left(); xb < bmiTmpClip.right(); xb++)
1385 color.
setRgba(bmiTmpClip.pixel(xb, yb));
1386 factorGrad = color.
alphaF();
1388 int xa = xb - factorGrad * delta.
x();
1389 int ya = yb - factorGrad * delta.
y();
1391 color.
setRgba(bmiSource_->pixel(xa, ya));
1406 bmiTmpClip.setPixel(xb, yb, color.
rgba());
1410 bmiTmpClip.setPixel(xb, yb, qRgba(255, 255, 255, 0));
1414 mBufferImg.paste(&bmiTmpClip);
1416 update(mEditor->view()->mapCanvasToScreen(mBufferImg.bounds()).toRect().adjusted(-1, -1, 1, 1));
1425 blitRect.extend(mEditor->view()->mapCanvasToScreen(mBufferImg.bounds()).toRect());
1427 QRect updateRect = mEditor->view()->mapCanvasToScreen(path.
boundingRect()).toRect();
1429 blitRect.extend(updateRect);
1441QPointF ScribbleArea::getCentralPoint()
1446void ScribbleArea::applyTransformedSelection()
1448 mCanvasPainter.ignoreTransformedSelection();
1450 Layer* layer = mEditor->layers()->currentLayer();
1451 if (layer ==
nullptr) {
return; }
1453 auto selectMan = mEditor->select();
1454 if (selectMan->somethingSelected())
1456 if (selectMan->mySelectionRect().isEmpty() || selectMan->selectionTransform().isIdentity()) {
return; }
1458 if (layer->type() == Layer::BITMAP)
1461 BitmapImage* bitmapImage = currentBitmapImage(layer);
1462 if (bitmapImage ==
nullptr) {
return; }
1463 BitmapImage transformedImage = bitmapImage->transformed(selectMan->mySelectionRect().toRect(), selectMan->selectionTransform(),
true);
1466 bitmapImage->clear(selectMan->mySelectionRect());
1469 else if (layer->type() == Layer::VECTOR)
1474 VectorImage* vectorImage = currentVectorImage(layer);
1475 if (vectorImage ==
nullptr) {
return; }
1480 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1486void ScribbleArea::cancelTransformedSelection()
1488 mCanvasPainter.ignoreTransformedSelection();
1490 auto selectMan = mEditor->select();
1491 if (selectMan->somethingSelected())
1493 Layer* layer = mEditor->layers()->currentLayer();
1494 if (layer ==
nullptr) {
return; }
1496 if (layer->type() == Layer::VECTOR)
1498 VectorImage* vectorImage = currentVectorImage(layer);
1499 if (vectorImage !=
nullptr)
1505 mEditor->select()->setSelection(selectMan->mySelectionRect(),
false);
1507 selectMan->resetSelectionProperties();
1510 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1515void ScribbleArea::displaySelectionProperties()
1517 Layer* layer = mEditor->layers()->currentLayer();
1518 if (layer ==
nullptr) {
return; }
1519 if (layer->type() == Layer::VECTOR)
1521 VectorImage* vectorImage = currentVectorImage(layer);
1522 if (vectorImage ==
nullptr) {
return; }
1524 if (currentTool()->type() == MOVE)
1527 if (selectedCurve != -1)
1529 mEditor->tools()->setWidth(vectorImage->curve(selectedCurve).getWidth());
1530 mEditor->tools()->setFeather(vectorImage->curve(selectedCurve).getFeather());
1531 mEditor->tools()->setInvisibility(vectorImage->curve(selectedCurve).isInvisible());
1532 mEditor->tools()->setPressure(vectorImage->curve(selectedCurve).getVariableWidth());
1533 mEditor->color()->setColorNumber(vectorImage->curve(selectedCurve).getColorNumber());
1537 if (selectedArea != -1)
1539 mEditor->color()->setColorNumber(vectorImage->mArea[selectedArea].mColorNumber);
1545void ScribbleArea::toggleThinLines()
1547 bool previousValue = mPrefs->isOn(SETTING::INVISIBLE_LINES);
1548 setEffect(SETTING::INVISIBLE_LINES, !previousValue);
1551void ScribbleArea::toggleOutlines()
1553 mIsSimplified = !mIsSimplified;
1554 setEffect(SETTING::OUTLINES, mIsSimplified);
1557void ScribbleArea::setLayerVisibility(LayerVisibility visibility)
1559 mLayerVisibility = visibility;
1560 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1565void ScribbleArea::increaseLayerVisibilityIndex()
1568 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1573void ScribbleArea::decreaseLayerVisibilityIndex()
1576 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1584BaseTool* ScribbleArea::currentTool()
const
1586 return editor()->tools()->currentTool();
1589BaseTool* ScribbleArea::getTool(ToolType eToolType)
1591 return editor()->tools()->getTool(eToolType);
1594void ScribbleArea::setCurrentTool(ToolType eToolMode)
1600 updateCanvasCursor();
1604void ScribbleArea::deleteSelection()
1606 auto selectMan = mEditor->select();
1607 if (selectMan->somethingSelected())
1609 Layer* layer = mEditor->layers()->currentLayer();
1610 if (layer ==
nullptr) {
return; }
1614 mEditor->backup(
tr(
"Delete Selection",
"Undo Step: clear the selection area."));
1616 selectMan->clearCurves();
1617 if (layer->type() == Layer::VECTOR)
1619 VectorImage* vectorImage = currentVectorImage(layer);
1620 Q_CHECK_PTR(vectorImage);
1623 else if (layer->type() == Layer::BITMAP)
1625 BitmapImage* bitmapImage = currentBitmapImage(layer);
1626 Q_CHECK_PTR(bitmapImage);
1627 bitmapImage->clear(selectMan->mySelectionRect());
1629 mEditor->setModified(mEditor->currentLayerIndex(), mEditor->currentFrame());
1633void ScribbleArea::clearImage()
1635 Layer* layer = mEditor->layers()->currentLayer();
1636 if (layer ==
nullptr) {
return; }
1638 if (layer->type() == Layer::VECTOR)
1640 mEditor->backup(
tr(
"Clear Image",
"Undo step text"));
1642 VectorImage* vectorImage = currentVectorImage(layer);
1643 if (vectorImage !=
nullptr)
1645 vectorImage->
clear();
1647 mEditor->select()->clearCurves();
1648 mEditor->select()->clearVertices();
1650 else if (layer->type() == Layer::BITMAP)
1652 mEditor->backup(
tr(
"Clear Image",
"Undo step text"));
1654 BitmapImage* bitmapImage = currentBitmapImage(layer);
1655 if (bitmapImage ==
nullptr)
return;
1656 bitmapImage->clear();
1662 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1665void ScribbleArea::paletteColorChanged(
QColor color)
1669 for (
int i = 0; i < mEditor->layers()->count(); i++)
1671 Layer* layer = mEditor->layers()->getLayer(i);
1672 if (layer->type() == Layer::VECTOR)
1674 VectorImage* vectorImage =
static_cast<LayerVector*
>(layer)->getVectorImageAtFrame(mEditor->currentFrame());
1675 if (vectorImage !=
nullptr)
1677 vectorImage->modification();
1685void ScribbleArea::floodFillError(
int errorType)
1688 if (errorType == 1) { message =
tr(
"There is a gap in your drawing (or maybe you have zoomed too much)."); }
1689 if (errorType == 2 || errorType == 3)
1691 message =
tr(
"Sorry! This doesn't always work."
1692 "Please try again (zoom a bit, click at another location... )<br>"
1693 "if it doesn't work, zoom a bit and check that your paths are connected by pressing F1.).");
1696 if (errorType == 1) { error =
tr(
"Out of bound.",
"Bucket tool fill error message"); }
1697 if (errorType == 2) { error =
tr(
"Could not find a closed path.",
"Bucket tool fill error message"); }
1698 if (errorType == 3) { error =
tr(
"Could not find the root index.",
"Bucket tool fill error message"); }
1700 mEditor->deselectAll();
void frameModified(int frameNumber)
This should be emitted after modifying the frame content.
QList< int > dirtyFrames() const
Returns a list of dirty frame positions.
void clearDirtyFrames()
Clear the list of dirty keyframes.
Qt::MouseButton button() const
Returns Qt::MouseButton()
Qt::KeyboardModifiers modifiers() const
Returns the modifier created by keyboard while a device was in use.
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 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 updateCurrentFrame()
Update current frame.
void invalidateAllCache()
Invalidate all cache.
void invalidateCacheForFrame(int frameNumber)
Invalidate cache for the given frame.
void updateFrame(int frame)
Update 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.
int getFirstSelectedArea()
VectorImage::getFirstSelectedArea.
int getFirstSelectedCurve()
VectorImage::getFirstSelectedCurve.
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)
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
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
void drawRect(const QRectF &rectangle)
void setBrush(const QBrush &brush)
void setPen(const QColor &color)
void setRenderHint(QPainter::RenderHint hint, bool on)
void setWorldMatrixEnabled(bool enable)
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)
QRect translated(int dx, int dy) const const
bool isEmpty() const const
QRect toRect() const const
void setInterval(int msec)
bool isActive() const const
const QPointF & posF() const const