From a1730a626c5143b5e25bb685b97534a0a1a00e7f Mon Sep 17 00:00:00 2001
From: wmayer
Date: Tue, 22 Apr 2025 19:27:06 +0200
Subject: [PATCH 1/6] Gui: Implement navigation style for NX
See forum threads:
https://forum.freecad.org/viewtopic.php?t=96459 or https://forum.freecad.org/viewtopic.php?t=96503
---
src/Gui/CMakeLists.txt | 1 +
src/Gui/Navigation/NavigationStyle.h | 32 ++
src/Gui/Navigation/SiemensNXStyle.cpp | 639 ++++++++++++++++++++++++++
src/Gui/SoFCDB.cpp | 1 +
4 files changed, 673 insertions(+)
create mode 100644 src/Gui/Navigation/SiemensNXStyle.cpp
diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index b3fff2e403..d6b7d6850d 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -938,6 +938,7 @@ SET(Navigation_CPP_SRCS
Navigation/CADNavigationStyle.cpp
Navigation/RevitNavigationStyle.cpp
Navigation/BlenderNavigationStyle.cpp
+ Navigation/SiemensNXStyle.cpp
Navigation/SolidWorksNavigationStyle.cpp
Navigation/MayaGestureNavigationStyle.cpp
Navigation/OpenCascadeNavigationStyle.cpp
diff --git a/src/Gui/Navigation/NavigationStyle.h b/src/Gui/Navigation/NavigationStyle.h
index be54296471..e606b179b9 100644
--- a/src/Gui/Navigation/NavigationStyle.h
+++ b/src/Gui/Navigation/NavigationStyle.h
@@ -51,6 +51,7 @@ class SoCamera;
class SoSensor;
class SbSphereSheetProjector;
+// NOLINTBEGIN(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
namespace Gui {
class View3DInventorViewer;
@@ -489,7 +490,38 @@ protected:
SbBool processSoEvent(const SoEvent * const ev) override;
};
+class GuiExport SiemensNXStyle : public UserNavigationStyle {
+ using inherited = UserNavigationStyle;
+
+ TYPESYSTEM_HEADER_WITH_OVERRIDE();
+
+public:
+ SiemensNXStyle();
+ ~SiemensNXStyle() override;
+ const char* mouseButtons(ViewerMode mode) override;
+ std::string userFriendlyName() const override;
+
+protected:
+ SbBool processSoEvent(const SoEvent * const ev) override;
+ SbBool processKeyboardEvent(const SoKeyboardEvent * const event) override;
+
+private:
+ struct Event;
+ struct NaviMachine;
+ struct IdleState;
+ struct AwaitingReleaseState;
+ struct AwaitingMoveState;
+ struct InteractState;
+ struct RotateState;
+ struct PanState;
+ struct ZoomState;
+ struct SelectionState;
+
+ std::unique_ptr naviMachine;
+};
+
} // namespace Gui
+// NOLINTEND(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
Q_DECLARE_OPERATORS_FOR_FLAGS(Gui::NavigationStyle::RotationCenterModes)
diff --git a/src/Gui/Navigation/SiemensNXStyle.cpp b/src/Gui/Navigation/SiemensNXStyle.cpp
new file mode 100644
index 0000000000..4420321e26
--- /dev/null
+++ b/src/Gui/Navigation/SiemensNXStyle.cpp
@@ -0,0 +1,639 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/***************************************************************************
+ * Copyright (c) 2025 Werner Mayer *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ **************************************************************************/
+
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#endif
+
+#include
+#include
+#include
+
+#include "Camera.h"
+#include "NavigationStyle.h"
+#include "View3DInventorViewer.h"
+
+// NOLINTBEGIN(cppcoreguidelines-pro-type-static-cast-downcast,
+// cppcoreguidelines-avoid*,
+// readability-avoid-const-params-in-decls)
+using namespace Gui;
+namespace sc = boost::statechart;
+using NS = SiemensNXStyle;
+
+struct NS::Event: public sc::event
+{
+ Event() : flags(new Flags){}
+ using Button = SoMouseButtonEvent::Button;
+ using Key = SoKeyboardEvent::Key;
+ bool isMouseButtonEvent() const {
+ return this->inventor_event->isOfType(SoMouseButtonEvent::getClassTypeId());
+ }
+ const SoMouseButtonEvent* asMouseButtonEvent() const {
+ return static_cast(this->inventor_event);
+ }
+ bool isPress(Button button) const {
+ return SoMouseButtonEvent::isButtonPressEvent(this->inventor_event, button);
+ }
+ bool isRelease(Button button) const {
+ return SoMouseButtonEvent::isButtonReleaseEvent(this->inventor_event, button);
+ }
+ bool isKeyPress(Key key) const {
+ return SoKeyboardEvent::isKeyPressEvent(this->inventor_event, key);
+ }
+ bool isKeyRelease(Key key) const {
+ return SoKeyboardEvent::isKeyReleaseEvent(this->inventor_event, key);
+ }
+ bool isKeyboardEvent() const {
+ return this->inventor_event->isOfType(SoKeyboardEvent::getClassTypeId());
+ }
+ const SoKeyboardEvent* asKeyboardEvent() const {
+ return static_cast(this->inventor_event);
+ }
+ bool isLocation2Event() const {
+ return this->inventor_event->isOfType(SoLocation2Event::getClassTypeId());
+ }
+ const SoLocation2Event* asLocation2Event() const {
+ return static_cast(this->inventor_event);
+ }
+ bool isMotion3Event() const {
+ return this->inventor_event->isOfType(SoMotion3Event::getClassTypeId());
+ }
+ const SoMotion3Event* asMotion3Event() const {
+ return static_cast(this->inventor_event);
+ }
+ bool isDownButton(unsigned int state) const {
+ return mbstate() == state;
+ }
+ bool isDownNoButton() const {
+ return mbstate() == 0;
+ }
+ bool isDownButton1() const {
+ return (mbstate() & BUTTON1DOWN) == BUTTON1DOWN;
+ }
+ bool isDownButton2() const {
+ return (mbstate() & BUTTON2DOWN) == BUTTON2DOWN;
+ }
+ bool isDownButton3() const {
+ return (mbstate() & BUTTON3DOWN) == BUTTON3DOWN;
+ }
+ bool isDownControl() const {
+ return (kbstate() & CTRLDOWN) == CTRLDOWN;
+ }
+ bool isDownShift() const {
+ return (kbstate() & SHIFTDOWN) == SHIFTDOWN;
+ }
+ bool isDownAlt() const {
+ return (kbstate() & ALTDOWN) == ALTDOWN;
+ }
+
+ enum {
+ // bits: 0-shift-ctrl-alt-0-lmb-mmb-rmb
+ BUTTON1DOWN = 0x00000100,
+ BUTTON2DOWN = 0x00000001,
+ BUTTON3DOWN = 0x00000010,
+ CTRLDOWN = 0x00100000,
+ SHIFTDOWN = 0x01000000,
+ ALTDOWN = 0x00010000,
+ MASKBUTTONS = BUTTON1DOWN | BUTTON2DOWN | BUTTON3DOWN,
+ MASKMODIFIERS = CTRLDOWN | SHIFTDOWN | ALTDOWN
+ };
+
+ const SoEvent* inventor_event{nullptr};
+ unsigned int modifiers{0};
+ unsigned int mbstate() const {return modifiers & MASKBUTTONS;}
+ unsigned int kbstate() const {return modifiers & MASKMODIFIERS;}
+
+ struct Flags{
+ bool processed = false;
+ bool propagated = false;
+ };
+ std::shared_ptr flags;
+};
+
+struct NS::NaviMachine: public sc::state_machine
+{
+ using superclass = sc::state_machine;
+ explicit NaviMachine(NS& ns) : ns(ns) {}
+ NS& ns;
+};
+
+struct NS::IdleState: public sc::state
+{
+ using reactions = sc::custom_reaction;
+ explicit IdleState(my_context ctx) : my_base(ctx)
+ {
+ auto &ns = this->outermost_context().ns;
+ ns.setViewingMode(NavigationStyle::IDLE);
+ }
+ sc::result react(const NS::Event& ev)
+ {
+ auto &ns = this->outermost_context().ns;
+ switch (ns.getViewingMode()) {
+ case NavigationStyle::SEEK_WAIT_MODE:
+ {
+ if (ev.isPress(SoMouseButtonEvent::BUTTON1)) {
+ ns.seekToPoint(ev.inventor_event->getPosition());
+ ns.setViewingMode(NavigationStyle::SEEK_MODE);
+ ev.flags->processed = true;
+ return transit();
+ }
+ break;
+ }
+ case NavigationStyle::SPINNING:
+ case NavigationStyle::SEEK_MODE:
+ {
+ if (!ev.flags->processed) {
+ if (ev.isMouseButtonEvent()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+ else if (ev.isKeyboardEvent() || ev.isMotion3Event()) {
+ ns.setViewingMode(NavigationStyle::IDLE);
+ }
+ }
+
+ break;
+ }
+ case NavigationStyle::BOXZOOM:
+ return forward_event();
+ }
+
+ // right-click
+ if (ev.isRelease(SoMouseButtonEvent::BUTTON2)
+ && ev.mbstate() == 0
+ && !ns.viewer->isEditing()
+ && ns.isPopupMenuEnabled()){
+ ns.openPopupMenu(ev.inventor_event->getPosition());
+ }
+
+ if (ev.isPress(SoMouseButtonEvent::BUTTON3)) {
+ if (ev.isDownShift()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isDownButton(NS::Event::BUTTON3DOWN)) {
+ ev.flags->processed = true;
+ return transit();
+ }
+ }
+
+ // Use processClickEvent()
+
+ // Implement selection callback
+ //if (ev.isLocation2Event() && ev.isDownButton1()) {
+ // ev.flags->processed = true;
+ // return transit();
+ //}
+
+ return forward_event();
+ }
+};
+
+struct NS::AwaitingReleaseState : public sc::state
+{
+ using reactions = sc::custom_reaction;
+ explicit AwaitingReleaseState(my_context ctx) : my_base(ctx)
+ {}
+
+ sc::result react(const NS::Event& /*ev*/)
+ {
+ return forward_event();
+ }
+};
+
+struct NS::InteractState: public sc::state
+{
+ using reactions = sc::custom_reaction;
+ explicit InteractState(my_context ctx):my_base(ctx)
+ {
+ auto &ns = this->outermost_context().ns;
+ ns.setViewingMode(NavigationStyle::INTERACT);
+ }
+
+ sc::result react(const NS::Event& /*ev*/) {
+ return forward_event();
+ }
+};
+
+struct NS::AwaitingMoveState: public sc::state
+{
+ using reactions = sc::custom_reaction;
+
+private:
+ SbVec2s base_pos;
+ SbTime since;
+
+public:
+ explicit AwaitingMoveState(my_context ctx):my_base(ctx)
+ {
+ auto &ns = this->outermost_context().ns;
+ ns.setViewingMode(NavigationStyle::DRAGGING);
+ this->base_pos = static_cast(this->triggering_event())->inventor_event->getPosition();
+ this->since = static_cast(this->triggering_event())->inventor_event->getTime();
+ }
+ sc::result react(const NS::Event& ev){
+ //this state consumes all mouse events.
+ ev.flags->processed = ev.isMouseButtonEvent() || ev.isLocation2Event();
+
+ if (ev.isLocation2Event()) {
+ return transit();
+ }
+
+ // right-click
+ if (ev.isPress(SoMouseButtonEvent::BUTTON2) && ev.isDownButton3()) {
+ return transit();
+ }
+
+ if (ev.isKeyPress(SoKeyboardEvent::LEFT_SHIFT)) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ // left-click
+ if (ev.isPress(SoMouseButtonEvent::BUTTON1) && ev.isDownButton3()) {
+ return transit();
+ }
+
+ if (ev.isKeyPress(SoKeyboardEvent::LEFT_CONTROL)) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ // middle-click
+ if (ev.isRelease(SoMouseButtonEvent::BUTTON3) && ev.isDownNoButton()) {
+ auto &ns = this->outermost_context().ns;
+ SbTime tmp = (ev.inventor_event->getTime() - this->since);
+ double dci = QApplication::doubleClickInterval() / 1000.0;
+
+ // is this a simple middle click?
+ if (tmp.getValue() < dci) {
+ ev.flags->processed = true;
+ SbVec2s pos = ev.inventor_event->getPosition();
+ ns.lookAtPoint(pos);
+ }
+ return transit();
+ }
+
+ return forward_event();
+ }
+};
+
+struct NS::RotateState: public sc::state
+{
+ using reactions = sc::custom_reaction;
+ explicit RotateState(my_context ctx) : my_base(ctx)
+ {
+ auto &ns = this->outermost_context().ns;
+ const auto inventorEvent = static_cast(this->triggering_event())->inventor_event;
+ ns.saveCursorPosition(inventorEvent);
+ ns.setViewingMode(NavigationStyle::DRAGGING);
+ this->base_pos = inventorEvent->getPosition();
+ }
+
+ sc::result react(const NS::Event& ev)
+ {
+ if (ev.isLocation2Event()) {
+ auto &ns = this->outermost_context().ns;
+ ns.addToLog(ev.inventor_event->getPosition(), ev.inventor_event->getTime());
+ const SbVec2s pos = ev.inventor_event->getPosition();
+ const SbVec2f posn = ns.normalizePixelPos(pos);
+ ns.spin(posn);
+ ns.moveCursorPosition();
+ ev.flags->processed = true;
+ }
+
+ // right-click
+ if (ev.isPress(SoMouseButtonEvent::BUTTON2) && ev.isDownButton3()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isKeyPress(SoKeyboardEvent::LEFT_SHIFT)) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ // left-click
+ if (ev.isPress(SoMouseButtonEvent::BUTTON1) && ev.isDownButton3()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isKeyPress(SoKeyboardEvent::LEFT_CONTROL)) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isRelease(SoMouseButtonEvent::BUTTON3) && ev.isDownNoButton()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+ return forward_event();
+ }
+
+private:
+ SbVec2s base_pos;
+};
+
+struct NS::PanState: public sc::state
+{
+ using reactions = sc::custom_reaction;
+ explicit PanState(my_context ctx):my_base(ctx)
+ {
+ auto &ns = this->outermost_context().ns;
+ const NS::Event* ev = static_cast(this->triggering_event());
+ ns.setViewingMode(NavigationStyle::PANNING);
+ this->base_pos = ev->inventor_event->getPosition();
+ this->ratio = ns.viewer->getSoRenderManager()->getViewportRegion().getViewportAspectRatio();
+ ns.centerTime = ev->inventor_event->getTime();
+ ns.setupPanningPlane(ns.getCamera());
+ }
+ sc::result react(const NS::Event& ev)
+ {
+ if (ev.isLocation2Event()){
+ ev.flags->processed = true;
+ SbVec2s pos = ev.inventor_event->getPosition();
+ auto &ns = this->outermost_context().ns;
+ ns.panCamera(ns.viewer->getSoRenderManager()->getCamera(),
+ this->ratio,
+ ns.panningplane,
+ ns.normalizePixelPos(pos),
+ ns.normalizePixelPos(this->base_pos));
+ this->base_pos = pos;
+ }
+
+ if (ev.isRelease(SoMouseButtonEvent::BUTTON2) && ev.isDownButton3()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isKeyRelease(SoKeyboardEvent::LEFT_SHIFT) && ev.isDownButton3()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isRelease(SoMouseButtonEvent::BUTTON3)) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ return forward_event();
+ }
+
+private:
+ SbVec2s base_pos;
+ float ratio {1.0F};
+};
+
+struct NS::ZoomState: public sc::state
+{
+ using reactions = sc::custom_reaction;
+ explicit ZoomState(my_context ctx) : my_base(ctx)
+ {
+ auto &ns = this->outermost_context().ns;
+ const NS::Event* ev = static_cast(this->triggering_event());
+ ns.setViewingMode(NavigationStyle::ZOOMING);
+ this->base_pos = ev->inventor_event->getPosition();
+ }
+
+ sc::result react(const NS::Event& ev)
+ {
+ if (ev.isLocation2Event()){
+ ev.flags->processed = true;
+ SbVec2s pos = ev.inventor_event->getPosition();
+ auto &ns = this->outermost_context().ns;
+ ns.zoomByCursor(ns.normalizePixelPos(pos),
+ ns.normalizePixelPos(this->base_pos));
+ this->base_pos = pos;
+ }
+
+ if (ev.isRelease(SoMouseButtonEvent::BUTTON1) && ev.isDownButton3()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isKeyRelease(SoKeyboardEvent::LEFT_CONTROL) && ev.isDownButton3()) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ if (ev.isRelease(SoMouseButtonEvent::BUTTON3)) {
+ ev.flags->processed = true;
+ return transit();
+ }
+
+ return forward_event();
+ }
+
+private:
+ SbVec2s base_pos;
+};
+
+struct NS::SelectionState: public sc::state
+{
+ using reactions = sc::custom_reaction;
+ explicit SelectionState(my_context ctx) : my_base(ctx)
+ {
+ auto &ns = this->outermost_context().ns;
+ const NS::Event* ev = static_cast(this->triggering_event());
+
+ ns.setViewingMode(NavigationStyle::BOXZOOM);
+ ns.startSelection(NavigationStyle::Rubberband);
+ fakeLeftButtonDown(ev->inventor_event->getPosition());
+ }
+
+ void fakeLeftButtonDown(const SbVec2s& pos)
+ {
+ SoMouseButtonEvent mbe;
+ mbe.setButton(SoMouseButtonEvent::BUTTON1);
+ mbe.setState(SoMouseButtonEvent::DOWN);
+ mbe.setPosition(pos);
+
+ auto &ns = this->outermost_context().ns;
+ ns.processEvent(&mbe);
+ }
+
+ sc::result react(const NS::Event& /*ev*/)
+ {
+ // This isn't called while selection mode is active
+ return transit();
+ }
+};
+
+// ----------------------------------------------------------------------------------
+
+/* TRANSLATOR Gui::SiemensNXStyle */
+
+TYPESYSTEM_SOURCE(Gui::SiemensNXStyle, Gui::UserNavigationStyle)
+
+SiemensNXStyle::SiemensNXStyle()
+ : naviMachine(new NS::NaviMachine(*this))
+{
+ naviMachine->initiate();
+}
+
+SiemensNXStyle::~SiemensNXStyle()
+{
+ naviMachine.reset();
+}
+
+const char* SiemensNXStyle::mouseButtons(ViewerMode mode)
+{
+ switch (mode) {
+ case NavigationStyle::SELECTION:
+ return QT_TR_NOOP("Press left mouse button");
+ case NavigationStyle::PANNING:
+ return QT_TR_NOOP("Press middle+right click");
+ case NavigationStyle::DRAGGING:
+ return QT_TR_NOOP("Press middle mouse button");
+ case NavigationStyle::ZOOMING:
+ return QT_TR_NOOP("Scroll mouse wheel");
+ default:
+ return "No description";
+ }
+}
+
+std::string SiemensNXStyle::userFriendlyName() const
+{
+ return {"Siemens NX"};
+}
+
+SbBool SiemensNXStyle::processKeyboardEvent(const SoKeyboardEvent * const event)
+{
+ // See https://forum.freecad.org/viewtopic.php?t=96459
+ // Isometric view: Home key button
+ // Trimetric view: End key button
+ // Fit all: CTRL+F
+ // Normal view: F8
+ switch (event->getKey()) {
+ case SoKeyboardEvent::F:
+ if (event->wasCtrlDown()) {
+ viewer->viewAll();
+ return true;
+ }
+ break;
+ case SoKeyboardEvent::HOME:
+ {
+ viewer->setCameraOrientation(Camera::rotation(Camera::Isometric));
+ return true;
+ }
+ case SoKeyboardEvent::END:
+ {
+ viewer->setCameraOrientation(Camera::rotation(Camera::Trimetric));
+ return true;
+ }
+ case SoKeyboardEvent::F8:
+ {
+ viewer->setCameraOrientation(Camera::rotation(Camera::Top));
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return inherited::processKeyboardEvent(event);
+}
+
+SbBool SiemensNXStyle::processSoEvent(const SoEvent * const ev)
+{
+ // Events when in "ready-to-seek" mode are ignored, except those
+ // which influence the seek mode itself -- these are handled further
+ // up the inheritance hierarchy.
+ if (this->isSeekMode()) {
+ return inherited::processSoEvent(ev);
+ }
+
+ // Switch off viewing mode (Bug #0000911)
+ if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) {
+ this->setViewing(false); // by default disable viewing mode to render the scene
+ }
+
+ // Mismatches in state of the modifier keys happens if the user
+ // presses or releases them outside the viewer window.
+ syncModifierKeys(ev);
+
+ // give the nodes in the foreground root the chance to handle events (e.g color bar)
+ if (!viewer->isEditing()) {
+ if (handleEventInForeground(ev)) {
+ return true;
+ }
+ }
+
+ NS::Event smev;
+ smev.inventor_event = ev;
+
+ // Spaceball/joystick handling
+ if (ev->isOfType(SoMotion3Event::getClassTypeId())){
+ smev.flags->processed = true;
+ this->processMotionEvent(static_cast(ev));
+ return true;
+ }
+
+ // Keyboard handling
+ if (ev->isOfType(SoKeyboardEvent::getClassTypeId())) {
+ const auto event = static_cast(ev);
+ smev.flags->processed = processKeyboardEvent(event);
+ }
+
+ if (smev.isMouseButtonEvent()) {
+ const auto button = smev.asMouseButtonEvent()->getButton();
+ const SbBool press = smev.asMouseButtonEvent()->getState() == SoButtonEvent::DOWN;
+ switch (button) {
+ case SoMouseButtonEvent::BUTTON1:
+ this->button1down = press;
+ break;
+ case SoMouseButtonEvent::BUTTON2:
+ this->button2down = press;
+ break;
+ case SoMouseButtonEvent::BUTTON3:
+ this->button3down = press;
+ break;
+ default:
+ break;
+ }
+ }
+
+ smev.modifiers =
+ (this->button1down ? NS::Event::BUTTON1DOWN : 0) |
+ (this->button2down ? NS::Event::BUTTON2DOWN : 0) |
+ (this->button3down ? NS::Event::BUTTON3DOWN : 0) |
+ (this->ctrldown ? NS::Event::CTRLDOWN : 0) |
+ (this->shiftdown ? NS::Event::SHIFTDOWN : 0) |
+ (this->altdown ? NS::Event::ALTDOWN : 0);
+
+ if (!smev.flags->processed) {
+ this->naviMachine->process_event(smev);
+ }
+
+ if (!smev.flags->propagated && !smev.flags->processed) {
+ return inherited::processSoEvent(ev);
+ }
+
+ return smev.flags->processed;
+}
+// NOLINTEND(cppcoreguidelines-pro-type-static-cast-downcast,
+// cppcoreguidelines-avoid*,
+// readability-avoid-const-params-in-decls)
diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp
index 29e80fbe31..11e1a76212 100644
--- a/src/Gui/SoFCDB.cpp
+++ b/src/Gui/SoFCDB.cpp
@@ -199,6 +199,7 @@ void Gui::SoFCDB::init()
OpenCascadeNavigationStyle ::init();
OpenSCADNavigationStyle ::init();
TinkerCADNavigationStyle ::init();
+ SiemensNXStyle ::init();
GLGraphicsItem ::init();
GLFlagWindow ::init();
From ba9c09fc6144d75384e121597959e947aa069498 Mon Sep 17 00:00:00 2001
From: wmayer
Date: Wed, 23 Apr 2025 13:01:49 +0200
Subject: [PATCH 2/6] Gui: Refactor navigation styles
Add new base class for state chart based navigation styles
---
src/Gui/CMakeLists.txt | 2 +
src/Gui/Navigation/NavigationStateChart.cpp | 233 ++++++++++++++++++++
src/Gui/Navigation/NavigationStateChart.h | 148 +++++++++++++
src/Gui/SoFCDB.cpp | 2 +
4 files changed, 385 insertions(+)
create mode 100644 src/Gui/Navigation/NavigationStateChart.cpp
create mode 100644 src/Gui/Navigation/NavigationStateChart.h
diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index d6b7d6850d..f793a48ebd 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -932,6 +932,7 @@ SET(View3D_SRCS
SOURCE_GROUP("View3D" FILES ${View3D_SRCS})
SET(Navigation_CPP_SRCS
+ Navigation/NavigationStateChart.cpp
Navigation/NavigationStyle.cpp
Navigation/NavigationStylePyImp.cpp
Navigation/InventorNavigationStyle.cpp
@@ -951,6 +952,7 @@ SET(Navigation_CPP_SRCS
)
SET(Navigation_SRCS
${Navigation_CPP_SRCS}
+ Navigation/NavigationStateChart.h
Navigation/NavigationStyle.h
Navigation/NavigationStyle.pyi
Navigation/GestureNavigationStyle.h
diff --git a/src/Gui/Navigation/NavigationStateChart.cpp b/src/Gui/Navigation/NavigationStateChart.cpp
new file mode 100644
index 0000000000..c146fbb9a6
--- /dev/null
+++ b/src/Gui/Navigation/NavigationStateChart.cpp
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/***************************************************************************
+ * Copyright (c) 2025 Werner Mayer *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ **************************************************************************/
+
+
+#include "PreCompiled.h"
+#include
+#include
+#include
+
+#include "Camera.h"
+#include "NavigationStateChart.h"
+#include "View3DInventorViewer.h"
+
+
+using namespace Gui;
+namespace sc = boost::statechart;
+using NS = NavigationStateChart;
+
+NS::Event::Event() : flags(new Flags)
+{}
+
+bool NS::Event::isMouseButtonEvent() const
+{
+ return this->inventor_event->isOfType(SoMouseButtonEvent::getClassTypeId());
+}
+
+const SoMouseButtonEvent* NS::Event::asMouseButtonEvent() const
+{
+ return static_cast(this->inventor_event);
+}
+
+bool NS::Event::isPress(Button button) const
+{
+ return SoMouseButtonEvent::isButtonPressEvent(this->inventor_event, button);
+}
+
+bool NS::Event::isRelease(Button button) const
+{
+ return SoMouseButtonEvent::isButtonReleaseEvent(this->inventor_event, button);
+}
+
+bool NS::Event::isKeyPress(Key key) const
+{
+ return SoKeyboardEvent::isKeyPressEvent(this->inventor_event, key);
+}
+
+bool NS::Event::isKeyRelease(Key key) const
+{
+ return SoKeyboardEvent::isKeyReleaseEvent(this->inventor_event, key);
+}
+
+bool NS::Event::isKeyboardEvent() const
+{
+ return this->inventor_event->isOfType(SoKeyboardEvent::getClassTypeId());
+}
+
+const SoKeyboardEvent* NS::Event::asKeyboardEvent() const
+{
+ return static_cast(this->inventor_event);
+}
+
+bool NS::Event::isLocation2Event() const
+{
+ return this->inventor_event->isOfType(SoLocation2Event::getClassTypeId());
+}
+
+const SoLocation2Event* NS::Event::asLocation2Event() const
+{
+ return static_cast(this->inventor_event);
+}
+
+bool NS::Event::isMotion3Event() const
+{
+ return this->inventor_event->isOfType(SoMotion3Event::getClassTypeId());
+}
+
+const SoMotion3Event* NS::Event::asMotion3Event() const
+{
+ return static_cast(this->inventor_event);
+}
+
+bool NS::Event::isDownButton(unsigned int state) const
+{
+ return mbstate() == state;
+}
+
+bool NS::Event::isDownNoButton() const
+{
+ return mbstate() == 0;
+}
+
+bool NS::Event::isDownButton1() const
+{
+ return (mbstate() & BUTTON1DOWN) == BUTTON1DOWN;
+}
+
+bool NS::Event::isDownButton2() const
+{
+ return (mbstate() & BUTTON2DOWN) == BUTTON2DOWN;
+}
+
+bool NS::Event::isDownButton3() const
+{
+ return (mbstate() & BUTTON3DOWN) == BUTTON3DOWN;
+}
+
+bool NS::Event::isDownControl() const
+{
+ return (kbstate() & CTRLDOWN) == CTRLDOWN;
+}
+
+bool NS::Event::isDownShift() const
+{
+ return (kbstate() & SHIFTDOWN) == SHIFTDOWN;
+}
+
+bool NS::Event::isDownAlt() const
+{
+ return (kbstate() & ALTDOWN) == ALTDOWN;
+}
+
+
+/* TRANSLATOR Gui::NavigationStateChart */
+
+TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStateChart, Gui::UserNavigationStyle)
+
+NavigationStateChart::NavigationStateChart()
+ : naviMachine(new NS::StateMachine())
+{
+}
+
+NavigationStateChart::~NavigationStateChart()
+{
+ naviMachine.reset();
+}
+
+SbBool NavigationStateChart::processSoEvent(const SoEvent * const ev)
+{
+ // Events when in "ready-to-seek" mode are ignored, except those
+ // which influence the seek mode itself -- these are handled further
+ // up the inheritance hierarchy.
+ if (this->isSeekMode()) {
+ return inherited::processSoEvent(ev);
+ }
+
+ // Switch off viewing mode (Bug #0000911)
+ if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) {
+ this->setViewing(false); // by default disable viewing mode to render the scene
+ }
+
+ // Mismatches in state of the modifier keys happens if the user
+ // presses or releases them outside the viewer window.
+ syncModifierKeys(ev);
+
+ // give the nodes in the foreground root the chance to handle events (e.g color bar)
+ if (!viewer->isEditing()) {
+ if (handleEventInForeground(ev)) {
+ return true;
+ }
+ }
+
+ NS::Event smev;
+ smev.inventor_event = ev;
+
+ // Spaceball/joystick handling
+ if (ev->isOfType(SoMotion3Event::getClassTypeId())){
+ smev.flags->processed = true;
+ this->processMotionEvent(static_cast(ev));
+ return true;
+ }
+
+ // Keyboard handling
+ if (ev->isOfType(SoKeyboardEvent::getClassTypeId())) {
+ const auto event = static_cast(ev);
+ smev.flags->processed = processKeyboardEvent(event);
+ }
+
+ if (smev.isMouseButtonEvent()) {
+ const auto button = smev.asMouseButtonEvent()->getButton();
+ const SbBool press = smev.asMouseButtonEvent()->getState() == SoButtonEvent::DOWN;
+ switch (button) {
+ case SoMouseButtonEvent::BUTTON1:
+ this->button1down = press;
+ break;
+ case SoMouseButtonEvent::BUTTON2:
+ this->button2down = press;
+ break;
+ case SoMouseButtonEvent::BUTTON3:
+ this->button3down = press;
+ break;
+ default:
+ break;
+ }
+ }
+
+ smev.modifiers =
+ (this->button1down ? NS::Event::BUTTON1DOWN : 0) |
+ (this->button2down ? NS::Event::BUTTON2DOWN : 0) |
+ (this->button3down ? NS::Event::BUTTON3DOWN : 0) |
+ (this->ctrldown ? NS::Event::CTRLDOWN : 0) |
+ (this->shiftdown ? NS::Event::SHIFTDOWN : 0) |
+ (this->altdown ? NS::Event::ALTDOWN : 0);
+
+ if (!smev.flags->processed) {
+ this->naviMachine->process_event(smev);
+ }
+
+ if (!smev.flags->propagated && !smev.flags->processed) {
+ return inherited::processSoEvent(ev);
+ }
+
+ return smev.flags->processed;
+}
diff --git a/src/Gui/Navigation/NavigationStateChart.h b/src/Gui/Navigation/NavigationStateChart.h
new file mode 100644
index 0000000000..f7e7a50008
--- /dev/null
+++ b/src/Gui/Navigation/NavigationStateChart.h
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/***************************************************************************
+ * Copyright (c) 2025 Werner Mayer *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ **************************************************************************/
+
+
+#ifndef GUI_NAVIGATIONSTATECHART_H
+#define GUI_NAVIGATIONSTATECHART_H
+
+#include
+#include
+
+// NOLINTBEGIN(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
+namespace Gui
+{
+
+class GuiExport NavigationStateChart : public UserNavigationStyle {
+ using inherited = UserNavigationStyle;
+
+ TYPESYSTEM_HEADER_WITH_OVERRIDE();
+
+public:
+ struct Event: public boost::statechart::event
+ {
+ using Button = SoMouseButtonEvent::Button;
+ using Key = SoKeyboardEvent::Key;
+
+ Event();
+ bool isMouseButtonEvent() const;
+ const SoMouseButtonEvent* asMouseButtonEvent() const;
+ bool isPress(Button button) const;
+ bool isRelease(Button button) const;
+ bool isKeyPress(Key key) const;
+ bool isKeyRelease(Key key) const;
+ bool isKeyboardEvent() const;
+ const SoKeyboardEvent* asKeyboardEvent() const;
+ bool isLocation2Event() const;
+ const SoLocation2Event* asLocation2Event() const;
+ bool isMotion3Event() const;
+ const SoMotion3Event* asMotion3Event() const;
+ bool isDownButton(unsigned int state) const;
+ bool isDownNoButton() const;
+ bool isDownButton1() const;
+ bool isDownButton2() const;
+ bool isDownButton3() const;
+ bool isDownControl() const;
+ bool isDownShift() const;
+ bool isDownAlt() const;
+
+ enum {
+ // bits: 0-shift-ctrl-alt-0-lmb-mmb-rmb
+ BUTTON1DOWN = 0x00000100,
+ BUTTON2DOWN = 0x00000001,
+ BUTTON3DOWN = 0x00000010,
+ CTRLDOWN = 0x00100000,
+ SHIFTDOWN = 0x01000000,
+ ALTDOWN = 0x00010000,
+ MASKBUTTONS = BUTTON1DOWN | BUTTON2DOWN | BUTTON3DOWN,
+ MASKMODIFIERS = CTRLDOWN | SHIFTDOWN | ALTDOWN
+ };
+
+ const SoEvent* inventor_event{nullptr};
+ unsigned int modifiers{0};
+ unsigned int mbstate() const {return modifiers & MASKBUTTONS;}
+ unsigned int kbstate() const {return modifiers & MASKMODIFIERS;}
+
+ struct Flags{
+ bool processed = false;
+ bool propagated = false;
+ };
+ std::shared_ptr flags;
+ };
+
+ class StateMachine
+ {
+ public:
+ template
+ void make_object(T* obj)
+ {
+ object = std::make_shared>(obj);
+ }
+
+ void process_event(const Event& ev)
+ {
+ if (object) {
+ object->process_event(ev);
+ }
+ }
+
+ struct Concept
+ {
+ virtual ~Concept() = default;
+ virtual void process_event(const Event&) = 0;
+ };
+
+ template< typename T >
+ struct Model : Concept
+ {
+ explicit Model(T* t) : object(t)
+ {
+ object->initiate();
+ }
+ ~Model() override
+ {
+ object.reset();
+ }
+ void process_event(const Event& ev) override
+ {
+ object->process_event(ev);
+ }
+
+ private:
+ std::shared_ptr object;
+ };
+
+ std::shared_ptr object;
+ };
+
+ NavigationStateChart();
+ ~NavigationStateChart() override;
+
+protected:
+ SbBool processSoEvent(const SoEvent * const ev) override;
+ std::unique_ptr naviMachine; // NOLINT
+};
+
+} // namespace Gui
+// NOLINTEND(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
+
+#endif // GUI_NAVIGATIONSTATECHART_H
diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp
index 11e1a76212..1e9e927075 100644
--- a/src/Gui/SoFCDB.cpp
+++ b/src/Gui/SoFCDB.cpp
@@ -53,6 +53,7 @@
#include "Inventor/Draggers/SoTransformDragger.h"
#include "Navigation/GestureNavigationStyle.h"
#include "Navigation/NavigationStyle.h"
+#include "Navigation/NavigationStateChart.h"
#include "SelectionObject.h"
#include "SoDevicePixelRatioElement.h"
#include "SoFCColorBar.h"
@@ -188,6 +189,7 @@ void Gui::SoFCDB::init()
NavigationStyle ::init();
UserNavigationStyle ::init();
+ NavigationStateChart ::init();
InventorNavigationStyle ::init();
CADNavigationStyle ::init();
RevitNavigationStyle ::init();
From 00e05045df0dc9315cf6ee214db9dbaaac82a781 Mon Sep 17 00:00:00 2001
From: wmayer
Date: Wed, 23 Apr 2025 13:49:23 +0200
Subject: [PATCH 3/6] Gui: Refactor navigation styles
Derive SiemensNXStyle from NavigationStateChart
---
src/Gui/CMakeLists.txt | 1 +
src/Gui/Navigation/NavigationStyle.h | 30 -----
src/Gui/Navigation/SiemensNXStyle.cpp | 180 +-------------------------
src/Gui/Navigation/SiemensNXStyle.h | 63 +++++++++
src/Gui/SoFCDB.cpp | 2 +-
5 files changed, 71 insertions(+), 205 deletions(-)
create mode 100644 src/Gui/Navigation/SiemensNXStyle.h
diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index f793a48ebd..49391e1c2b 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -958,6 +958,7 @@ SET(Navigation_SRCS
Navigation/GestureNavigationStyle.h
Navigation/NavigationAnimator.h
Navigation/NavigationAnimation.h
+ Navigation/SiemensNXStyle.h
)
SOURCE_GROUP("Navigation" FILES ${Navigation_SRCS})
diff --git a/src/Gui/Navigation/NavigationStyle.h b/src/Gui/Navigation/NavigationStyle.h
index e606b179b9..152b6f030a 100644
--- a/src/Gui/Navigation/NavigationStyle.h
+++ b/src/Gui/Navigation/NavigationStyle.h
@@ -490,36 +490,6 @@ protected:
SbBool processSoEvent(const SoEvent * const ev) override;
};
-class GuiExport SiemensNXStyle : public UserNavigationStyle {
- using inherited = UserNavigationStyle;
-
- TYPESYSTEM_HEADER_WITH_OVERRIDE();
-
-public:
- SiemensNXStyle();
- ~SiemensNXStyle() override;
- const char* mouseButtons(ViewerMode mode) override;
- std::string userFriendlyName() const override;
-
-protected:
- SbBool processSoEvent(const SoEvent * const ev) override;
- SbBool processKeyboardEvent(const SoKeyboardEvent * const event) override;
-
-private:
- struct Event;
- struct NaviMachine;
- struct IdleState;
- struct AwaitingReleaseState;
- struct AwaitingMoveState;
- struct InteractState;
- struct RotateState;
- struct PanState;
- struct ZoomState;
- struct SelectionState;
-
- std::unique_ptr naviMachine;
-};
-
} // namespace Gui
// NOLINTEND(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
diff --git a/src/Gui/Navigation/SiemensNXStyle.cpp b/src/Gui/Navigation/SiemensNXStyle.cpp
index 4420321e26..98721dee98 100644
--- a/src/Gui/Navigation/SiemensNXStyle.cpp
+++ b/src/Gui/Navigation/SiemensNXStyle.cpp
@@ -32,7 +32,7 @@
#include
#include "Camera.h"
-#include "NavigationStyle.h"
+#include "SiemensNXStyle.h"
#include "View3DInventorViewer.h"
// NOLINTBEGIN(cppcoreguidelines-pro-type-static-cast-downcast,
@@ -40,98 +40,9 @@
// readability-avoid-const-params-in-decls)
using namespace Gui;
namespace sc = boost::statechart;
+using SC = NavigationStateChart;
using NS = SiemensNXStyle;
-struct NS::Event: public sc::event
-{
- Event() : flags(new Flags){}
- using Button = SoMouseButtonEvent::Button;
- using Key = SoKeyboardEvent::Key;
- bool isMouseButtonEvent() const {
- return this->inventor_event->isOfType(SoMouseButtonEvent::getClassTypeId());
- }
- const SoMouseButtonEvent* asMouseButtonEvent() const {
- return static_cast(this->inventor_event);
- }
- bool isPress(Button button) const {
- return SoMouseButtonEvent::isButtonPressEvent(this->inventor_event, button);
- }
- bool isRelease(Button button) const {
- return SoMouseButtonEvent::isButtonReleaseEvent(this->inventor_event, button);
- }
- bool isKeyPress(Key key) const {
- return SoKeyboardEvent::isKeyPressEvent(this->inventor_event, key);
- }
- bool isKeyRelease(Key key) const {
- return SoKeyboardEvent::isKeyReleaseEvent(this->inventor_event, key);
- }
- bool isKeyboardEvent() const {
- return this->inventor_event->isOfType(SoKeyboardEvent::getClassTypeId());
- }
- const SoKeyboardEvent* asKeyboardEvent() const {
- return static_cast(this->inventor_event);
- }
- bool isLocation2Event() const {
- return this->inventor_event->isOfType(SoLocation2Event::getClassTypeId());
- }
- const SoLocation2Event* asLocation2Event() const {
- return static_cast(this->inventor_event);
- }
- bool isMotion3Event() const {
- return this->inventor_event->isOfType(SoMotion3Event::getClassTypeId());
- }
- const SoMotion3Event* asMotion3Event() const {
- return static_cast(this->inventor_event);
- }
- bool isDownButton(unsigned int state) const {
- return mbstate() == state;
- }
- bool isDownNoButton() const {
- return mbstate() == 0;
- }
- bool isDownButton1() const {
- return (mbstate() & BUTTON1DOWN) == BUTTON1DOWN;
- }
- bool isDownButton2() const {
- return (mbstate() & BUTTON2DOWN) == BUTTON2DOWN;
- }
- bool isDownButton3() const {
- return (mbstate() & BUTTON3DOWN) == BUTTON3DOWN;
- }
- bool isDownControl() const {
- return (kbstate() & CTRLDOWN) == CTRLDOWN;
- }
- bool isDownShift() const {
- return (kbstate() & SHIFTDOWN) == SHIFTDOWN;
- }
- bool isDownAlt() const {
- return (kbstate() & ALTDOWN) == ALTDOWN;
- }
-
- enum {
- // bits: 0-shift-ctrl-alt-0-lmb-mmb-rmb
- BUTTON1DOWN = 0x00000100,
- BUTTON2DOWN = 0x00000001,
- BUTTON3DOWN = 0x00000010,
- CTRLDOWN = 0x00100000,
- SHIFTDOWN = 0x01000000,
- ALTDOWN = 0x00010000,
- MASKBUTTONS = BUTTON1DOWN | BUTTON2DOWN | BUTTON3DOWN,
- MASKMODIFIERS = CTRLDOWN | SHIFTDOWN | ALTDOWN
- };
-
- const SoEvent* inventor_event{nullptr};
- unsigned int modifiers{0};
- unsigned int mbstate() const {return modifiers & MASKBUTTONS;}
- unsigned int kbstate() const {return modifiers & MASKMODIFIERS;}
-
- struct Flags{
- bool processed = false;
- bool propagated = false;
- };
- std::shared_ptr flags;
-};
-
struct NS::NaviMachine: public sc::state_machine
{
using superclass = sc::state_machine;
@@ -141,13 +52,13 @@ struct NS::NaviMachine: public sc::state_machine
struct NS::IdleState: public sc::state
{
- using reactions = sc::custom_reaction;
+ using reactions = sc::custom_reaction;
explicit IdleState(my_context ctx) : my_base(ctx)
{
auto &ns = this->outermost_context().ns;
ns.setViewingMode(NavigationStyle::IDLE);
}
- sc::result react(const NS::Event& ev)
+ sc::result react(const SC::Event& ev)
{
auto &ns = this->outermost_context().ns;
switch (ns.getViewingMode()) {
@@ -194,7 +105,7 @@ struct NS::IdleState: public sc::state
return transit();
}
- if (ev.isDownButton(NS::Event::BUTTON3DOWN)) {
+ if (ev.isDownButton(SC::Event::BUTTON3DOWN)) {
ev.flags->processed = true;
return transit();
}
@@ -490,14 +401,12 @@ struct NS::SelectionState: public sc::state
TYPESYSTEM_SOURCE(Gui::SiemensNXStyle, Gui::UserNavigationStyle)
SiemensNXStyle::SiemensNXStyle()
- : naviMachine(new NS::NaviMachine(*this))
{
- naviMachine->initiate();
+ naviMachine->make_object(new NS::NaviMachine(*this));
}
SiemensNXStyle::~SiemensNXStyle()
{
- naviMachine.reset();
}
const char* SiemensNXStyle::mouseButtons(ViewerMode mode)
@@ -557,83 +466,6 @@ SbBool SiemensNXStyle::processKeyboardEvent(const SoKeyboardEvent * const event)
return inherited::processKeyboardEvent(event);
}
-SbBool SiemensNXStyle::processSoEvent(const SoEvent * const ev)
-{
- // Events when in "ready-to-seek" mode are ignored, except those
- // which influence the seek mode itself -- these are handled further
- // up the inheritance hierarchy.
- if (this->isSeekMode()) {
- return inherited::processSoEvent(ev);
- }
-
- // Switch off viewing mode (Bug #0000911)
- if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) {
- this->setViewing(false); // by default disable viewing mode to render the scene
- }
-
- // Mismatches in state of the modifier keys happens if the user
- // presses or releases them outside the viewer window.
- syncModifierKeys(ev);
-
- // give the nodes in the foreground root the chance to handle events (e.g color bar)
- if (!viewer->isEditing()) {
- if (handleEventInForeground(ev)) {
- return true;
- }
- }
-
- NS::Event smev;
- smev.inventor_event = ev;
-
- // Spaceball/joystick handling
- if (ev->isOfType(SoMotion3Event::getClassTypeId())){
- smev.flags->processed = true;
- this->processMotionEvent(static_cast(ev));
- return true;
- }
-
- // Keyboard handling
- if (ev->isOfType(SoKeyboardEvent::getClassTypeId())) {
- const auto event = static_cast(ev);
- smev.flags->processed = processKeyboardEvent(event);
- }
-
- if (smev.isMouseButtonEvent()) {
- const auto button = smev.asMouseButtonEvent()->getButton();
- const SbBool press = smev.asMouseButtonEvent()->getState() == SoButtonEvent::DOWN;
- switch (button) {
- case SoMouseButtonEvent::BUTTON1:
- this->button1down = press;
- break;
- case SoMouseButtonEvent::BUTTON2:
- this->button2down = press;
- break;
- case SoMouseButtonEvent::BUTTON3:
- this->button3down = press;
- break;
- default:
- break;
- }
- }
-
- smev.modifiers =
- (this->button1down ? NS::Event::BUTTON1DOWN : 0) |
- (this->button2down ? NS::Event::BUTTON2DOWN : 0) |
- (this->button3down ? NS::Event::BUTTON3DOWN : 0) |
- (this->ctrldown ? NS::Event::CTRLDOWN : 0) |
- (this->shiftdown ? NS::Event::SHIFTDOWN : 0) |
- (this->altdown ? NS::Event::ALTDOWN : 0);
-
- if (!smev.flags->processed) {
- this->naviMachine->process_event(smev);
- }
-
- if (!smev.flags->propagated && !smev.flags->processed) {
- return inherited::processSoEvent(ev);
- }
-
- return smev.flags->processed;
-}
// NOLINTEND(cppcoreguidelines-pro-type-static-cast-downcast,
// cppcoreguidelines-avoid*,
// readability-avoid-const-params-in-decls)
diff --git a/src/Gui/Navigation/SiemensNXStyle.h b/src/Gui/Navigation/SiemensNXStyle.h
new file mode 100644
index 0000000000..efd36afadc
--- /dev/null
+++ b/src/Gui/Navigation/SiemensNXStyle.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/***************************************************************************
+ * Copyright (c) 2025 Werner Mayer *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ **************************************************************************/
+
+
+#ifndef GUI_SIEMENSNXSTYLE_H
+#define GUI_SIEMENSNXSTYLE_H
+
+#include
+
+// NOLINTBEGIN(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
+namespace Gui
+{
+
+class GuiExport SiemensNXStyle : public NavigationStateChart {
+ using inherited = NavigationStateChart;
+
+ TYPESYSTEM_HEADER_WITH_OVERRIDE();
+
+public:
+ SiemensNXStyle();
+ ~SiemensNXStyle() override;
+ const char* mouseButtons(ViewerMode mode) override;
+ std::string userFriendlyName() const override;
+
+protected:
+ SbBool processKeyboardEvent(const SoKeyboardEvent * const event) override;
+
+private:
+ struct NaviMachine;
+ struct IdleState;
+ struct AwaitingReleaseState;
+ struct AwaitingMoveState;
+ struct InteractState;
+ struct RotateState;
+ struct PanState;
+ struct ZoomState;
+ struct SelectionState;
+};
+
+} // namespace Gui
+// NOLINTEND(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
+
+#endif // GUI_SIEMENSNXSTYLE_H
diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp
index 1e9e927075..ab6f365df4 100644
--- a/src/Gui/SoFCDB.cpp
+++ b/src/Gui/SoFCDB.cpp
@@ -53,7 +53,7 @@
#include "Inventor/Draggers/SoTransformDragger.h"
#include "Navigation/GestureNavigationStyle.h"
#include "Navigation/NavigationStyle.h"
-#include "Navigation/NavigationStateChart.h"
+#include "Navigation/SiemensNXStyle.h"
#include "SelectionObject.h"
#include "SoDevicePixelRatioElement.h"
#include "SoFCColorBar.h"
From 969c147be2948ab6eb9ccc5f23149ddab407e1c3 Mon Sep 17 00:00:00 2001
From: wmayer
Date: Wed, 23 Apr 2025 14:12:19 +0200
Subject: [PATCH 4/6] Gui: Refactor navigation styles
Simplify type erasure
---
src/Gui/Navigation/NavigationStateChart.cpp | 4 +-
src/Gui/Navigation/NavigationStateChart.h | 86 ++++++++++-----------
src/Gui/Navigation/SiemensNXStyle.cpp | 2 +-
3 files changed, 42 insertions(+), 50 deletions(-)
diff --git a/src/Gui/Navigation/NavigationStateChart.cpp b/src/Gui/Navigation/NavigationStateChart.cpp
index c146fbb9a6..70a12f8f67 100644
--- a/src/Gui/Navigation/NavigationStateChart.cpp
+++ b/src/Gui/Navigation/NavigationStateChart.cpp
@@ -145,9 +145,7 @@ bool NS::Event::isDownAlt() const
TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStateChart, Gui::UserNavigationStyle)
NavigationStateChart::NavigationStateChart()
- : naviMachine(new NS::StateMachine())
-{
-}
+{}
NavigationStateChart::~NavigationStateChart()
{
diff --git a/src/Gui/Navigation/NavigationStateChart.h b/src/Gui/Navigation/NavigationStateChart.h
index f7e7a50008..9e60708d1a 100644
--- a/src/Gui/Navigation/NavigationStateChart.h
+++ b/src/Gui/Navigation/NavigationStateChart.h
@@ -32,6 +32,8 @@
namespace Gui
{
+class NaviStateMachine;
+
class GuiExport NavigationStateChart : public UserNavigationStyle {
using inherited = UserNavigationStyle;
@@ -89,57 +91,49 @@ public:
std::shared_ptr flags;
};
- class StateMachine
- {
- public:
- template
- void make_object(T* obj)
- {
- object = std::make_shared>(obj);
- }
-
- void process_event(const Event& ev)
- {
- if (object) {
- object->process_event(ev);
- }
- }
-
- struct Concept
- {
- virtual ~Concept() = default;
- virtual void process_event(const Event&) = 0;
- };
-
- template< typename T >
- struct Model : Concept
- {
- explicit Model(T* t) : object(t)
- {
- object->initiate();
- }
- ~Model() override
- {
- object.reset();
- }
- void process_event(const Event& ev) override
- {
- object->process_event(ev);
- }
-
- private:
- std::shared_ptr object;
- };
-
- std::shared_ptr object;
- };
-
NavigationStateChart();
~NavigationStateChart() override;
protected:
SbBool processSoEvent(const SoEvent * const ev) override;
- std::unique_ptr naviMachine; // NOLINT
+ std::unique_ptr naviMachine; // NOLINT
+};
+
+class GuiExport NaviStateMachine
+{
+public:
+ NaviStateMachine(const NaviStateMachine&) = delete;
+ NaviStateMachine(NaviStateMachine&&) = delete;
+ NaviStateMachine& operator= (const NaviStateMachine&) = delete;
+ NaviStateMachine& operator= (NaviStateMachine&&) = delete;
+
+ NaviStateMachine() = default;
+ virtual ~NaviStateMachine() = default;
+
+ virtual void process_event(const NavigationStateChart::Event&) = 0;
+};
+
+template< typename T >
+class NaviStateMachineT : public NaviStateMachine
+{
+public:
+ explicit NaviStateMachineT(T* t) : object(t)
+ {
+ object->initiate();
+ }
+
+ ~NaviStateMachineT() override
+ {
+ object.reset();
+ }
+
+ void process_event(const NavigationStateChart::Event& ev) override
+ {
+ object->process_event(ev);
+ }
+
+private:
+ std::unique_ptr object;
};
} // namespace Gui
diff --git a/src/Gui/Navigation/SiemensNXStyle.cpp b/src/Gui/Navigation/SiemensNXStyle.cpp
index 98721dee98..044e5f545c 100644
--- a/src/Gui/Navigation/SiemensNXStyle.cpp
+++ b/src/Gui/Navigation/SiemensNXStyle.cpp
@@ -402,7 +402,7 @@ TYPESYSTEM_SOURCE(Gui::SiemensNXStyle, Gui::UserNavigationStyle)
SiemensNXStyle::SiemensNXStyle()
{
- naviMachine->make_object(new NS::NaviMachine(*this));
+ naviMachine.reset(new NaviStateMachineT(new NaviMachine(*this)));
}
SiemensNXStyle::~SiemensNXStyle()
From fc5b5fd9c6fbe606904acc9ffff8afd8cddf3c1c Mon Sep 17 00:00:00 2001
From: Max Wilfinger
Date: Fri, 6 Jun 2025 10:04:29 +0200
Subject: [PATCH 5/6] Added UI for Siemens NX navigation style. Ordered
navigation styles alphabetically.
---
src/Gui/SoFCDB.cpp | 14 ++--
src/Mod/Tux/NavigationIndicatorGui.py | 82 +++++++++++++++----
src/Mod/Tux/Resources/Tux.qrc | 2 +
.../icons/NavigationSiemensNX_dark.svg | 50 +++++++++++
.../icons/NavigationSiemensNX_light.svg | 50 +++++++++++
5 files changed, 175 insertions(+), 23 deletions(-)
create mode 100644 src/Mod/Tux/Resources/icons/NavigationSiemensNX_dark.svg
create mode 100644 src/Mod/Tux/Resources/icons/NavigationSiemensNX_light.svg
diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp
index ab6f365df4..7a0dc4718c 100644
--- a/src/Gui/SoFCDB.cpp
+++ b/src/Gui/SoFCDB.cpp
@@ -190,18 +190,18 @@ void Gui::SoFCDB::init()
NavigationStyle ::init();
UserNavigationStyle ::init();
NavigationStateChart ::init();
- InventorNavigationStyle ::init();
- CADNavigationStyle ::init();
- RevitNavigationStyle ::init();
BlenderNavigationStyle ::init();
- SolidWorksNavigationStyle ::init();
- MayaGestureNavigationStyle ::init();
- TouchpadNavigationStyle ::init();
+ CADNavigationStyle ::init();
GestureNavigationStyle ::init();
+ MayaGestureNavigationStyle ::init();
OpenCascadeNavigationStyle ::init();
+ InventorNavigationStyle ::init();
OpenSCADNavigationStyle ::init();
- TinkerCADNavigationStyle ::init();
+ RevitNavigationStyle ::init();
SiemensNXStyle ::init();
+ SolidWorksNavigationStyle ::init();
+ TinkerCADNavigationStyle ::init();
+ TouchpadNavigationStyle ::init();
GLGraphicsItem ::init();
GLFlagWindow ::init();
diff --git a/src/Mod/Tux/NavigationIndicatorGui.py b/src/Mod/Tux/NavigationIndicatorGui.py
index 84b7f3db7b..3e68c64a90 100644
--- a/src/Mod/Tux/NavigationIndicatorGui.py
+++ b/src/Mod/Tux/NavigationIndicatorGui.py
@@ -74,9 +74,10 @@ def RePopulateIcons():
a6.setIcon(QtGui.QIcon(":/icons/NavigationOpenInventor_" + StyleSheetType + ".svg"))
a7.setIcon(QtGui.QIcon(":/icons/NavigationOpenSCAD_" + StyleSheetType + ".svg"))
a8.setIcon(QtGui.QIcon(":/icons/NavigationRevit_" + StyleSheetType + ".svg"))
- a9.setIcon(QtGui.QIcon(":/icons/NavigationSolidWorks_" + StyleSheetType + ".svg"))
- a10.setIcon(QtGui.QIcon(":/icons/NavigationTinkerCAD_" + StyleSheetType + ".svg"))
- a11.setIcon(QtGui.QIcon(":/icons/NavigationTouchpad_" + StyleSheetType + ".svg"))
+ a9.setIcon(QtGui.QIcon(":/icons/NavigationSiemensNX_" + StyleSheetType + ".svg"))
+ a10.setIcon(QtGui.QIcon(":/icons/NavigationSolidWorks_" + StyleSheetType + ".svg"))
+ a11.setIcon(QtGui.QIcon(":/icons/NavigationTinkerCAD_" + StyleSheetType + ".svg"))
+ a12.setIcon(QtGui.QIcon(":/icons/NavigationTouchpad_" + StyleSheetType + ".svg"))
def retranslateUi():
@@ -474,6 +475,48 @@ def retranslateUi():
global t9
t9 = (
+ "Siemens NX "
+ + text06
+ + """
+
+
+ | """
+ + text01
+ + """ |
+ """
+ + text02
+ + """ |
+ """
+ + text02
+ + """ |
+ """
+ + text03
+ + """ |
+ """
+ + text04
+ + """ |
+ """
+ + text04
+ + """ |
+
+
+  |
+  |
+  |
+  |
+  |
+  |
+
+
+ """
+ + text08
+ + ": "
+ + text10
+ + "
"
+ )
+
+ global t10
+ t10 = (
"SolidWorks "
+ text06
+ """
@@ -510,8 +553,8 @@ def retranslateUi():
+ ""
)
- global t10
- t10 = (
+ global t11
+ t11 = (
"TinkerCAD "
+ text06
+ """
@@ -539,8 +582,8 @@ def retranslateUi():
"""
)
- global t11
- t11 = (
+ global t12
+ t12 = (
"Touchpad "
+ text06
+ """
@@ -716,19 +759,24 @@ a8.setData("Gui::RevitNavigationStyle")
a8.setObjectName("Indicator_NavigationRevit")
a9 = QtGui.QAction(gStyle)
-a9.setText("SolidWorks ")
-a9.setData("Gui::SolidWorksNavigationStyle")
-a9.setObjectName("Indicator_NavigationSolidWorks")
+a9.setText("Siemens NX ")
+a9.setData("Gui::SiemensNXStyle")
+a9.setObjectName("Indicator_NavigationSiemensNX")
a10 = QtGui.QAction(gStyle)
-a10.setText("TinkerCAD ")
-a10.setData("Gui::TinkerCADNavigationStyle")
-a10.setObjectName("Indicator_NavigationTinkerCAD")
+a10.setText("SolidWorks ")
+a10.setData("Gui::SolidWorksNavigationStyle")
+a10.setObjectName("Indicator_NavigationSolidWorks")
a11 = QtGui.QAction(gStyle)
-a11.setText("Touchpad ")
-a11.setData("Gui::TouchpadNavigationStyle")
-a11.setObjectName("Indicator_NavigationTouchpad")
+a11.setText("TinkerCAD ")
+a11.setData("Gui::TinkerCADNavigationStyle")
+a11.setObjectName("Indicator_NavigationTinkerCAD")
+
+a12 = QtGui.QAction(gStyle)
+a12.setText("Touchpad ")
+a12.setData("Gui::TouchpadNavigationStyle")
+a12.setObjectName("Indicator_NavigationTouchpad")
RePopulateIcons()
@@ -746,6 +794,7 @@ menu.addAction(a8)
menu.addAction(a9)
menu.addAction(a10)
menu.addAction(a11)
+menu.addAction(a12)
pView.Attach(indicator)
@@ -787,6 +836,7 @@ def onTooltip():
a9.setToolTip(t9)
a10.setToolTip(t10)
a11.setToolTip(t11)
+ a12.setToolTip(t12)
p.SetBool("Tooltip", 1)
else:
for i in gStyle.actions():
diff --git a/src/Mod/Tux/Resources/Tux.qrc b/src/Mod/Tux/Resources/Tux.qrc
index 6ec43834ca..413d549458 100644
--- a/src/Mod/Tux/Resources/Tux.qrc
+++ b/src/Mod/Tux/Resources/Tux.qrc
@@ -47,6 +47,8 @@
icons/NavigationOpenSCAD_dark.svg
icons/NavigationRevit_light.svg
icons/NavigationRevit_dark.svg
+ icons/NavigationSiemensNX_light.svg
+ icons/NavigationSiemensNX_dark.svg
icons/NavigationSolidWorks_light.svg
icons/NavigationSolidWorks_dark.svg
icons/NavigationTinkerCAD_light.svg
diff --git a/src/Mod/Tux/Resources/icons/NavigationSiemensNX_dark.svg b/src/Mod/Tux/Resources/icons/NavigationSiemensNX_dark.svg
new file mode 100644
index 0000000000..38ab2c06cc
--- /dev/null
+++ b/src/Mod/Tux/Resources/icons/NavigationSiemensNX_dark.svg
@@ -0,0 +1,50 @@
+
+
+
+
diff --git a/src/Mod/Tux/Resources/icons/NavigationSiemensNX_light.svg b/src/Mod/Tux/Resources/icons/NavigationSiemensNX_light.svg
new file mode 100644
index 0000000000..0064477a86
--- /dev/null
+++ b/src/Mod/Tux/Resources/icons/NavigationSiemensNX_light.svg
@@ -0,0 +1,50 @@
+
+
+
+
From d9a0b6909a876c996c4aceccd5207369c3ed6b02 Mon Sep 17 00:00:00 2001
From: Max Wilfinger
Date: Fri, 6 Jun 2025 15:32:05 +0200
Subject: [PATCH 6/6] Renaming Gui::SiemensNXStyle to
Gui::SiemensNXNavigationStyle for consistency
---
src/Gui/CMakeLists.txt | 4 ++--
...XStyle.cpp => SiemensNXNavigationStyle.cpp} | 18 +++++++++---------
...ensNXStyle.h => SiemensNXNavigationStyle.h} | 12 ++++++------
src/Gui/SoFCDB.cpp | 4 ++--
src/Mod/Tux/NavigationIndicatorGui.py | 2 +-
5 files changed, 20 insertions(+), 20 deletions(-)
rename src/Gui/Navigation/{SiemensNXStyle.cpp => SiemensNXNavigationStyle.cpp} (96%)
rename src/Gui/Navigation/{SiemensNXStyle.h => SiemensNXNavigationStyle.h} (89%)
diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index 49391e1c2b..ab93d16cac 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -939,7 +939,7 @@ SET(Navigation_CPP_SRCS
Navigation/CADNavigationStyle.cpp
Navigation/RevitNavigationStyle.cpp
Navigation/BlenderNavigationStyle.cpp
- Navigation/SiemensNXStyle.cpp
+ Navigation/SiemensNXNavigationStyle.cpp
Navigation/SolidWorksNavigationStyle.cpp
Navigation/MayaGestureNavigationStyle.cpp
Navigation/OpenCascadeNavigationStyle.cpp
@@ -958,7 +958,7 @@ SET(Navigation_SRCS
Navigation/GestureNavigationStyle.h
Navigation/NavigationAnimator.h
Navigation/NavigationAnimation.h
- Navigation/SiemensNXStyle.h
+ Navigation/SiemensNXNavigationStyle.h
)
SOURCE_GROUP("Navigation" FILES ${Navigation_SRCS})
diff --git a/src/Gui/Navigation/SiemensNXStyle.cpp b/src/Gui/Navigation/SiemensNXNavigationStyle.cpp
similarity index 96%
rename from src/Gui/Navigation/SiemensNXStyle.cpp
rename to src/Gui/Navigation/SiemensNXNavigationStyle.cpp
index 044e5f545c..45090aa2bf 100644
--- a/src/Gui/Navigation/SiemensNXStyle.cpp
+++ b/src/Gui/Navigation/SiemensNXNavigationStyle.cpp
@@ -32,7 +32,7 @@
#include
#include "Camera.h"
-#include "SiemensNXStyle.h"
+#include "SiemensNXNavigationStyle.h"
#include "View3DInventorViewer.h"
// NOLINTBEGIN(cppcoreguidelines-pro-type-static-cast-downcast,
@@ -41,7 +41,7 @@
using namespace Gui;
namespace sc = boost::statechart;
using SC = NavigationStateChart;
-using NS = SiemensNXStyle;
+using NS = SiemensNXNavigationStyle;
struct NS::NaviMachine: public sc::state_machine
{
@@ -396,20 +396,20 @@ struct NS::SelectionState: public sc::state
// ----------------------------------------------------------------------------------
-/* TRANSLATOR Gui::SiemensNXStyle */
+/* TRANSLATOR Gui::SiemensNXNavigationStyle */
-TYPESYSTEM_SOURCE(Gui::SiemensNXStyle, Gui::UserNavigationStyle)
+TYPESYSTEM_SOURCE(Gui::SiemensNXNavigationStyle, Gui::UserNavigationStyle)
-SiemensNXStyle::SiemensNXStyle()
+SiemensNXNavigationStyle::SiemensNXNavigationStyle()
{
naviMachine.reset(new NaviStateMachineT(new NaviMachine(*this)));
}
-SiemensNXStyle::~SiemensNXStyle()
+SiemensNXNavigationStyle::~SiemensNXNavigationStyle()
{
}
-const char* SiemensNXStyle::mouseButtons(ViewerMode mode)
+const char* SiemensNXNavigationStyle::mouseButtons(ViewerMode mode)
{
switch (mode) {
case NavigationStyle::SELECTION:
@@ -425,12 +425,12 @@ const char* SiemensNXStyle::mouseButtons(ViewerMode mode)
}
}
-std::string SiemensNXStyle::userFriendlyName() const
+std::string SiemensNXNavigationStyle::userFriendlyName() const
{
return {"Siemens NX"};
}
-SbBool SiemensNXStyle::processKeyboardEvent(const SoKeyboardEvent * const event)
+SbBool SiemensNXNavigationStyle::processKeyboardEvent(const SoKeyboardEvent* const event)
{
// See https://forum.freecad.org/viewtopic.php?t=96459
// Isometric view: Home key button
diff --git a/src/Gui/Navigation/SiemensNXStyle.h b/src/Gui/Navigation/SiemensNXNavigationStyle.h
similarity index 89%
rename from src/Gui/Navigation/SiemensNXStyle.h
rename to src/Gui/Navigation/SiemensNXNavigationStyle.h
index efd36afadc..a888551df0 100644
--- a/src/Gui/Navigation/SiemensNXStyle.h
+++ b/src/Gui/Navigation/SiemensNXNavigationStyle.h
@@ -22,8 +22,8 @@
**************************************************************************/
-#ifndef GUI_SIEMENSNXSTYLE_H
-#define GUI_SIEMENSNXSTYLE_H
+#ifndef GUI_SIEMENSNXNAVIGATIONSTYLE_H
+#define GUI_SIEMENSNXNAVIGATIONSTYLE_H
#include
@@ -31,14 +31,14 @@
namespace Gui
{
-class GuiExport SiemensNXStyle : public NavigationStateChart {
+class GuiExport SiemensNXNavigationStyle : public NavigationStateChart {
using inherited = NavigationStateChart;
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
- SiemensNXStyle();
- ~SiemensNXStyle() override;
+ SiemensNXNavigationStyle();
+ ~SiemensNXNavigationStyle() override;
const char* mouseButtons(ViewerMode mode) override;
std::string userFriendlyName() const override;
@@ -60,4 +60,4 @@ private:
} // namespace Gui
// NOLINTEND(cppcoreguidelines-avoid*, readability-avoid-const-params-in-decls)
-#endif // GUI_SIEMENSNXSTYLE_H
+#endif // GUI_SIEMENSNXNAVIGATIONSTYLE_H
diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp
index 7a0dc4718c..19b32fda94 100644
--- a/src/Gui/SoFCDB.cpp
+++ b/src/Gui/SoFCDB.cpp
@@ -53,7 +53,7 @@
#include "Inventor/Draggers/SoTransformDragger.h"
#include "Navigation/GestureNavigationStyle.h"
#include "Navigation/NavigationStyle.h"
-#include "Navigation/SiemensNXStyle.h"
+#include "Navigation/SiemensNXNavigationStyle.h"
#include "SelectionObject.h"
#include "SoDevicePixelRatioElement.h"
#include "SoFCColorBar.h"
@@ -198,7 +198,7 @@ void Gui::SoFCDB::init()
InventorNavigationStyle ::init();
OpenSCADNavigationStyle ::init();
RevitNavigationStyle ::init();
- SiemensNXStyle ::init();
+ SiemensNXNavigationStyle ::init();
SolidWorksNavigationStyle ::init();
TinkerCADNavigationStyle ::init();
TouchpadNavigationStyle ::init();
diff --git a/src/Mod/Tux/NavigationIndicatorGui.py b/src/Mod/Tux/NavigationIndicatorGui.py
index 3e68c64a90..194ead53ab 100644
--- a/src/Mod/Tux/NavigationIndicatorGui.py
+++ b/src/Mod/Tux/NavigationIndicatorGui.py
@@ -760,7 +760,7 @@ a8.setObjectName("Indicator_NavigationRevit")
a9 = QtGui.QAction(gStyle)
a9.setText("Siemens NX ")
-a9.setData("Gui::SiemensNXStyle")
+a9.setData("Gui::SiemensNXNavigationStyle")
a9.setObjectName("Indicator_NavigationSiemensNX")
a10 = QtGui.QAction(gStyle)