| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <QApplication> |
| |
|
| |
|
| | #include <Base/Console.h> |
| |
|
| | #include "Navigation/NavigationStyle.h" |
| | #include "SoTouchEvents.h" |
| | #include "View3DInventorViewer.h" |
| |
|
| |
|
| | using namespace Gui; |
| |
|
| | |
| |
|
| | |
| |
|
| | TYPESYSTEM_SOURCE(Gui::MayaGestureNavigationStyle, Gui::UserNavigationStyle) |
| |
|
| | MayaGestureNavigationStyle::MayaGestureNavigationStyle() |
| | { |
| | mouseMoveThreshold = QApplication::startDragDistance(); |
| | mouseMoveThresholdBroken = false; |
| | mousedownConsumedCount = 0; |
| | thisClickIsComplex = false; |
| | inGesture = false; |
| | } |
| |
|
| | MayaGestureNavigationStyle::~MayaGestureNavigationStyle() = default; |
| |
|
| | const char* MayaGestureNavigationStyle::mouseButtons(ViewerMode mode) |
| | { |
| | switch (mode) { |
| | case NavigationStyle::SELECTION: |
| | return QT_TR_NOOP("Tap OR click left mouse button."); |
| | case NavigationStyle::PANNING: |
| | return QT_TR_NOOP("Drag screen with two fingers OR press Alt + middle mouse button."); |
| | case NavigationStyle::DRAGGING: |
| | 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." |
| | ); |
| | case NavigationStyle::ZOOMING: |
| | return QT_TR_NOOP( |
| | "Pinch (place two fingers on the screen and drag them apart from or towards each " |
| | "other) OR scroll mouse wheel OR press Alt + right mouse button OR PgUp/PgDown on " |
| | "keyboard." |
| | ); |
| | default: |
| | return "No description"; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | bool MayaGestureNavigationStyle::testMoveThreshold(const SbVec2s currentPos) const |
| | { |
| | SbVec2s movedBy = currentPos - this->mousedownPos; |
| | return SbVec2f(movedBy).length() >= this->mouseMoveThreshold; |
| | } |
| |
|
| | void MayaGestureNavigationStyle::zoomByCursor(const SbVec2f& thispos, const SbVec2f& prevpos) |
| | { |
| | const float dx = thispos[0] - prevpos[0]; |
| | const float dy = thispos[1] - prevpos[1]; |
| |
|
| | |
| | float value = (dx - dy) * 10.0f; |
| |
|
| | if (this->invertZoom) { |
| | value = -value; |
| | } |
| | zoom(viewer->getSoRenderManager()->getCamera(), value); |
| | } |
| |
|
| | SbBool MayaGestureNavigationStyle::processSoEvent(const SoEvent* const ev) |
| | { |
| | |
| | |
| | |
| | if (this->isSeekMode()) { |
| | return inherited::processSoEvent(ev); |
| | } |
| | |
| | if (!this->isSeekMode() && !this->isAnimating() && this->isViewing()) { |
| | this->setViewing(false); |
| | } |
| | |
| |
|
| | const SoType type(ev->getTypeId()); |
| | |
| | bool evIsButton = type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId()); |
| | bool evIsKeyboard = type.isDerivedFrom(SoKeyboardEvent::getClassTypeId()); |
| | bool evIsLoc2 = type.isDerivedFrom(SoLocation2Event::getClassTypeId()); |
| | bool evIsLoc3 = type.isDerivedFrom(SoMotion3Event::getClassTypeId()); |
| | bool evIsGesture = type.isDerivedFrom(SoGestureEvent::getClassTypeId()); |
| |
|
| | const SbVec2f prevnormalized = this->lastmouseposition; |
| | const SbVec2s pos(ev->getPosition()); |
| | const SbVec2f posn = this->normalizePixelPos(pos); |
| | |
| | |
| | |
| | float ratio = viewer->getSoRenderManager()->getViewportRegion().getViewportAspectRatio(); |
| |
|
| | if (evIsButton || evIsLoc2) { |
| | this->lastmouseposition = posn; |
| | } |
| |
|
| | const ViewerMode curmode = this->currentmode; |
| | |
| |
|
| | |
| | enum |
| | { |
| | BUTTON1DOWN = 1 << 0, |
| | BUTTON2DOWN = 1 << 1, |
| | BUTTON3DOWN = 1 << 2, |
| | CTRLDOWN = 1 << 3, |
| | SHIFTDOWN = 1 << 4, |
| | ALTDOWN = 1 << 5, |
| | MASKBUTTONS = BUTTON1DOWN | BUTTON2DOWN | BUTTON3DOWN, |
| | MASKMODIFIERS = CTRLDOWN | SHIFTDOWN | ALTDOWN |
| | }; |
| | unsigned int comboBefore = |
| | (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) |
| | | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) |
| | | (this->shiftdown ? SHIFTDOWN : 0) | (this->altdown ? ALTDOWN : 0); |
| |
|
| | |
| | int cntMBBefore = (comboBefore & BUTTON1DOWN ? 1 : 0) |
| | |
| | + (comboBefore & BUTTON2DOWN ? 1 : 0) + (comboBefore & BUTTON3DOWN ? 1 : 0); |
| | if (cntMBBefore >= 2) { |
| | this->thisClickIsComplex = true; |
| | } |
| | if (cntMBBefore == 0) { |
| | this->thisClickIsComplex = false; |
| | this->mousedownConsumedCount = 0; |
| | } |
| |
|
| | |
| | |
| | syncModifierKeys(ev); |
| | |
| | |
| | if (evIsButton) { |
| | auto 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->button1down = press; |
| | break; |
| | case SoMouseButtonEvent::BUTTON2: |
| | this->button2down = press; |
| | break; |
| | case SoMouseButtonEvent::BUTTON3: |
| | this->button3down = press; |
| | break; |
| | |
| | } |
| | } |
| | |
| |
|
| | unsigned int comboAfter = |
| | (this->button1down ? BUTTON1DOWN : 0) | (this->button2down ? BUTTON2DOWN : 0) |
| | | (this->button3down ? BUTTON3DOWN : 0) | (this->ctrldown ? CTRLDOWN : 0) |
| | | (this->shiftdown ? SHIFTDOWN : 0) | (this->altdown ? ALTDOWN : 0); |
| |
|
| | |
| | int cntMBAfter = (comboAfter & BUTTON1DOWN ? 1 : 0) |
| | |
| | + (comboAfter & BUTTON2DOWN ? 1 : 0) + (comboAfter & BUTTON3DOWN ? 1 : 0); |
| | if (cntMBAfter >= 2) { |
| | this->thisClickIsComplex = true; |
| | } |
| | |
| | |
| | |
| |
|
| | |
| | if (evIsLoc2 || evIsButton) { |
| | this->mouseMoveThresholdBroken |= this->testMoveThreshold(pos); |
| | } |
| |
|
| | |
| | if (evIsGesture) { |
| | auto gesture = static_cast<const SoGestureEvent*>(ev); |
| | switch (gesture->state) { |
| | case SoGestureEvent::SbGSStart: |
| | |
| | |
| | inGesture = true; |
| | break; |
| | case SoGestureEvent::SbGSUpdate: |
| | assert(inGesture); |
| | inGesture = true; |
| | break; |
| | case SoGestureEvent::SbGSEnd: |
| | assert(inGesture); |
| | inGesture = false; |
| | break; |
| | case SoGestureEvent::SbGsCanceled: |
| | assert(inGesture); |
| | inGesture = false; |
| | break; |
| | default: |
| | assert(0); |
| | inGesture = false; |
| | } |
| | } |
| | if (evIsButton) { |
| | if (inGesture) { |
| | inGesture = false; |
| | |
| | setViewingMode(NavigationStyle::SELECTION); |
| | |
| | } |
| | } |
| |
|
| | bool suppressLMBDrag = false; |
| | if (viewer->isEditing()) { |
| | |
| | suppressLMBDrag = !(comboAfter & ALTDOWN); |
| | } |
| |
|
| | |
| |
|
| | SbBool processed = false; |
| | bool propagated = false; |
| | |
| | |
| |
|
| | |
| | if (!viewer->isEditing()) { |
| | processed = handleEventInForeground(ev); |
| | } |
| | if (processed) { |
| | goto finalize; |
| | } |
| |
|
| | |
| | if (evIsKeyboard) { |
| | auto const event = (const SoKeyboardEvent*)ev; |
| | const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; |
| | switch (event->getKey()) { |
| | case SoKeyboardEvent::H: |
| | |
| | if (!viewer->isEditing()) { |
| | processed = true; |
| | if (!press) { |
| | setupPanningPlane(viewer->getCamera()); |
| | lookAtPoint(event->getPosition()); |
| | } |
| | } |
| | break; |
| | default: |
| | break; |
| | } |
| | } |
| | if (processed) { |
| | goto finalize; |
| | } |
| |
|
| | |
| | if (evIsLoc3) { |
| | auto const event = static_cast<const SoMotion3Event*>(ev); |
| | if (event) { |
| | this->processMotionEvent(event); |
| | } |
| | processed = true; |
| | } |
| | if (processed) { |
| | goto finalize; |
| | } |
| |
|
| | |
| | switch (curmode) { |
| | case NavigationStyle::SELECTION: |
| | |
| | if (viewer->isEditing()) { |
| | if (evIsButton) { |
| | auto const event = (const SoMouseButtonEvent*)ev; |
| | const SbBool press = event->getState() == SoButtonEvent::DOWN; |
| | const int button = event->getButton(); |
| |
|
| | if (!press && button == SoMouseButtonEvent::BUTTON1) { |
| | setViewingMode(NavigationStyle::IDLE); |
| | break; |
| | } |
| | } |
| |
|
| | if (this->button1down) { |
| | break; |
| | } |
| | } |
| | [[fallthrough]]; |
| | case NavigationStyle::IDLE: |
| | |
| | if (viewer->isEditing()) { |
| | if (evIsButton) { |
| | auto const event = (const SoMouseButtonEvent*)ev; |
| | const SbBool press = event->getState() == SoButtonEvent::DOWN; |
| | const int button = event->getButton(); |
| |
|
| | if (press && button == SoMouseButtonEvent::BUTTON1 && !this->altdown) { |
| | setViewingMode(NavigationStyle::SELECTION); |
| | break; |
| | } |
| | } |
| | } |
| | [[fallthrough]]; |
| | case NavigationStyle::INTERACT: { |
| | |
| |
|
| | |
| | if (evIsKeyboard) { |
| | auto const event = (const SoKeyboardEvent*)ev; |
| | const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; |
| |
|
| | switch (event->getKey()) { |
| | case SoKeyboardEvent::S: |
| | case SoKeyboardEvent::HOME: |
| | case SoKeyboardEvent::LEFT_ARROW: |
| | case SoKeyboardEvent::UP_ARROW: |
| | case SoKeyboardEvent::RIGHT_ARROW: |
| | case SoKeyboardEvent::DOWN_ARROW: |
| | processed = inherited::processSoEvent(ev); |
| | propagated = true; |
| | break; |
| | case SoKeyboardEvent::PAGE_UP: |
| | if (press) { |
| | doZoom(viewer->getSoRenderManager()->getCamera(), getDelta(), posn); |
| | } |
| | processed = true; |
| | break; |
| | case SoKeyboardEvent::PAGE_DOWN: |
| | if (press) { |
| | doZoom(viewer->getSoRenderManager()->getCamera(), -getDelta(), posn); |
| | } |
| | processed = true; |
| | break; |
| | default: |
| | break; |
| | } |
| | } |
| | if (processed) { |
| | goto finalize; |
| | } |
| |
|
| |
|
| | |
| | if (evIsButton) { |
| | auto const event = (const SoMouseButtonEvent*)ev; |
| | const int button = event->getButton(); |
| | const SbBool press |
| | = event->getState() == SoButtonEvent::DOWN ? true : false; |
| | switch (button) { |
| | case SoMouseButtonEvent::BUTTON1: |
| | case SoMouseButtonEvent::BUTTON2: |
| | if (press) { |
| | if (this->thisClickIsComplex && this->mouseMoveThresholdBroken) { |
| | |
| | |
| | } |
| | else { |
| | |
| | |
| | |
| | this->mousedownPos = pos; |
| | this->mouseMoveThresholdBroken = false; |
| | setupPanningPlane( |
| | viewer->getSoRenderManager()->getCamera() |
| | ); |
| | int& cnt = this->mousedownConsumedCount; |
| | this->mousedownConsumedEvents[cnt] |
| | = *event; |
| | |
| | |
| | cnt++; |
| | assert(cnt <= 2); |
| | if (cnt > static_cast<int>(sizeof(mousedownConsumedEvents))) { |
| | cnt = sizeof(mousedownConsumedEvents); |
| | } |
| | processed = true; |
| | |
| | } |
| | } |
| | else { |
| | if (button == SoMouseButtonEvent::BUTTON2 && !this->thisClickIsComplex) { |
| | if (!viewer->isEditing() && this->isPopupMenuEnabled()) { |
| | processed = true; |
| | this->openPopupMenu(event->getPosition()); |
| | } |
| | } |
| | if (!processed) { |
| | |
| | |
| | for (int i = 0; i < this->mousedownConsumedCount; i++) { |
| | inherited::processSoEvent( |
| | &(this->mousedownConsumedEvents[i]) |
| | ); |
| | } |
| | this->mousedownConsumedCount = 0; |
| | processed = inherited::processSoEvent( |
| | ev |
| | ); |
| | |
| | propagated = true; |
| | } |
| | } |
| | break; |
| | case SoMouseButtonEvent::BUTTON3: |
| | |
| | if (press & this->altdown) { |
| | setViewingMode(NavigationStyle::PANNING); |
| | } |
| | else if (press) { |
| | |
| | setupPanningPlane(viewer->getCamera()); |
| | lookAtPoint(event->getPosition()); |
| | } |
| | processed = true; |
| | break; |
| | } |
| | } |
| |
|
| | |
| | if (evIsLoc2) { |
| | if (this->mouseMoveThresholdBroken && (this->button1down || this->button2down) |
| | && mousedownConsumedCount > 0) { |
| | |
| |
|
| | |
| | if ((this->button1down && !suppressLMBDrag && this->altdown) |
| | || (this->button2down && this->altdown)) { |
| | |
| | |
| | this->mousedownConsumedCount = 0; |
| |
|
| | |
| | |
| | |
| | saveCursorPosition(ev); |
| | setViewingMode( |
| | this->button1down ? NavigationStyle::DRAGGING : NavigationStyle::ZOOMING |
| | ); |
| | processed = true; |
| | } |
| | else { |
| | |
| | |
| | |
| | for (int i = 0; i < this->mousedownConsumedCount; i++) { |
| | inherited::processSoEvent( |
| | &(this->mousedownConsumedEvents[i]) |
| | ); |
| | } |
| | this->mousedownConsumedCount = 0; |
| | processed = inherited::processSoEvent(ev); |
| | |
| | |
| | propagated = true; |
| | } |
| | } |
| | if (mousedownConsumedCount > 0) { |
| | processed = true; |
| | |
| | } |
| | } |
| |
|
| | |
| | if (evIsGesture |
| | && !this->button2down) { |
| | |
| | |
| | |
| | |
| | |
| | auto gesture = static_cast<const SoGestureEvent*>(ev); |
| | if (gesture->state == SoGestureEvent::SbGSStart |
| | || gesture->state == SoGestureEvent::SbGSUpdate) { |
| | |
| | |
| | |
| | if (type.isDerivedFrom(SoGesturePanEvent::getClassTypeId())) { |
| | setupPanningPlane(viewer->getSoRenderManager()->getCamera()); |
| | |
| | |
| | setViewingMode(NavigationStyle::PANNING); |
| | processed = true; |
| | } |
| | else if (type.isDerivedFrom(SoGesturePinchEvent::getClassTypeId())) { |
| | setupPanningPlane(viewer->getSoRenderManager()->getCamera()); |
| | |
| | |
| | saveCursorPosition(ev); |
| | setViewingMode(NavigationStyle::DRAGGING); |
| | processed = true; |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | } break; |
| | case NavigationStyle::DRAGGING: |
| | case NavigationStyle::ZOOMING: |
| | case NavigationStyle::PANNING: { |
| | |
| |
|
| | |
| |
|
| | |
| | if (evIsButton) { |
| | auto const event = (const SoMouseButtonEvent*)ev; |
| | const int button = event->getButton(); |
| | switch (button) { |
| | case SoMouseButtonEvent::BUTTON1: |
| | case SoMouseButtonEvent::BUTTON2: |
| | case SoMouseButtonEvent::BUTTON3: |
| | |
| | if (comboAfter & BUTTON1DOWN || comboAfter & BUTTON2DOWN) { |
| | |
| | if (comboAfter & BUTTON1DOWN && comboAfter & BUTTON2DOWN) { |
| | setRotationCenter(getFocalPoint()); |
| | } |
| | else { |
| | saveCursorPosition(ev); |
| | } |
| | setViewingMode( |
| | (comboAfter & BUTTON1DOWN) ? NavigationStyle::DRAGGING |
| | : NavigationStyle::PANNING |
| | ); |
| | processed = true; |
| | } |
| | else { |
| | |
| | setViewingMode(NavigationStyle::IDLE); |
| | processed = true; |
| | } |
| | break; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | if (evIsLoc2 && !this->inGesture && this->mouseMoveThresholdBroken) { |
| | if (curmode == NavigationStyle::ZOOMING) { |
| | this->zoomByCursor(posn, prevnormalized); |
| | processed = true; |
| | } |
| | else if (curmode == NavigationStyle::PANNING) { |
| | panCamera( |
| | viewer->getSoRenderManager()->getCamera(), |
| | ratio, |
| | this->panningplane, |
| | posn, |
| | prevnormalized |
| | ); |
| | processed = true; |
| | } |
| | else if (curmode == NavigationStyle::DRAGGING) { |
| | if (comboAfter & BUTTON1DOWN && comboAfter & BUTTON2DOWN) { |
| | |
| | NavigationStyle::doRotate( |
| | viewer->getSoRenderManager()->getCamera(), |
| | (posn - prevnormalized)[0] * (-2), |
| | SbVec2f(0.5, 0.5) |
| | ); |
| | processed = true; |
| | } |
| | else { |
| | |
| | |
| | this->spin_simplified(posn, prevnormalized); |
| | processed = true; |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | if (evIsGesture) { |
| | auto gesture = static_cast<const SoGestureEvent*>(ev); |
| | assert(gesture); |
| | if (gesture->state == SoGestureEvent::SbGSEnd) { |
| | setViewingMode(NavigationStyle::SELECTION); |
| | processed = true; |
| | } |
| | else if (gesture->state == SoGestureEvent::SbGSUpdate) { |
| | if (type.isDerivedFrom(SoGesturePinchEvent::getClassTypeId())) { |
| | auto const event = static_cast<const SoGesturePinchEvent*>(ev); |
| | if (this->zoomAtCursor) { |
| | |
| | |
| | SbVec2f panDist = this->normalizePixelPos(event->deltaCenter.getValue()); |
| | NavigationStyle::panCamera( |
| | viewer->getSoRenderManager()->getCamera(), |
| | ratio, |
| | this->panningplane, |
| | panDist, |
| | SbVec2f(0, 0) |
| | ); |
| | } |
| | NavigationStyle::doZoom( |
| | viewer->getSoRenderManager()->getCamera(), |
| | -logf(event->deltaZoom), |
| | this->normalizePixelPos(event->curCenter) |
| | ); |
| | if (event->deltaAngle != 0) { |
| | NavigationStyle::doRotate( |
| | viewer->getSoRenderManager()->getCamera(), |
| | event->deltaAngle, |
| | this->normalizePixelPos(event->curCenter) |
| | ); |
| | } |
| | processed = true; |
| | } |
| | if (type.isDerivedFrom(SoGesturePanEvent::getClassTypeId())) { |
| | auto const event = static_cast<const SoGesturePanEvent*>(ev); |
| | |
| | |
| | SbVec2f panDist = this->normalizePixelPos(event->deltaOffset); |
| | NavigationStyle::panCamera( |
| | viewer->getSoRenderManager()->getCamera(), |
| | ratio, |
| | this->panningplane, |
| | panDist, |
| | SbVec2f(0, 0) |
| | ); |
| | processed = true; |
| | } |
| | } |
| | else { |
| | |
| | |
| | processed = true; |
| | } |
| | } |
| |
|
| | } break; |
| | case NavigationStyle::SEEK_WAIT_MODE: { |
| | if (evIsButton) { |
| | auto const event = (const SoMouseButtonEvent*)ev; |
| | const int button = event->getButton(); |
| | const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false; |
| | if (button == SoMouseButtonEvent::BUTTON1 && press) { |
| | this->seekToPoint(pos); |
| | this->setViewingMode(NavigationStyle::SEEK_MODE); |
| | processed = true; |
| | } |
| | } |
| | }; |
| | |
| | case NavigationStyle::SPINNING: |
| | case NavigationStyle::SEEK_MODE: { |
| | |
| | if (!processed) { |
| | if (evIsButton || evIsGesture || evIsKeyboard || evIsLoc3) { |
| | setViewingMode(NavigationStyle::SELECTION); |
| | } |
| | } |
| | } break; |
| | case NavigationStyle::BOXZOOM: |
| | default: |
| | |
| | break; |
| | } |
| |
|
| | if (!processed && !propagated) { |
| | processed = inherited::processSoEvent(ev); |
| | propagated = true; |
| | } |
| |
|
| | |
| | finalize: |
| | return processed; |
| | } |
| |
|