mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-12 07:04:12 +02:00
83b9f32bd0
Discussion #599's own scope explicitly deferred this ("Related, not proposed here... a natural follow-up once basic pan/zoom motion works"). Basic pan/zoom now works (previous commits on this branch), so this adds it -- generically, for whichever SpaceMouseBackend is in use, not tied to libspnav specifically, matching the seam the previous commit built. ## Reuses ShortcutManager instead of inventing a second action registry ShortcutManager is already an app-wide registry of every named, rebindable action -- undo, redo, rotate selection, cut/copy/paste, autonum configure, and dozens more -- each carried by a live QAction or QAbstractButton. A device button binding to one of *those* ids, rather than to a bespoke QET-3D-mouse-only action list, means the discussion's own examples (rotate/mirror/undo) are available for free, and any action added to the app in the future is automatically bindable too. Added ShortcutManager::trigger(id): find the first still-alive target for an id and call QAction::trigger() or QAbstractButton::click(), whichever it is. Deliberately not disambiguated by which window is currently active, unlike SpaceMouseListener's own pan/zoom dispatch -- a target's owning top-level window isn't reliably discoverable from a bare QAction. Correct in the overwhelming common case of one open editor window; documented in the header as a known simplification, not silently assumed correct. ## The binding itself: SpaceMouseButtonMap A thin QSettings-backed button-number -> action-id map, unbound by default for every button on every device -- nothing happens on any button press until the user opens Configuration > Souris 3D and binds something, matching this whole feature's "silent until asked for" default. ## Backend side: SpaceMouseBackend::buttonPressed(int) Added to the platform interface alongside the existing motion() signal. SpnavBackend now handles SPNAV_EVENT_BUTTON (previously explicitly ignored) and emits on press only -- release is not reported, since nothing downstream has a use for it. A future non-spnav backend implements the same signal and gets button support for free through SpaceMouseListener::applyButton(), without that logic being duplicated or re-verified per backend -- the same reasoning the previous commit's seam was built around. ## Configuration UI: SpaceMouseConfigPage Modelled directly on the existing ShortcutsConfigPage -- same QTableWidget shape, same "persist on applyConf(), not live" contract -- one row per binding: button number (spin box, unbounded, since button count and numbering genuinely vary from 2 to 30+ across real devices and this could not be checked against hardware) and action (combo box populated from ShortcutManager::instance().allShortcuts(), the exact same live registry the Shortcuts page itself lists). Only added to the Configuration dialog when QET_SPACEMOUSE_SUPPORT is compiled in. ## Verified, including the one thing that doesn't need hardware to prove Rebuilt from scratch both ways: option off adds zero new object code (confirmed via a forced rebuild of the one unconditionally-changed file, shortcutmanager.cpp, which alone picked up new warning-free code); option on compiles all four new/changed files warning-free and links clean. The backend's button *detection* (SPNAV_EVENT_BUTTON -> buttonPressed signal) still cannot be verified without a real device or daemon -- same limitation as the motion path from the previous commits, stated plainly rather than glossed over. What *is* fully verified, because none of it needs hardware: - SpaceMouseButtonMap: unbound by default, set/read-back, clearing via an empty id, enumeration -- all confirmed via a standalone harness linked against the real compiled objects. - ShortcutManager::trigger(): registered a real QAction, confirmed trigger() fires it exactly once and returns true; confirmed it returns false (not a crash) for an unknown id. - SpnavBackend: constructs safely with no daemon present (isAvailable() false, as it must be), and both its motion and buttonPressed signals are correctly wired per Qt's own metaobject data (QSignalSpy). - The configuration page end-to-end, via a real Xvfb session: opened Configuration > Souris 3D, confirmed the action combo box lists the live, real ShortcutManager registry (undo, rotate, cut/copy/paste, dozens more -- not a mock), added rows, edited the button number, removed rows, selected "Éditeur de schémas — Pivoter" (Rotate -- the discussion's own example) for button 3, clicked OK, and confirmed via the actual settings file that it persisted exactly as "buttons\3=diagrameditor.rotate_selection". Reopened the dialog and confirmed it read back correctly. This is a full, real round trip through the UI, not a claim.
81 lines
3.4 KiB
C++
81 lines
3.4 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef SPACEMOUSEBACKEND_H
|
|
#define SPACEMOUSEBACKEND_H
|
|
|
|
#include <QObject>
|
|
|
|
/**
|
|
@brief The SpaceMouseBackend class
|
|
Platform seam for discussion #599's 3D mouse support. A backend owns
|
|
one platform's connection to the actual 6-DOF device driver -- opening
|
|
it, pumping whatever event source that platform uses, closing it -- and
|
|
reports motion through the one signal below. Everything platform-
|
|
independent (which DiagramView to apply motion to, the pan/zoom
|
|
primitives to call, the Z-to-zoom-factor mapping) lives in
|
|
SpaceMouseListener instead, once, so it does not have to be duplicated
|
|
or re-verified per backend.
|
|
|
|
SpnavBackend (Linux, spacenavd/libspnav) is the only implementation so
|
|
far -- built, linked, and its "no daemon/device present" path actually
|
|
run in the environment this was written in. A Windows/macOS backend
|
|
(3Dconnexion's proprietary 3DxWare SDK) would implement this same
|
|
interface and be selected in SpaceMouseListener's constructor, without
|
|
changing SpnavBackend or anything downstream of the motion signal.
|
|
Deliberately not attempted here: this was written on Linux with no
|
|
3DxWare SDK and no Windows/macOS toolchain available to compile,
|
|
link, or run a single line of it against, and shipping platform code
|
|
that has never even built would be a materially different, weaker
|
|
thing than everything else in this feature.
|
|
*/
|
|
class SpaceMouseBackend : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit SpaceMouseBackend(QObject *parent = nullptr) : QObject(parent) {}
|
|
~SpaceMouseBackend() override = default;
|
|
|
|
/// True once this backend actually has a live connection to a
|
|
/// driver/daemon. False is the ordinary case -- no daemon
|
|
/// running, no device attached -- not an error; see
|
|
/// SpaceMouseListener's class comment for why that distinction
|
|
/// matters.
|
|
virtual bool isAvailable() const = 0;
|
|
|
|
signals:
|
|
/// One raw device sample. dx/dy are the two axes
|
|
/// SpaceMouseListener maps to horizontal/vertical pan, dz the
|
|
/// one it maps to zoom. Units and range are whatever the
|
|
/// backend's own driver reports -- SpaceMouseListener's own
|
|
/// scale/divisor constants are what turn them into pixels and a
|
|
/// zoom factor, not this signal.
|
|
void motion(int dx, int dy, int dz);
|
|
|
|
/// One device button was pressed. \a button is whatever index
|
|
/// the backend's own driver numbers it as -- there is no
|
|
/// portable numbering across device models, which is exactly
|
|
/// why the binding from a button to a QET action
|
|
/// (SpaceMouseButtonMap) is user-configurable rather than
|
|
/// hardcoded. Emitted on press only; release is not reported,
|
|
/// since nothing here has a use for it.
|
|
void buttonPressed(int button);
|
|
};
|
|
|
|
#endif // SPACEMOUSEBACKEND_H
|