diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp
index ff0406835..d6403eb3f 100644
--- a/app/src/generalpage.cpp
+++ b/app/src/generalpage.cpp
@@ -103,7 +103,7 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage)
connect(ui->antialiasingBox, &QCheckBox::stateChanged, this, &GeneralPage::antiAliasCheckboxStateChanged);
connect(ui->curveSmoothingLevel, &QSlider::valueChanged, this, &GeneralPage::curveSmoothingChanged);
connect(ui->highResBox, &QCheckBox::stateChanged, this, &GeneralPage::highResCheckboxStateChanged);
- connect(ui->dottedCursorBox, &QCheckBox::stateChanged, this, &GeneralPage::dottedCursorCheckboxStateChanged);
+ connect(ui->canvasCursorBox, &QCheckBox::stateChanged, this, &GeneralPage::canvasCursorCheckboxStateChanged);
connect(ui->gridSizeInputW, spinValueChanged, this, &GeneralPage::gridWidthChanged);
connect(ui->gridSizeInputH, spinValueChanged, this, &GeneralPage::gridHeightChanged);
connect(ui->actionSafeCheckBox, &QCheckBox::stateChanged, this, &GeneralPage::actionSafeCheckBoxStateChanged);
@@ -141,8 +141,8 @@ void GeneralPage::updateValues()
ui->toolCursorsBox->setChecked(mManager->isOn(SETTING::TOOL_CURSOR));
QSignalBlocker b5(ui->antialiasingBox);
ui->antialiasingBox->setChecked(mManager->isOn(SETTING::ANTIALIAS));
- QSignalBlocker b6(ui->dottedCursorBox);
- ui->dottedCursorBox->setChecked(mManager->isOn(SETTING::DOTTED_CURSOR));
+ QSignalBlocker b6(ui->canvasCursorBox);
+ ui->canvasCursorBox->setChecked(mManager->isOn(SETTING::CANVAS_CURSOR));
QSignalBlocker b7(ui->gridSizeInputW);
ui->gridSizeInputW->setValue(mManager->getInt(SETTING::GRID_SIZE_W));
QSignalBlocker b11(ui->gridSizeInputH);
@@ -233,9 +233,9 @@ void GeneralPage::toolCursorsCheckboxStateChanged(int b)
mManager->set(SETTING::TOOL_CURSOR, b != Qt::Unchecked);
}
-void GeneralPage::dottedCursorCheckboxStateChanged(int b)
+void GeneralPage::canvasCursorCheckboxStateChanged(int b)
{
- mManager->set(SETTING::DOTTED_CURSOR, b != Qt::Unchecked);
+ mManager->set(SETTING::CANVAS_CURSOR, b != Qt::Unchecked);
}
void GeneralPage::gridWidthChanged(int value)
diff --git a/app/src/generalpage.h b/app/src/generalpage.h
index 239e6b8b9..0767090e0 100644
--- a/app/src/generalpage.h
+++ b/app/src/generalpage.h
@@ -51,7 +51,7 @@ private slots:
void shadowsCheckboxStateChanged(int b);
void antiAliasCheckboxStateChanged(int b);
void toolCursorsCheckboxStateChanged(int b);
- void dottedCursorCheckboxStateChanged(int b);
+ void canvasCursorCheckboxStateChanged(int b);
void highResCheckboxStateChanged(int b);
void gridCheckBoxStateChanged(int b);
void curveSmoothingChanged(int value);
diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp
index da3d6ee2b..480ff2e38 100644
--- a/app/src/mainwindow2.cpp
+++ b/app/src/mainwindow2.cpp
@@ -999,7 +999,6 @@ void MainWindow2::preferences()
{
clearKeyboardShortcuts();
setupKeyboardShortcuts();
- ui->scribbleArea->updateCanvasCursor();
mPrefDialog = nullptr;
});
diff --git a/app/src/tooloptionwidget.cpp b/app/src/tooloptionwidget.cpp
index 5c51c4206..64a45ca6e 100644
--- a/app/src/tooloptionwidget.cpp
+++ b/app/src/tooloptionwidget.cpp
@@ -27,6 +27,7 @@ GNU General Public License for more details.
#include "util.h"
#include "layer.h"
#include "layermanager.h"
+#include "stroketool.h"
#include "toolmanager.h"
ToolOptionWidget::ToolOptionWidget(QWidget* parent) : BaseDockWidget(parent)
@@ -53,11 +54,11 @@ void ToolOptionWidget::initUI()
QSettings settings(PENCIL2D, PENCIL2D);
- ui->sizeSlider->init(tr("Width"), SpinSlider::EXPONENT, SpinSlider::INTEGER, 1, 200);
+ ui->sizeSlider->init(tr("Width"), SpinSlider::EXPONENT, SpinSlider::INTEGER, StrokeTool::WIDTH_MIN, StrokeTool::WIDTH_MAX);
ui->sizeSlider->setValue(settings.value("brushWidth", "3").toDouble());
ui->brushSpinBox->setValue(settings.value("brushWidth", "3").toDouble());
- ui->featherSlider->init(tr("Feather"), SpinSlider::LOG, SpinSlider::INTEGER, 1, 99);
+ ui->featherSlider->init(tr("Feather"), SpinSlider::LOG, SpinSlider::INTEGER, StrokeTool::FEATHER_MIN, StrokeTool::FEATHER_MAX);
ui->featherSlider->setValue(settings.value("brushFeather", "5").toDouble());
ui->featherSpinBox->setValue(settings.value("brushFeather", "5").toDouble());
}
diff --git a/app/ui/generalpage.ui b/app/ui/generalpage.ui
index 5586b0b6b..14229078f 100644
--- a/app/ui/generalpage.ui
+++ b/app/ui/generalpage.ui
@@ -115,9 +115,9 @@
-
-
+
- Dotted Cursor
+ Canvas Cursor
@@ -515,7 +515,7 @@
windowOpacityLevel
shadowsBox
toolCursorsBox
- dottedCursorBox
+ canvasCursorBox
checkerBackgroundButton
whiteBackgroundButton
greyBackgroundButton
diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro
index d1725c897..4b0642ecf 100644
--- a/core_lib/core_lib.pro
+++ b/core_lib/core_lib.pro
@@ -26,6 +26,7 @@ INCLUDEPATH += src \
PRECOMPILED_HEADER = src/corelib-pch.h
HEADERS += \
+ src/canvascursorpainter.h \
src/corelib-pch.h \
src/graphics/bitmap/bitmapbucket.h \
src/graphics/bitmap/bitmapimage.h \
@@ -115,6 +116,7 @@ HEADERS += \
SOURCES += src/graphics/bitmap/bitmapimage.cpp \
+ src/canvascursorpainter.cpp \
src/graphics/bitmap/bitmapbucket.cpp \
src/graphics/bitmap/tile.cpp \
src/graphics/bitmap/tiledbuffer.cpp \
diff --git a/core_lib/src/canvascursorpainter.cpp b/core_lib/src/canvascursorpainter.cpp
new file mode 100644
index 000000000..3118d7e55
--- /dev/null
+++ b/core_lib/src/canvascursorpainter.cpp
@@ -0,0 +1,97 @@
+/*
+
+Pencil2D - Traditional Animation Software
+Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
+Copyright (C) 2012-2020 Matthew Chiawen Chang
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+#include "canvascursorpainter.h"
+
+#include
+
+CanvasCursorPainter::CanvasCursorPainter()
+{
+ setupPen();
+}
+
+void CanvasCursorPainter::setupPen()
+{
+ mCursorPen = QPen(Qt::gray);
+ mCursorPen.setWidthF(1);
+ mCursorPen.setCosmetic(true);
+}
+
+void CanvasCursorPainter::paint(QPainter& painter, const QRect& blitRect)
+{
+ if (mOptions.isAdjusting || mOptions.showCursor) {
+ if (mOptions.useFeather) {
+ paintFeatherCursor(painter, blitRect, mOptions.widthRect, mOptions.featherRect);
+ }
+ paintWidthCursor(painter, blitRect, mOptions.widthRect);
+ mIsDirty = true;
+ }
+}
+
+void CanvasCursorPainter::preparePainter(const CanvasCursorPainterOptions& painterOptions, const QTransform& viewTransform)
+{
+ mOptions = painterOptions;
+ if (mOptions.isAdjusting || mOptions.showCursor) {
+ mOptions.widthRect = viewTransform.mapRect(mOptions.widthRect);
+ mOptions.featherRect = viewTransform.mapRect(mOptions.featherRect);
+ }
+}
+
+void CanvasCursorPainter::paintFeatherCursor(QPainter& painter, const QRect& blitRect, const QRectF& widthCircleBounds, const QRectF& featherCircleBounds)
+{
+ // When the circles are too close to each other, the rendering will appear dotted or almost
+ // invisible at certain zoom levels.
+ if (widthCircleBounds.width() - featherCircleBounds.width() <= 1) {
+ return;
+ }
+
+ painter.save();
+
+ painter.setClipRect(blitRect);
+ painter.setPen(mCursorPen);
+ painter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
+ painter.drawEllipse(featherCircleBounds);
+
+ painter.restore();
+}
+
+void CanvasCursorPainter::paintWidthCursor(QPainter& painter, const QRect& blitRect, const QRectF& widthCircleBounds)
+{
+ painter.save();
+
+ painter.setClipRect(blitRect);
+ painter.setPen(mCursorPen);
+
+ painter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
+
+ // Only draw the cross when the width is bigger than the cross itself
+ if (widthCircleBounds.width() > 8) {
+ const QPointF& pos = widthCircleBounds.center();
+ painter.drawLine(QPointF(pos.x() - 2, pos.y()), QPointF(pos.x() + 2, pos.y()));
+ painter.drawLine(QPointF(pos.x(), pos.y() - 2), QPointF(pos.x(), pos.y() + 2));
+ }
+
+ painter.drawEllipse(widthCircleBounds);
+ painter.restore();
+
+ mDirtyRect = widthCircleBounds.toAlignedRect();
+}
+
+void CanvasCursorPainter::clearDirty()
+{
+ mDirtyRect = QRect();
+ mIsDirty = false;
+}
diff --git a/core_lib/src/canvascursorpainter.h b/core_lib/src/canvascursorpainter.h
new file mode 100644
index 000000000..9d8ad7412
--- /dev/null
+++ b/core_lib/src/canvascursorpainter.h
@@ -0,0 +1,61 @@
+/*
+
+Pencil2D - Traditional Animation Software
+Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
+Copyright (C) 2012-2020 Matthew Chiawen Chang
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+*/
+#ifndef CANVASCURSORPAINTER_H
+#define CANVASCURSORPAINTER_H
+
+#include
+
+class QPainter;
+
+struct CanvasCursorPainterOptions
+{
+ QRectF widthRect;
+ QRectF featherRect;
+ bool isAdjusting;
+ bool useFeather = false;
+ bool showCursor = false;
+};
+
+class CanvasCursorPainter
+{
+
+public:
+ CanvasCursorPainter();
+ void paint(QPainter& painter, const QRect& blitRect);
+
+ void preparePainter(const CanvasCursorPainterOptions& painterOptions, const QTransform& viewTransform);
+
+ const QRect dirtyRect() { return mDirtyRect; }
+ bool isDirty() const { return mIsDirty; }
+ void clearDirty();
+
+private:
+
+ void setupPen();
+
+ /// @brief precision circular cursor: used for drawing a cursor on the canvas.
+ void paintWidthCursor(QPainter& painter, const QRect& blitRect, const QRectF& widthCircleBounds);
+ void paintFeatherCursor(QPainter& painter, const QRect& blitRect, const QRectF& widthCircleBounds, const QRectF& featherCircleBounds);
+
+ CanvasCursorPainterOptions mOptions;
+ QRect mDirtyRect;
+ bool mIsDirty = false;
+
+ QPen mCursorPen;
+};
+
+#endif // CANVASCURSORPAINTER_H
diff --git a/core_lib/src/graphics/bitmap/tiledbuffer.cpp b/core_lib/src/graphics/bitmap/tiledbuffer.cpp
index 5d4929e64..1009625e0 100644
--- a/core_lib/src/graphics/bitmap/tiledbuffer.cpp
+++ b/core_lib/src/graphics/bitmap/tiledbuffer.cpp
@@ -48,16 +48,15 @@ Tile* TiledBuffer::getTileFromIndex(const TileIndex& tileIndex)
return selectedTile;
}
-void TiledBuffer::drawBrush(const QPointF& point, int brushWidth, int brushCursorWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing) {
+void TiledBuffer::drawBrush(const QPointF& point, int brushWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing) {
const QRectF brushRect(point.x() - 0.5 * brushWidth, point.y() - 0.5 * brushWidth, brushWidth, brushWidth);
const float tileSize = UNIFORM_TILE_SIZE;
- const int width = qMax(brushCursorWidth,brushWidth);
// Gather the number of tiles that fits the size of the brush width
- const int xLeft = qFloor((qFloor(point.x() - width)) / tileSize);
- const int xRight = qFloor((qFloor(point.x() + width)) / tileSize);
- const int yTop = qFloor(qFloor(point.y() - width) / tileSize);
- const int yBottom = qFloor(qFloor(point.y() + width) / tileSize);
+ const int xLeft = qFloor((qFloor(point.x() - brushWidth)) / tileSize);
+ const int xRight = qFloor((qFloor(point.x() + brushWidth)) / tileSize);
+ const int yTop = qFloor(qFloor(point.y() - brushWidth) / tileSize);
+ const int yBottom = qFloor(qFloor(point.y() + brushWidth) / tileSize);
for (int tileY = yTop; tileY <= yBottom; tileY++) {
for (int tileX = xLeft; tileX <= xRight; tileX++) {
@@ -108,11 +107,10 @@ void TiledBuffer::drawImage(const QImage& image, const QRect& imageBounds, QPain
}
-void TiledBuffer::drawPath(QPainterPath path, int cursorWidth, QPen pen, QBrush brush,
+void TiledBuffer::drawPath(QPainterPath path, QPen pen, QBrush brush,
QPainter::CompositionMode cm, bool antialiasing)
{
- const int pathWidth = pen.width();
- const int width = (qMax(pathWidth,cursorWidth) + 1);
+ const int width = pen.width();;
const float tileSize = UNIFORM_TILE_SIZE;
const QRectF pathRect = path.boundingRect();
diff --git a/core_lib/src/graphics/bitmap/tiledbuffer.h b/core_lib/src/graphics/bitmap/tiledbuffer.h
index 3e29cfed8..642492666 100644
--- a/core_lib/src/graphics/bitmap/tiledbuffer.h
+++ b/core_lib/src/graphics/bitmap/tiledbuffer.h
@@ -59,9 +59,9 @@ class TiledBuffer: public QObject
bool isValid() const { return !mTiles.isEmpty(); }
/** Draws a brush with the specified parameters to the tiled buffer */
- void drawBrush(const QPointF& point, int brushWidth, int brushCursorWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing);
+ void drawBrush(const QPointF& point, int brushWidth, QPen pen, QBrush brush, QPainter::CompositionMode cm, bool antialiasing);
/** Draws a path with the specified parameters to the tiled buffer */
- void drawPath(QPainterPath path, int cursorWidth, QPen pen, QBrush brush,
+ void drawPath(QPainterPath path, QPen pen, QBrush brush,
QPainter::CompositionMode cm, bool antialiasing);
/** Draws a image with the specified parameters to the tiled buffer */
void drawImage(const QImage& image, const QRect& imageBounds, QPainter::CompositionMode cm, bool antialiasing);
diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp
index d39359c02..143983cb0 100644
--- a/core_lib/src/interface/scribblearea.cpp
+++ b/core_lib/src/interface/scribblearea.cpp
@@ -45,7 +45,9 @@ GNU General Public License for more details.
#include "selectionmanager.h"
#include "overlaymanager.h"
-ScribbleArea::ScribbleArea(QWidget* parent) : QWidget(parent), mCanvasPainter(mCanvas), mCameraPainter(mCanvas)
+ScribbleArea::ScribbleArea(QWidget* parent) : QWidget(parent),
+ mCanvasPainter(mCanvas),
+ mCameraPainter(mCanvas)
{
setObjectName("ScribbleArea");
@@ -85,7 +87,6 @@ bool ScribbleArea::init()
const int curveSmoothingLevel = mPrefs->getInt(SETTING::CURVE_SMOOTHING);
mCurveSmoothingLevel = curveSmoothingLevel / 20.0; // default value is 1.0
- mQuickSizing = mPrefs->isOn(SETTING::QUICK_SIZING);
mMakeInvisible = false;
mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION);
@@ -94,8 +95,6 @@ bool ScribbleArea::init()
mDeltaFactor = mEditor->preference()->isOn(SETTING::INVERT_SCROLL_ZOOM_DIRECTION) ? -1 : 1;
- updateCanvasCursor();
-
setMouseTracking(true); // reacts to mouse move events, even if the button is not pressed
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
setTabletTracking(true); // tablet tracking first added in 5.9
@@ -151,9 +150,6 @@ void ScribbleArea::settingUpdated(SETTING setting)
case SETTING::ONION_WHILE_PLAYBACK:
invalidateAllCache();
break;
- case SETTING::QUICK_SIZING:
- mQuickSizing = mPrefs->isOn(SETTING::QUICK_SIZING);
- break;
case SETTING::MULTILAYER_ONION:
mMultiLayerOnionSkin = mPrefs->isOn(SETTING::MULTILAYER_ONION);
invalidateAllCache();
@@ -174,7 +170,6 @@ void ScribbleArea::settingUpdated(SETTING setting)
void ScribbleArea::updateToolCursor()
{
setCursor(currentTool()->cursor());
- updateCanvasCursor();
}
void ScribbleArea::setCurveSmoothing(int newSmoothingLevel)
@@ -388,11 +383,15 @@ void ScribbleArea::onObjectLoaded()
bool ScribbleArea::event(QEvent *event)
{
+ bool processed = false;
if (event->type() == QEvent::WindowDeactivate)
{
editor()->tools()->clearTemporaryTool();
+ processed = true;
}
- return QWidget::event(event);
+
+ processed = currentTool()->event(event) || processed;
+ return QWidget::event(event) || processed;
}
/************************************************************************/
@@ -569,7 +568,6 @@ void ScribbleArea::wheelEvent(QWheelEvent* event)
const qreal newScale = currentScale * std::pow(100, (delta * mDeltaFactor) / (12.0 * 120));
mEditor->view()->scaleAtOffset(newScale, offset);
}
- updateCanvasCursor();
event->accept();
}
@@ -590,7 +588,7 @@ void ScribbleArea::tabletEvent(QTabletEvent *e)
editor()->tools()->tabletRestorePrevTool();
}
- if (event.eventType() == QTabletEvent::TabletPress)
+ if (event.eventType() == PointerEvent::Press)
{
event.accept();
mStrokeManager->pointerPressEvent(&event);
@@ -616,7 +614,7 @@ void ScribbleArea::tabletEvent(QTabletEvent *e)
}
mTabletInUse = event.isAccepted();
}
- else if (event.eventType() == QTabletEvent::TabletMove)
+ else if (event.eventType() == PointerEvent::Move)
{
if (!(event.buttons() & (Qt::LeftButton | Qt::RightButton)) || mTabletInUse)
{
@@ -624,7 +622,7 @@ void ScribbleArea::tabletEvent(QTabletEvent *e)
pointerMoveEvent(&event);
}
}
- else if (event.eventType() == QTabletEvent::TabletRelease)
+ else if (event.eventType() == PointerEvent::Release)
{
mTabletReleaseMillisAgo = 0;
mMouseFilterTimer->start();
@@ -673,18 +671,7 @@ void ScribbleArea::pointerPressEvent(PointerEvent* event)
editor()->tools()->setTemporaryTool(HAND, event->buttons()))
{
currentTool()->pointerPressEvent(event);
- }
-
- const bool isPressed = event->buttons() & Qt::LeftButton;
- if (isPressed && mQuickSizing)
- {
- if (currentTool()->startAdjusting(event->modifiers(), 1))
- {
- return;
- }
- }
-
- if (event->button() == Qt::LeftButton)
+ } else if (event->button() == Qt::LeftButton)
{
currentTool()->pointerPressEvent(event);
}
@@ -692,31 +679,11 @@ void ScribbleArea::pointerPressEvent(PointerEvent* event)
void ScribbleArea::pointerMoveEvent(PointerEvent* event)
{
- updateCanvasCursor();
-
- if (event->buttons() & (Qt::LeftButton | Qt::RightButton))
- {
-
- // --- use SHIFT + drag to resize WIDTH / use CTRL + drag to resize FEATHER ---
- if (currentTool()->isAdjusting())
- {
- currentTool()->adjustCursor(event->modifiers());
- return;
- }
- }
-
currentTool()->pointerMoveEvent(event);
}
void ScribbleArea::pointerReleaseEvent(PointerEvent* event)
{
- if (currentTool()->isAdjusting())
- {
- currentTool()->stopAdjusting();
- mEditor->tools()->setWidth(static_cast(currentTool()->properties.width));
- return; // [SHIFT]+drag OR [CTRL]+drag
- }
-
currentTool()->pointerReleaseEvent(event);
editor()->tools()->tryClearTemporaryTool(event->button());
@@ -878,58 +845,6 @@ void ScribbleArea::clearDrawingBuffer()
mTiledBuffer.clear();
}
-void ScribbleArea::paintCanvasCursor(QPainter& painter)
-{
- QTransform view = mEditor->view()->getView();
- QPointF mousePos = currentTool()->isAdjusting() ? currentTool()->getCurrentPressPoint() : currentTool()->getCurrentPoint();
- int centerCal = mCursorImg.width() / 2;
-
- mTransformedCursorPos = view.map(mousePos);
-
- // reset matrix
- view.reset();
-
- painter.setTransform(view);
- mCursorCenterPos.setX(centerCal);
- mCursorCenterPos.setY(centerCal);
-
- painter.drawPixmap(QPoint(static_cast(mTransformedCursorPos.x() - mCursorCenterPos.x()),
- static_cast(mTransformedCursorPos.y() - mCursorCenterPos.y())),
- mCursorImg);
-
- mCursorCenterPos.setX(centerCal);
- mCursorCenterPos.setY(centerCal);
-}
-
-void ScribbleArea::updateCanvasCursor()
-{
- float scalingFac = mEditor->view()->scaling();
- qreal brushWidth = currentTool()->properties.width;
- qreal brushFeather = currentTool()->properties.feather;
- if (currentTool()->isAdjusting())
- {
- mCursorImg = currentTool()->quickSizeCursor(scalingFac);
- }
- else if (mEditor->preference()->isOn(SETTING::DOTTED_CURSOR))
- {
- bool useFeather = currentTool()->properties.useFeather;
- mCursorImg = currentTool()->canvasCursor(static_cast(brushWidth), static_cast(brushFeather), useFeather, scalingFac, width());
- }
- else
- {
- mCursorImg = QPixmap(); // if the above does not comply, deallocate image
- }
-
- // When we're using a tool, the TiledBuffer will take care of this;
- // we don't want to cause needless updates
- if (!currentTool()->isActive()) {
- // update cursor rect
- QPoint translatedPos(static_cast(mTransformedCursorPos.x() - mCursorCenterPos.x()),
- static_cast(mTransformedCursorPos.y() - mCursorCenterPos.y()));
- update(mCursorImg.rect().adjusted(-1, -1, 1, 1).translated(translatedPos));
- }
-}
-
void ScribbleArea::handleDrawingOnEmptyFrame()
{
auto layer = mEditor->layers()->currentLayer();
@@ -1046,7 +961,7 @@ void ScribbleArea::paintEvent(QPaintEvent* event)
painter.setClipRect(event->rect());
painter.drawPixmap(QPointF(), mCanvas);
- currentTool()->paint(painter);
+ currentTool()->paint(painter, event->rect());
if (!editor()->playback()->isPlaying()) // we don't need to display the following when the animation is playing
{
@@ -1123,8 +1038,6 @@ void ScribbleArea::paintEvent(QPaintEvent* event)
}
}
- paintCanvasCursor(painter);
-
mOverlayPainter.paint(painter, rect());
// paints the selection outline
@@ -1271,13 +1184,13 @@ void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor color, qreal
void ScribbleArea::drawPath(QPainterPath path, QPen pen, QBrush brush, QPainter::CompositionMode cm)
{
- mTiledBuffer.drawPath(mEditor->view()->mapScreenToCanvas(path), mEditor->view()->mapScreenToCanvas(mCursorImg.rect()).width(), pen, brush, cm, mPrefs->isOn(SETTING::ANTIALIAS));
+ mTiledBuffer.drawPath(mEditor->view()->mapScreenToCanvas(path), pen, brush, cm, mPrefs->isOn(SETTING::ANTIALIAS));
}
void ScribbleArea::drawPen(QPointF thePoint, qreal brushWidth, QColor fillColor, bool useAA)
{
// We use Source as opposed to SourceOver here to avoid the dabs being added on top of each other
- mTiledBuffer.drawBrush(thePoint, brushWidth, mEditor->view()->mapScreenToCanvas(mCursorImg.rect()).width(), Qt::NoPen, QBrush(fillColor, Qt::SolidPattern), QPainter::CompositionMode_Source, useAA);
+ mTiledBuffer.drawBrush(thePoint, brushWidth, Qt::NoPen, QBrush(fillColor, Qt::SolidPattern), QPainter::CompositionMode_Source, useAA);
}
void ScribbleArea::drawPencil(QPointF thePoint, qreal brushWidth, qreal fixedBrushFeather, QColor fillColor, qreal opacity)
@@ -1298,7 +1211,7 @@ void ScribbleArea::drawBrush(QPointF thePoint, qreal brushWidth, qreal mOffset,
{
brush = QBrush(fillColor, Qt::SolidPattern);
}
- mTiledBuffer.drawBrush(thePoint, brushWidth, mEditor->view()->mapScreenToCanvas(mCursorImg.rect()).width(), Qt::NoPen, brush, compMode, useAA);
+ mTiledBuffer.drawBrush(thePoint, brushWidth, Qt::NoPen, brush, compMode, useAA);
}
void ScribbleArea::drawPolyline(QPainterPath path, QPen pen, bool useAA)
@@ -1314,7 +1227,7 @@ void ScribbleArea::drawPolyline(QPainterPath path, QPen pen, bool useAA)
blitRect.extend(updateRect);
mTiledBuffer.clear();
- mTiledBuffer.drawPath(path, mEditor->view()->mapScreenToCanvas(mCursorImg.rect()).width(), pen, Qt::NoBrush, QPainter::CompositionMode_SourceOver, useAA);
+ mTiledBuffer.drawPath(path, pen, Qt::NoBrush, QPainter::CompositionMode_SourceOver, useAA);
// And update only the affected area
update(blitRect.adjusted(-1, -1, 1, 1));
diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h
index c31ffca13..277f29d7d 100644
--- a/core_lib/src/interface/scribblearea.h
+++ b/core_lib/src/interface/scribblearea.h
@@ -174,7 +174,6 @@ public slots:
void liquifyBrush(BitmapImage *bmiSource_, QPointF srcPoint_, QPointF thePoint_, qreal brushWidth_, qreal offset_, qreal opacity_);
void paintBitmapBuffer();
- void paintCanvasCursor(QPainter& painter);
void clearDrawingBuffer();
void setGaussianGradient(QGradient &gradient, QColor color, qreal opacity, qreal offset);
@@ -182,16 +181,11 @@ public slots:
void pointerMoveEvent(PointerEvent*);
void pointerReleaseEvent(PointerEvent*);
- void updateCanvasCursor();
-
/// Call this when starting to use a paint tool. Checks whether we are drawing
/// on an empty frame, and if so, takes action according to use preference.
void handleDrawingOnEmptyFrame();
TiledBuffer mTiledBuffer;
-
- QPixmap mCursorImg;
-
private:
/** Invalidate the layer pixmap and camera painter caches.
@@ -227,7 +221,6 @@ public slots:
Editor* mEditor = nullptr;
- bool mQuickSizing = true;
LayerVisibility mLayerVisibility = LayerVisibility::ALL;
bool mMakeInvisible = false;
qreal mCurveSmoothingLevel = 0.0;
@@ -258,9 +251,6 @@ public slots:
QTimer* mMouseFilterTimer = nullptr;
- QPoint mCursorCenterPos;
- QPointF mTransformedCursorPos;
-
PreferenceManager* mPrefs = nullptr;
QPixmap mCanvas;
diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp
index 229881a8f..b889f3686 100644
--- a/core_lib/src/managers/preferencemanager.cpp
+++ b/core_lib/src/managers/preferencemanager.cpp
@@ -73,7 +73,7 @@ void PreferenceManager::loadPrefs()
// General
set(SETTING::ANTIALIAS, settings.value(SETTING_ANTIALIAS, true).toBool());
set(SETTING::TOOL_CURSOR, settings.value(SETTING_TOOL_CURSOR, true).toBool());
- set(SETTING::DOTTED_CURSOR, settings.value(SETTING_DOTTED_CURSOR, true).toBool());
+ set(SETTING::CANVAS_CURSOR, settings.value(SETTING_CANVAS_CURSOR, true).toBool());
set(SETTING::HIGH_RESOLUTION, settings.value(SETTING_HIGH_RESOLUTION, true).toBool());
set(SETTING::SHADOW, settings.value(SETTING_SHADOW, false).toBool());
set(SETTING::QUICK_SIZING, settings.value(SETTING_QUICK_SIZING, true).toBool());
@@ -421,8 +421,8 @@ void PreferenceManager::set(SETTING option, bool value)
case SETTING::TOOL_CURSOR:
settings.setValue(SETTING_TOOL_CURSOR, value);
break;
- case SETTING::DOTTED_CURSOR:
- settings.setValue(SETTING_DOTTED_CURSOR, value);
+ case SETTING::CANVAS_CURSOR:
+ settings.setValue(SETTING_CANVAS_CURSOR, value);
break;
case SETTING::HIGH_RESOLUTION:
settings.setValue(SETTING_HIGH_RESOLUTION, value);
diff --git a/core_lib/src/managers/toolmanager.cpp b/core_lib/src/managers/toolmanager.cpp
index 14233ec79..b124b767d 100644
--- a/core_lib/src/managers/toolmanager.cpp
+++ b/core_lib/src/managers/toolmanager.cpp
@@ -112,6 +112,7 @@ void ToolManager::setCurrentTool(ToolType eToolType)
}
mCurrentTool = getTool(eToolType);
+ mCurrentTool->enteringThisTool();
if (mTemporaryTool == nullptr && mTabletEraserTool == nullptr)
{
emit toolChanged(eToolType);
diff --git a/core_lib/src/tool/basetool.cpp b/core_lib/src/tool/basetool.cpp
index d02496cb4..c59bd5077 100644
--- a/core_lib/src/tool/basetool.cpp
+++ b/core_lib/src/tool/basetool.cpp
@@ -18,20 +18,12 @@ GNU General Public License for more details.
#include "basetool.h"
#include
-#include
-#include
#include "editor.h"
#include "viewmanager.h"
-#include "toolmanager.h"
#include "scribblearea.h"
#include "strokemanager.h"
#include "pointerevent.h"
-// ---- shared static variables ---- ( only one instance for all the tools )
-qreal BaseTool::msOriginalPropertyValue; // start value (width, feather ..)
-bool BaseTool::msIsAdjusting = false;
-
-
QString BaseTool::TypeName(ToolType type)
{
static std::array map;
@@ -73,6 +65,15 @@ QCursor BaseTool::cursor()
return Qt::ArrowCursor;
}
+bool BaseTool::leavingThisTool()
+{
+ for (auto& connection : mActiveConnections) {
+ disconnect(connection);
+ mActiveConnections.removeOne(connection);
+ }
+ return true;
+}
+
void BaseTool::initialize(Editor* editor)
{
Q_ASSERT(editor);
@@ -118,207 +119,11 @@ bool BaseTool::isDrawingTool()
return true;
}
-/**
- * @brief precision circular cursor: used for drawing a cursor within scribble area.
- * @return QPixmap
- */
-QPixmap BaseTool::canvasCursor(float width, float feather, bool useFeather, float scalingFac, int windowWidth)
-{
- float propWidth = width * scalingFac;
- float propFeather = feather * scalingFac;
-
- float cursorWidth = 0.0f;
- float xyA = 0.0f;
- float xyB = 0.0f;
- float whA = 0.0f;
- float whB = 0.0f;
-
- if (useFeather)
- {
- cursorWidth = propWidth + 0.5 * propFeather;
- xyA = 1 + propFeather / 2;
- xyB = 1 + propFeather / 8;
- whA = qMax(0, propWidth - xyA - 1);
- whB = qMax(0, cursorWidth - propFeather / 4 - 2);
- }
- else
- {
- cursorWidth = (propWidth + 0.5);
- whA = qMax(0, propWidth - 1);
- whB = qMax(0, cursorWidth / 4 - 2);
- }
-
- float radius = cursorWidth / 2;
-
- // deallocate when cursor width gets some value larger than the widget
- if (cursorWidth > windowWidth * 2)
- {
- return QPixmap(0, 0);
- }
-
- if (cursorWidth < 1) { cursorWidth = 1; }
-
- QPixmap cursorPixmap = QPixmap(cursorWidth, cursorWidth);
- if (!cursorPixmap.isNull())
- {
- cursorPixmap.fill(QColor(255, 255, 255, 0));
- QPainter cursorPainter(&cursorPixmap);
- QPen cursorPen = cursorPainter.pen();
- cursorPainter.setRenderHint(QPainter::Antialiasing);
-
- // Draw cross in center
- cursorPen.setStyle(Qt::SolidLine);
- cursorPen.setColor(QColor(0, 0, 0, 127));
- cursorPainter.setPen(cursorPen);
- cursorPainter.drawLine(QPointF(radius - 2, radius), QPointF(radius + 2, radius));
- cursorPainter.drawLine(QPointF(radius, radius - 2), QPointF(radius, radius + 2));
-
- // Draw outer circle
- if (useFeather)
- {
- cursorPen.setStyle(Qt::DotLine);
- cursorPen.setColor(QColor(0, 0, 0, 255));
- cursorPainter.setPen(cursorPen);
- cursorPainter.drawEllipse(QRectF(xyB, xyB, whB, whB));
- cursorPen.setDashOffset(4);
- cursorPen.setColor(QColor(255, 255, 255, 255));
- cursorPainter.setPen(cursorPen);
- cursorPainter.drawEllipse(QRectF(xyB, xyB, whB, whB));
- }
-
- // Draw inner circle
- cursorPen.setStyle(Qt::DotLine);
- cursorPen.setColor(QColor(0, 0, 0, 255));
- cursorPainter.setPen(cursorPen);
- cursorPainter.drawEllipse(QRectF(xyA, xyA, whA, whA));
- cursorPen.setDashOffset(4);
- cursorPen.setColor(QColor(255, 255, 255, 255));
- cursorPainter.setPen(cursorPen);
- cursorPainter.drawEllipse(QRectF(xyA, xyA, whA, whA));
-
- cursorPainter.end();
- }
- return cursorPixmap;
-}
-
bool BaseTool::isActive()
{
return strokeManager()->isActive();
}
-/**
- * @brief precision circular cursor: used for drawing stroke size while adjusting
- * @return QPixmap
- */
-QPixmap BaseTool::quickSizeCursor(qreal scalingFac)
-{
- qreal propSize = qMax(0., properties.width) * scalingFac;
- qreal propFeather = qMax(0., properties.feather) * scalingFac;
- QRectF cursorRect(0, 0, propSize+2, propSize+2);
-
- QRectF sizeRect = cursorRect.adjusted(1, 1, -1, -1);
- qreal featherRadius = (1 - propFeather / 100) * propSize / 2.;
-
- QPixmap cursorPixmap = QPixmap(cursorRect.size().toSize());
- if (!cursorPixmap.isNull())
- {
- cursorPixmap.fill(QColor(255, 255, 255, 0));
- QPainter cursorPainter(&cursorPixmap);
- cursorPainter.setRenderHints(QPainter::Antialiasing, true);
-
- // Draw width (outside circle)
- cursorPainter.setPen(QColor(255, 127, 127, 127));
- cursorPainter.setBrush(QColor(0, 255, 127, 127));
- cursorPainter.drawEllipse(sizeRect);
-
- // Draw feather (inside circle)
- cursorPainter.setCompositionMode(QPainter::CompositionMode_Darken);
- cursorPainter.setPen(QColor(0, 0, 0, 0));
- cursorPainter.setBrush(QColor(0, 191, 95, 127));
- cursorPainter.drawEllipse(cursorRect.center(), featherRadius, featherRadius);
-
- // Draw cursor in center
- cursorPainter.setRenderHints(QPainter::Antialiasing, false);
- cursorPainter.setPen(QColor(0, 0, 0, 255));
- cursorPainter.drawLine(cursorRect.center() - QPoint(2, 0), cursorRect.center() + QPoint(2, 0));
- cursorPainter.drawLine(cursorRect.center() - QPoint(0, 2), cursorRect.center() + QPoint(0, 2));
-
- cursorPainter.end();
- }
- return cursorPixmap;
-}
-
-bool BaseTool::startAdjusting(Qt::KeyboardModifiers modifiers, qreal step)
-{
- if (mQuickSizingProperties.contains(modifiers))
- {
- switch (mQuickSizingProperties.value(modifiers)) {
- case WIDTH:
- msOriginalPropertyValue = properties.width;
- break;
- case FEATHER:
- msOriginalPropertyValue = properties.feather;
- break;
- case TOLERANCE:
- msOriginalPropertyValue = properties.tolerance;
- break;
- default:
- qDebug() << "Unhandled quick sizing property for tool" << typeName();
- Q_ASSERT(false);
- return false;
- }
-
- msIsAdjusting = true;
- mAdjustmentStep = step;
- mScribbleArea->updateCanvasCursor();
- return true;
- }
- return false;
-}
-
-void BaseTool::stopAdjusting()
-{
- msIsAdjusting = false;
- mAdjustmentStep = 0;
- msOriginalPropertyValue = 0;
- mEditor->getScribbleArea()->updateCanvasCursor();
-}
-
-void BaseTool::adjustCursor(Qt::KeyboardModifiers modifiers)
-{
- qreal inc = qPow(msOriginalPropertyValue * 100, 0.5);
- qreal newValue = inc + getCurrentPoint().x();
-
- if (newValue < 0)
- {
- newValue = 0;
- }
-
- newValue = qPow(newValue, 2) / 100;
- if (mAdjustmentStep > 0)
- {
- int tempValue = static_cast(newValue / mAdjustmentStep); // + 0.5 ?
- newValue = tempValue * mAdjustmentStep;
- }
-
- switch (mQuickSizingProperties.value(modifiers))
- {
- case WIDTH:
- mEditor->tools()->setWidth(qBound(1., newValue, 200.));
- break;
- case FEATHER:
- mEditor->tools()->setFeather(qBound(2., newValue, 200.));
- break;
- case TOLERANCE:
- mEditor->tools()->setTolerance(qBound(0., newValue, 100.));
- break;
- default:
- qDebug() << "Unhandled quick sizing property for tool" << typeName();
- Q_ASSERT(false);
- break;
- }
-}
-
QPointF BaseTool::getCurrentPressPixel() const
{
return strokeManager()->getCurrentPressPixel();
diff --git a/core_lib/src/tool/basetool.h b/core_lib/src/tool/basetool.h
index 533b59491..1c18ca635 100644
--- a/core_lib/src/tool/basetool.h
+++ b/core_lib/src/tool/basetool.h
@@ -24,6 +24,7 @@ GNU General Public License for more details.
#include
#include
#include
+#include
#include "pencildef.h"
class QPixmap;
@@ -90,18 +91,9 @@ class BaseTool : public QObject
virtual bool keyPressEvent(QKeyEvent*) { return false; }
virtual bool keyReleaseEvent(QKeyEvent*) { return false; }
- // dynamic cursor adjustment
- virtual bool startAdjusting(Qt::KeyboardModifiers modifiers, qreal argStep);
- virtual void stopAdjusting();
- virtual void adjustCursor(Qt::KeyboardModifiers modifiers);
-
virtual void clearToolData() {}
virtual void resetToDefault() {}
- static QPixmap canvasCursor(float brushWidth, float brushFeather, bool useFeather, float scalingFac, int windowWidth);
- QPixmap quickSizeCursor(qreal scalingFac);
- static bool isAdjusting() { return msIsAdjusting; }
-
/** Check if the tool is active.
*
* An active tool is definied as one which is actively modifying the buffer.
@@ -133,9 +125,14 @@ class BaseTool : public QObject
virtual void setPathDotColorType(const DotColorType dotColorType);
virtual void resetCameraPath();
- virtual void paint(QPainter& painter) { Q_UNUSED(painter) };
+ virtual void paint(QPainter& painter, const QRect& blitRect) { Q_UNUSED(painter) Q_UNUSED(blitRect) }
+
+ /// Will clean up `active` connections
+ virtual bool leavingThisTool();
- virtual bool leavingThisTool() { return true; }
+ /// Setup `active` connections here that should only emit while tool is active
+ /// `leavingThisTool` will handle the cleanup of `active` connections
+ virtual bool enteringThisTool() { return true; }
Properties properties;
@@ -162,15 +159,10 @@ class BaseTool : public QObject
Editor* mEditor = nullptr;
ScribbleArea* mScribbleArea = nullptr;
-
- QHash mQuickSizingProperties;
+ QList mActiveConnections;
private:
StrokeManager* mStrokeManager = nullptr;
- qreal mAdjustmentStep = 0.0f;
-
- static bool msIsAdjusting;
- static qreal msOriginalPropertyValue; // start from previous value (width, or feather ...)
};
#endif // BASETOOL_H
diff --git a/core_lib/src/tool/brushtool.cpp b/core_lib/src/tool/brushtool.cpp
index 4bec803d5..f7127dcc6 100644
--- a/core_lib/src/tool/brushtool.cpp
+++ b/core_lib/src/tool/brushtool.cpp
@@ -46,6 +46,8 @@ ToolType BrushTool::type()
void BrushTool::loadSettings()
{
+ StrokeTool::loadSettings();
+
mPropertyEnabled[WIDTH] = true;
mPropertyEnabled[FEATHER] = true;
mPropertyEnabled[PRESSURE] = true;
@@ -139,14 +141,24 @@ QCursor BrushTool::cursor()
void BrushTool::pointerPressEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
mMouseDownPoint = getCurrentPoint();
mLastBrushPoint = getCurrentPoint();
startStroke(event->inputType());
+
+ StrokeTool::pointerPressEvent(event);
}
void BrushTool::pointerMoveEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->buttons() & Qt::LeftButton && event->inputType() == mCurrentInputType)
{
mCurrentPressure = strokeManager()->getPressure();
@@ -154,10 +166,16 @@ void BrushTool::pointerMoveEvent(PointerEvent* event)
if (properties.stabilizerLevel != strokeManager()->getStabilizerLevel())
strokeManager()->setStabilizerLevel(properties.stabilizerLevel);
}
+
+ StrokeTool::pointerMoveEvent(event);
}
void BrushTool::pointerReleaseEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->inputType() != mCurrentInputType) return;
Layer* layer = mEditor->layers()->currentLayer();
@@ -178,6 +196,7 @@ void BrushTool::pointerReleaseEvent(PointerEvent *event)
}
endStroke();
+ StrokeTool::pointerReleaseEvent(event);
}
// draw a single paint dab at the given location
diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp
index 6ef11c59c..54e57f5aa 100644
--- a/core_lib/src/tool/buckettool.cpp
+++ b/core_lib/src/tool/buckettool.cpp
@@ -230,20 +230,6 @@ void BucketTool::pointerReleaseEvent(PointerEvent* event)
endStroke();
}
-bool BucketTool::startAdjusting(Qt::KeyboardModifiers modifiers, qreal argStep)
-{
- mQuickSizingProperties.clear();
- if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR)
- {
- mQuickSizingProperties.insert(Qt::ShiftModifier, WIDTH);
- }
- else
- {
- mQuickSizingProperties.insert(Qt::ControlModifier, TOLERANCE);
- }
- return BaseTool::startAdjusting(modifiers, argStep);
-}
-
void BucketTool::paintBitmap()
{
mBitmapBucket.paint(getCurrentPoint(), [this](BucketState progress, int layerIndex, int frameIndex)
diff --git a/core_lib/src/tool/buckettool.h b/core_lib/src/tool/buckettool.h
index 4f9660a61..99f65e869 100644
--- a/core_lib/src/tool/buckettool.h
+++ b/core_lib/src/tool/buckettool.h
@@ -40,8 +40,6 @@ class BucketTool : public StrokeTool
void pointerMoveEvent(PointerEvent*) override;
void pointerReleaseEvent(PointerEvent*) override;
- bool startAdjusting(Qt::KeyboardModifiers modifiers, qreal argStep) override;
-
void setTolerance(const int tolerance) override;
void setToleranceEnabled(const bool enabled) override;
void setWidth(const qreal width) override;
diff --git a/core_lib/src/tool/cameratool.cpp b/core_lib/src/tool/cameratool.cpp
index e82edb487..ab3928539 100644
--- a/core_lib/src/tool/cameratool.cpp
+++ b/core_lib/src/tool/cameratool.cpp
@@ -438,7 +438,7 @@ void CameraTool::transformView(LayerCamera* layerCamera, CameraMoveType mode, co
curCam->modification();
}
-void CameraTool::paint(QPainter& painter)
+void CameraTool::paint(QPainter& painter, const QRect& blitRect)
{
int frameIndex = mEditor->currentFrame();
LayerCamera* cameraLayerBelow = static_cast(mEditor->object()->getLayerBelow(mEditor->currentLayerIndex(), Layer::CAMERA));
diff --git a/core_lib/src/tool/cameratool.h b/core_lib/src/tool/cameratool.h
index 83f99bc8d..51adb8b44 100644
--- a/core_lib/src/tool/cameratool.h
+++ b/core_lib/src/tool/cameratool.h
@@ -51,7 +51,7 @@ class CameraTool : public BaseTool
QCursor cursor() override;
ToolType type() override { return ToolType::CAMERA; }
- void paint(QPainter& painter) override;
+ void paint(QPainter& painter, const QRect& blitRect) override;
void loadSettings() override;
diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp
index 7d57ade7e..d87ac2a12 100644
--- a/core_lib/src/tool/erasertool.cpp
+++ b/core_lib/src/tool/erasertool.cpp
@@ -42,6 +42,8 @@ ToolType EraserTool::type()
void EraserTool::loadSettings()
{
+ StrokeTool::loadSettings();
+
mPropertyEnabled[WIDTH] = true;
mPropertyEnabled[USEFEATHER] = true;
mPropertyEnabled[FEATHER] = true;
@@ -149,13 +151,23 @@ QCursor EraserTool::cursor()
void EraserTool::pointerPressEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
startStroke(event->inputType());
mLastBrushPoint = getCurrentPoint();
mMouseDownPoint = getCurrentPoint();
+
+ StrokeTool::pointerPressEvent(event);
}
void EraserTool::pointerMoveEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->buttons() & Qt::LeftButton && event->inputType() == mCurrentInputType)
{
mCurrentPressure = strokeManager()->getPressure();
@@ -163,10 +175,16 @@ void EraserTool::pointerMoveEvent(PointerEvent* event)
if (properties.stabilizerLevel != strokeManager()->getStabilizerLevel())
strokeManager()->setStabilizerLevel(properties.stabilizerLevel);
}
+
+ StrokeTool::pointerMoveEvent(event);
}
void EraserTool::pointerReleaseEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->inputType() != mCurrentInputType) return;
mEditor->backup(typeName());
@@ -183,6 +201,8 @@ void EraserTool::pointerReleaseEvent(PointerEvent *event)
removeVectorPaint();
endStroke();
+
+ StrokeTool::pointerReleaseEvent(event);
}
// draw a single paint dab at the given location
diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp
index ed3757da7..e93ffe252 100644
--- a/core_lib/src/tool/movetool.cpp
+++ b/core_lib/src/tool/movetool.cpp
@@ -319,6 +319,8 @@ void MoveTool::applyTransformation()
bool MoveTool::leavingThisTool()
{
+ BaseTool::leavingThisTool();
+
if (currentPaintableLayer())
{
applyTransformation();
diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp
index cd2169870..4fde93f17 100644
--- a/core_lib/src/tool/penciltool.cpp
+++ b/core_lib/src/tool/penciltool.cpp
@@ -39,6 +39,8 @@ PencilTool::PencilTool(QObject* parent) : StrokeTool(parent)
void PencilTool::loadSettings()
{
+ StrokeTool::loadSettings();
+
mPropertyEnabled[WIDTH] = true;
mPropertyEnabled[PRESSURE] = true;
mPropertyEnabled[VECTORMERGE] = false;
@@ -51,10 +53,7 @@ void PencilTool::loadSettings()
properties.pressure = settings.value("pencilPressure", true).toBool();
properties.stabilizerLevel = settings.value("pencilLineStabilization", StabilizationLevel::STRONG).toInt();
properties.useAA = DISABLED;
- properties.useFeather = true;
properties.useFillContour = false;
- // properties.invisibility = 1;
- // properties.preserveAlpha = 0;
mQuickSizingProperties.insert(Qt::ShiftModifier, WIDTH);
}
@@ -63,7 +62,7 @@ void PencilTool::resetToDefault()
{
setWidth(4.0);
setFeather(50);
- setUseFeather(true);
+ setUseFeather(false);
setStabilizerLevel(StabilizationLevel::STRONG);
}
@@ -147,6 +146,10 @@ QCursor PencilTool::cursor()
void PencilTool::pointerPressEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
mMouseDownPoint = getCurrentPoint();
mLastBrushPoint = getCurrentPoint();
@@ -157,10 +160,16 @@ void PencilTool::pointerPressEvent(PointerEvent *event)
{
mScribbleArea->toggleThinLines();
}
+
+ StrokeTool::pointerPressEvent(event);
}
void PencilTool::pointerMoveEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->buttons() & Qt::LeftButton && event->inputType() == mCurrentInputType)
{
mCurrentPressure = strokeManager()->getPressure();
@@ -168,10 +177,15 @@ void PencilTool::pointerMoveEvent(PointerEvent* event)
if (properties.stabilizerLevel != strokeManager()->getStabilizerLevel())
strokeManager()->setStabilizerLevel(properties.stabilizerLevel);
}
+ StrokeTool::pointerMoveEvent(event);
}
void PencilTool::pointerReleaseEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->inputType() != mCurrentInputType) return;
mEditor->backup(typeName());
@@ -190,6 +204,8 @@ void PencilTool::pointerReleaseEvent(PointerEvent *event)
paintVectorStroke(layer);
}
endStroke();
+
+ StrokeTool::pointerReleaseEvent(event);
}
// draw a single paint dab at the given location
@@ -254,7 +270,6 @@ void PencilTool::drawStroke()
}
else if (layer->type() == Layer::VECTOR)
{
- properties.useFeather = false;
mCurrentWidth = 0; // FIXME: WTF?
QPen pen(mEditor->color()->frontColor(),
1,
diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp
index 64dbed970..a2f985872 100644
--- a/core_lib/src/tool/pentool.cpp
+++ b/core_lib/src/tool/pentool.cpp
@@ -38,6 +38,8 @@ PenTool::PenTool(QObject* parent) : StrokeTool(parent)
void PenTool::loadSettings()
{
+ StrokeTool::loadSettings();
+
mPropertyEnabled[WIDTH] = true;
mPropertyEnabled[PRESSURE] = true;
mPropertyEnabled[VECTORMERGE] = true;
@@ -118,14 +120,24 @@ QCursor PenTool::cursor()
void PenTool::pointerPressEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
mMouseDownPoint = getCurrentPoint();
mLastBrushPoint = getCurrentPoint();
startStroke(event->inputType());
+
+ StrokeTool::pointerPressEvent(event);
}
void PenTool::pointerMoveEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->buttons() & Qt::LeftButton && event->inputType() == mCurrentInputType)
{
mCurrentPressure = strokeManager()->getPressure();
@@ -133,10 +145,16 @@ void PenTool::pointerMoveEvent(PointerEvent* event)
if (properties.stabilizerLevel != strokeManager()->getStabilizerLevel())
strokeManager()->setStabilizerLevel(properties.stabilizerLevel);
}
+
+ StrokeTool::pointerMoveEvent(event);
}
void PenTool::pointerReleaseEvent(PointerEvent *event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->inputType() != mCurrentInputType) return;
mEditor->backup(typeName());
@@ -157,6 +175,8 @@ void PenTool::pointerReleaseEvent(PointerEvent *event)
paintVectorStroke(layer);
}
endStroke();
+
+ StrokeTool::pointerReleaseEvent(event);
}
// draw a single paint dab at the given location
diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp
index 4d723b487..5a3c664cd 100644
--- a/core_lib/src/tool/polylinetool.cpp
+++ b/core_lib/src/tool/polylinetool.cpp
@@ -30,7 +30,7 @@ GNU General Public License for more details.
#include "vectorimage.h"
-PolylineTool::PolylineTool(QObject* parent) : BaseTool(parent)
+PolylineTool::PolylineTool(QObject* parent) : StrokeTool(parent)
{
}
@@ -41,6 +41,8 @@ ToolType PolylineTool::type()
void PolylineTool::loadSettings()
{
+ StrokeTool::loadSettings();
+
mPropertyEnabled[WIDTH] = true;
mPropertyEnabled[BEZIER] = true;
mPropertyEnabled[ANTI_ALIASING] = true;
@@ -54,6 +56,8 @@ void PolylineTool::loadSettings()
properties.preserveAlpha = OFF;
properties.useAA = settings.value("brushAA").toBool();
properties.stabilizerLevel = -1;
+
+ mQuickSizingProperties.insert(Qt::ShiftModifier, WIDTH);
}
void PolylineTool::resetToDefault()
@@ -92,6 +96,7 @@ void PolylineTool::setAA(const int AA)
bool PolylineTool::leavingThisTool()
{
+ StrokeTool::leavingThisTool();
if (mPoints.size() > 0)
{
cancelPolyline();
@@ -118,6 +123,10 @@ void PolylineTool::clearToolData()
void PolylineTool::pointerPressEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
Layer* layer = mEditor->layers()->currentLayer();
if (event->button() == Qt::LeftButton)
@@ -140,19 +149,33 @@ void PolylineTool::pointerPressEvent(PointerEvent* event)
emit isActiveChanged(POLYLINE, true);
}
}
+
+ StrokeTool::pointerPressEvent(event);
}
-void PolylineTool::pointerMoveEvent(PointerEvent*)
+void PolylineTool::pointerMoveEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
Layer* layer = mEditor->layers()->currentLayer();
if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR)
{
drawPolyline(mPoints, getCurrentPoint());
}
+
+ StrokeTool::pointerMoveEvent(event);
}
-void PolylineTool::pointerReleaseEvent(PointerEvent *)
-{}
+void PolylineTool::pointerReleaseEvent(PointerEvent* event)
+{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
+ StrokeTool::pointerReleaseEvent(event);
+}
void PolylineTool::pointerDoubleClickEvent(PointerEvent*)
{
diff --git a/core_lib/src/tool/polylinetool.h b/core_lib/src/tool/polylinetool.h
index 41ce32a82..b1b11683d 100644
--- a/core_lib/src/tool/polylinetool.h
+++ b/core_lib/src/tool/polylinetool.h
@@ -20,9 +20,9 @@ GNU General Public License for more details.
#include
-#include "basetool.h"
+#include "stroketool.h"
-class PolylineTool : public BaseTool
+class PolylineTool : public StrokeTool
{
Q_OBJECT
public:
diff --git a/core_lib/src/tool/smudgetool.cpp b/core_lib/src/tool/smudgetool.cpp
index de94077e6..e3594b9ae 100644
--- a/core_lib/src/tool/smudgetool.cpp
+++ b/core_lib/src/tool/smudgetool.cpp
@@ -44,6 +44,8 @@ ToolType SmudgeTool::type()
void SmudgeTool::loadSettings()
{
+ StrokeTool::loadSettings();
+
mPropertyEnabled[WIDTH] = true;
mPropertyEnabled[FEATHER] = true;
@@ -121,7 +123,7 @@ bool SmudgeTool::keyPressEvent(QKeyEvent *event)
mScribbleArea->setCursor(cursor()); // update cursor
return true;
}
- return BaseTool::keyPressEvent(event);
+ return StrokeTool::keyPressEvent(event);
}
bool SmudgeTool::keyReleaseEvent(QKeyEvent *event)
@@ -132,12 +134,14 @@ bool SmudgeTool::keyReleaseEvent(QKeyEvent *event)
mScribbleArea->setCursor(cursor()); // update cursor
return true;
}
- return BaseTool::keyReleaseEvent(event);
+ return StrokeTool::keyReleaseEvent(event);
}
void SmudgeTool::pointerPressEvent(PointerEvent* event)
{
- //qDebug() << "smudgetool: mousePressEvent";
+ if (handleQuickSizing(event)) {
+ return;
+ }
Layer* layer = mEditor->layers()->currentLayer();
auto selectMan = mEditor->select();
@@ -186,10 +190,16 @@ void SmudgeTool::pointerPressEvent(PointerEvent* event)
}
}
}
+
+ StrokeTool::pointerPressEvent(event);
}
void SmudgeTool::pointerMoveEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->inputType() != mCurrentInputType) return;
Layer* layer = mEditor->layers()->currentLayer();
@@ -240,10 +250,16 @@ void SmudgeTool::pointerMoveEvent(PointerEvent* event)
mScribbleArea->update();
}
}
+
+ StrokeTool::pointerMoveEvent(event);
}
void SmudgeTool::pointerReleaseEvent(PointerEvent* event)
{
+ if (handleQuickSizing(event)) {
+ return;
+ }
+
if (event->inputType() != mCurrentInputType) return;
Layer* layer = mEditor->layers()->currentLayer();
@@ -276,6 +292,8 @@ void SmudgeTool::pointerReleaseEvent(PointerEvent* event)
mEditor->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame());
}
}
+
+ StrokeTool::pointerReleaseEvent(event);
}
void SmudgeTool::drawStroke()
diff --git a/core_lib/src/tool/stroketool.cpp b/core_lib/src/tool/stroketool.cpp
index 6b8e8c112..5da6ad003 100644
--- a/core_lib/src/tool/stroketool.cpp
+++ b/core_lib/src/tool/stroketool.cpp
@@ -21,8 +21,12 @@ GNU General Public License for more details.
#include "scribblearea.h"
#include "strokemanager.h"
#include "viewmanager.h"
+#include "preferencemanager.h"
#include "editor.h"
#include "toolmanager.h"
+#include "mathutils.h"
+
+#include "canvascursorpainter.h"
#ifdef Q_OS_MAC
extern "C" {
@@ -38,11 +42,55 @@ extern "C" {
}
#endif
+const qreal StrokeTool::FEATHER_MIN = 1.;
+const qreal StrokeTool::FEATHER_MAX = 99.;
+const qreal StrokeTool::WIDTH_MIN = 1.;
+const qreal StrokeTool::WIDTH_MAX = 200.;
+
+// ---- shared static variables ---- ( only one instance for all the tools )
+bool StrokeTool::msIsAdjusting = false;
+bool StrokeTool::mQuickSizingEnabled = false;
+
StrokeTool::StrokeTool(QObject* parent) : BaseTool(parent)
{
detectWhichOSX();
}
+void StrokeTool::loadSettings()
+{
+ mQuickSizingEnabled = mEditor->preference()->isOn(SETTING::QUICK_SIZING);
+ mCanvasCursorEnabled = mEditor->preference()->isOn(SETTING::CANVAS_CURSOR);
+
+ /// Given the way that we update preferences currently, this connection should not be removed
+ /// when the tool is not active.
+ connect(mEditor->preference(), &PreferenceManager::optionChanged, this, &StrokeTool::onPreferenceChanged);
+}
+
+bool StrokeTool::enteringThisTool()
+{
+ mActiveConnections.append(connect(mEditor->view(), &ViewManager::viewChanged, this, &StrokeTool::onViewUpdated));
+ return true;
+}
+
+bool StrokeTool::leavingThisTool()
+{
+ return BaseTool::leavingThisTool();
+}
+
+void StrokeTool::onPreferenceChanged(SETTING setting)
+{
+ if (setting == SETTING::QUICK_SIZING) {
+ mQuickSizingEnabled = mEditor->preference()->isOn(setting);
+ } else if (setting == SETTING::CANVAS_CURSOR) {
+ mCanvasCursorEnabled = mEditor->preference()->isOn(setting);
+ }
+}
+
+void StrokeTool::onViewUpdated()
+{
+ updateCanvasCursor();
+}
+
void StrokeTool::startStroke(PointerEvent::InputType inputType)
{
if (emptyFrameActionEnabled())
@@ -119,3 +167,175 @@ void StrokeTool::drawStroke()
mFirstDraw = false;
}
}
+
+bool StrokeTool::handleQuickSizing(PointerEvent* event)
+{
+ if (event->eventType() == PointerEvent::Press) {
+ if (mQuickSizingEnabled) {
+ return startAdjusting(event->modifiers());
+ }
+ } else if (event->eventType() == PointerEvent::Move) {
+ if (event->buttons() & Qt::LeftButton && msIsAdjusting) {
+ adjustCursor(event->modifiers());
+ return true;
+ }
+ } else if (event->eventType() == PointerEvent::Release) {
+ if (msIsAdjusting) {
+ stopAdjusting();
+ return true;
+ }
+ }
+ return false;
+}
+
+void StrokeTool::pointerPressEvent(PointerEvent*)
+{
+ updateCanvasCursor();
+}
+
+void StrokeTool::pointerMoveEvent(PointerEvent*)
+{
+ updateCanvasCursor();
+}
+
+void StrokeTool::pointerReleaseEvent(PointerEvent*)
+{
+ updateCanvasCursor();
+}
+
+bool StrokeTool::event(QEvent *event)
+{
+ if (event->type() == QEvent::Leave && !isActive()) {
+ mCanvasCursorEnabled = false;
+ updateCanvasCursor();
+ QObject::event(event);
+ return true;
+ } else if (event->type() == QEvent::Enter) {
+ mCanvasCursorEnabled = mEditor->preference()->isOn(SETTING::CANVAS_CURSOR);
+ QObject::event(event);
+ return true;
+ }
+ return QObject::event(event);
+}
+
+void StrokeTool::updateCanvasCursor()
+{
+ const qreal brushWidth = properties.width;
+ const qreal brushFeather = properties.feather;
+
+ const QPointF& cursorPos = msIsAdjusting ? mAdjustPosition : getCurrentPoint();
+ const qreal cursorRad = brushWidth * 0.5;
+ const QPointF& cursorOffset = QPointF(cursorPos.x() - cursorRad, cursorPos.y() - cursorRad);
+
+ CanvasCursorPainterOptions options;
+ options.widthRect = QRectF(cursorOffset, QSizeF(brushWidth, brushWidth));
+
+ const qreal featherWidthFactor = MathUtils::normalize(brushFeather, 0.0, FEATHER_MAX);
+ options.featherRect = QRectF(options.widthRect.center().x() - (cursorRad * featherWidthFactor),
+ options.widthRect.center().y() - (cursorRad * featherWidthFactor),
+ brushWidth * featherWidthFactor,
+ brushWidth * featherWidthFactor);
+ options.showCursor = mCanvasCursorEnabled;
+ options.isAdjusting = msIsAdjusting && mQuickSizingEnabled;
+ options.useFeather = mPropertyEnabled[FEATHER];
+
+ mCanvasCursorPainter.preparePainter(options, mEditor->view()->getView());
+
+ const QRect& dirtyRect = mCanvasCursorPainter.dirtyRect();
+ const QRect& updateRect = mEditor->view()->getView().mapRect(QRectF(cursorOffset, QSizeF(brushWidth, brushWidth))).toAlignedRect();
+
+ if (!msIsAdjusting && !mCanvasCursorEnabled) {
+ if (mCanvasCursorPainter.isDirty()) {
+ // Adjusted to account for some pixel bleeding outside the update rect
+ mScribbleArea->update(mCanvasCursorPainter.dirtyRect().adjusted(-2, -2, 2, 2));
+ mCanvasCursorPainter.clearDirty();
+ }
+ return;
+ }
+
+ // Adjusted to account for some pixel bleeding outside the update rect
+ mScribbleArea->update(updateRect.united(dirtyRect).adjusted(-2, -2, 2, 2));
+}
+
+bool StrokeTool::startAdjusting(Qt::KeyboardModifiers modifiers)
+{
+ if (!mQuickSizingProperties.contains(modifiers))
+ {
+ return false;
+ }
+
+ const QPointF& currentPressPoint = getCurrentPressPoint();
+ const QPointF& currentPoint = getCurrentPoint();
+ auto propertyType = mQuickSizingProperties.value(modifiers);
+ switch (propertyType) {
+ case WIDTH: {
+ const qreal factor = 0.5;
+ const qreal rad = properties.width * factor;
+ const qreal distance = QLineF(currentPressPoint - QPointF(rad, rad), currentPoint).length();
+ mAdjustPosition = currentPressPoint - QPointF(distance * factor, distance * factor);
+ break;
+ }
+ case FEATHER: {
+ const qreal factor = 0.5;
+ const qreal cursorRad = properties.width * factor;
+ const qreal featherWidthFactor = MathUtils::normalize(properties.feather, 0.0, FEATHER_MAX);
+ const qreal offset = (cursorRad * featherWidthFactor) * factor;
+ const qreal distance = QLineF(currentPressPoint - QPointF(offset, offset), currentPoint).length();
+ mAdjustPosition = currentPressPoint - QPointF(distance, distance);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ qWarning() << "Unhandled quick sizing property for tool" << typeName();
+ return false;
+ }
+
+ msIsAdjusting = true;
+ updateCanvasCursor();
+ return true;
+}
+
+void StrokeTool::stopAdjusting()
+{
+ msIsAdjusting = false;
+ mAdjustPosition = QPointF();
+ updateCanvasCursor();
+}
+
+void StrokeTool::adjustCursor(Qt::KeyboardModifiers modifiers)
+{
+ switch (mQuickSizingProperties.value(modifiers))
+ {
+ case WIDTH: {
+ // The adjusted position is based on the radius of the circle, so in order to
+ // map it back to its original value, we can multiply by the factor we divided with
+ const qreal newValue = QLineF(mAdjustPosition, getCurrentPoint()).length() * 2.0;
+
+ mEditor->tools()->setWidth(qBound(WIDTH_MIN, newValue, WIDTH_MAX));
+ break;
+ }
+ case FEATHER: {
+ // The radius of the width is the max value we can get
+ const qreal inputMin = 0.0;
+ const qreal inputMax = properties.width * 0.5;
+ const qreal distance = QLineF(mAdjustPosition, getCurrentPoint()).length();
+ const qreal outputMax = FEATHER_MAX;
+ const qreal outputMin = 0.0;
+
+ // We flip min and max here in order to get the inverted value for the UI
+ const qreal mappedValue = MathUtils::map(distance, inputMin, inputMax, outputMax, outputMin);
+
+ mEditor->tools()->setFeather(qBound(FEATHER_MIN, mappedValue, FEATHER_MAX));
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ qWarning() << "Unhandled quick sizing property for tool" << typeName();
+ }
+ updateCanvasCursor();
+}
+
+void StrokeTool::paint(QPainter& painter, const QRect& blitRect)
+{
+ mCanvasCursorPainter.paint(painter, blitRect);
+}
diff --git a/core_lib/src/tool/stroketool.h b/core_lib/src/tool/stroketool.h
index 7f97c793b..28bc766c8 100644
--- a/core_lib/src/tool/stroketool.h
+++ b/core_lib/src/tool/stroketool.h
@@ -20,6 +20,9 @@ GNU General Public License for more details.
#include "basetool.h"
#include "pointerevent.h"
+#include "preferencesdef.h"
+
+#include "canvascursorpainter.h"
#include
#include
@@ -36,9 +39,42 @@ class StrokeTool : public BaseTool
void drawStroke();
void endStroke();
+ bool leavingThisTool() override;
+ bool enteringThisTool() override;
+
+ void updateCanvasCursor();
+
+ static const qreal FEATHER_MIN;
+ static const qreal FEATHER_MAX;
+ static const qreal WIDTH_MIN;
+ static const qreal WIDTH_MAX;
+
+ void loadSettings() override;
+
bool keyPressEvent(QKeyEvent* event) override;
+ void pointerPressEvent(PointerEvent* event) override;
+ void pointerMoveEvent(PointerEvent* event) override;
+ void pointerReleaseEvent(PointerEvent* event) override;
+ bool event(QEvent *event) override;
+
+ bool handleQuickSizing(PointerEvent* event);
+
+ void paint(QPainter& painter, const QRect& blitRect) override;
+
+public slots:
+ void onPreferenceChanged(SETTING setting);
+ void onViewUpdated();
protected:
+ // dynamic cursor adjustment
+ virtual bool startAdjusting(Qt::KeyboardModifiers modifiers);
+ virtual void stopAdjusting();
+ virtual void adjustCursor(Qt::KeyboardModifiers modifiers);
+
+ static bool mQuickSizingEnabled;
+ static bool msIsAdjusting;
+
+ QHash mQuickSizingProperties;
bool mFirstDraw = false;
QList mStrokePoints;
@@ -56,8 +92,12 @@ class StrokeTool : public BaseTool
/// Returns true by default.
virtual bool emptyFrameActionEnabled();
-private:
+ bool mCanvasCursorEnabled = false;
QPointF mLastPixel { 0, 0 };
+
+ QPointF mAdjustPosition;
+
+ CanvasCursorPainter mCanvasCursorPainter;
};
#endif // STROKETOOL_H
diff --git a/core_lib/src/util/mathutils.h b/core_lib/src/util/mathutils.h
index 7583e5bc1..858515cb6 100644
--- a/core_lib/src/util/mathutils.h
+++ b/core_lib/src/util/mathutils.h
@@ -16,6 +16,31 @@ namespace MathUtils
{
return qAtan2(b.y() - a.y(), b.x() - a.x());
}
+
+ /** Map one range onto another
+ * \param x The input value
+ * \param inputMin The input min value
+ * \param inputMax The input max value
+ * \param outputMin The output min value
+ * \param outputMax The output max value
+ * \return The value of x mapped to the corresponding range between outputMin and outputMax
+ */
+ inline qreal map(qreal x, qreal inputMin, qreal inputMax, qreal outputMin, qreal outputMax)
+ {
+ qreal slope = (outputMax - outputMin) / (inputMax - inputMin);
+ return outputMin + slope * (x - inputMin);
+ }
+
+ /** Normalize x to a value between 0 and 1;
+ * \param x The input value
+ * \param min The input min value
+ * \param max The input max value
+ * \return The value of x normalized to a range between 0 and 1
+ */
+ inline qreal normalize(qreal x, qreal min, qreal max)
+ {
+ return qAbs((x - max) / (min - max));
+ }
}
#endif // MATHUTILS_H
diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h
index e1b9b11ac..adf5aceb0 100644
--- a/core_lib/src/util/pencildef.h
+++ b/core_lib/src/util/pencildef.h
@@ -117,9 +117,6 @@ inline LayerVisibility& operator--(LayerVisibility& vis)
// Max frames that can be imported and loaded onto the timeline
const static int MaxFramesBound = 9999;
-// Spacer for rotation handle offset
-const static float RotationHandleOffset = 50;
-
// shortcuts command code
#define CMD_NEW_FILE "CmdNewFile"
#define CMD_OPEN_FILE "CmdOpenFile"
@@ -228,7 +225,7 @@ const static float RotationHandleOffset = 50;
#define SETTING_AUTO_SAVE "AutoSave"
#define SETTING_AUTO_SAVE_NUMBER "AutosaveNumber"
#define SETTING_TOOL_CURSOR "ToolCursors"
-#define SETTING_DOTTED_CURSOR "DottedCursors"
+#define SETTING_CANVAS_CURSOR "DottedCursors"
#define SETTING_HIGH_RESOLUTION "HighResPosition"
#define SETTING_BACKGROUND_STYLE "Background"
#define SETTING_WINDOW_OPACITY "WindowOpacity"
diff --git a/core_lib/src/util/pointerevent.cpp b/core_lib/src/util/pointerevent.cpp
index b65c720ac..dc7c0f202 100644
--- a/core_lib/src/util/pointerevent.cpp
+++ b/core_lib/src/util/pointerevent.cpp
@@ -209,17 +209,37 @@ bool PointerEvent::isAccepted()
return false;
}
-QEvent::Type PointerEvent::eventType() const
+PointerEvent::Type PointerEvent::eventType() const
{
if (mMouseEvent)
{
- return mMouseEvent->type();
+ switch (mMouseEvent->type())
+ {
+ case QEvent::MouseButtonPress:
+ return Type::Press;
+ case QEvent::MouseMove:
+ return Type::Move;
+ case QEvent::MouseButtonRelease:
+ return Type::Release;
+ default:
+ return Type::Unmapped;
+ }
}
else if (mTabletEvent)
{
- return mTabletEvent->type();
- }
- return QEvent::None;
+ switch (mTabletEvent->type())
+ {
+ case QEvent::TabletPress:
+ return Type::Press;
+ case QEvent::TabletMove:
+ return Type::Move;
+ case QEvent::TabletRelease:
+ return Type::Release;
+ default:
+ return Type::Unmapped;
+ }
+ }
+ return Type::Unmapped;
}
PointerEvent::InputType PointerEvent::inputType() const
diff --git a/core_lib/src/util/pointerevent.h b/core_lib/src/util/pointerevent.h
index 871fe69a1..aad7ed692 100644
--- a/core_lib/src/util/pointerevent.h
+++ b/core_lib/src/util/pointerevent.h
@@ -14,6 +14,13 @@ class PointerEvent
Unknown
};
+ enum Type {
+ Press,
+ Move,
+ Release,
+ Unmapped
+ };
+
PointerEvent(QMouseEvent* event);
PointerEvent(QTabletEvent* event);
~PointerEvent();
@@ -70,7 +77,7 @@ class PointerEvent
bool isAccepted();
- QEvent::Type eventType() const;
+ Type eventType() const;
InputType inputType() const;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
diff --git a/core_lib/src/util/preferencesdef.h b/core_lib/src/util/preferencesdef.h
index b71878eed..e8eb21605 100644
--- a/core_lib/src/util/preferencesdef.h
+++ b/core_lib/src/util/preferencesdef.h
@@ -30,7 +30,7 @@ enum class SETTING
ONION_BLUE,
ONION_RED,
TOOL_CURSOR,
- DOTTED_CURSOR,
+ CANVAS_CURSOR,
HIGH_RESOLUTION,
WINDOW_OPACITY,
SHOW_STATUS_BAR,