FreeCAD

Форк
0
/
MayaGestureNavigationStyle.cpp 
624 строки · 29.2 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2015 Victor Titov (DeepSOIC) <vv.titov@gmail.com>       *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************
22
 *                                                                         *
23
 *   Minor modifications made by Pablo Gil (pablogil) in order to create   *
24
 *   a Maya or Unity 3D mouse navigation style:                            *
25
 *         ALT + left mouse button    = orbit                              *
26
 *         ALT + right mouse button   = zoom                               *
27
 *         ALT + middle mouse button  = pan                                *
28
 *                                                                         *
29
 *   Thanks Victor for your help!                                          *
30
 *                                                                         *
31
 ***************************************************************************/
32

33
/*
34
 *A few notes on this style. (by DeepSOIC)
35
 *
36
 * In this style, LMB serves dual purpose. It is selecting objects, as well as
37
 * spinning the view. The trick that enables it is as follows: The mousedown
38
 * event is consumed an saved, but otherwise remains unprocessed. If a drag is
39
 * detected while the button is down, the event is finally consumed (the saved
40
 * one is discarded), and spinning starts. If there is no drag detected before
41
 * the button is released, the saved mousedown is propagated to inherited,
42
 * followed by the mouseup. The same trick is used for RMB, so up to two
43
 * mousedown can be postponed.
44
 *
45
 * This navigation style does not exactly follow the structure of other
46
 * navigation styles, it does not fill many of the global variables defined in
47
 * NavigationStyle.
48
 *
49
 * This mode does not support locking cursor position on screen when
50
 * navigating, since with absolute pointing devices like pen and touch it makes
51
 * no sense (this style was specifically crafted for such devices).
52
 *
53
 * In this style, setViewing is not used (because I could not figure out how to
54
 * use it properly, and it seems to just work without it).
55
 *
56
 * This style wasn't tested with space during development (I don't have one).
57
 */
58

59
#include "PreCompiled.h"
60
#ifndef _PreComp_
61
# include <QApplication>
62
#endif
63

64
#include <Base/Console.h>
65

66
#include "NavigationStyle.h"
67
#include "SoTouchEvents.h"
68
#include "View3DInventorViewer.h"
69

70

71
using namespace Gui;
72

73
// ----------------------------------------------------------------------------------
74

75
/* TRANSLATOR Gui::MayaGestureNavigationStyle */
76

77
TYPESYSTEM_SOURCE(Gui::MayaGestureNavigationStyle, Gui::UserNavigationStyle)
78

79
MayaGestureNavigationStyle::MayaGestureNavigationStyle()
80
{
81
    mouseMoveThreshold = QApplication::startDragDistance();
82
    mouseMoveThresholdBroken = false;
83
    mousedownConsumedCount = 0;
84
    thisClickIsComplex = false;
85
    inGesture = false;
86
}
87

88
MayaGestureNavigationStyle::~MayaGestureNavigationStyle() = default;
89

90
const char* MayaGestureNavigationStyle::mouseButtons(ViewerMode mode)
91
{
92
    switch (mode) {
93
    case NavigationStyle::SELECTION:
94
        return QT_TR_NOOP("Tap OR click left mouse button.");
95
    case NavigationStyle::PANNING:
96
        return QT_TR_NOOP("Drag screen with two fingers OR press ALT + middle mouse button.");
97
    case NavigationStyle::DRAGGING:
98
        return QT_TR_NOOP("Drag screen with one finger OR press ALT + left mouse button. In Sketcher and other edit modes, hold Alt in addition.");
99
    case NavigationStyle::ZOOMING:
100
        return QT_TR_NOOP("Pinch (place two fingers on the screen and drag them apart from or towards each other) OR scroll middle mouse button OR press ALT + right mouse button OR PgUp/PgDown on keyboard.");
101
    default:
102
        return "No description";
103
    }
104
}
105

106
/*!
107
 * \brief MayaGestureNavigationStyle::testMoveThreshold tests if the mouse has moved far enough to constder it a drag.
108
 * \param currentPos current position of mouse cursor, in local pixel coordinates.
109
 * \return true if the mouse was moved far enough. False if it's within the boundary. Ignores MayaGestureNavigationStyle::mouseMoveThresholdBroken flag.
110
 */
111
bool MayaGestureNavigationStyle::testMoveThreshold(const SbVec2s currentPos) const {
112
    SbVec2s movedBy = currentPos - this->mousedownPos;
113
    return SbVec2f(movedBy).length() >= this->mouseMoveThreshold;
114
}
115

116
SbBool MayaGestureNavigationStyle::processSoEvent(const SoEvent * const ev)
117
{
118
    // Events when in "ready-to-seek" mode are ignored, except those
119
    // which influence the seek mode itself -- these are handled further
120
    // up the inheritance hierarchy.
121
    if (this->isSeekMode()) {
122
        return inherited::processSoEvent(ev);
123
    }
124
    // Switch off viewing mode (Bug #0000911)
125
    if (!this->isSeekMode()&& !this->isAnimating() && this->isViewing() )
126
        this->setViewing(false); // by default disable viewing mode to render the scene
127
    //setViewing() is never used in this style, so the previous if is very unlikely to be hit.
128

129
    const SoType type(ev->getTypeId());
130
    //define some shortcuts...
131
    bool evIsButton = type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId());
132
    bool evIsKeyboard = type.isDerivedFrom(SoKeyboardEvent::getClassTypeId());
133
    bool evIsLoc2 = type.isDerivedFrom(SoLocation2Event::getClassTypeId());//mouse movement
134
    bool evIsLoc3 = type.isDerivedFrom(SoMotion3Event::getClassTypeId());//spaceball/joystick movement
135
    bool evIsGesture = type.isDerivedFrom(SoGestureEvent::getClassTypeId());//touchscreen gesture
136

137
    const SbVec2f prevnormalized = this->lastmouseposition;
138
    const SbVec2s pos(ev->getPosition());//not valid for gestures
139
    const SbVec2f posn = this->normalizePixelPos(pos);
140
    //pos: local coordinates of event, in pixels
141
    //posn: normalized local coordinates of event ((0,0) = lower left corner, (1,1) = upper right corner)
142
    float ratio = viewer->getSoRenderManager()->getViewportRegion().getViewportAspectRatio();
143

144
    if (evIsButton || evIsLoc2){
145
        this->lastmouseposition = posn;
146
    }
147

148
    const ViewerMode curmode = this->currentmode;
149
    //ViewerMode newmode = curmode;
150

151
    //make a unified mouse+modifiers state value (combo)
152
    enum {
153
        BUTTON1DOWN = 1 << 0,
154
        BUTTON2DOWN = 1 << 1,
155
        BUTTON3DOWN = 1 << 2,
156
        CTRLDOWN =    1 << 3,
157
        SHIFTDOWN =   1 << 4,
158
        ALTDOWN =     1 << 5,
159
        MASKBUTTONS = BUTTON1DOWN | BUTTON2DOWN | BUTTON3DOWN,
160
        MASKMODIFIERS = CTRLDOWN | SHIFTDOWN | ALTDOWN
161
    };
162
    unsigned int comboBefore = //before = state before this event
163
        (this->button1down ? BUTTON1DOWN : 0) |
164
        (this->button2down ? BUTTON2DOWN : 0) |
165
        (this->button3down ? BUTTON3DOWN : 0) |
166
        (this->ctrldown ? CTRLDOWN : 0) |
167
        (this->shiftdown ? SHIFTDOWN : 0) |
168
        (this->altdown ? ALTDOWN : 0);
169

170
    //test for complex clicks
171
    int cntMBBefore = (comboBefore & BUTTON1DOWN ? 1 : 0 ) //cntMBBefore = how many buttons were down when this event arrived?
172
                  +(comboBefore & BUTTON2DOWN ? 1 : 0 )
173
                  +(comboBefore & BUTTON3DOWN ? 1 : 0 );
174
    if (cntMBBefore>=2) this->thisClickIsComplex = true;
175
    if (cntMBBefore==0) {//a good chance to reset some click-related stuff
176
        this->thisClickIsComplex = false;
177
        this->mousedownConsumedCount = 0;//shouldn't be necessary, just a fail-safe.
178
    }
179

180
    // Mismatches in state of the modifier keys happens if the user
181
    // presses or releases them outside the viewer window.
182
    syncModifierKeys(ev);
183
    //before this block, mouse button states in NavigationStyle::buttonXdown reflected those before current event arrived.
184
    //track mouse button states
185
    if (evIsButton) {
186
        auto const event = (const SoMouseButtonEvent *) ev;
187
        const int button = event->getButton();
188
        const SbBool press //the button was pressed (if false -> released)
189
                = event->getState() == SoButtonEvent::DOWN ? true : false;
190
        switch (button) {
191
        case SoMouseButtonEvent::BUTTON1:
192
            this->button1down = press;
193
            break;
194
        case SoMouseButtonEvent::BUTTON2:
195
            this->button2down = press;
196
            break;
197
        case SoMouseButtonEvent::BUTTON3:
198
            this->button3down = press;
199
            break;
200
        //whatever else, we don't track
201
        }
202
    }
203
    //after this block, the new states of the buttons are already in.
204

205
    unsigned int comboAfter = //after = state after this event (current, essentially)
206
        (this->button1down ? BUTTON1DOWN : 0) |
207
        (this->button2down ? BUTTON2DOWN : 0) |
208
        (this->button3down ? BUTTON3DOWN : 0) |
209
        (this->ctrldown ? CTRLDOWN : 0) |
210
        (this->shiftdown ? SHIFTDOWN : 0) |
211
        (this->altdown ? ALTDOWN : 0);
212

213
    //test for complex clicks (again)
214
    int cntMBAfter = (comboAfter & BUTTON1DOWN ? 1 : 0 ) //cntMBAfter = how many buttons were down when this event arrived?
215
                  +(comboAfter & BUTTON2DOWN ? 1 : 0 )
216
                  +(comboAfter & BUTTON3DOWN ? 1 : 0 );
217
    if (cntMBAfter>=2) this->thisClickIsComplex = true;
218
    //if (cntMBAfter==0) this->thisClickIsComplex = false;//don't reset the flag now, we need to know that this mouseUp was an end of a click that was complex. The flag will reset by the before-check in the next event.
219

220
    //test for move detection
221
    if (evIsLoc2 || evIsButton){
222
        this->mouseMoveThresholdBroken |= this->testMoveThreshold(pos);
223
    }
224

225
    //track gestures
226
    if (evIsGesture) {
227
        auto gesture = static_cast<const SoGestureEvent*>(ev);
228
        switch(gesture->state) {
229
        case SoGestureEvent::SbGSStart:
230
            //assert(!inGesture);//start of another gesture before the first finished? Happens all the time for Pan gesture... No idea why!  --DeepSOIC
231
            inGesture = true;
232
        break;
233
        case SoGestureEvent::SbGSUpdate:
234
            assert(inGesture);//gesture update without start?
235
            inGesture = true;
236
        break;
237
        case SoGestureEvent::SbGSEnd:
238
            assert(inGesture);//gesture ended without starting?
239
            inGesture = false;
240
        break;
241
        case SoGestureEvent::SbGsCanceled:
242
            assert(inGesture);//gesture canceled without starting?
243
            inGesture=false;
244
        break;
245
        default:
246
            assert(0);//shouldn't happen
247
            inGesture = false;
248
        }
249
    }
250
    if (evIsButton) {
251
        if(inGesture){
252
            inGesture = false;//reset the flag when mouse clicks are received, to ensure enabling mouse navigation back.
253
            setViewingMode(NavigationStyle::SELECTION);//exit navigation asap, to proceed with regular processing of the click
254
        }
255
    }
256

257
    bool suppressLMBDrag = false;
258
    if(viewer->isEditing()){
259
        //in edit mode, disable lmb dragging (spinning). Holding Alt enables it.
260
        suppressLMBDrag = !(comboAfter & ALTDOWN);
261
    }
262

263
    //----------all this were preparations. Now comes the event handling! ----------
264

265
    SbBool processed = false;//a return value for the  BlahblahblahNavigationStyle::processSoEvent
266
    bool propagated = false;//an internal flag indicating that the event has been already passed to inherited, to suppress the automatic doing of this at the end.
267
    //goto finalize = return processed. Might be important to do something before done (none now).
268

269
    // give the nodes in the foreground root the chance to handle events (e.g color bar)
270
    if (!viewer->isEditing()) {
271
        processed = handleEventInForeground(ev);
272
    }
273
    if (processed)
274
        goto finalize;
275

276
    // Mode-independent keyboard handling
277
    if (evIsKeyboard) {
278
        auto const event = (const SoKeyboardEvent *) ev;
279
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
280
        switch (event->getKey()) {
281
        case SoKeyboardEvent::H:
282
            processed = true;
283
            if(!press){
284
                SbBool ret = NavigationStyle::lookAtPoint(event->getPosition());
285
                if(!ret){
286
                    this->interactiveCountDec();
287
                    Base::Console().Log(
288
                        "No object under cursor! Can't set new center of rotation.\n");
289
                }
290
            }
291
            break;
292
        default:
293
            break;
294
        }
295
    }
296
    if (processed)
297
        goto finalize;
298

299
    //mode-independent spaceball/joystick handling
300
    if (evIsLoc3) {
301
        auto const event = static_cast<const SoMotion3Event *>(ev);
302
        if (event)
303
            this->processMotionEvent(event);
304
        processed = true;
305
    }
306
    if (processed)
307
        goto finalize;
308

309
    //all mode-dependent stuff is within this switch.
310
    switch(curmode){
311
    case NavigationStyle::SELECTION:
312
        // Prevent interrupting rubber-band selection in sketcher
313
        if (viewer->isEditing()) {
314
            if (evIsButton) {
315
                auto const event = (const SoMouseButtonEvent*)ev;
316
                const SbBool press = event->getState() == SoButtonEvent::DOWN;
317
                const int button = event->getButton();
318

319
                if (!press && button == SoMouseButtonEvent::BUTTON1) {
320
                    setViewingMode(NavigationStyle::IDLE);
321
                    break;
322
                }
323
            }
324

325
            if (this->button1down) {
326
                break;
327
            }
328
        }
329
        [[fallthrough]];
330
    case NavigationStyle::IDLE:
331
        // Prevent interrupting rubber-band selection in sketcher
332
        if (viewer->isEditing()) {
333
            if (evIsButton) {
334
                auto const event = (const SoMouseButtonEvent*)ev;
335
                const SbBool press = event->getState() == SoButtonEvent::DOWN;
336
                const int button = event->getButton();
337

338
                if (press && button == SoMouseButtonEvent::BUTTON1 && !this->altdown) {
339
                    setViewingMode(NavigationStyle::SELECTION);
340
                    break;
341
                }
342
            }
343
        }
344
        [[fallthrough]];
345
    case NavigationStyle::INTERACT: {
346
        //idle and interaction
347

348
        //keyboard
349
        if (evIsKeyboard) {
350
            auto const event = (const SoKeyboardEvent *) ev;
351
            const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
352

353
            switch(event->getKey()){
354
            case SoKeyboardEvent::S:
355
            case SoKeyboardEvent::HOME:
356
            case SoKeyboardEvent::LEFT_ARROW:
357
            case SoKeyboardEvent::UP_ARROW:
358
            case SoKeyboardEvent::RIGHT_ARROW:
359
            case SoKeyboardEvent::DOWN_ARROW:
360
                processed = inherited::processSoEvent(ev);
361
                propagated = true;
362
                break;
363
            case SoKeyboardEvent::PAGE_UP:
364
                if(press){
365
                    doZoom(viewer->getSoRenderManager()->getCamera(), getDelta(), posn);
366
                }
367
                processed = true;
368
                break;
369
            case SoKeyboardEvent::PAGE_DOWN:
370
                if(press){
371
                    doZoom(viewer->getSoRenderManager()->getCamera(), -getDelta(), posn);
372
                }
373
                processed = true;
374
                break;
375
            default:
376
                break;
377
            }//switch key
378
        }
379
        if (processed)
380
            goto finalize;
381

382

383
        // Mouse Button / Spaceball Button handling
384
        if (evIsButton) {
385
            auto const event = (const SoMouseButtonEvent *) ev;
386
            const int button = event->getButton();
387
            const SbBool press //the button was pressed (if false -> released)
388
                    = event->getState() == SoButtonEvent::DOWN ? true : false;
389
            switch(button){
390
            case SoMouseButtonEvent::BUTTON1:
391
            case SoMouseButtonEvent::BUTTON2:
392
                if(press){
393
                    if(this->thisClickIsComplex && this->mouseMoveThresholdBroken){
394
                        //this should prevent re-attempts to enter navigation when doing more clicks after a move.
395
                    } else {
396
                        //on LMB-down or RMB-down, we don't know yet if we should propagate it or process it. Save the event to be refired later, when it becomes clear.
397
                        //reset/start move detection machine
398
                        this->mousedownPos = pos;
399
                        this->mouseMoveThresholdBroken = false;
400
                        pan(viewer->getSoRenderManager()->getCamera());//set up panningplane
401
                        int &cnt = this->mousedownConsumedCount;
402
                        this->mousedownConsumedEvents[cnt] = *event;//hopefully, a shallow copy is enough. There are no pointers stored in events, apparently. Will lose a subclass, though.
403
                        cnt++;
404
                        assert(cnt<=2);
405
                        if(cnt>static_cast<int>(sizeof(mousedownConsumedEvents))){
406
                            cnt=sizeof(mousedownConsumedEvents);//we are in trouble
407
                        }
408
                        processed = true;//just consume this event, and wait for the move threshold to be broken to start dragging/panning
409
                    }
410
                } else {//release
411
                    if (button == SoMouseButtonEvent::BUTTON2 && !this->thisClickIsComplex) {
412
                        if (!viewer->isEditing() && this->isPopupMenuEnabled()) {
413
                            processed=true;
414
                            this->openPopupMenu(event->getPosition());
415
                        }
416
                    }
417
                    if(! processed) {
418
                        //re-synthesize all previously-consumed mouseDowns, if any. They might have been re-synthesized already when threshold was broken.
419
                        for( int i=0;   i < this->mousedownConsumedCount;   i++ ){
420
                            inherited::processSoEvent(& (this->mousedownConsumedEvents[i]));//simulate the previously-comsumed mousedown.
421
                        }
422
                        this->mousedownConsumedCount = 0;
423
                        processed = inherited::processSoEvent(ev);//explicitly, just for clarity that we are sending a full click sequence.
424
                        propagated = true;
425
                    }
426
                }
427
                break;
428
            case SoMouseButtonEvent::BUTTON3://press the wheel
429
                // starts PANNING mode
430
                if(press & this->altdown){
431
                    setViewingMode(NavigationStyle::PANNING);
432
                } else if(press){
433
                    // if not PANNING then look at point
434
                    SbBool ret = NavigationStyle::lookAtPoint(event->getPosition());
435
                    if(!ret){
436
                        this->interactiveCountDec();
437
                        Base::Console().Log(
438
                            "No object under cursor! Can't set new center of rotation.\n");
439
                    }
440
                }
441
                processed = true;
442
                break;
443
            }
444
        }
445

446
        //mouse moves - test for move threshold breaking
447
        if (evIsLoc2) {
448
            if (this->mouseMoveThresholdBroken && (this->button1down || this->button2down) && mousedownConsumedCount > 0) {
449
                //mousemovethreshold has JUST been broken
450

451
                //test if we should enter navigation
452
                if ((this->button1down && !suppressLMBDrag && this->altdown) || (this->button2down && this->altdown)) {
453
                    //yes, we are entering navigation.
454
                    //throw away consumed mousedowns.
455
                    this->mousedownConsumedCount = 0;
456

457
                    // start DRAGGING mode (orbit)
458
                    // if not pressing left mouse button then it assumes is right mouse button and starts ZOOMING mode
459
                    setRotationCenter(getFocalPoint());
460
                    setViewingMode(this->button1down ? NavigationStyle::DRAGGING : NavigationStyle::ZOOMING);
461
                    processed = true;
462
                } else {
463
                    //no, we are not entering navigation.
464
                    //re-synthesize all previously-consumed mouseDowns, if any, and propagate this mousemove.
465
                    for( int i=0;   i < this->mousedownConsumedCount;   i++ ){
466
                        inherited::processSoEvent(& (this->mousedownConsumedEvents[i]));//simulate the previously-comsumed mousedown.
467
                    }
468
                    this->mousedownConsumedCount = 0;
469
                    processed = inherited::processSoEvent(ev);//explicitly, just for clarity that we are sending a full click sequence.
470
                    propagated = true;
471
                }
472
            }
473
            if (mousedownConsumedCount  > 0)
474
                processed = true;//if we are still deciding if it's a drag or not, consume mouseMoves.
475
        }
476

477
        //gesture start
478
        if (evIsGesture && /*!this->button1down &&*/ !this->button2down){//ignore gestures when mouse buttons are down. Button1down check was disabled because of wrong state after doubleclick on sketcher constraint to edit datum
479
            auto gesture = static_cast<const SoGestureEvent*>(ev);
480
            if (gesture->state == SoGestureEvent::SbGSStart
481
                    || gesture->state == SoGestureEvent::SbGSUpdate) {//even if we didn't get a start, assume the first update is a start (sort-of fail-safe).
482
                if (type.isDerivedFrom(SoGesturePanEvent::getClassTypeId())) {
483
                    pan(viewer->getSoRenderManager()->getCamera());//set up panning plane
484
                    setViewingMode(NavigationStyle::PANNING);
485
                    processed = true;
486
                } else if (type.isDerivedFrom(SoGesturePinchEvent::getClassTypeId())) {
487
                    pan(viewer->getSoRenderManager()->getCamera());//set up panning plane
488
                    setRotationCenter(getFocalPoint());
489
                    setViewingMode(NavigationStyle::DRAGGING);
490
                    processed = true;
491
                } //all other gestures - ignore!
492
            }
493
        }
494

495
        //loc2 (mousemove) - ignore.
496

497
    } break;//end of idle and interaction
498
    case NavigationStyle::DRAGGING:
499
    case NavigationStyle::ZOOMING:
500
    case NavigationStyle::PANNING:{
501
        //actual navigation
502

503
        //no keyboard.
504

505
        // Mouse Button / Spaceball Button handling
506
        if (evIsButton) {
507
            auto const event = (const SoMouseButtonEvent *) ev;
508
            const int button = event->getButton();
509
            switch(button){
510
                case SoMouseButtonEvent::BUTTON1:
511
                case SoMouseButtonEvent::BUTTON2:
512
                case SoMouseButtonEvent::BUTTON3: // allows to release button3 into SELECTION mode
513
                    if(comboAfter & BUTTON1DOWN || comboAfter & BUTTON2DOWN) {
514
                        //don't leave navigation till all buttons have been released
515
                        setRotationCenter(getFocalPoint());
516
                        setViewingMode((comboAfter & BUTTON1DOWN) ? NavigationStyle::DRAGGING : NavigationStyle::PANNING);
517
                        processed = true;
518
                    } else { //all buttons are released
519
                        //end of dragging/panning/whatever
520
                        setViewingMode(NavigationStyle::SELECTION);
521
                        processed = true;
522
                    } //end of else (some buttons down)
523
                break;
524
            } //switch(button)
525
        } //if(evIsButton)
526

527
        //the essence part 1!
528
        //mouse movement into camera motion. Suppress if in gesture. Ignore until threshold is surpassed.
529
        if (evIsLoc2 && ! this->inGesture && this->mouseMoveThresholdBroken) {
530
            if (curmode == NavigationStyle::ZOOMING) {//doesn't happen
531
                this->zoomByCursor(posn, prevnormalized);
532
                processed = true;
533
            } else if (curmode == NavigationStyle::PANNING) {
534
                panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
535
                processed = true;
536
            } else if (curmode == NavigationStyle::DRAGGING) {
537
                if (comboAfter & BUTTON1DOWN && comboAfter & BUTTON2DOWN) {
538
                    //two mouse buttons down - tilting!
539
                    NavigationStyle::doRotate(viewer->getSoRenderManager()->getCamera(),
540
                                              (posn - prevnormalized)[0]*(-2),
541
                                              SbVec2f(0.5,0.5));
542
                    processed = true;
543
                } else {//one mouse button - normal spinning
544
                    //this will also handle the single-finger drag (there's no gesture used, pseudomouse is enough)
545
                    //this->addToLog(event->getPosition(), event->getTime());
546
                    this->spin_simplified(viewer->getSoRenderManager()->getCamera(),
547
                                          posn, prevnormalized);
548
                    processed = true;
549
                }
550
            }
551
        }
552

553
        //the essence part 2!
554
        //gesture into camera motion
555
        if (evIsGesture){
556
            auto gesture = static_cast<const SoGestureEvent*>(ev);
557
            assert(gesture);
558
            if (gesture->state == SoGestureEvent::SbGSEnd) {
559
                setViewingMode(NavigationStyle::SELECTION);
560
                processed=true;
561
            } else if (gesture->state == SoGestureEvent::SbGSUpdate){
562
                if(type.isDerivedFrom(SoGesturePinchEvent::getClassTypeId())){
563
                    auto const event = static_cast<const SoGesturePinchEvent*>(ev);
564
                    if (this->zoomAtCursor){
565
                        //this is just dealing with the pan part of pinch gesture. Taking care of zooming to pos is done in doZoom.
566
                        SbVec2f panDist = this->normalizePixelPos(event->deltaCenter.getValue());
567
                        NavigationStyle::panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, panDist, SbVec2f(0,0));
568
                    }
569
                    NavigationStyle::doZoom(viewer->getSoRenderManager()->getCamera(),-logf(event->deltaZoom),this->normalizePixelPos(event->curCenter));
570
                    if (event->deltaAngle != 0)
571
                        NavigationStyle::doRotate(viewer->getSoRenderManager()->getCamera(),event->deltaAngle,this->normalizePixelPos(event->curCenter));
572
                    processed = true;
573
                }
574
                if(type.isDerivedFrom(SoGesturePanEvent::getClassTypeId())){
575
                    auto const event = static_cast<const SoGesturePanEvent*>(ev);
576
                        //this is just dealing with the pan part of pinch gesture. Taking care of zooming to pos is done in doZoom.
577
                    SbVec2f panDist = this->normalizePixelPos(event->deltaOffset);
578
                    NavigationStyle::panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, panDist, SbVec2f(0,0));
579
                    processed = true;
580
                }
581
            } else {
582
                //shouldn't happen. Gestures are not expected to start in the middle of navigation.
583
                //we'll consume it, without reacting.
584
                processed=true;
585
            }
586
        }
587

588
    } break;//end of actual navigation
589
    case NavigationStyle::SEEK_WAIT_MODE:{
590
        if (evIsButton) {
591
            auto const event = (const SoMouseButtonEvent *) ev;
592
            const int button = event->getButton();
593
            const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
594
            if (button == SoMouseButtonEvent::BUTTON1 && press) {
595
                this->seekToPoint(pos); // implicitly calls interactiveCountInc()
596
                this->setViewingMode(NavigationStyle::SEEK_MODE);
597
                processed = true;
598
            }
599
        }
600
    } ; //not end of SEEK_WAIT_MODE. Fall through by design!!!
601
        /* FALLTHRU */
602
    case NavigationStyle::SPINNING:
603
    case NavigationStyle::SEEK_MODE: {
604
        //animation modes
605
        if (!processed) {
606
            if (evIsButton || evIsGesture || evIsKeyboard || evIsLoc3)
607
                setViewingMode(NavigationStyle::SELECTION);
608
        }
609
    } break; //end of animation modes
610
    case NavigationStyle::BOXZOOM:
611
    default:
612
        //all the rest - will be pass on to inherited, later.
613
        break;
614
    }
615

616
    if (! processed && ! propagated) {
617
        processed = inherited::processSoEvent(ev);
618
        propagated = true;
619
    }
620

621
    //-----------------------end of event handling---------------------
622
finalize:
623
    return processed;
624
}
625

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.