1
/***************************************************************************
2
* Copyright (c) 2011 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
***************************************************************************/
24
#include "PreCompiled.h"
26
# include <Inventor/nodes/SoCamera.h>
27
# include <QApplication>
30
#include "NavigationStyle.h"
31
#include "SoMouseWheelEvent.h"
32
#include "View3DInventorViewer.h"
37
// ----------------------------------------------------------------------------------
39
/* TRANSLATOR Gui::InventorNavigationStyle */
41
TYPESYSTEM_SOURCE(Gui::InventorNavigationStyle, Gui::UserNavigationStyle)
43
InventorNavigationStyle::InventorNavigationStyle() = default;
45
InventorNavigationStyle::~InventorNavigationStyle() = default;
47
const char* InventorNavigationStyle::mouseButtons(ViewerMode mode)
50
case NavigationStyle::SELECTION:
51
return QT_TR_NOOP("Press CTRL and left mouse button");
52
case NavigationStyle::PANNING:
53
return QT_TR_NOOP("Press middle mouse button");
54
case NavigationStyle::DRAGGING:
55
return QT_TR_NOOP("Press left mouse button");
56
case NavigationStyle::ZOOMING:
57
return QT_TR_NOOP("Scroll middle mouse button");
59
return "No description";
63
std::string InventorNavigationStyle::userFriendlyName() const
65
// do not mark this for translation
66
return "OpenInventor";
69
SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev)
71
// Events when in "ready-to-seek" mode are ignored, except those
72
// which influence the seek mode itself -- these are handled further
73
// up the inheritance hierarchy.
74
if (this->isSeekMode()) {
75
return inherited::processSoEvent(ev);
77
// Switch off viewing mode (Bug #0000911)
78
if (!this->isSeekMode()&& !this->isAnimating() && this->isViewing() )
79
this->setViewing(false); // by default disable viewing mode to render the scene
81
const SoType type(ev->getTypeId());
83
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
84
const SbVec2s pos(ev->getPosition());
85
const SbVec2f posn = normalizePixelPos(pos);
87
const SbVec2f prevnormalized = this->lastmouseposition;
88
this->lastmouseposition = posn;
90
// Set to true if any event processing happened. Note that it is not
91
// necessary to restrict ourselves to only do one "action" for an
92
// event, we only need this flag to see if any processing happened
94
SbBool processed = false;
96
const ViewerMode curmode = this->currentmode;
97
ViewerMode newmode = curmode;
99
// Mismatches in state of the modifier keys happens if the user
100
// presses or releases them outside the viewer window.
101
syncModifierKeys(ev);
103
// give the nodes in the foreground root the chance to handle events (e.g color bar)
104
if (!viewer->isEditing()) {
105
processed = handleEventInForeground(ev);
111
if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
112
auto event = static_cast<const SoKeyboardEvent *>(ev);
113
processed = processKeyboardEvent(event);
116
// Mouse Button / Spaceball Button handling
117
if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
118
const auto event = (const SoMouseButtonEvent *) ev;
119
const int button = event->getButton();
120
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
122
// SoDebugError::postInfo("processSoEvent", "button = %d", button);
124
case SoMouseButtonEvent::BUTTON1:
125
this->button1down = press;
126
if (press && ev->wasShiftDown() &&
127
(this->currentmode != NavigationStyle::SELECTION)) {
128
this->centerTime = ev->getTime();
129
float ratio = vp.getViewportAspectRatio();
130
SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio);
131
this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
132
this->lockrecenter = false;
134
else if (!press && ev->wasShiftDown() &&
135
(this->currentmode != NavigationStyle::SELECTION)) {
136
SbTime tmp = (ev->getTime() - this->centerTime);
137
float dci = (float)QApplication::doubleClickInterval()/1000.0f;
138
// is it just a left click?
139
if (tmp.getValue() < dci && !this->lockrecenter) {
140
if (!this->lookAtPoint(pos)) {
141
panToCenter(panningplane, posn);
142
this->interactiveCountDec();
147
else if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
148
newmode = NavigationStyle::SEEK_MODE;
149
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
151
this->lockrecenter = true;
153
else if (press && (this->currentmode == NavigationStyle::IDLE)) {
154
this->setViewing(true);
156
this->lockrecenter = true;
158
else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
159
this->setViewing(false);
161
this->lockrecenter = true;
163
else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
165
this->lockrecenter = true;
168
processed = processClickEvent(event);
171
case SoMouseButtonEvent::BUTTON2:
172
// If we are in edit mode then simply ignore the RMB events
173
// to pass the event to the base class.
174
this->lockrecenter = true;
176
// Don't show the context menu after dragging, panning or zooming
177
if (!press && (hasDragged || hasPanned || hasZoomed)) {
180
else if (!press && !viewer->isEditing()) {
181
if (this->currentmode != NavigationStyle::ZOOMING &&
182
this->currentmode != NavigationStyle::PANNING &&
183
this->currentmode != NavigationStyle::DRAGGING) {
184
if (this->isPopupMenuEnabled()) {
185
this->openPopupMenu(event->getPosition());
189
this->button2down = press;
191
case SoMouseButtonEvent::BUTTON3:
193
this->centerTime = ev->getTime();
194
float ratio = vp.getViewportAspectRatio();
195
SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio);
196
this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
197
this->lockrecenter = false;
200
SbTime tmp = (ev->getTime() - this->centerTime);
201
float dci = (float)QApplication::doubleClickInterval()/1000.0f;
202
// is it just a middle click?
203
if (tmp.getValue() < dci && !this->lockrecenter) {
204
if (!this->lookAtPoint(pos)) {
205
panToCenter(panningplane, posn);
206
this->interactiveCountDec();
211
this->button3down = press;
218
// Mouse Movement handling
219
if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
220
this->lockrecenter = true;
221
const auto event = (const SoLocation2Event *) ev;
222
if (this->currentmode == NavigationStyle::ZOOMING) {
223
this->zoomByCursor(posn, prevnormalized);
226
else if (this->currentmode == NavigationStyle::PANNING) {
227
float ratio = vp.getViewportAspectRatio();
228
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
231
else if (this->currentmode == NavigationStyle::DRAGGING) {
232
this->addToLog(event->getPosition(), event->getTime());
234
moveCursorPosition();
239
// Spaceball & Joystick handling
240
if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
241
const auto event = static_cast<const SoMotion3Event *>(ev);
243
this->processMotionEvent(event);
248
BUTTON1DOWN = 1 << 0,
249
BUTTON3DOWN = 1 << 1,
255
(this->button1down ? BUTTON1DOWN : 0) |
256
(this->button2down ? BUTTON2DOWN : 0) |
257
(this->button3down ? BUTTON3DOWN : 0) |
258
(this->ctrldown ? CTRLDOWN : 0) |
259
(this->shiftdown ? SHIFTDOWN : 0);
263
if (curmode == NavigationStyle::SPINNING) { break; }
264
newmode = NavigationStyle::IDLE;
266
if (curmode == NavigationStyle::DRAGGING) {
268
newmode = NavigationStyle::SPINNING;
272
if (curmode == NavigationStyle::SELECTION) { break; }
273
if (newmode != NavigationStyle::DRAGGING) {
274
saveCursorPosition(ev);
276
newmode = NavigationStyle::DRAGGING;
279
case CTRLDOWN|SHIFTDOWN:
280
case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN:
281
newmode = NavigationStyle::PANNING;
284
case CTRLDOWN|BUTTON1DOWN:
286
case SHIFTDOWN|BUTTON1DOWN:
287
newmode = NavigationStyle::SELECTION;
289
case BUTTON1DOWN|BUTTON3DOWN:
290
case CTRLDOWN|BUTTON3DOWN:
291
case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
292
newmode = NavigationStyle::ZOOMING;
299
// Process when selection button is pressed together with other buttons that could trigger different actions.
300
if (this->button1down && (this->button2down || this->button3down)) {
304
// Prevent interrupting rubber-band selection in sketcher
305
if (viewer->isEditing() && curmode == NavigationStyle::SELECTION && newmode != NavigationStyle::IDLE) {
306
newmode = NavigationStyle::SELECTION;
310
if (newmode != curmode) {
311
this->setViewingMode(newmode);
314
// If not handled in this class, pass on upwards in the inheritance
316
if (ev->isOfType(SoMouseWheelEvent::getClassTypeId()))
317
processed = inherited::processSoEvent(ev);
318
else if ((curmode == NavigationStyle::SELECTION ||
319
newmode == NavigationStyle::SELECTION ||
320
viewer->isEditing()) && !processed)
321
processed = inherited::processSoEvent(ev);