From 22f97844d9ddb35464650ad3c2d92eb985411d07 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Fri, 12 Nov 2021 17:24:03 -0700 Subject: [PATCH] Rewrite temporary tool handling This moves all the handling of temporary tools out of ScribbleArea and into ToolManager. There are also changes to the implementation and behavior that will make it more verstatile and able to handle weird corner cases better (ex. shortcuts while using temporary tools). --- app/src/statusbar.cpp | 9 +- core_lib/src/interface/scribblearea.cpp | 126 +++++++----------------- core_lib/src/interface/scribblearea.h | 8 -- core_lib/src/managers/toolmanager.cpp | 118 ++++++++++++++++++---- core_lib/src/managers/toolmanager.h | 21 +++- core_lib/src/tool/handtool.cpp | 7 +- core_lib/src/tool/polylinetool.cpp | 14 ++- core_lib/src/tool/polylinetool.h | 2 + core_lib/src/tool/selecttool.cpp | 6 +- core_lib/src/tool/smudgetool.cpp | 16 +-- core_lib/src/tool/stroketool.cpp | 23 ++--- core_lib/src/tool/stroketool.h | 1 - 12 files changed, 192 insertions(+), 159 deletions(-) diff --git a/app/src/statusbar.cpp b/app/src/statusbar.cpp index db00a9a69..c2ffcb750 100644 --- a/app/src/statusbar.cpp +++ b/app/src/statusbar.cpp @@ -100,14 +100,7 @@ void StatusBar::updateToolStatus(ToolType tool) mToolLabel->setText(tr("Click and drag to create or modify a selection. Hold Alt to modify its contents or press Backspace to clear them.")); break; case MOVE: - if (mEditor->getScribbleArea()->isTemporaryTool()) - { - mToolLabel->setText(tr("Click and drag to move an object.")); - } - else - { - mToolLabel->setText(tr("Click and drag to move an object. Hold Ctrl to rotate.")); - } + mToolLabel->setText(tr("Click and drag to move an object. Hold Ctrl to rotate.")); break; case HAND: mToolLabel->setText(tr("Click and drag to pan. Hold Ctrl to zoom or Alt to rotate.")); diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 81703b490..ccc156f86 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -353,8 +353,9 @@ void ScribbleArea::setModified(int layerNumber, int frameNumber) bool ScribbleArea::event(QEvent *event) { - if (event->type() == QEvent::WindowDeactivate) { - setPrevTool(); + if (event->type() == QEvent::WindowDeactivate) + { + editor()->tools()->clearTemporaryTool(); } return QWidget::event(event); } @@ -371,7 +372,6 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) mKeyboardInUse = true; if (isPointerInUse()) { return; } // prevents shortcuts calls while drawing - if (mInstantTool) { return; } // prevents shortcuts calls while using instant tool if (currentTool()->keyPressEvent(event)) { @@ -379,9 +379,9 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) } // --- fixed control key shortcuts --- - if (event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) + if (event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier) && + editor()->tools()->setTemporaryTool(ERASER, 0, event->modifiers())) { - setTemporaryTool(ERASER); return; } @@ -389,9 +389,12 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) auto selectMan = mEditor->select(); bool isSomethingSelected = selectMan->somethingSelected(); - if (isSomethingSelected) { + if (isSomethingSelected) + { keyEventForSelection(event); - } else { + } + else + { keyEvent(event); } } @@ -404,37 +407,40 @@ void ScribbleArea::keyEventForSelection(QKeyEvent* event) case Qt::Key_Right: selectMan->translate(QPointF(1, 0)); paintTransformedSelection(); - break; + return; case Qt::Key_Left: selectMan->translate(QPointF(-1, 0)); paintTransformedSelection(); - break; + return; case Qt::Key_Up: selectMan->translate(QPointF(0, -1)); paintTransformedSelection(); - break; + return; case Qt::Key_Down: selectMan->translate(QPointF(0, 1)); paintTransformedSelection(); - break; + return; case Qt::Key_Return: applyTransformedSelection(); mEditor->deselectAll(); - break; + return; case Qt::Key_Escape: cancelTransformedSelection(); mEditor->deselectAll(); - break; + return; case Qt::Key_Backspace: deleteSelection(); mEditor->deselectAll(); - break; + return; case Qt::Key_Space: - setTemporaryTool(HAND); // just call "setTemporaryTool()" to activate temporarily any tool + if (editor()->tools()->setTemporaryTool(HAND, Qt::Key_Space, Qt::NoModifier)) { + return; + } break; default: - event->ignore(); + break; } + event->ignore(); } void ScribbleArea::keyEvent(QKeyEvent* event) @@ -443,29 +449,26 @@ void ScribbleArea::keyEvent(QKeyEvent* event) { case Qt::Key_Right: mEditor->scrubForward(); - event->ignore(); break; case Qt::Key_Left: mEditor->scrubBackward(); - event->ignore(); break; case Qt::Key_Up: mEditor->layers()->gotoNextLayer(); - event->ignore(); break; case Qt::Key_Down: mEditor->layers()->gotoPreviouslayer(); - event->ignore(); - break; - case Qt::Key_Return: - event->ignore(); break; case Qt::Key_Space: - setTemporaryTool(HAND); // just call "setTemporaryTool()" to activate temporarily any tool + if(editor()->tools()->setTemporaryTool(HAND, Qt::Key_Space, Qt::NoModifier)) + { + return; + } break; default: - event->ignore(); + break; } + event->ignore(); } void ScribbleArea::keyReleaseEvent(QKeyEvent *event) @@ -478,14 +481,10 @@ void ScribbleArea::keyReleaseEvent(QKeyEvent *event) mKeyboardInUse = false; + editor()->tools()->tryClearTemporaryTool(event->key()); + if (isPointerInUse()) { return; } - if (mInstantTool) // temporary tool - { - currentTool()->keyReleaseEvent(event); - setPrevTool(); - return; - } if (currentTool()->keyReleaseEvent(event)) { // has been handled by tool @@ -622,10 +621,10 @@ void ScribbleArea::pointerPressEvent(PointerEvent* event) } } - if (event->buttons() & (Qt::MidButton | Qt::RightButton)) + if (event->buttons() & (Qt::MidButton | Qt::RightButton) && + editor()->tools()->setTemporaryTool(HAND, event->buttons())) { - setTemporaryTool(HAND); - getTool(HAND)->pointerPressEvent(event); + currentTool()->pointerPressEvent(event); } const bool isPressed = event->buttons() & Qt::LeftButton; @@ -659,13 +658,6 @@ void ScribbleArea::pointerMoveEvent(PointerEvent* event) } } - if (event->buttons() == Qt::RightButton) - { - setCursor(getTool(HAND)->cursor()); - getTool(HAND)->pointerMoveEvent(event); - event->accept(); - return; - } currentTool()->pointerMoveEvent(event); } @@ -687,11 +679,7 @@ void ScribbleArea::pointerReleaseEvent(PointerEvent* event) //qDebug() << "release event"; currentTool()->pointerReleaseEvent(event); - // ---- last check (at the very bottom of mouseRelease) ---- - if (mInstantTool && !mKeyboardInUse) // temp tool and released all keys ? - { - setPrevTool(); - } + editor()->tools()->tryClearTemporaryTool(event->button()); } void ScribbleArea::handleDoubleClick() @@ -1630,48 +1618,13 @@ BaseTool* ScribbleArea::getTool(ToolType eToolType) return editor()->tools()->getTool(eToolType); } -// TODO: check this method void ScribbleArea::setCurrentTool(ToolType eToolMode) { - if (currentTool() != nullptr && eToolMode != currentTool()->type()) - { - //qDebug() << "Set Current Tool" << BaseTool::TypeName(eToolMode); - if (BaseTool::TypeName(eToolMode) == "") - { - // tool does not exist - //Q_ASSERT_X( false, "", "" ); - return; - } - - if (currentTool()->type() == MOVE) - { - paintTransformedSelection(); - mEditor->deselectAll(); - } - else if (currentTool()->type() == POLYLINE) - { - mEditor->deselectAll(); - } - } - - mPrevToolType = currentTool()->type(); + Q_UNUSED(eToolMode) // change cursor setCursor(currentTool()->cursor()); updateCanvasCursor(); - //qDebug() << "fn: setCurrentTool " << "call: setCursor()" << "current tool" << currentTool()->typeName(); -} - -void ScribbleArea::setTemporaryTool(ToolType eToolMode) -{ - // Only switch to temporary tool if not already in this state - // and temporary tool is not already the current tool. - if (!mInstantTool && currentTool()->type() != eToolMode) - { - mInstantTool = true; // used to return to previous tool when finished (keyRelease). - mPrevTemporalToolType = currentTool()->type(); - editor()->tools()->setCurrentTool(eToolMode); - } } void ScribbleArea::deleteSelection() @@ -1735,15 +1688,6 @@ void ScribbleArea::clearImage() setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); } -void ScribbleArea::setPrevTool() -{ - if (mInstantTool) - { - editor()->tools()->setCurrentTool(mPrevTemporalToolType); - mInstantTool = false; - } -} - void ScribbleArea::paletteColorChanged(QColor color) { Q_UNUSED(color) diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 2348609e4..6477a9491 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -137,15 +137,12 @@ class ScribbleArea : public QWidget BaseTool* currentTool() const; BaseTool* getTool(ToolType eToolMode); void setCurrentTool(ToolType eToolMode); - void setTemporaryTool(ToolType eToolMode); - void setPrevTool(); void floodFillError(int errorType); bool isMouseInUse() const { return mMouseInUse; } bool isTabletInUse() const { return mTabletInUse; } bool isPointerInUse() const { return mMouseInUse || mTabletInUse; } - bool isTemporaryTool() const { return mInstantTool; } void keyEvent(QKeyEvent* event); void keyEventForSelection(QKeyEvent* event); @@ -245,8 +242,6 @@ public slots: VectorImage* currentVectorImage(Layer* layer) const; MoveMode mMoveMode = MoveMode::NONE; - ToolType mPrevTemporalToolType = ERASER; - ToolType mPrevToolType = PEN; // previous tool (except temporal) BitmapImage mBitmapSelection; // used to temporary store a transformed portion of a bitmap image @@ -283,9 +278,6 @@ public slots: QPoint mCursorCenterPos; QPointF mTransformedCursorPos; - //instant tool (temporal eg. eraser) - bool mInstantTool = false; //whether or not using temporal tool - PreferenceManager* mPrefs = nullptr; QPixmap mCanvas; diff --git a/core_lib/src/managers/toolmanager.cpp b/core_lib/src/managers/toolmanager.cpp index 2a7ba5600..d47d806f5 100644 --- a/core_lib/src/managers/toolmanager.cpp +++ b/core_lib/src/managers/toolmanager.cpp @@ -37,8 +37,6 @@ ToolManager::ToolManager(Editor* editor) : BaseManager(editor, __FUNCTION__) bool ToolManager::init() { - mIsSwitchedToEraser = false; - mToolSetHash.insert(PEN, new PenTool(this)); mToolSetHash.insert(PENCIL, new PencilTool(this)); mToolSetHash.insert(BRUSH, new BrushTool(this)); @@ -71,6 +69,19 @@ Status ToolManager::save(Object*) return Status::OK; } +BaseTool* ToolManager::currentTool() +{ + if (mTemporaryTool != nullptr) + { + return mTemporaryTool; + } + else if (mTabletEraserTool != nullptr) + { + return mTabletEraserTool; + } + return mCurrentTool; +} + BaseTool* ToolManager::getTool(ToolType eToolType) { return mToolSetHash[eToolType]; @@ -83,23 +94,27 @@ void ToolManager::setDefaultTool() ToolType defaultToolType = PENCIL; setCurrentTool(defaultToolType); - meTabletBackupTool = defaultToolType; + mTabletEraserTool = nullptr; + mTemporaryTool = nullptr; } void ToolManager::setCurrentTool(ToolType eToolType) { if (mCurrentTool != nullptr) { - leavingThisTool(); + mCurrentTool->leavingThisTool(); } mCurrentTool = getTool(eToolType); - emit toolChanged(eToolType); + if (mTemporaryTool == nullptr && mTabletEraserTool == nullptr) + { + emit toolChanged(eToolType); + } } bool ToolManager::leavingThisTool() { - return mCurrentTool->leavingThisTool(); + return currentTool()->leavingThisTool(); } void ToolManager::cleanupAllToolsData() @@ -274,24 +289,91 @@ int ToolManager::propertySwitch(bool condition, int tool) void ToolManager::tabletSwitchToEraser() { - if (!mIsSwitchedToEraser) + mTabletEraserTool = getTool(ERASER); + if (mTemporaryTool == nullptr) { - mIsSwitchedToEraser = true; - - meTabletBackupTool = mCurrentTool->type(); - setCurrentTool(ERASER); + emit toolChanged(ERASER); } } void ToolManager::tabletRestorePrevTool() { - if (mIsSwitchedToEraser) + mTabletEraserTool = nullptr; + if (mTemporaryTool == nullptr) + { + emit toolChanged(currentTool()->type()); + } +} + +bool ToolManager::setTemporaryTool(ToolType eToolType, int keys, Qt::KeyboardModifiers modifiers) +{ + if (mTemporaryTool != nullptr) return false; + mTemporaryTriggerKeys = keys; + mTemporaryTriggerModifiers = modifiers; + mTemporaryTriggerMouseButtons = Qt::NoButton; + setTemporaryTool(eToolType); + return true; +} + +bool ToolManager::setTemporaryTool(ToolType eToolType, Qt::MouseButtons buttons) +{ + if (mTemporaryTool != nullptr) return false; + mTemporaryTriggerKeys = 0; + mTemporaryTriggerModifiers = Qt::NoModifier; + mTemporaryTriggerMouseButtons = buttons; + setTemporaryTool(eToolType); + return true; +} + +bool ToolManager::tryClearTemporaryTool(int key) +{ + Qt::KeyboardModifier modifier = Qt::NoModifier; + switch(key) + { + case Qt::Key_Control: + modifier = Qt::ControlModifier; + break; + case Qt::Key_Shift: + modifier = Qt::ShiftModifier; + break; + case Qt::Key_Alt: + modifier = Qt::AltModifier; + break; + case Qt::Key_Meta: + modifier = Qt::MetaModifier; + break; + } + + if ((mTemporaryTriggerKeys & key) != 0 || + (mTemporaryTriggerModifiers & modifier) != 0) + { + clearTemporaryTool(); + return true; + } + return false; +} + +bool ToolManager::tryClearTemporaryTool(Qt::MouseButton button) +{ + if (mTemporaryTriggerMouseButtons != Qt::NoButton && (mTemporaryTriggerMouseButtons & button) != 0) { - mIsSwitchedToEraser = false; - if (meTabletBackupTool == INVALID_TOOL) - { - meTabletBackupTool = PENCIL; - } - setCurrentTool(meTabletBackupTool); + clearTemporaryTool(); + return true; } + return false; +} + +void ToolManager::setTemporaryTool(ToolType eToolType) +{ + mTemporaryTool = getTool(eToolType); + emit toolChanged(eToolType); +} + +void ToolManager::clearTemporaryTool() +{ + mTemporaryTool = nullptr; + mTemporaryTriggerKeys = 0; + mTemporaryTriggerModifiers = Qt::NoModifier; + mTemporaryTriggerMouseButtons = Qt::NoButton; + emit toolChanged(currentTool()->type()); } diff --git a/core_lib/src/managers/toolmanager.h b/core_lib/src/managers/toolmanager.h index eb2de659f..d431f041b 100644 --- a/core_lib/src/managers/toolmanager.h +++ b/core_lib/src/managers/toolmanager.h @@ -35,15 +35,20 @@ class ToolManager : public BaseManager Status load(Object*) override; Status save(Object*) override; - BaseTool* currentTool() { return mCurrentTool; } + BaseTool* currentTool(); BaseTool* getTool(ToolType eToolType); void setDefaultTool(); void setCurrentTool(ToolType eToolType); + void tabletSwitchToEraser(); + void tabletRestorePrevTool(); + bool setTemporaryTool(ToolType eToolType, int keys, Qt::KeyboardModifiers modifiers); + bool setTemporaryTool(ToolType eToolType, Qt::MouseButtons buttons); + bool tryClearTemporaryTool(int key); + bool tryClearTemporaryTool(Qt::MouseButton button); + void clearTemporaryTool(); void cleanupAllToolsData(); bool leavingThisTool(); - void tabletSwitchToEraser(); - void tabletRestorePrevTool(); int propertySwitch(bool condition, int property); signals: @@ -77,9 +82,15 @@ public slots: void setUseFillContour(bool); private: + void setTemporaryTool(ToolType eToolType); + BaseTool* mCurrentTool = nullptr; - ToolType meTabletBackupTool = PENCIL; - bool mIsSwitchedToEraser = false; + BaseTool* mTabletEraserTool = nullptr; + BaseTool* mTemporaryTool = nullptr; + Qt::KeyboardModifiers mTemporaryTriggerModifiers = Qt::NoModifier; + int mTemporaryTriggerKeys = 0; + Qt::MouseButtons mTemporaryTriggerMouseButtons = Qt::NoButton; + QHash mToolSetHash; int mOldValue = 0; diff --git a/core_lib/src/tool/handtool.cpp b/core_lib/src/tool/handtool.cpp index 9ab28875c..387c66e26 100644 --- a/core_lib/src/tool/handtool.cpp +++ b/core_lib/src/tool/handtool.cpp @@ -70,12 +70,7 @@ void HandTool::pointerMoveEvent(PointerEvent* event) void HandTool::pointerReleaseEvent(PointerEvent* event) { - //---- stop the hand tool if this was mid button - if (event->button() == Qt::MidButton) - { - qDebug("[HandTool] Stop Hand Tool"); - mScribbleArea->setPrevTool(); - } + Q_UNUSED(event) mIsHeld = false; mScribbleArea->updateToolCursor(); } diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index 724f1888b..2280bb48e 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -91,6 +91,16 @@ void PolylineTool::setAA(const int AA) settings.sync(); } +bool PolylineTool::leavingThisTool() +{ + if (mPoints.size() > 0) + { + cancelPolyline(); + clearToolData(); + } + return true; +} + bool PolylineTool::isActive() { return !mPoints.isEmpty(); @@ -180,10 +190,10 @@ bool PolylineTool::keyPressEvent(QKeyEvent* event) break; default: - return false; + break; } - return false; + return BaseTool::keyPressEvent(event); } void PolylineTool::drawPolyline(QList points, QPointF endPoint) diff --git a/core_lib/src/tool/polylinetool.h b/core_lib/src/tool/polylinetool.h index 8e911cc9f..41ce32a82 100644 --- a/core_lib/src/tool/polylinetool.h +++ b/core_lib/src/tool/polylinetool.h @@ -45,6 +45,8 @@ class PolylineTool : public BaseTool void setFeather(const qreal feather) override; void setAA(const int AA) override; + bool leavingThisTool() override; + virtual bool isActive() override; private: diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index 3e838a346..e36410a23 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -242,14 +242,16 @@ bool SelectTool::keyPressEvent(QKeyEvent* event) switch (event->key()) { case Qt::Key_Alt: - mScribbleArea->setTemporaryTool(MOVE); + if (mEditor->tools()->setTemporaryTool(MOVE, 0, Qt::AltModifier)) { + return true; + } break; default: break; } // Follow the generic behaviour anyway - return false; + return BaseTool::keyPressEvent(event); } QPointF SelectTool::offsetFromPressPos() diff --git a/core_lib/src/tool/smudgetool.cpp b/core_lib/src/tool/smudgetool.cpp index ab5700315..f844ef667 100644 --- a/core_lib/src/tool/smudgetool.cpp +++ b/core_lib/src/tool/smudgetool.cpp @@ -121,16 +121,18 @@ bool SmudgeTool::keyPressEvent(QKeyEvent *event) mScribbleArea->setCursor(cursor()); // update cursor return true; } - return false; + return BaseTool::keyPressEvent(event); } -bool SmudgeTool::keyReleaseEvent(QKeyEvent*) +bool SmudgeTool::keyReleaseEvent(QKeyEvent *event) { - - toolMode = 0; // default mode - mScribbleArea->setCursor(cursor()); // update cursor - - return true; + if (event->key() == Qt::Key_Alt) + { + toolMode = 0; // default mode + mScribbleArea->setCursor(cursor()); // update cursor + return true; + } + return BaseTool::keyReleaseEvent(event); } void SmudgeTool::pointerPressEvent(PointerEvent* event) diff --git a/core_lib/src/tool/stroketool.cpp b/core_lib/src/tool/stroketool.cpp index 7cbd5fe94..743ceb0a8 100644 --- a/core_lib/src/tool/stroketool.cpp +++ b/core_lib/src/tool/stroketool.cpp @@ -22,6 +22,7 @@ GNU General Public License for more details. #include "strokemanager.h" #include "viewmanager.h" #include "editor.h" +#include "toolmanager.h" #ifdef Q_OS_MAC extern "C" { @@ -70,19 +71,19 @@ bool StrokeTool::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Alt: - mScribbleArea->setTemporaryTool(EYEDROPPER); - return true; + if (mEditor->tools()->setTemporaryTool(EYEDROPPER, 0, Qt::AltModifier)) + { + return true; + } + break; case Qt::Key_Space: - mScribbleArea->setTemporaryTool(HAND); // just call "setTemporaryTool()" to activate temporarily any tool - return true; + if (mEditor->tools()->setTemporaryTool(HAND, event->key(), Qt::NoModifier)) + { + return true; + } + break; } - return false; -} - -bool StrokeTool::keyReleaseEvent(QKeyEvent *event) -{ - Q_UNUSED(event); - return true; + return BaseTool::keyPressEvent(event); } bool StrokeTool::emptyFrameActionEnabled() diff --git a/core_lib/src/tool/stroketool.h b/core_lib/src/tool/stroketool.h index cd2456cbb..e4b5c7d92 100644 --- a/core_lib/src/tool/stroketool.h +++ b/core_lib/src/tool/stroketool.h @@ -37,7 +37,6 @@ class StrokeTool : public BaseTool void endStroke(); bool keyPressEvent(QKeyEvent* event) override; - bool keyReleaseEvent(QKeyEvent* event) override; protected: bool mFirstDraw = false;