From a1c9ab658caf5c8deb98f37a358d29eb1bfa84ee Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 26 Oct 2021 00:21:31 +0200 Subject: [PATCH] Gui: add support of OpenSCAD navigation style --- src/Gui/CMakeLists.txt | 1 + src/Gui/NavigationStyle.h | 17 ++ src/Gui/OpenSCADNavigationStyle.cpp | 347 ++++++++++++++++++++++++++++ src/Gui/SoFCDB.cpp | 1 + 4 files changed, 366 insertions(+) create mode 100644 src/Gui/OpenSCADNavigationStyle.cpp diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 3c6a607e9c67..b901e97e8dfe 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -838,6 +838,7 @@ SET(View3D_CPP_SRCS BlenderNavigationStyle.cpp MayaGestureNavigationStyle.cpp OpenCascadeNavigationStyle.cpp + OpenSCADNavigationStyle.cpp TouchpadNavigationStyle.cpp GestureNavigationStyle.cpp SplitView3DInventor.cpp diff --git a/src/Gui/NavigationStyle.h b/src/Gui/NavigationStyle.h index 2903ac0caa6b..659d8f9e033d 100644 --- a/src/Gui/NavigationStyle.h +++ b/src/Gui/NavigationStyle.h @@ -410,6 +410,23 @@ class GuiExport OpenCascadeNavigationStyle : public UserNavigationStyle { SoMouseButtonEvent mouseDownConsumedEvent; }; +class GuiExport OpenSCADNavigationStyle : public UserNavigationStyle { + typedef UserNavigationStyle inherited; + + TYPESYSTEM_HEADER(); + +public: + OpenSCADNavigationStyle(); + ~OpenSCADNavigationStyle(); + const char* mouseButtons(ViewerMode); + +protected: + SbBool processSoEvent(const SoEvent * const ev); + +private: + SoMouseButtonEvent mouseDownConsumedEvent; +}; + } // namespace Gui Q_DECLARE_OPERATORS_FOR_FLAGS(Gui::NavigationStyle::RotationCenterModes) diff --git a/src/Gui/OpenSCADNavigationStyle.cpp b/src/Gui/OpenSCADNavigationStyle.cpp new file mode 100644 index 000000000000..0148e46eb35d --- /dev/null +++ b/src/Gui/OpenSCADNavigationStyle.cpp @@ -0,0 +1,347 @@ +/*************************************************************************** + * Copyright (c) 2021 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include "InventorAll.h" +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include "NavigationStyle.h" +#include "View3DInventorViewer.h" +#include "Application.h" +#include "MenuManager.h" +#include "MouseSelection.h" + +using namespace Gui; + +// ---------------------------------------------------------------------------------- + +/* TRANSLATOR Gui::OpenSCADNavigationStyle */ + +TYPESYSTEM_SOURCE(Gui::OpenSCADNavigationStyle, Gui::UserNavigationStyle) + +OpenSCADNavigationStyle::OpenSCADNavigationStyle() +{ +} + +OpenSCADNavigationStyle::~OpenSCADNavigationStyle() +{ +} + +const char* OpenSCADNavigationStyle::mouseButtons(ViewerMode mode) +{ + switch (mode) { + case NavigationStyle::SELECTION: + return QT_TR_NOOP("Press left mouse button"); + case NavigationStyle::PANNING: + return QT_TR_NOOP("Press right mouse button and move mouse"); + case NavigationStyle::DRAGGING: + return QT_TR_NOOP("Press left mouse button and move mouse"); + case NavigationStyle::ZOOMING: + return QT_TR_NOOP("Press SHIFT and middle or right mouse button"); + default: + return "No description"; + } +} + +SbBool OpenSCADNavigationStyle::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 + if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) + this->setViewing(false); // by default disable viewing mode to render the scene + + const SoType type(ev->getTypeId()); + + const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion(); + const SbVec2s size(vp.getViewportSizePixels()); + const SbVec2f prevnormalized = this->lastmouseposition; + const SbVec2s pos(ev->getPosition()); + const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1), + (float) pos[1] / (float) std::max((int)(size[1] - 1), 1)); + + this->lastmouseposition = posn; + + // Set to true if any event processing happened. Note that it is not + // necessary to restrict ourselves to only do one "action" for an + // event, we only need this flag to see if any processing happened + // at all. + SbBool processed = false; + + const ViewerMode curmode = this->currentmode; + ViewerMode newmode = curmode; + + // Mismatches in state of the modifier keys happens if the user + // presses or releases them outside the viewer window. + if (this->ctrldown != ev->wasCtrlDown()) { + this->ctrldown = ev->wasCtrlDown(); + } + if (this->shiftdown != ev->wasShiftDown()) { + this->shiftdown = ev->wasShiftDown(); + } + if (this->altdown != ev->wasAltDown()) { + this->altdown = ev->wasAltDown(); + } + + // give the nodes in the foreground root the chance to handle events (e.g color bar) + if (!viewer->isEditing()) { + processed = handleEventInForeground(ev); + if (processed) + return true; + } + + // Keyboard handling + if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { + const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; + const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; + switch (event->getKey()) { + case SoKeyboardEvent::LEFT_CONTROL: + case SoKeyboardEvent::RIGHT_CONTROL: + this->ctrldown = press; + break; + case SoKeyboardEvent::LEFT_SHIFT: + case SoKeyboardEvent::RIGHT_SHIFT: + this->shiftdown = press; + break; + case SoKeyboardEvent::LEFT_ALT: + case SoKeyboardEvent::RIGHT_ALT: + this->altdown = press; + break; + case SoKeyboardEvent::H: + processed = true; + viewer->saveHomePosition(); + break; + case SoKeyboardEvent::S: + case SoKeyboardEvent::HOME: + case SoKeyboardEvent::LEFT_ARROW: + case SoKeyboardEvent::UP_ARROW: + case SoKeyboardEvent::RIGHT_ARROW: + case SoKeyboardEvent::DOWN_ARROW: + if (!this->isViewing()) + this->setViewing(true); + break; + default: + break; + } + } + + // Mouse Button / Spaceball Button handling + if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { + const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; + const int button = event->getButton(); + const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; + + switch (button) { + case SoMouseButtonEvent::BUTTON1: + this->lockrecenter = true; + this->button1down = press; + if (press && (curmode == NavigationStyle::SEEK_WAIT_MODE)) { + newmode = NavigationStyle::SEEK_MODE; + this->seekToPoint(pos); // implicitly calls interactiveCountInc() + processed = true; + } + else if (!press && (curmode == NavigationStyle::ZOOMING)) { + newmode = NavigationStyle::IDLE; + processed = true; + } + else if (!press && (curmode == NavigationStyle::DRAGGING)) { + this->setViewing(false); + processed = true; + } + else if (viewer->isEditing() && (curmode == NavigationStyle::SPINNING)) { + processed = true; + } + // issue #0002433: avoid to swallow the UP event if down the + // scene graph somewhere a dialog gets opened + else if (press) { + SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime()); + float dci = (float)QApplication::doubleClickInterval()/1000.0f; + // a double-click? + if (tmp.getValue() < dci) { + mouseDownConsumedEvent = *event; + mouseDownConsumedEvent.setTime(ev->getTime()); + processed = true; + } + else { + mouseDownConsumedEvent.setTime(ev->getTime()); + // 'ANY' is used to mark that we don't know yet if it will + // be a double-click event. + mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); + } + } + else if (!press) { + if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) { + // now handle the postponed event + inherited::processSoEvent(&mouseDownConsumedEvent); + mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY); + } + } + break; + case SoMouseButtonEvent::BUTTON2: + // If we are in edit mode then simply ignore the RMB events + // to pass the event to the base class. + this->lockrecenter = true; + this->button2down = press; + if (!viewer->isEditing()) { + // If we are in zoom or pan mode ignore RMB events otherwise + // the canvas doesn't get any release events + if (curmode != NavigationStyle::ZOOMING && + curmode != NavigationStyle::PANNING && + curmode != NavigationStyle::DRAGGING) { + if (this->isPopupMenuEnabled()) { + if (!press) { // release right mouse button + this->openPopupMenu(event->getPosition()); + } + } + } + } + // Alternative way of rotating & zooming + if (press && (curmode == NavigationStyle::PANNING || + curmode == NavigationStyle::ZOOMING)) { + newmode = NavigationStyle::DRAGGING; + saveCursorPosition(ev); + this->centerTime = ev->getTime(); + processed = true; + } + else if (!press && (curmode == NavigationStyle::DRAGGING)) { + newmode = NavigationStyle::IDLE; + processed = true; + } + break; + case SoMouseButtonEvent::BUTTON3: + this->button3down = press; + if (press) { + this->centerTime = ev->getTime(); + float ratio = vp.getViewportAspectRatio(); + SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio); + this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue()); + this->lockrecenter = false; + } + else if (curmode == NavigationStyle::PANNING) { + newmode = NavigationStyle::IDLE; + processed = true; + } + break; + default: + break; + } + } + + // Mouse Movement handling + if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) { + this->lockrecenter = true; + const SoLocation2Event * const event = (const SoLocation2Event *) ev; + if (curmode == NavigationStyle::SELECTION) { + newmode = NavigationStyle::DRAGGING; + saveCursorPosition(ev); + this->centerTime = ev->getTime(); + } + else if (curmode == NavigationStyle::ZOOMING) { + // OpenSCAD uses vertical mouse position, not horizontal + // this->zoomByCursor(posn, prevnormalized); + float value = (posn[1] - prevnormalized[1]) * 10.0f; + if (this->invertZoom) + value = -value; + zoom(viewer->getSoRenderManager()->getCamera(), value); + processed = true; + } + else if (curmode == NavigationStyle::PANNING) { + float ratio = vp.getViewportAspectRatio(); + panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized); + processed = true; + } + else if (curmode == NavigationStyle::DRAGGING) { + this->addToLog(event->getPosition(), event->getTime()); + this->spin(posn); + moveCursorPosition(); + processed = true; + } + } + + // Spaceball & Joystick handling + if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { + const SoMotion3Event * const event = static_cast(ev); + if (event) + this->processMotionEvent(event); + processed = true; + } + + enum { + BUTTON1DOWN = 1 << 0, + BUTTON3DOWN = 1 << 1, + CTRLDOWN = 1 << 2, + SHIFTDOWN = 1 << 3, + BUTTON2DOWN = 1 << 4 + }; + unsigned int combo = + (this->button1down ? BUTTON1DOWN : 0) | + (this->button2down ? BUTTON2DOWN : 0) | + (this->button3down ? BUTTON3DOWN : 0) | + (this->ctrldown ? CTRLDOWN : 0) | + (this->shiftdown ? SHIFTDOWN : 0); + + switch (combo) { + case 0: + if (curmode == NavigationStyle::SPINNING) { break; } + newmode = NavigationStyle::IDLE; + break; + case BUTTON1DOWN: + if (newmode != NavigationStyle::DRAGGING) + newmode = NavigationStyle::SELECTION; + break; + case BUTTON2DOWN: + newmode = NavigationStyle::PANNING; + break; + case BUTTON3DOWN: + case SHIFTDOWN|BUTTON2DOWN: + case SHIFTDOWN|BUTTON3DOWN: + newmode = NavigationStyle::ZOOMING; + break; + default: + break; + } + + if (newmode != curmode) { + this->setViewingMode(newmode); + } + + // If not handled in this class, pass on upwards in the inheritance + // hierarchy. + if (!processed) + processed = inherited::processSoEvent(ev); + return processed; +} diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index 3d3214962eac..066cb3e6d8e4 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -184,6 +184,7 @@ void Gui::SoFCDB::init() TouchpadNavigationStyle ::init(); GestureNavigationStyle ::init(); OpenCascadeNavigationStyle ::init(); + OpenSCADNavigationStyle ::init(); GLGraphicsItem ::init(); GLFlagWindow ::init();