diff --git a/sources/editor/elementview.cpp b/sources/editor/elementview.cpp index b1f4e30ec..c9d254f70 100644 --- a/sources/editor/elementview.cpp +++ b/sources/editor/elementview.cpp @@ -117,6 +117,18 @@ void ElementView::scaleClamped(qreal factor) scale(factor, factor); } +/** + @brief ElementView::zoom + Zoom by an arbitrary factor, for a continuous input such as a 3D mouse. + Same clamping as the wheel zoom. + @param zoom_factor : > 1 zooms in, < 1 zooms out +*/ +void ElementView::zoom(qreal zoom_factor) +{ + adjustSceneRect(); + scaleClamped(zoom_factor); +} + /** Agrandit le schema (+33% = inverse des -25 % de zoomMoins()) */ diff --git a/sources/editor/elementview.h b/sources/editor/elementview.h index 09168b996..50f5358da 100644 --- a/sources/editor/elementview.h +++ b/sources/editor/elementview.h @@ -41,6 +41,7 @@ class ElementView : public QGraphicsView { ElementScene *scene() const; void setScene(ElementScene *); QRectF viewedSceneRect() const; + void zoom(qreal zoom_factor); protected: void mousePressEvent(QMouseEvent *) override; diff --git a/sources/spacemouse/spacemouselistener.cpp b/sources/spacemouse/spacemouselistener.cpp index 770cfd964..2426077fe 100644 --- a/sources/spacemouse/spacemouselistener.cpp +++ b/sources/spacemouse/spacemouselistener.cpp @@ -24,6 +24,8 @@ #endif #include "../diagramview.h" +#include "../editor/elementview.h" +#include "../editor/ui/qetelementeditor.h" #include "../projectview.h" #include "../qetdiagrameditor.h" #include "../shortcutmanager.h" @@ -47,6 +49,16 @@ namespace { //one-line fix once someone with a device tries it. constexpr qreal ZOOM_DIVISOR = 1000.0; constexpr qreal PAN_SCALE = 1.0; + + //Pan a view by one motion sample, through its scrollbars -- the same + //way both editors' own middle-button drag pans them. + void panView(QGraphicsView *view, int dx, int dy) + { + view->horizontalScrollBar()->setValue( + view->horizontalScrollBar()->value() - qRound(dx * PAN_SCALE)); + view->verticalScrollBar()->setValue( + view->verticalScrollBar()->value() - qRound(dy * PAN_SCALE)); + } } /** @@ -96,11 +108,12 @@ qreal SpaceMouseListener::zoomFactorForZAxis(int z) /** @brief SpaceMouseListener::applyMotion - Apply one motion sample to whichever DiagramView is currently active. + Apply one motion sample to the view of the active window: the current + folio of a diagram editor, or the drawing of an element editor. X/Y translation pans it, Z translation zooms it -- the same two - primitives (scrollbars, DiagramView::zoom()) DiagramView::wheelEvent() - already drives from a physical wheel, so there is no new navigation - logic here, only a new input source feeding the existing one. + primitives (scrollbars, zoom()) each view's wheelEvent() already drives + from a physical wheel, so there is no new navigation logic here, only a + new input source feeding the existing one. Which of a device's three translation axes is "left/right" vs "forward/back" vs "up/down", and their sign, is a hardware convention @@ -112,31 +125,46 @@ qreal SpaceMouseListener::zoomFactorForZAxis(int z) */ void SpaceMouseListener::applyMotion(int dx, int dy, int dz) { - auto *editor = qobject_cast(qApp->activeWindow()); - if (!editor) { - return; - } + QWidget *window = qApp->activeWindow(); - ProjectView *project_view = editor->currentProjectView(); - if (!project_view) { - return; - } - - DiagramView *view = project_view->currentDiagram(); - if (!view) { - return; - } - - if (dx || dy) + if (auto *editor = qobject_cast(window)) { - view->horizontalScrollBar()->setValue( - view->horizontalScrollBar()->value() - qRound(dx * PAN_SCALE)); - view->verticalScrollBar()->setValue( - view->verticalScrollBar()->value() - qRound(dy * PAN_SCALE)); - } + ProjectView *project_view = editor->currentProjectView(); + if (!project_view) { + return; + } - if (dz) { - view->zoom(zoomFactorForZAxis(dz)); + DiagramView *view = project_view->currentDiagram(); + if (!view) { + return; + } + + if (dx || dy) { + panView(view, dx, dy); + } + if (dz) { + view->zoom(zoomFactorForZAxis(dz)); + } + } + else if (auto *element_editor = qobject_cast(window)) + { + ElementView *view = element_editor->elementView(); + if (!view) { + return; + } + + if (dx || dy) + { + //The element editor's scene rect only just covers what is + //on screen, so grow it before each sample, as its own + //middle-button pan does on release -- otherwise the + //scrollbars have no range and the pan does nothing. + view->adjustSceneRect(); + panView(view, dx, dy); + } + if (dz) { + view->zoom(zoomFactorForZAxis(dz)); + } } } diff --git a/sources/spacemouse/spacemouselistener.h b/sources/spacemouse/spacemouselistener.h index 8ef30da82..00c6b822c 100644 --- a/sources/spacemouse/spacemouselistener.h +++ b/sources/spacemouse/spacemouselistener.h @@ -25,16 +25,16 @@ class SpaceMouseBackend; /** @brief The SpaceMouseListener class https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/599 : - bridges a 3Dconnexion SpaceMouse/SpacePilot 6-DOF device to - DiagramView's existing pan/zoom primitives (the same - horizontalScrollBar()/verticalScrollBar()/zoom() calls - DiagramView::wheelEvent() already uses for a physical wheel), and its + bridges a 3Dconnexion SpaceMouse/SpacePilot 6-DOF device to the + existing pan/zoom primitives of DiagramView and ElementView (the same + horizontalScrollBar()/verticalScrollBar()/zoom() calls their + wheelEvent() already uses for a physical wheel), and its buttons to named QET actions via ShortcutManager -- the same registry keyboard shortcuts already use, so a device button can trigger anything in that registry (undo, redo, rotate selection, ...) without QET having a second, device-specific action list. - Everything here is platform-independent: which DiagramView to apply + Everything here is platform-independent: which view to apply motion to, the pan/zoom calls, the Z-to-zoom-factor mapping, and button dispatch via SpaceMouseButtonMap + ShortcutManager. Talking to the actual device driver is a SpaceMouseBackend's job (see its class @@ -73,7 +73,7 @@ class SpaceMouseListener : public QObject private slots: /// Apply one motion sample -- from whichever backend is in use - /// -- to whichever DiagramView is currently active. + /// -- to the view of the active diagram or element editor. void applyMotion(int dx, int dy, int dz); /// Look up which action id, if any, SpaceMouseButtonMap binds