1
/***************************************************************************
2
* Copyright (c) 2021 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
# include <Inventor/nodes/SoCamera.h>
26
# include <QApplication>
29
#include "NavigationStyle.h"
30
#include "View3DInventorViewer.h"
35
// ----------------------------------------------------------------------------------
37
/* TRANSLATOR Gui::TinkerCADNavigationStyle */
39
TYPESYSTEM_SOURCE(Gui::TinkerCADNavigationStyle, Gui::UserNavigationStyle)
41
TinkerCADNavigationStyle::TinkerCADNavigationStyle() = default;
43
TinkerCADNavigationStyle::~TinkerCADNavigationStyle() = default;
45
const char* TinkerCADNavigationStyle::mouseButtons(ViewerMode mode)
48
case NavigationStyle::SELECTION:
49
return QT_TR_NOOP("Press left mouse button");
50
case NavigationStyle::PANNING:
51
return QT_TR_NOOP("Press middle mouse button");
52
case NavigationStyle::DRAGGING:
53
return QT_TR_NOOP("Press right mouse button");
54
case NavigationStyle::ZOOMING:
55
return QT_TR_NOOP("Scroll middle mouse button");
57
return "No description";
61
SbBool TinkerCADNavigationStyle::processSoEvent(const SoEvent * const ev)
63
// Events when in "ready-to-seek" mode are ignored, except those
64
// which influence the seek mode itself -- these are handled further
65
// up the inheritance hierarchy.
66
if (this->isSeekMode()) {
67
return inherited::processSoEvent(ev);
69
// Switch off viewing mode
70
if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
71
this->setViewing(false); // by default disable viewing mode to render the scene
73
const SoType type(ev->getTypeId());
75
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
76
const SbVec2s pos(ev->getPosition());
77
const SbVec2f posn = normalizePixelPos(pos);
79
const SbVec2f prevnormalized = this->lastmouseposition;
80
this->lastmouseposition = posn;
82
// Set to true if any event processing happened. Note that it is not
83
// necessary to restrict ourselves to only do one "action" for an
84
// event, we only need this flag to see if any processing happened
86
SbBool processed = false;
88
const ViewerMode curmode = this->currentmode;
89
ViewerMode newmode = curmode;
91
// Mismatches in state of the modifier keys happens if the user
92
// presses or releases them outside the viewer window.
95
// give the nodes in the foreground root the chance to handle events (e.g color bar)
96
if (!viewer->isEditing()) {
97
processed = handleEventInForeground(ev);
103
if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
104
const auto event = static_cast<const SoKeyboardEvent *>(ev);
105
processed = processKeyboardEvent(event);
108
// Mouse Button / Spaceball Button handling
109
if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
110
const auto event = (const SoMouseButtonEvent *) ev;
111
const int button = event->getButton();
112
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
115
case SoMouseButtonEvent::BUTTON1:
116
this->button1down = press;
117
if (press && (curmode == NavigationStyle::SEEK_WAIT_MODE)) {
118
newmode = NavigationStyle::SEEK_MODE;
119
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
122
else if (viewer->isEditing() && (curmode == NavigationStyle::SPINNING)) {
126
processed = processClickEvent(event);
129
case SoMouseButtonEvent::BUTTON2:
130
// If we are in edit mode then simply ignore the RMB events
131
// to pass the event to the base class.
132
this->button2down = press;
134
mouseDownConsumedEvent = *event;
135
mouseDownConsumedEvent.setTime(ev->getTime());
138
// About to start rotating
139
if (press && (curmode == NavigationStyle::IDLE)) {
140
// Use this variable to spot move events
141
saveCursorPosition(ev);
142
this->centerTime = ev->getTime();
145
// Don't show the context menu after dragging, panning or zooming
146
else if (!press && (hasDragged || hasPanned || hasZoomed)) {
150
newmode = NavigationStyle::IDLE;
151
if (!viewer->isEditing()) {
152
if (this->currentmode != NavigationStyle::ZOOMING &&
153
this->currentmode != NavigationStyle::PANNING) {
154
if (this->isPopupMenuEnabled()) {
155
this->openPopupMenu(event->getPosition());
162
case SoMouseButtonEvent::BUTTON3:
163
this->button3down = press;
165
this->centerTime = ev->getTime();
166
float ratio = vp.getViewportAspectRatio();
167
SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio);
168
this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
170
else if (curmode == NavigationStyle::PANNING) {
171
newmode = NavigationStyle::IDLE;
180
// Mouse Movement handling
181
if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
182
const auto event = (const SoLocation2Event *) ev;
183
if (curmode == NavigationStyle::PANNING) {
184
float ratio = vp.getViewportAspectRatio();
185
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
188
else if (curmode == NavigationStyle::DRAGGING) {
189
this->addToLog(event->getPosition(), event->getTime());
191
moveCursorPosition();
196
// Spaceball & Joystick handling
197
if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
198
const auto event = static_cast<const SoMotion3Event *>(ev);
200
this->processMotionEvent(event);
205
BUTTON1DOWN = 1 << 0,
206
BUTTON3DOWN = 1 << 1,
212
(this->button1down ? BUTTON1DOWN : 0) |
213
(this->button2down ? BUTTON2DOWN : 0) |
214
(this->button3down ? BUTTON3DOWN : 0) |
215
(this->ctrldown ? CTRLDOWN : 0) |
216
(this->shiftdown ? SHIFTDOWN : 0);
220
if (curmode == NavigationStyle::SPINNING) { break; }
221
newmode = NavigationStyle::IDLE;
224
newmode = NavigationStyle::SELECTION;
227
if (newmode != NavigationStyle::DRAGGING) {
228
saveCursorPosition(ev);
230
newmode = NavigationStyle::DRAGGING;
233
newmode = NavigationStyle::PANNING;
239
// Process when selection button is pressed together with other buttons that could trigger different actions.
240
if (this->button1down && (this->button2down || this->button3down)) {
244
// Prevent interrupting rubber-band selection in sketcher
245
if (viewer->isEditing() && curmode == NavigationStyle::SELECTION && newmode != NavigationStyle::IDLE) {
246
newmode = NavigationStyle::SELECTION;
250
if (newmode != curmode) {
251
this->setViewingMode(newmode);
254
// If not handled in this class, pass on upwards in the inheritance
257
processed = inherited::processSoEvent(ev);