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()->
event(event) || processed;
399void ScribbleArea::keyPressEvent(
QKeyEvent *event)
404 if (isPointerInUse()) {
return; }
406 if (currentTool()->keyPressEvent(event))
413 editor()->tools()->setTemporaryTool(ERASER, {},
event->modifiers()))
420 auto selectMan = mEditor->select();
421 bool isSomethingSelected = selectMan->somethingSelected();
422 if (isSomethingSelected)
424 keyEventForSelection(event);
432void ScribbleArea::keyEventForSelection(
QKeyEvent* event)
434 auto selectMan = mEditor->select();
435 switch (event->
key())
438 selectMan->translate(
QPointF(1, 0));
439 selectMan->calculateSelectionTransformation();
443 selectMan->translate(
QPointF(-1, 0));
444 selectMan->calculateSelectionTransformation();
448 selectMan->translate(
QPointF(0, -1));
449 selectMan->calculateSelectionTransformation();
453 selectMan->translate(
QPointF(0, 1));
454 selectMan->calculateSelectionTransformation();
458 applyTransformedSelection();
459 mEditor->deselectAll();
462 cancelTransformedSelection();
463 mEditor->deselectAll();
467 mEditor->deselectAll();
481void ScribbleArea::keyEvent(
QKeyEvent* event)
483 switch (event->
key())
486 mEditor->scrubForward();
489 mEditor->scrubBackward();
492 mEditor->layers()->gotoNextLayer();
495 mEditor->layers()->gotoPreviouslayer();
509void ScribbleArea::keyReleaseEvent(
QKeyEvent *event)
517 if (event->
key() == 0)
523 editor()->tools()->tryClearTemporaryTool(
static_cast<Qt::Key>(event->
key()));
526 if (isPointerInUse()) {
return; }
528 if (currentTool()->keyReleaseEvent(event))
540 if (isPointerInUse())
return;
543 const QPoint pixels =
event->pixelDelta();
544 const QPoint angle =
event->angleDelta();
545#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
546 const QPointF offset = mEditor->view()->mapScreenToCanvas(event->
position());
548 const QPointF offset = mEditor->view()->mapScreenToCanvas(event->
posF());
551 const qreal currentScale = mEditor->view()->scaling();
555 if (!isX11 && !pixels.
isNull())
565 const qreal newScale = currentScale * std::pow(100, (delta * mDeltaFactor) / (12.0 * 120));
566 mEditor->view()->scaleAtOffset(newScale, offset);
575#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
576 if (event.pointerType() == QPointingDevice::PointerType::Eraser)
581 editor()->tools()->tabletSwitchToEraser();
585 editor()->tools()->tabletRestorePrevTool();
588 if (event.eventType() == PointerEvent::Press)
593 mIsFirstClick =
false;
594 mDoubleClickTimer->
start();
595 pointerPressEvent(&event);
600 mTabletPressPos = e->
posF();
602 if (mDoubleClickMillis <= DOUBLE_CLICK_THRESHOLD && distance < 5.0) {
603 currentTool()->pointerDoubleClickEvent(&event);
608 pointerPressEvent(&event);
611 mTabletInUse =
event.isAccepted();
613 else if (event.eventType() == PointerEvent::Move)
617 pointerMoveEvent(&event);
620 else if (event.eventType() == PointerEvent::Release)
622 mTabletReleaseMillisAgo = 0;
623 mMouseFilterTimer->
start();
626 pointerReleaseEvent(&event);
627 mTabletInUse =
false;
631#if defined Q_OS_LINUX
647void ScribbleArea::pointerPressEvent(
PointerEvent* event)
649 bool isCameraLayer = mEditor->layers()->currentLayer()->type() == Layer::CAMERA;
652 Layer* layer = mEditor->layers()->currentLayer();
653 if (!layer->visible())
664 editor()->tools()->setTemporaryTool(HAND, event->
buttons()))
666 currentTool()->pointerPressEvent(event);
669 currentTool()->pointerPressEvent(event);
675 currentTool()->pointerMoveEvent(event);
678void ScribbleArea::pointerReleaseEvent(
PointerEvent* event)
680 currentTool()->pointerReleaseEvent(event);
682 editor()->tools()->tryClearTemporaryTool(event->
button());
685void ScribbleArea::handleDoubleClick()
687 mDoubleClickMillis += 100;
689 if (mDoubleClickMillis >= DOUBLE_CLICK_THRESHOLD)
691 mDoubleClickMillis = 0;
692 mIsFirstClick =
true;
693 mDoubleClickTimer->
stop();
697void ScribbleArea::tabletReleaseEventFired()
705 mTabletReleaseMillisAgo += 50;
707 if (mTabletReleaseMillisAgo >= MOUSE_FILTER_THRESHOLD) {
708 mTabletReleaseMillisAgo = 0;
709 mMouseFilterTimer->
stop();
713bool ScribbleArea::isLayerPaintable()
const
715 Layer* layer = mEditor->layers()->currentLayer();
716 if (layer ==
nullptr) {
return false; }
718 return layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR;
723 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD))
730 pointerPressEvent(&event);
731 mMouseInUse =
event.isAccepted();
736 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD)) { e->
ignore();
return; }
739 pointerMoveEvent(&event);
742void ScribbleArea::mouseReleaseEvent(
QMouseEvent* e)
744 if (mTabletInUse || (mMouseFilterTimer->
isActive() && mTabletReleaseMillisAgo < MOUSE_FILTER_THRESHOLD)) { e->
ignore();
return; }
747 pointerReleaseEvent(&event);
751void ScribbleArea::mouseDoubleClickEvent(
QMouseEvent* e)
753 if (mTabletInUse) { e->
ignore();
return; }
756 currentTool()->pointerDoubleClickEvent(&event);
765 mEditor->view()->setCanvasSize(
size());
769 mCanvasPainter.reset();
770 mCameraPainter.reset();
773void ScribbleArea::showLayerNotVisibleWarning()
776 tr(
"You are trying to modify a hidden layer! Please select another layer (or make the current layer visible)."),
781void ScribbleArea::paintBitmapBuffer()
785 Q_ASSERT(layer->type() == Layer::BITMAP);
787 int frameNumber = mEditor->currentFrame();
791 if (layer->getLastKeyFrameAtPosition(frameNumber) ==
nullptr)
797 BitmapImage* targetImage = currentBitmapImage(layer);
798 if (targetImage !=
nullptr)
801 switch (currentTool()->type())
809 if (currentTool()->properties.preserveAlpha)
817 targetImage->paste(&mTiledBuffer, cm);
820 QRect rect = mEditor->view()->mapCanvasToScreen(mTiledBuffer.bounds()).toRect();
824 layer->setModified(frameNumber,
true);
825 mTiledBuffer.
clear();
828void ScribbleArea::clearDrawingBuffer()
830 mTiledBuffer.
clear();
835 auto layer = mEditor->layers()->currentLayer();
837 if (!layer || !layer->isPaintable())
842 if (currentTool()->type() == ERASER) {
846 int frameNumber = mEditor->currentFrame();
847 if (layer->getKeyFrameAt(frameNumber)) {
return; }
850 int action = mPrefs->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION);
851 auto previousKeyFrame = layer->getLastKeyFrameAtPosition(frameNumber);
854 case KEEP_DRAWING_ON_PREVIOUS_KEY:
856 if (previousKeyFrame ==
nullptr) {
863 case DUPLICATE_PREVIOUS_KEY:
865 if (previousKeyFrame !=
nullptr) {
866 KeyFrame* dupKey = previousKeyFrame->clone();
868 mEditor->scrubTo(frameNumber);
879 drawCanvas(frameNumber, mCanvas.
rect());
888 int currentFrame = mEditor->currentFrame();
889 if (!currentTool()->isActive())
892 const int frameNumber = mEditor->layers()->lastFrameAtFrame(currentFrame);
896 drawCanvas(currentFrame, event->
rect());
900 auto cacheKeyIter = mPixmapCacheKeys.
find(
static_cast<unsigned>(frameNumber));
904 drawCanvas(currentFrame, event->
rect());
916 prepCanvas(currentFrame);
917 prepCameraPainter(currentFrame);
918 prepOverlays(currentFrame);
920 mCanvasPainter.paintCached(event->
rect());
921 mCameraPainter.paintCached(event->
rect());
924 if (currentTool()->type() == MOVE)
926 Layer* layer = mEditor->layers()->currentLayer();
928 if (layer->type() == Layer::VECTOR)
930 VectorImage* vectorImage = currentVectorImage(layer);
931 if (vectorImage !=
nullptr)
933 vectorImage->setModified(
true);
941 painter.setWorldMatrixEnabled(
false);
946 painter.setClipRect(event->
rect());
947 painter.drawPixmap(
QPointF(), mCanvas);
949 currentTool()->paint(painter, event->
rect());
951 if (!editor()->playback()->isPlaying())
953 Layer* layer = mEditor->layers()->currentLayer();
954 if (layer->type() == Layer::VECTOR)
956 VectorImage* vectorImage = currentVectorImage(layer);
957 if (vectorImage !=
nullptr)
959 switch (currentTool()->type())
964 auto selectMan = mEditor->select();
966 painter.setWorldMatrixEnabled(
false);
970 painter.setPen(pen2);
973 color =
QColor(200, 200, 200);
974 painter.setBrush(color);
976 for (
int k = 0; k < vectorSelection.curve.
size(); k++)
978 int curveNumber = vectorSelection.curve.
at(k);
980 for (
int vertexNumber = -1; vertexNumber < vectorImage->
getCurveSize(curveNumber); vertexNumber++)
983 QRectF rectangle(mEditor->view()->mapCanvasToScreen(vertexPoint) -
QPointF(3.0, 3.0),
QSizeF(7, 7));
984 if (
rect().contains(mEditor->view()->mapCanvasToScreen(vertexPoint).
toPoint()))
986 painter.drawRect(rectangle);
991 color =
QColor(100, 100, 255);
992 painter.setBrush(color);
993 for (
int k = 0; k < vectorSelection.vertex.
size(); k++)
995 VertexRef vertexRef = vectorSelection.vertex.
at(k);
998 painter.drawRect(rectangle0);
1001 color =
QColor(255, 0, 0);
1002 painter.setBrush(color);
1004 if (vectorSelection.curve.
size() > 0)
1006 for (
int k = 0; k < closestVertices.
size(); k++)
1012 painter.drawRect(rectangle);
1026 mOverlayPainter.paint(painter,
rect());
1029 if (mEditor->select()->somethingSelected())
1031 paintSelectionVisuals(painter);
1037 painter.setWorldMatrixEnabled(
false);
1046void ScribbleArea::paintSelectionVisuals(
QPainter &painter)
1048 Object*
object = mEditor->object();
1050 auto selectMan = mEditor->select();
1052 QRectF currentSelectionRect = selectMan->mySelectionRect();
1054 if (currentSelectionRect.
isEmpty()) {
return; }
1056 TransformParameters params = { currentSelectionRect, editor()->view()->getView(), selectMan->selectionTransform() };
1057 mSelectionPainter.paint(painter,
object, mEditor->currentLayerIndex(), currentTool(), params);
1058 emit selectionUpdated();
1063 Q_ASSERT(layer->type() == Layer::BITMAP);
1064 auto bitmapLayer =
static_cast<LayerBitmap*
>(layer);
1065 return bitmapLayer->getLastBitmapImageAtFrame(mEditor->currentFrame());
1070 Q_ASSERT(layer->type() == Layer::VECTOR);
1071 auto vectorLayer =
static_cast<LayerVector*
>(layer);
1072 return vectorLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0);
1075void ScribbleArea::prepCameraPainter(
int frame)
1077 Object*
object = mEditor->object();
1079 mCameraPainter.preparePainter(
object,
1080 mEditor->currentLayerIndex(),
1082 mEditor->view()->getView(),
1083 mEditor->playback()->isPlaying(),
1085 mPrefs->getFloat(SETTING::LAYER_VISIBILITY_THRESHOLD),
1086 mEditor->view()->getViewScaleInverse());
1089 onionSkinOptions.enabledWhilePlaying = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK);
1090 onionSkinOptions.isPlaying = mEditor->playback()->isPlaying();
1091 onionSkinOptions.isAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute");
1092 onionSkinOptions.skinPrevFrames = mPrefs->isOn(SETTING::PREV_ONION);
1093 onionSkinOptions.skinNextFrames = mPrefs->isOn(SETTING::NEXT_ONION);
1094 onionSkinOptions.colorizePrevFrames = mPrefs->isOn(SETTING::ONION_RED);
1095 onionSkinOptions.colorizeNextFrames = mPrefs->isOn(SETTING::ONION_BLUE);
1096 onionSkinOptions.framesToSkinPrev = mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM);
1097 onionSkinOptions.framesToSkinNext = mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
1098 onionSkinOptions.maxOpacity = mPrefs->getInt(SETTING::ONION_MAX_OPACITY);
1099 onionSkinOptions.minOpacity = mPrefs->getInt(SETTING::ONION_MIN_OPACITY);
1101 mCameraPainter.setOnionSkinPainterOptions(onionSkinOptions);
1104void ScribbleArea::prepCanvas(
int frame)
1106 Object*
object = mEditor->object();
1109 o.bAntiAlias = mPrefs->isOn(SETTING::ANTIALIAS);
1110 o.bThinLines = mPrefs->isOn(SETTING::INVISIBLE_LINES);
1111 o.bOutlines = mPrefs->isOn(SETTING::OUTLINES);
1112 o.eLayerVisibility = mLayerVisibility;
1113 o.fLayerVisibilityThreshold = mPrefs->getFloat(SETTING::LAYER_VISIBILITY_THRESHOLD);
1114 o.scaling = mEditor->view()->scaling();
1118 onionSkinOptions.enabledWhilePlaying = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK);
1119 onionSkinOptions.isPlaying = mEditor->playback()->isPlaying();
1120 onionSkinOptions.isAbsolute = (mPrefs->getString(SETTING::ONION_TYPE) ==
"absolute");
1121 onionSkinOptions.skinPrevFrames = mPrefs->isOn(SETTING::PREV_ONION);
1122 onionSkinOptions.skinNextFrames = mPrefs->isOn(SETTING::NEXT_ONION);
1123 onionSkinOptions.colorizePrevFrames = mPrefs->isOn(SETTING::ONION_RED);
1124 onionSkinOptions.colorizeNextFrames = mPrefs->isOn(SETTING::ONION_BLUE);
1125 onionSkinOptions.framesToSkinPrev = mPrefs->getInt(SETTING::ONION_PREV_FRAMES_NUM);
1126 onionSkinOptions.framesToSkinNext = mPrefs->getInt(SETTING::ONION_NEXT_FRAMES_NUM);
1127 onionSkinOptions.maxOpacity = mPrefs->getInt(SETTING::ONION_MAX_OPACITY);
1128 onionSkinOptions.minOpacity = mPrefs->getInt(SETTING::ONION_MIN_OPACITY);
1130 mCanvasPainter.setOnionSkinOptions(onionSkinOptions);
1131 mCanvasPainter.setOptions(o);
1135 mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse());
1136 mCanvasPainter.setTransformedSelection(sm->mySelectionRect().
toRect(), sm->selectionTransform());
1138 mCanvasPainter.setPaintSettings(
object, mEditor->layers()->currentLayerIndex(), frame, &mTiledBuffer);
1141void ScribbleArea::drawCanvas(
int frame,
QRect rect)
1144 prepCameraPainter(frame);
1145 prepOverlays(frame);
1146 mCanvasPainter.paint(
rect);
1147 mCameraPainter.paint(
rect);
1150void ScribbleArea::setGaussianGradient(
QGradient &gradient,
QColor color, qreal opacity, qreal offset)
1152 if (offset < 0) { offset = 0; }
1153 if (offset > 100) { offset = 100; }
1155 int r = color.
red();
1156 int g = color.
green();
1157 int b = color.
blue();
1158 qreal a = color.
alphaF();
1160 int mainColorAlpha = qRound(a * 255 * opacity);
1163 int alphaAdded = qRound((mainColorAlpha * offset) / 100);
1167 gradient.
setColorAt(1.0 - (offset / 100.0),
QColor(r, g, b, mainColorAlpha - alphaAdded));
1172 mTiledBuffer.
drawPath(mEditor->view()->mapScreenToCanvas(path), pen, brush, cm, mPrefs->isOn(SETTING::ANTIALIAS));
1175void ScribbleArea::drawPen(
QPointF thePoint, qreal brushWidth,
QColor fillColor,
bool useAA)
1181void ScribbleArea::drawPencil(
QPointF thePoint, qreal brushWidth, qreal fixedBrushFeather,
QColor fillColor, qreal opacity)
1192 setGaussianGradient(radialGrad, fillColor, opacity, mOffset);
1208 blitRect.extend(mEditor->view()->mapCanvasToScreen(mTiledBuffer.bounds()).toRect());
1210 QRect updateRect = mEditor->view()->mapCanvasToScreen(path.
boundingRect()).toRect();
1212 blitRect.extend(updateRect);
1214 mTiledBuffer.
clear();
1221void ScribbleArea::endStroke()
1223 if (mEditor->layers()->currentLayer()->type() == Layer::BITMAP) {
1224 paintBitmapBuffer();
1230void ScribbleArea::flipSelection(
bool flipVertical)
1235void ScribbleArea::prepOverlays(
int frame)
1239 o.bGrid = mPrefs->isOn(SETTING::GRID);
1240 o.nGridSizeW = mPrefs->getInt(SETTING::GRID_SIZE_W);
1241 o.nGridSizeH = mPrefs->getInt(SETTING::GRID_SIZE_H);
1242 o.bCenter = mPrefs->isOn(SETTING::OVERLAY_CENTER);
1243 o.bThirds = mPrefs->isOn(SETTING::OVERLAY_THIRDS);
1244 o.bGoldenRatio = mPrefs->isOn(SETTING::OVERLAY_GOLDEN);
1245 o.bSafeArea = mPrefs->isOn(SETTING::OVERLAY_SAFE);
1246 o.bPerspective1 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE1);
1247 o.bPerspective2 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE2);
1248 o.bPerspective3 = mPrefs->isOn(SETTING::OVERLAY_PERSPECTIVE3);
1249 o.nOverlayAngle = mPrefs->getInt(SETTING::OVERLAY_ANGLE);
1250 o.bActionSafe = mPrefs->isOn(SETTING::ACTION_SAFE_ON);
1251 o.nActionSafe = mPrefs->getInt(SETTING::ACTION_SAFE);
1252 o.bShowSafeAreaHelperText = mPrefs->isOn(SETTING::OVERLAY_SAFE_HELPER_TEXT_ON);
1253 o.bTitleSafe = mPrefs->isOn(SETTING::TITLE_SAFE_ON);
1254 o.nTitleSafe = mPrefs->getInt(SETTING::TITLE_SAFE);
1255 o.nOverlayAngle = mPrefs->getInt(SETTING::OVERLAY_ANGLE);
1256 o.bShowHandle = mEditor->tools()->currentTool()->type() == MOVE && mEditor->layers()->currentLayer()->type() != Layer::CAMERA;
1258 o.mSinglePerspPoint = mEditor->overlays()->getSinglePerspectivePoint();
1259 o.mLeftPerspPoint = mEditor->overlays()->getLeftPerspectivePoint();
1260 o.mRightPerspPoint = mEditor->overlays()->getRightPerspectivePoint();
1261 o.mMiddlePerspPoint = mEditor->overlays()->getMiddlePerspectivePoint();
1263 o.nFrameIndex = frame;
1265 mOverlayPainter.setOptions(o);
1266 mOverlayPainter.preparePainter(mEditor->layers()->getCameraLayerBelow(mEditor->currentLayerIndex()),
palette());
1269 mOverlayPainter.setViewTransform(vm->getView());
1272void ScribbleArea::blurBrush(
BitmapImage *bmiSource_,
QPointF srcPoint_,
QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_)
1275 setGaussianGradient(radialGrad,
QColor(255, 255, 255, 127), opacity_, mOffset_);
1277 QRectF srcRect(srcPoint_.
x() - 0.5 * brushWidth_, srcPoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1278 QRectF trgRect(thePoint_.
x() - 0.5 * brushWidth_, thePoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1280 BitmapImage bmiSrcClip = bmiSource_->copy(srcRect.toAlignedRect());
1284 bmiSrcClip.bounds().
moveTo(trgRect.topLeft().toPoint());
1289void ScribbleArea::liquifyBrush(
BitmapImage *bmiSource_,
QPointF srcPoint_,
QPointF thePoint_, qreal brushWidth_, qreal mOffset_, qreal opacity_)
1291 QPointF delta = (thePoint_ - srcPoint_);
1292 QRectF trgRect(thePoint_.
x() - 0.5 * brushWidth_, thePoint_.
y() - 0.5 * brushWidth_, brushWidth_, brushWidth_);
1295 setGaussianGradient(radialGrad,
QColor(255, 255, 255, 255), opacity_, mOffset_);
1302 qreal factor, factorGrad;
1304 for (
int yb = bmiTmpClip.top(); yb < bmiTmpClip.bottom(); yb++)
1306 for (
int xb = bmiTmpClip.left(); xb < bmiTmpClip.right(); xb++)
1309 color.
setRgba(bmiTmpClip.pixel(xb, yb));
1310 factorGrad = color.
alphaF();
1312 int xa = xb - factorGrad * delta.
x();
1313 int ya = yb - factorGrad * delta.
y();
1315 color.
setRgba(bmiSource_->pixel(xa, ya));
1330 bmiTmpClip.setPixel(xb, yb, color.
rgba());
1334 bmiTmpClip.setPixel(xb, yb, qRgba(255, 255, 255, 0));
1344QPointF ScribbleArea::getCentralPoint()
1349void ScribbleArea::applyTransformedSelection()
1351 mCanvasPainter.ignoreTransformedSelection();
1353 Layer* layer = mEditor->layers()->currentLayer();
1354 if (layer ==
nullptr) {
return; }
1356 auto selectMan = mEditor->select();
1357 if (selectMan->somethingSelected())
1359 if (selectMan->mySelectionRect().isEmpty() || selectMan->selectionTransform().isIdentity()) {
return; }
1361 if (layer->type() == Layer::BITMAP)
1364 BitmapImage* bitmapImage = currentBitmapImage(layer);
1365 if (bitmapImage ==
nullptr) {
return; }
1366 BitmapImage transformedImage = bitmapImage->transformed(selectMan->mySelectionRect().toRect(), selectMan->selectionTransform(),
true);
1369 bitmapImage->clear(selectMan->mySelectionRect());
1372 else if (layer->type() == Layer::VECTOR)
1377 VectorImage* vectorImage = currentVectorImage(layer);
1378 if (vectorImage ==
nullptr) {
return; }
1383 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1389void ScribbleArea::cancelTransformedSelection()
1391 mCanvasPainter.ignoreTransformedSelection();
1393 auto selectMan = mEditor->select();
1394 if (selectMan->somethingSelected())
1396 Layer* layer = mEditor->layers()->currentLayer();
1397 if (layer ==
nullptr) {
return; }
1399 if (layer->type() == Layer::VECTOR)
1401 VectorImage* vectorImage = currentVectorImage(layer);
1402 if (vectorImage !=
nullptr)
1408 mEditor->select()->setSelection(selectMan->mySelectionRect(),
false);
1410 selectMan->resetSelectionProperties();
1413 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1418void ScribbleArea::toggleThinLines()
1420 bool previousValue = mPrefs->isOn(SETTING::INVISIBLE_LINES);
1421 setEffect(SETTING::INVISIBLE_LINES, !previousValue);
1424void ScribbleArea::setLayerVisibility(LayerVisibility visibility)
1426 mLayerVisibility = visibility;
1427 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1432void ScribbleArea::increaseLayerVisibilityIndex()
1435 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1440void ScribbleArea::decreaseLayerVisibilityIndex()
1443 mPrefs->set(SETTING::LAYER_VISIBILITY,
static_cast<int>(mLayerVisibility));
1451BaseTool* ScribbleArea::currentTool()
const
1453 return editor()->tools()->currentTool();
1456void ScribbleArea::deleteSelection()
1458 auto selectMan = mEditor->select();
1459 if (selectMan->somethingSelected())
1461 Layer* layer = mEditor->layers()->currentLayer();
1462 if (layer ==
nullptr) {
return; }
1466 mEditor->backup(
tr(
"Delete Selection",
"Undo Step: clear the selection area."));
1468 selectMan->clearCurves();
1469 if (layer->type() == Layer::VECTOR)
1471 VectorImage* vectorImage = currentVectorImage(layer);
1472 Q_CHECK_PTR(vectorImage);
1475 else if (layer->type() == Layer::BITMAP)
1477 BitmapImage* bitmapImage = currentBitmapImage(layer);
1478 Q_CHECK_PTR(bitmapImage);
1479 bitmapImage->clear(selectMan->mySelectionRect());
1481 mEditor->setModified(mEditor->currentLayerIndex(), mEditor->currentFrame());
1485void ScribbleArea::clearImage()
1487 Layer* layer = mEditor->layers()->currentLayer();
1488 if (layer ==
nullptr) {
return; }
1490 if (layer->type() == Layer::VECTOR)
1492 mEditor->backup(
tr(
"Clear Image",
"Undo step text"));
1494 VectorImage* vectorImage = currentVectorImage(layer);
1495 if (vectorImage !=
nullptr)
1497 vectorImage->
clear();
1499 mEditor->select()->clearCurves();
1500 mEditor->select()->clearVertices();
1502 else if (layer->type() == Layer::BITMAP)
1504 mEditor->backup(
tr(
"Clear Image",
"Undo step text"));
1506 BitmapImage* bitmapImage = currentBitmapImage(layer);
1507 if (bitmapImage ==
nullptr)
return;
1508 bitmapImage->clear();
1514 mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
1517void ScribbleArea::paletteColorChanged(
QColor color)
1521 for (
int i = 0; i < mEditor->layers()->count(); i++)
1523 Layer* layer = mEditor->layers()->getLayer(i);
1524 if (layer->type() == Layer::VECTOR)
1526 VectorImage* vectorImage =
static_cast<LayerVector*
>(layer)->getVectorImageAtFrame(mEditor->currentFrame());
1527 if (vectorImage !=
nullptr)
1529 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 drawBrush(const QPointF &point, qreal brushWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing)
Draws a brush with the specified parameters to 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.
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)
virtual bool event(QEvent *e)
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