1
/***************************************************************************
2
* Copyright (c) 2012 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 <QApplication>
28
#include "NavigationStyle.h"
29
#include "View3DInventorViewer.h"
34
// ----------------------------------------------------------------------------------
36
/* TRANSLATOR Gui::TouchpadNavigationStyle */
38
TYPESYSTEM_SOURCE(Gui::TouchpadNavigationStyle, Gui::UserNavigationStyle)
40
TouchpadNavigationStyle::TouchpadNavigationStyle() = default;
42
TouchpadNavigationStyle::~TouchpadNavigationStyle() = default;
44
const char* TouchpadNavigationStyle::mouseButtons(ViewerMode mode)
47
case NavigationStyle::SELECTION:
48
return QT_TR_NOOP("Press left mouse button");
49
case NavigationStyle::PANNING:
50
return QT_TR_NOOP("Press SHIFT button");
51
case NavigationStyle::DRAGGING:
52
return QT_TR_NOOP("Press ALT button");
53
case NavigationStyle::ZOOMING:
54
return QT_TR_NOOP("Press CTRL and SHIFT buttons");
56
return "No description";
60
SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev)
62
// Events when in "ready-to-seek" mode are ignored, except those
63
// which influence the seek mode itself -- these are handled further
64
// up the inheritance hierarchy.
65
if (this->isSeekMode()) {
66
return inherited::processSoEvent(ev);
68
// Switch off viewing mode (Bug #0000911)
69
if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
70
this->setViewing(false); // by default disable viewing mode to render the scene
72
const SoType type(ev->getTypeId());
74
const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
75
const SbVec2s pos(ev->getPosition());
76
const SbVec2f posn = normalizePixelPos(pos);
78
const SbVec2f prevnormalized = this->lastmouseposition;
79
this->lastmouseposition = posn;
81
// Set to true if any event processing happened. Note that it is not
82
// necessary to restrict ourselves to only do one "action" for an
83
// event, we only need this flag to see if any processing happened
85
SbBool processed = false;
87
const ViewerMode curmode = this->currentmode;
88
ViewerMode newmode = curmode;
90
// Mismatches in state of the modifier keys happens if the user
91
// presses or releases them outside the viewer window.
94
// give the nodes in the foreground root the chance to handle events (e.g color bar)
95
if (!viewer->isEditing()) {
96
processed = handleEventInForeground(ev);
102
if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
103
const auto event = static_cast<const SoKeyboardEvent *>(ev);
104
processed = processKeyboardEvent(event);
107
// Mouse Button / Spaceball Button handling
108
if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
109
const auto event = (const SoMouseButtonEvent *) ev;
110
const int button = event->getButton();
111
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
113
// SoDebugError::postInfo("processSoEvent", "button = %d", button);
115
case SoMouseButtonEvent::BUTTON1:
116
this->lockrecenter = true;
117
this->button1down = press;
118
if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
119
newmode = NavigationStyle::SEEK_MODE;
120
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
123
else if (press && (this->currentmode == NavigationStyle::PANNING ||
124
this->currentmode == NavigationStyle::ZOOMING)) {
125
newmode = NavigationStyle::DRAGGING;
126
saveCursorPosition(ev);
127
this->centerTime = ev->getTime();
130
else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
134
processed = processClickEvent(event);
137
case SoMouseButtonEvent::BUTTON2:
138
// If we are in edit mode then simply ignore the RMB events
139
// to pass the event to the base class.
140
this->lockrecenter = true;
142
// Don't show the context menu after dragging, panning or zooming
143
if (!press && (hasDragged || hasPanned || hasZoomed)) {
146
else if (!press && !viewer->isEditing()) {
147
if (this->currentmode != NavigationStyle::ZOOMING &&
148
this->currentmode != NavigationStyle::PANNING &&
149
this->currentmode != NavigationStyle::DRAGGING) {
150
if (this->isPopupMenuEnabled()) {
151
this->openPopupMenu(event->getPosition());
155
// Alternative way of rotating & zooming
156
if (press && (this->currentmode == NavigationStyle::PANNING ||
157
this->currentmode == NavigationStyle::ZOOMING)) {
158
newmode = NavigationStyle::DRAGGING;
159
saveCursorPosition(ev);
160
this->centerTime = ev->getTime();
163
this->button2down = press;
170
// Mouse Movement handling
171
if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
172
this->lockrecenter = true;
173
const auto event = (const SoLocation2Event *) ev;
174
if (this->currentmode == NavigationStyle::ZOOMING) {
175
this->zoomByCursor(posn, prevnormalized);
178
else if (this->currentmode == NavigationStyle::PANNING) {
179
float ratio = vp.getViewportAspectRatio();
180
panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
183
else if (this->currentmode == NavigationStyle::DRAGGING) {
184
this->addToLog(event->getPosition(), event->getTime());
186
moveCursorPosition();
191
// Spaceball & Joystick handling
192
if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
193
const auto event = static_cast<const SoMotion3Event *>(ev);
195
this->processMotionEvent(event);
200
BUTTON1DOWN = 1 << 0,
201
BUTTON2DOWN = 1 << 1,
207
(this->button1down ? BUTTON1DOWN : 0) |
208
(this->button2down ? BUTTON2DOWN : 0) |
209
(this->ctrldown ? CTRLDOWN : 0) |
210
(this->shiftdown ? SHIFTDOWN : 0) |
211
(this->altdown ? ALTDOWN : 0);
215
if (curmode == NavigationStyle::SPINNING) { break; }
216
newmode = NavigationStyle::IDLE;
219
// make sure not to change the selection when stopping spinning
220
if (curmode == NavigationStyle::SPINNING)
221
newmode = NavigationStyle::IDLE;
223
newmode = NavigationStyle::SELECTION;
226
newmode = NavigationStyle::IDLE;
229
// Shift + left mouse click enables dragging.
230
// If the mouse is released the event should not be forwarded to the base
231
// class that eventually performs a selection.
232
if (newmode == NavigationStyle::DRAGGING) {
235
newmode = NavigationStyle::PANNING;
238
if (newmode != NavigationStyle::DRAGGING) {
239
saveCursorPosition(ev);
241
newmode = NavigationStyle::DRAGGING;
243
case CTRLDOWN|SHIFTDOWN:
244
case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN:
245
// Left mouse button doesn't change the zoom
246
// behaviour but when pressing or releasing it then do not forward the
247
// event to the base class that eventually performs a selection.
248
if (newmode == NavigationStyle::ZOOMING) {
251
newmode = NavigationStyle::ZOOMING;
257
// Process when selection button is pressed together with other buttons that could trigger different actions.
258
if (this->button1down && (this->button2down || this->button3down || this->altdown)) {
262
// Prevent interrupting rubber-band selection in sketcher
263
if (viewer->isEditing() && curmode == NavigationStyle::SELECTION && newmode != NavigationStyle::IDLE) {
264
newmode = NavigationStyle::SELECTION;
268
if (newmode != curmode) {
269
this->setViewingMode(newmode);
272
// If not handled in this class, pass on upwards in the inheritance
275
processed = inherited::processSoEvent(ev);