diff --git a/toonz/sources/tnztools/vectorerasertool.cpp b/toonz/sources/tnztools/vectorerasertool.cpp index 1ea2bc58..2f332f31 100644 --- a/toonz/sources/tnztools/vectorerasertool.cpp +++ b/toonz/sources/tnztools/vectorerasertool.cpp @@ -484,8 +484,7 @@ void EraserTool::startErase( m_indexes.resize(size); for (UINT i = 0; i < size; i++) m_indexes[i] = i; - assert(m_undo == 0); - delete m_undo; + if (m_undo) delete m_undo; TXshSimpleLevel *level = TTool::getApplication()->getCurrentLevel()->getSimpleLevel(); m_undo = new UndoEraser(level, getCurrentFid()); diff --git a/toonz/sources/toonz/sceneviewer.cpp b/toonz/sources/toonz/sceneviewer.cpp index 16acdc48..4502de18 100644 --- a/toonz/sources/toonz/sceneviewer.cpp +++ b/toonz/sources/toonz/sceneviewer.cpp @@ -444,10 +444,7 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent) , m_mouseButton(Qt::NoButton) , m_foregroundDrawing(false) , m_tabletEvent(false) - , m_tabletActive(false) , m_tabletMove(false) - , m_tabletPressed(false) - , m_tabletReleased(false) , m_buttonClicked(false) , m_referenceMode(NORMAL_REFERENCE) , m_previewMode(NO_PREVIEW) @@ -491,8 +488,10 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent) setFocusPolicy(Qt::StrongFocus); setAcceptDrops(true); this->setMouseTracking(true); - // to be introduced from Qt 5.9 - // this->setTabletTracking(true); +// introduced from Qt 5.9 +#if QT_VERSION >= 0x050900 + this->setTabletTracking(true); +#endif for (int i = 0; i < tArrayCount(m_viewAff); i++) setViewMatrix(getNormalZoomScale(), i); diff --git a/toonz/sources/toonz/sceneviewer.h b/toonz/sources/toonz/sceneviewer.h index eed96a78..323b0c14 100644 --- a/toonz/sources/toonz/sceneviewer.h +++ b/toonz/sources/toonz/sceneviewer.h @@ -69,8 +69,13 @@ class SceneViewer final : public GLWidgetForHighDpi, QPoint m_pos; Qt::MouseButton m_mouseButton; bool m_foregroundDrawing; - bool m_tabletEvent, m_tabletPressed, m_tabletReleased, m_tabletMove, - m_tabletActive; + bool m_tabletEvent, m_tabletMove; + enum TabletState { + None = 0, + Touched, + OnStroke, + Released + } m_tabletState = None; // used to handle wrong mouse drag events! bool m_buttonClicked, m_toolSwitched; bool m_shownOnce = false; @@ -310,6 +315,9 @@ protected: void onPress(const TMouseEvent &event); void onMove(const TMouseEvent &event); void onRelease(const TMouseEvent &event); + void onContextMenu(const QPoint &pos, const QPoint &globalPos); + void onEnter(); + void onLeave(); void wheelEvent(QWheelEvent *) override; void keyPressEvent(QKeyEvent *event) override; diff --git a/toonz/sources/toonz/sceneviewerevents.cpp b/toonz/sources/toonz/sceneviewerevents.cpp index 0364666d..6300139b 100644 --- a/toonz/sources/toonz/sceneviewerevents.cpp +++ b/toonz/sources/toonz/sceneviewerevents.cpp @@ -222,15 +222,16 @@ void SceneViewer::onButtonPressed(FlipConsole::EGadget button) { } //----------------------------------------------------------------------------- +// when using tablet on OSX, use tabletEvent instead of all the mouse-related +// events +// on Windows or on other OS, handle only left-button case void SceneViewer::tabletEvent(QTabletEvent *e) { if (m_freezedStatus != NO_FREEZED) return; - m_tabletEvent = true; - m_pressure = e->pressure(); - m_tabletPressed = false; - m_tabletReleased = false; - m_tabletMove = false; + m_tabletEvent = true; + m_pressure = e->pressure(); + m_tabletMove = false; // Management of the Eraser pointer ToolHandle *toolHandle = TApp::instance()->getCurrentTool(); if (e->pointerType() == QTabletEvent::Eraser) { @@ -252,11 +253,23 @@ void SceneViewer::tabletEvent(QTabletEvent *e) { } switch (e->type()) { case QEvent::TabletPress: { +#ifdef MACOSX // In OSX tablet action may cause only tabletEvent, not followed by // mousePressEvent. // So call onPress here in order to enable processing. - // This separation done is only for the left Button (regular pen touch), - // because + if (e->button() == Qt::LeftButton) m_tabletState = Touched; + TMouseEvent mouseEvent; + initToonzEvent(mouseEvent, e, height(), m_pressure, getDevPixRatio()); + onPress(mouseEvent); + + // create context menu on right click here + if (e->button() == Qt::RightButton) { + m_mouseButton = Qt::NoButton; + onContextMenu(e->pos(), e->globalPos()); + } +#else + // for Windows, use tabletEvent only for the left Button + // (regular pen touch), because // the current Qt seems to fail to catch the Wacom's button binding properly // with QTabletEvent->button() when pressing middle or right button. // So, in such case set m_tabletEvent = FALSE and let the mousePressEvent to @@ -264,39 +277,69 @@ void SceneViewer::tabletEvent(QTabletEvent *e) { if (e->button() == Qt::LeftButton) { TMouseEvent mouseEvent; initToonzEvent(mouseEvent, e, height(), e->pressure(), getDevPixRatio()); - m_tabletPressed = true; + m_tabletState = Touched; onPress(mouseEvent); } else m_tabletEvent = false; +#endif + } break; case QEvent::TabletRelease: { - if (m_tabletActive) { - m_tabletReleased = true; +#ifdef MACOSX + if (m_tabletState == OnStroke) m_tabletState = Released; + + TMouseEvent mouseEvent; + initToonzEvent(mouseEvent, e, height(), m_pressure, getDevPixRatio()); + onRelease(mouseEvent); + + if (TApp::instance()->getCurrentTool()->isToolBusy()) + TApp::instance()->getCurrentTool()->setToolBusy(false); +#else + if (m_tabletState == OnStroke) { + m_tabletState = Released; TMouseEvent mouseEvent; initToonzEvent(mouseEvent, e, height(), e->pressure(), getDevPixRatio()); onRelease(mouseEvent); } else m_tabletEvent = false; +#endif } break; - // for now "TabletMove" will be called only when with some button. - // setTabletTracking(bool) will be introduced in Qt5.9 case QEvent::TabletMove: { - if (m_tabletActive) { - QPoint curPos = e->pos() * getDevPixRatio(); - // It seems that the tabletEvent is called more often than mouseMoveEvent. - // So I fire the interval timer in order to limit the following process - // to be called in 50fps in maximum. - if (curPos != m_lastMousePos && !m_isBusyOnTabletMove) { - m_isBusyOnTabletMove = true; - TMouseEvent mouseEvent; - initToonzEvent(mouseEvent, e, height(), e->pressure(), - getDevPixRatio()); - m_tabletMove = true; - QTimer::singleShot(20, this, SLOT(releaseBusyOnTabletMove())); - onMove(mouseEvent); - } - } else +#ifdef MACOSX + // for now OSX seems to fail to call enter/leaveEvent properly while + // the tablet is floating + bool isHoveringInsideViewer = + !rect().marginsRemoved(QMargins(5, 5, 5, 5)).contains(e->pos()); + // call the fake enter event + if (isHoveringInsideViewer) onEnter(); +#else + // for Windowsm, use tabletEvent only for the left Button + if (m_tabletState != OnStroke) { m_tabletEvent = false; + break; + } +#endif + // cancel stroke to prevent drawing while floating + if (m_tabletState == OnStroke && m_pressure == 0.0) { + resetTabletStatus(); + break; + } + QPoint curPos = e->pos() * getDevPixRatio(); + // It seems that the tabletEvent is called more often than mouseMoveEvent. + // So I fire the interval timer in order to limit the following process + // to be called in 50fps in maximum. + if (curPos != m_lastMousePos && !m_isBusyOnTabletMove) { + m_isBusyOnTabletMove = true; + TMouseEvent mouseEvent; + initToonzEvent(mouseEvent, e, height(), m_pressure, getDevPixRatio()); + m_tabletMove = true; + QTimer::singleShot(20, this, SLOT(releaseBusyOnTabletMove())); + onMove(mouseEvent); + } +#ifdef MACOSX + // call the fake leave event if the pen is hovering the viewer edge + if (!isHoveringInsideViewer) onLeave(); +#endif } break; default: break; @@ -306,7 +349,11 @@ void SceneViewer::tabletEvent(QTabletEvent *e) { //----------------------------------------------------------------------------- -void SceneViewer::leaveEvent(QEvent *) { +void SceneViewer::leaveEvent(QEvent *) { onLeave(); } + +//----------------------------------------------------------------------------- + +void SceneViewer::onLeave() { if (!m_isMouseEntered) return; m_isMouseEntered = false; @@ -319,7 +366,11 @@ void SceneViewer::leaveEvent(QEvent *) { //----------------------------------------------------------------------------- -void SceneViewer::enterEvent(QEvent *) { +void SceneViewer::enterEvent(QEvent *) { onEnter(); } + +//----------------------------------------------------------------------------- + +void SceneViewer::onEnter() { if (m_isMouseEntered) return; m_isMouseEntered = true; @@ -372,7 +423,6 @@ void SceneViewer::mouseMoveEvent(QMouseEvent *event) { } //----------------------------------------------------------------------------- - void SceneViewer::onMove(const TMouseEvent &event) { if (m_freezedStatus != NO_FREEZED) return; @@ -476,9 +526,7 @@ void SceneViewer::onMove(const TMouseEvent &event) { // << " buttonClicked=" << m_buttonClicked; // separate tablet events from mouse events - // don't perform a drag event if tablet not active - if (m_tabletActive && !m_tabletMove) return; - if (m_tabletEvent && m_tabletActive && m_tabletMove) { + if (m_tabletEvent && m_tabletState == OnStroke && m_tabletMove) { tool->leftButtonDrag(pos, event); } @@ -610,15 +658,14 @@ void SceneViewer::onPress(const TMouseEvent &event) { pos.y /= m_dpiScale.y; } // separate tablet and mouse events - if (m_tabletEvent && m_tabletPressed) { - m_tabletActive = true; + if (m_tabletEvent && m_tabletState == Touched) { + m_tabletState = OnStroke; tool->leftButtonDown(pos, event); } else if (m_mouseButton == Qt::LeftButton) { TApp::instance()->getCurrentTool()->setToolBusy(true); tool->leftButtonDown(pos, event); } if (m_mouseButton == Qt::RightButton) tool->rightButtonDown(pos, event); - m_tabletPressed = false; } //----------------------------------------------------------------------------- @@ -661,8 +708,6 @@ void SceneViewer::onRelease(const TMouseEvent &event) { if (m_mouseButton != event.button()) return; - // reject if tablet was active and the up button is not actually the pen. - if (m_tabletActive && !m_tabletReleased) return; if (m_current3DDevice != NONE) { m_mouseButton = Qt::NoButton; m_tabletEvent = false; @@ -701,19 +746,17 @@ void SceneViewer::onRelease(const TMouseEvent &event) { pos.y /= m_dpiScale.y; } - if (m_mouseButton == Qt::LeftButton || m_tabletReleased) { + if (m_mouseButton == Qt::LeftButton || m_tabletState == Released) { if (!m_toolSwitched) tool->leftButtonUp(pos, event); TApp::instance()->getCurrentTool()->setToolBusy(false); } } quit: - m_mouseButton = Qt::NoButton; - m_tabletPressed = false; - m_tabletActive = false; - m_tabletReleased = false; - m_tabletMove = false; - m_pressure = 0; + m_mouseButton = Qt::NoButton; + m_tabletState = None; + m_tabletMove = false; + m_pressure = 0; // Leave m_tabletEvent as-is in order to check whether the onRelease is called // from tabletEvent or not in mouseReleaseEvent. } @@ -728,14 +771,12 @@ quit: // QTBUG-53628. void SceneViewer::resetTabletStatus() { if (!m_buttonClicked) return; - m_mouseButton = Qt::NoButton; - m_tabletEvent = false; - m_tabletPressed = false; - m_tabletActive = false; - m_tabletReleased = false; - m_tabletMove = false; - m_pressure = 0; - m_buttonClicked = false; + m_mouseButton = Qt::NoButton; + m_tabletEvent = false; + m_tabletState = None; + m_tabletMove = false; + m_pressure = 0; + m_buttonClicked = false; if (TApp::instance()->getCurrentTool()->isToolBusy()) TApp::instance()->getCurrentTool()->setToolBusy(false); } @@ -1372,6 +1413,7 @@ using namespace ImageUtils; //----------------------------------------------------------------------------- void SceneViewer::contextMenuEvent(QContextMenuEvent *e) { + if (m_tabletEvent) return; #ifndef _WIN32 /* On windows the widget receive the release event before the menu is shown, on linux and osx the release event is lost, never @@ -1382,12 +1424,19 @@ void SceneViewer::contextMenuEvent(QContextMenuEvent *e) { QApplication::instance()->sendEvent(this, &fakeRelease); #endif + onContextMenu(e->pos(), e->globalPos()); +} + +//----------------------------------------------------------------------------- + +void SceneViewer::onContextMenu(const QPoint &pos, const QPoint &globalPos) { if (m_freezedStatus != NO_FREEZED) return; if (m_isLocator) return; - + static bool menuVisible = false; + if (menuVisible) return; + menuVisible = true; int devPixRatio = getDevPixRatio(); - TPoint winPos(e->pos().x() * devPixRatio, - height() - e->pos().y() * devPixRatio); + TPoint winPos(pos.x() * devPixRatio, height() - pos.y() * devPixRatio); std::vector columnIndices; // enable to select all the columns regardless of the click position for (int i = 0; @@ -1398,9 +1447,9 @@ void SceneViewer::contextMenuEvent(QContextMenuEvent *e) { SceneViewerContextMenu *menu = new SceneViewerContextMenu(this); TTool *tool = TApp::instance()->getCurrentTool()->getTool(); - TPointD pos = ((tool) ? tool->getMatrix().inv() : TAffine()) * - winToWorld(e->pos() * devPixRatio); - menu->addEnterGroupCommands(pos); + TPointD p = ((tool) ? tool->getMatrix().inv() : TAffine()) * + winToWorld(pos * devPixRatio); + menu->addEnterGroupCommands(p); menu->addLevelCommands(columnIndices); @@ -1411,8 +1460,9 @@ void SceneViewer::contextMenuEvent(QContextMenuEvent *e) { cvp->addShowHideContextMenu(menu); } - menu->exec(e->globalPos()); + menu->exec(globalPos); delete menu; + menuVisible = false; } //-----------------------------------------------------------------------------