From b57c37ca6226f77a323dcb32fb0b8d3bb03cd704 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sat, 26 Sep 2026 13:49:27 +1200 Subject: [PATCH 1/2] Run commands with right-drag mouse gestures Hold the right button on a folio and drag: a ring appears around the point where the button went down, showing up to eight commands, and the one in the mouse's direction is highlighted with its name underneath. Releasing runs it; releasing near the centre cancels. These are SolidWorks' mouse gestures. The commands are the shortcut bar's for the selection, placed clockwise from the top, so customising the bar customises the ring. As with the context menu, a right press selects what is under the mouse first. A plain right click still opens the context menu, now on release on every platform. The view tracks the right button and opens the menu itself; the platform's own right-click event (sent on press on X11, on release on Windows) is ignored while gestures are on, so the menu is never opened twice. The keyboard menu is unchanged. The view keeps out of the way while a tool or a placement is running, since a right click cancels or finishes those, and while a text is being edited. The new General option "Gestes de la souris avec le bouton droit" (diagrameditor/mouse_gestures, on by default) turns it off and restores the previous right button exactly. Discussion #1033. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG (cherry picked from commit a625142f36e619bb4d4f3551b6086f2dd8eabc86) --- cmake/qet_compilation_vars.cmake | 2 + sources/diagramgestureoverlay.cpp | 185 ++++++++++++++++++ sources/diagramgestureoverlay.h | 60 ++++++ sources/diagramview.cpp | 112 ++++++++++- sources/diagramview.h | 10 + .../configpage/generalconfigurationpage.cpp | 2 + .../ui/configpage/generalconfigurationpage.ui | 10 + 7 files changed, 373 insertions(+), 8 deletions(-) create mode 100644 sources/diagramgestureoverlay.cpp create mode 100644 sources/diagramgestureoverlay.h diff --git a/cmake/qet_compilation_vars.cmake b/cmake/qet_compilation_vars.cmake index b3d973e29..69e987e9b 100644 --- a/cmake/qet_compilation_vars.cmake +++ b/cmake/qet_compilation_vars.cmake @@ -289,6 +289,8 @@ set(QET_SRC_FILES ${QET_DIR}/sources/shortcutbarsettings.h ${QET_DIR}/sources/diagramcontexttoolbar.cpp ${QET_DIR}/sources/diagramcontexttoolbar.h + ${QET_DIR}/sources/diagramgestureoverlay.cpp + ${QET_DIR}/sources/diagramgestureoverlay.h ${QET_DIR}/sources/titleblockcell.cpp ${QET_DIR}/sources/titleblockcell.h ${QET_DIR}/sources/titleblockproperties.cpp diff --git a/sources/diagramgestureoverlay.cpp b/sources/diagramgestureoverlay.cpp new file mode 100644 index 000000000..03d2606d1 --- /dev/null +++ b/sources/diagramgestureoverlay.cpp @@ -0,0 +1,185 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech 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, either version 2 of the License, or + (at your option) any later version. + + QElectroTech 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. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include "diagramgestureoverlay.h" + +#include +#include +#include +#include +#include + +namespace { +const int outer_radius = 84; + /// Releasing closer than this to the centre cancels +const int inner_radius = 22; +const int icon_radius = 56; +const int icon_size = 22; + /// Wider than the ring, so a long command name under it is not cut +const int overlay_width = 280; +} + +/** + @brief DiagramGestureOverlay::DiagramGestureOverlay + @param viewport : the view's viewport, which it is drawn on. It lets the + mouse through, so the view keeps receiving the drag. +*/ +DiagramGestureOverlay::DiagramGestureOverlay(QWidget *viewport) : + QWidget(viewport) +{ + setAttribute(Qt::WA_TransparentForMouseEvents); + setAttribute(Qt::WA_TranslucentBackground); + setFixedSize(overlay_width, 2 * outer_radius + 2 + 24); + hide(); +} + +/** + @return whether right-drag gestures are on (a preference) +*/ +bool DiagramGestureOverlay::isEnabled() +{ + return QSettings().value(QStringLiteral("diagrameditor/mouse_gestures"), + true).toBool(); +} + +/** + @brief DiagramGestureOverlay::showAt + Show the ring centred on @a center with @a actions, at most eight, + clockwise from the top. +*/ +void DiagramGestureOverlay::showAt(const QPoint ¢er, + const QList &actions) +{ + m_center = center; + m_actions = actions.mid(0, sectors); + m_active = -1; + move(center - QPoint(overlay_width / 2, outer_radius + 1)); + show(); + raise(); +} + +/** + @brief DiagramGestureOverlay::sectorAt + @return the sector in the direction of @a viewport_pos from the centre, + 0 at the top then clockwise, or -1 within the cancel radius +*/ +int DiagramGestureOverlay::sectorAt(const QPoint &viewport_pos) const +{ + const QPoint d = viewport_pos - m_center; + if (qHypot(d.x(), d.y()) < inner_radius) { + return -1; + } + //Angle clockwise from the top, in degrees + qreal angle = qRadiansToDegrees(qAtan2(d.x(), -d.y())); + if (angle < 0) { + angle += 360; + } + return int(qRound(angle / (360.0 / sectors))) % sectors; +} + +/** + @return the command in the direction of @a viewport_pos, or nullptr when + there is none there or it is disabled +*/ +QAction *DiagramGestureOverlay::actionAt(const QPoint &viewport_pos) const +{ + const int sector = sectorAt(viewport_pos); + if (sector < 0 || sector >= m_actions.count()) { + return nullptr; + } + QAction *action = m_actions.at(sector); + return action->isEnabled() ? action : nullptr; +} + +void DiagramGestureOverlay::setPointer(const QPoint &viewport_pos) +{ + const int sector = sectorAt(viewport_pos); + if (sector != m_active) { + m_active = sector; + update(); + } +} + +void DiagramGestureOverlay::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + const QPointF c(overlay_width / 2, outer_radius + 1); + const qreal step = 360.0 / sectors; + + QColor base = palette().color(QPalette::Window); + base.setAlpha(225); + painter.setPen(palette().color(QPalette::Mid)); + painter.setBrush(base); + painter.drawEllipse(c, outer_radius, outer_radius); + + //Highlight the sector the mouse points at, if it holds a command + if (m_active >= 0 && m_active < m_actions.count() + && m_actions.at(m_active)->isEnabled()) + { + QPainterPath wedge; + wedge.moveTo(c); + //Qt angles run counter-clockwise from 3 o'clock + const qreal start = 90 - m_active * step - step / 2; + wedge.arcTo(QRectF(c.x() - outer_radius, c.y() - outer_radius, + 2 * outer_radius, 2 * outer_radius), start, step); + wedge.closeSubpath(); + painter.setPen(Qt::NoPen); + painter.setBrush(palette().color(QPalette::Highlight)); + painter.drawPath(wedge); + } + + painter.setPen(palette().color(QPalette::Mid)); + painter.setBrush(palette().color(QPalette::Window)); + painter.drawEllipse(c, inner_radius, inner_radius); + + for (int i = 0 ; i < m_actions.count() ; ++i) + { + QAction *action = m_actions.at(i); + const qreal a = qDegreesToRadians(i * step); + const QPointF p(c.x() + icon_radius * qSin(a), c.y() - icon_radius * qCos(a)); + const QRect r(int(p.x()) - icon_size / 2, int(p.y()) - icon_size / 2, + icon_size, icon_size); + const QIcon::Mode mode = action->isEnabled() ? QIcon::Normal : QIcon::Disabled; + if (!action->icon().isNull()) { + action->icon().paint(&painter, r, Qt::AlignCenter, mode); + } else { + painter.setPen(palette().color(action->isEnabled() ? QPalette::Active : QPalette::Disabled, + QPalette::WindowText)); + painter.drawText(r.adjusted(-12, 0, 12, 0), Qt::AlignCenter, + action->text().remove(QLatin1Char('&')).left(3)); + } + } + + //Name of the highlighted command, under the ring + if (m_active >= 0 && m_active < m_actions.count()) + { + const QString name = m_actions.at(m_active)->text().remove(QLatin1Char('&')); + const QRect label(0, 2 * outer_radius + 4, width(), 20); + QFont f = font(); + f.setBold(true); + painter.setFont(f); + const QRect text = painter.fontMetrics().boundingRect(label, Qt::AlignCenter, name) + .adjusted(-6, -2, 6, 2); + painter.setPen(Qt::NoPen); + painter.setBrush(base); + painter.drawRoundedRect(text, 4, 4); + painter.setPen(palette().color(QPalette::WindowText)); + painter.drawText(label, Qt::AlignCenter, name); + } +} diff --git a/sources/diagramgestureoverlay.h b/sources/diagramgestureoverlay.h new file mode 100644 index 000000000..5fca8dfc2 --- /dev/null +++ b/sources/diagramgestureoverlay.h @@ -0,0 +1,60 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech 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, either version 2 of the License, or + (at your option) any later version. + + QElectroTech 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. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#ifndef DIAGRAMGESTUREOVERLAY_H +#define DIAGRAMGESTUREOVERLAY_H + +#include +#include + +class QAction; + +/** + @brief The ring shown while right-dragging on a folio: up to eight + commands around the point where the button went down, the one in the + mouse's direction highlighted. Releasing runs it, releasing near the + centre cancels -- SolidWorks' mouse gestures. + + Commands are placed clockwise from the top. The ring only draws; the + view tracks the mouse and asks sectorAt() on release. +*/ +class DiagramGestureOverlay : public QWidget +{ + Q_OBJECT + + public: + explicit DiagramGestureOverlay(QWidget *viewport); + + void showAt(const QPoint ¢er, const QList &actions); + void setPointer(const QPoint &viewport_pos); + int sectorAt(const QPoint &viewport_pos) const; + QAction *actionAt(const QPoint &viewport_pos) const; + + static bool isEnabled(); + + static const int sectors = 8; + + protected: + void paintEvent(QPaintEvent *event) override; + + private: + QPoint m_center; + QList m_actions; + int m_active = -1; +}; + +#endif // DIAGRAMGESTUREOVERLAY_H diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index e6be0675a..5e2ef56fa 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -38,6 +38,7 @@ #include "undocommand/addgraphicsobjectcommand.h" #include "diagram.h" #include "diagramcontexttoolbar.h" +#include "diagramgestureoverlay.h" #include "shortcutbarsettings.h" #include "shortcutmanager.h" #include "ElementsCollection/xmlelementcollection.h" @@ -108,6 +109,7 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) : } m_context_toolbar = new DiagramContextToolbar(viewport()); + m_gesture_overlay = new DiagramGestureOverlay(viewport()); connect(m_diagram, &QGraphicsScene::selectionChanged, this, [this]() { if (m_diagram->selectedItems().isEmpty()) { m_context_toolbar->hide(); @@ -635,6 +637,36 @@ void DiagramView::mousePressEvent(QMouseEvent *e) m_press_pos = e->position().toPoint(); } + //Right button: a click opens the context menu on release, a drag is + //a gesture (DiagramGestureOverlay). Left alone while a tool runs -- + //a right click cancels or finishes it -- and while a text is edited. + m_swallow_native_menu = false; + if (e->button() == Qt::RightButton + && DiagramGestureOverlay::isEnabled() + && !m_diagram->eventInterfaceIsRunning() + && !m_diagram->focusItem()) + { + m_gesture_tracking = true; + m_swallow_native_menu = true; + m_gesture_origin = e->position().toPoint(); + m_context_toolbar->hide(); + + //Select what is under the mouse, as the context menu does, so + //a gesture acts on it + if (QGraphicsItem *item = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) { + if (!item->isSelected()) { + m_diagram->clearSelection(); + //Clearing the selection can delete handler items, so + //look the item up again (see contextMenuEvent) + if (QGraphicsItem *again = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) { + again->setSelected(true); + } + } + } + e->accept(); + return; + } + //Start drag view when hold the middle button if (e->button() == Qt::MiddleButton) { @@ -686,6 +718,20 @@ void DiagramView::mouseMoveEvent(QMouseEvent *e) setToolTip(tr("X: %1 Y: %2").arg(e->pos().x()).arg(e->pos().y())); if (m_event_interface && m_event_interface->mouseMoveEvent(e)) return; + if (m_gesture_tracking) + { + const QPoint pos = e->position().toPoint(); + if (!m_gesture_overlay->isVisible() + && (pos - m_gesture_origin).manhattanLength() > 2 * QApplication::startDragDistance()) { + m_gesture_overlay->showAt(m_gesture_origin, selectionCommands()); + } + if (m_gesture_overlay->isVisible()) { + m_gesture_overlay->setPointer(pos); + } + e->accept(); + return; + } + // Drag the view if (e->buttons() == Qt::MiddleButton) { @@ -747,6 +793,34 @@ void DiagramView::mouseReleaseEvent(QMouseEvent *e) { if (m_event_interface && m_event_interface->mouseReleaseEvent(e)) return; + if (m_gesture_tracking && e->button() == Qt::RightButton) + { + m_gesture_tracking = false; + const QPoint pos = e->position().toPoint(); + if (m_gesture_overlay->isVisible()) + { + //A gesture: run the command it points at, if any + QAction *action = m_gesture_overlay->actionAt(pos); + m_gesture_overlay->hide(); + if (action) { + action->trigger(); + } + } + else + { + //A plain right click: the context menu, opened here on + //release on every platform + QContextMenuEvent menu_event(QContextMenuEvent::Mouse, pos, + e->globalPosition().toPoint(), + e->modifiers()); + m_menu_from_gesture = true; + contextMenuEvent(&menu_event); + m_menu_from_gesture = false; + } + e->accept(); + return; + } + // Stop drag view if (e->button() == Qt::MiddleButton) { @@ -804,6 +878,27 @@ void DiagramView::mouseReleaseEvent(QMouseEvent *e) } } +/** + @brief DiagramView::selectionCommands + @return the shortcut bar's commands for the current selection, as this + window's actions +*/ +QList DiagramView::selectionCommands() const +{ + QList actions; + QETDiagramEditor *qde = diagramEditor(); + if (!qde) { + return actions; + } + const auto context = ShortcutBarSettings::contextFor(m_diagram->selectedItems()); + for (const QString &id : ShortcutBarSettings::ids(context)) { + if (QAction *action = ShortcutManager::instance().action(id, qde)) { + actions << action; + } + } + return actions; +} + /** @brief DiagramView::showContextToolbar After a click that leaves something selected, show the shortcut bar's @@ -823,14 +918,7 @@ void DiagramView::showContextToolbar(const QPoint &viewport_pos) return; } - QList actions; - const auto context = ShortcutBarSettings::contextFor(selection); - for (const QString &id : ShortcutBarSettings::ids(context)) { - if (QAction *action = ShortcutManager::instance().action(id, qde)) { - actions << action; - } - } - m_context_toolbar->showAt(viewport_pos, actions); + m_context_toolbar->showAt(viewport_pos, selectionCommands()); } /** @@ -1599,6 +1687,14 @@ void DiagramView::contextMenuEvent(QContextMenuEvent *e) //right-click gets. const bool from_keyboard = e->reason() == QContextMenuEvent::Keyboard; + //With gestures on, a right press is tracked by mousePressEvent and + //the menu opened on release; the platform's own event (sent on press + //on X11, on release on Windows) would open it a second time. + if (!from_keyboard && m_swallow_native_menu && !m_menu_from_gesture) { + e->accept(); + return; + } + if (from_keyboard) { //Aim at the selection when there is one, so the menu appears diff --git a/sources/diagramview.h b/sources/diagramview.h index a0c311cd1..18e4d3ddc 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -28,6 +28,7 @@ class CellRuler; class Conductor; class Diagram; class DiagramContextToolbar; +class DiagramGestureOverlay; class QETDiagramEditor; class DVEventInterface; class QInputEvent; @@ -59,6 +60,14 @@ class DiagramView : public PaletteGraphicsView QPoint m_paste_here_pos; QPoint m_press_pos; DiagramContextToolbar *m_context_toolbar = nullptr; + /// Right-drag gestures: tracking since the right button went down + bool m_gesture_tracking = false; + /// The platform's own right-click menu event is to be ignored: + /// the view opens the menu itself on release + bool m_swallow_native_menu = false; + bool m_menu_from_gesture = false; + QPoint m_gesture_origin; + DiagramGestureOverlay *m_gesture_overlay = nullptr; QPoint m_last_mouse_pos = QPoint(-1, -1); QPointF m_drag_last_pos; bool m_fresh_focus_in, @@ -131,6 +140,7 @@ class DiagramView : public PaletteGraphicsView void updateCellRulers(); void placeCellRulers(); void showContextToolbar(const QPoint &viewport_pos); + QList selectionCommands() const; /// Lowest and highest allowed value of the view transform scale (m11). /// Prevents wheel-zoom from driving the transform to overflow, which diff --git a/sources/ui/configpage/generalconfigurationpage.cpp b/sources/ui/configpage/generalconfigurationpage.cpp index bd58a2e2a..1340b9b66 100644 --- a/sources/ui/configpage/generalconfigurationpage.cpp +++ b/sources/ui/configpage/generalconfigurationpage.cpp @@ -71,6 +71,7 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) : //is the unchecked state -- a preference reads better as an opt-out. ui->m_collection_dblclick_edits->setChecked(!settings.value("elementscollection/double-click-inserts", true).toBool()); ui->m_context_toolbar_cb->setChecked(settings.value("diagrameditor/context_toolbar", true).toBool()); + ui->m_mouse_gestures_cb->setChecked(settings.value("diagrameditor/mouse_gestures", true).toBool()); ui->DiagramEditor_xGrid_sb->setValue(settings.value("diagrameditor/Xgrid", 10).toInt()); ui->DiagramEditor_yGrid_sb->setValue(settings.value("diagrameditor/Ygrid", 10).toInt()); for (const qreal divisor : TextGrid::divisors) @@ -300,6 +301,7 @@ void GeneralConfigurationPage::applyConf() settings.setValue("diagrameditor/guides_display_startup", ui->guides_startup_cb->isChecked()); settings.setValue("elementscollection/double-click-inserts", !ui->m_collection_dblclick_edits->isChecked()); settings.setValue("diagrameditor/context_toolbar", ui->m_context_toolbar_cb->isChecked()); + settings.setValue("diagrameditor/mouse_gestures", ui->m_mouse_gestures_cb->isChecked()); //Grid step and key navigation settings.setValue("diagrameditor/Xgrid", ui->DiagramEditor_xGrid_sb->value()); settings.setValue("diagrameditor/Ygrid", ui->DiagramEditor_yGrid_sb->value()); diff --git a/sources/ui/configpage/generalconfigurationpage.ui b/sources/ui/configpage/generalconfigurationpage.ui index de4b7445c..177314d93 100644 --- a/sources/ui/configpage/generalconfigurationpage.ui +++ b/sources/ui/configpage/generalconfigurationpage.ui @@ -97,6 +97,16 @@ + + + + Maintenir le bouton droit et glisser dans une direction lance une commande de la barre de raccourcis. Un simple clic droit ouvre toujours le menu contextuel, au relâchement du bouton. + + + Gestes de la souris avec le bouton droit + + + From f850d0bee86ac0b56b29418bcfccc64879fa2beb Mon Sep 17 00:00:00 2001 From: ispyisail Date: Sun, 27 Sep 2026 01:34:55 +1200 Subject: [PATCH 2/2] Keep mouse gestures working while a tool is running Most commands on the empty-folio ring start a drawing tool, and the view left the right button alone while a tool ran, so the gesture after one that started a tool only cancelled the tool: every other gesture opened the context menu instead of the ring. Now a right drag always shows the ring. A running tool is ended when the drag starts, as picking another tool from the toolbar would. A plain right click still goes to the tool, which cancels or finishes it as before. Discussion #1033. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG --- sources/diagramview.cpp | 63 +++++++++++++++++++++++++++++------------ sources/diagramview.h | 2 ++ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 423a1ce46..a6f854df8 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -640,33 +640,43 @@ void DiagramView::mousePressEvent(QMouseEvent *e) } //Right button: a click opens the context menu on release, a drag is - //a gesture (DiagramGestureOverlay). Left alone while a tool runs -- - //a right click cancels or finishes it -- and while a text is edited. + //a gesture (DiagramGestureOverlay). Left alone while a text is edited. m_swallow_native_menu = false; + m_gesture_over_tool = false; if (e->button() == Qt::RightButton && DiagramGestureOverlay::isEnabled() - && !m_diagram->eventInterfaceIsRunning() && !m_diagram->focusItem()) { m_gesture_tracking = true; - m_swallow_native_menu = true; m_gesture_origin = e->position().toPoint(); m_context_toolbar->hide(); - //Select what is under the mouse, as the context menu does, so - //a gesture acts on it - if (QGraphicsItem *item = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) { - if (!item->isSelected()) { - m_diagram->clearSelection(); - //Clearing the selection can delete handler items, so - //look the item up again (see contextMenuEvent) - if (QGraphicsItem *again = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) { - again->setSelected(true); + //A tool is running, often one a gesture just started. A right + //click still goes to it -- it cancels or finishes the tool -- so + //the press carries on to the scene. A drag ends the tool and + //shows the ring (see mouseMoveEvent). + if (m_diagram->eventInterfaceIsRunning()) { + m_gesture_over_tool = true; + } + else + { + m_swallow_native_menu = true; + + //Select what is under the mouse, as the context menu does, so + //a gesture acts on it + if (QGraphicsItem *item = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) { + if (!item->isSelected()) { + m_diagram->clearSelection(); + //Clearing the selection can delete handler items, so + //look the item up again (see contextMenuEvent) + if (QGraphicsItem *again = m_diagram->itemAt(mapToScene(m_gesture_origin), transform())) { + again->setSelected(true); + } } } + e->accept(); + return; } - e->accept(); - return; } //Start drag view when hold the middle button @@ -725,13 +735,24 @@ void DiagramView::mouseMoveEvent(QMouseEvent *e) const QPoint pos = e->position().toPoint(); if (!m_gesture_overlay->isVisible() && (pos - m_gesture_origin).manhattanLength() > 2 * QApplication::startDragDistance()) { + if (m_gesture_over_tool) { + //The drag is a gesture: end the tool, and ignore the + //platform's right-click menu like any other gesture + m_diagram->clearEventInterface(); + m_swallow_native_menu = true; + } m_gesture_overlay->showAt(m_gesture_origin, selectionCommands()); } if (m_gesture_overlay->isVisible()) { m_gesture_overlay->setPointer(pos); + e->accept(); + return; + } + //Not a drag yet: a running tool keeps following the mouse + if (!m_gesture_over_tool) { + e->accept(); + return; } - e->accept(); - return; } // Drag the view @@ -795,7 +816,10 @@ void DiagramView::mouseReleaseEvent(QMouseEvent *e) { if (m_event_interface && m_event_interface->mouseReleaseEvent(e)) return; - if (m_gesture_tracking && e->button() == Qt::RightButton) + //A plain right click on a running tool falls through: the tool + //handles it, as it always has + if (m_gesture_tracking && e->button() == Qt::RightButton + && !(m_gesture_over_tool && !m_gesture_overlay->isVisible())) { m_gesture_tracking = false; const QPoint pos = e->position().toPoint(); @@ -822,6 +846,9 @@ void DiagramView::mouseReleaseEvent(QMouseEvent *e) e->accept(); return; } + if (e->button() == Qt::RightButton) { + m_gesture_tracking = false; + } // Stop drag view if (e->button() == Qt::MiddleButton) diff --git a/sources/diagramview.h b/sources/diagramview.h index f77c3fad2..14ae6df19 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -66,6 +66,8 @@ class DiagramView : public PaletteGraphicsView /// the view opens the menu itself on release bool m_swallow_native_menu = false; bool m_menu_from_gesture = false; + /// The right press went to a running tool; a drag ends the tool + bool m_gesture_over_tool = false; QPoint m_gesture_origin; DiagramGestureOverlay *m_gesture_overlay = nullptr; QPoint m_last_mouse_pos = QPoint(-1, -1);