InventorNavigationStyle.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <cfloat>
00027 # include "InventorAll.h"
00028 # include <QAction>
00029 # include <QActionGroup>
00030 # include <QApplication>
00031 # include <QByteArray>
00032 # include <QCursor>
00033 # include <QList>
00034 # include <QMenu>
00035 # include <QMetaObject>
00036 # include <QRegExp>
00037 #endif
00038 
00039 #include <Inventor/sensors/SoTimerSensor.h>
00040 
00041 #include <App/Application.h>
00042 #include "NavigationStyle.h"
00043 #include "View3DInventorViewer.h"
00044 #include "Application.h"
00045 #include "MenuManager.h"
00046 #include "MouseSelection.h"
00047 
00048 using namespace Gui;
00049 
00050 // ----------------------------------------------------------------------------------
00051 
00052 /* TRANSLATOR Gui::InventorNavigationStyle */
00053 
00054 TYPESYSTEM_SOURCE(Gui::InventorNavigationStyle, Gui::UserNavigationStyle);
00055 
00056 InventorNavigationStyle::InventorNavigationStyle()
00057 {
00058 }
00059 
00060 InventorNavigationStyle::~InventorNavigationStyle()
00061 {
00062 }
00063 
00064 const char* InventorNavigationStyle::mouseButtons(ViewerMode mode)
00065 {
00066     switch (mode) {
00067     case NavigationStyle::SELECTION:
00068         return QT_TR_NOOP("Press CTRL and left mouse button");
00069     case NavigationStyle::PANNING:
00070         return QT_TR_NOOP("Press middle mouse button");
00071     case NavigationStyle::DRAGGING:
00072         return QT_TR_NOOP("Press left mouse button");
00073     case NavigationStyle::ZOOMING:
00074         return QT_TR_NOOP("Scroll middle mouse button");
00075     default:
00076         return "No description";
00077     }
00078 }
00079 
00080 SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev)
00081 {
00082     // Events when in "ready-to-seek" mode are ignored, except those
00083     // which influence the seek mode itself -- these are handled further
00084     // up the inheritance hierarchy.
00085     if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
00086 
00087     const SoType type(ev->getTypeId());
00088 
00089     const SbViewportRegion & vp = viewer->getViewportRegion();
00090     const SbVec2s size(vp.getViewportSizePixels());
00091     const SbVec2f prevnormalized = this->lastmouseposition;
00092     const SbVec2s pos(ev->getPosition());
00093     const SbVec2f posn((float) pos[0] / (float) SoQtMax((int)(size[0] - 1), 1),
00094                        (float) pos[1] / (float) SoQtMax((int)(size[1] - 1), 1));
00095 
00096     this->lastmouseposition = posn;
00097 
00098     // Set to TRUE if any event processing happened. Note that it is not
00099     // necessary to restrict ourselves to only do one "action" for an
00100     // event, we only need this flag to see if any processing happened
00101     // at all.
00102     SbBool processed = FALSE;
00103 
00104     const ViewerMode curmode = this->currentmode;
00105     ViewerMode newmode = curmode;
00106 
00107     // Mismatches in state of the modifier keys happens if the user
00108     // presses or releases them outside the viewer window.
00109     if (this->ctrldown != ev->wasCtrlDown()) {
00110         this->ctrldown = ev->wasCtrlDown();
00111     }
00112     if (this->shiftdown != ev->wasShiftDown()) {
00113         this->shiftdown = ev->wasShiftDown();
00114     }
00115     if (this->altdown != ev->wasAltDown()) {
00116         this->altdown = ev->wasAltDown();
00117     }
00118 
00119     // give the nodes in the foreground root the chance to handle events (e.g color bar)
00120     if (!processed && !viewer->isEditing()) {
00121         processed = handleEventInForeground(ev);
00122         if (processed)
00123             return TRUE;
00124     }
00125 
00126     // Keyboard handling
00127     if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
00128         const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
00129         const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
00130         switch (event->getKey()) {
00131         case SoKeyboardEvent::LEFT_CONTROL:
00132         case SoKeyboardEvent::RIGHT_CONTROL:
00133             this->ctrldown = press;
00134             break;
00135         case SoKeyboardEvent::LEFT_SHIFT:
00136         case SoKeyboardEvent::RIGHT_SHIFT:
00137             this->shiftdown = press;
00138             break;
00139         case SoKeyboardEvent::LEFT_ALT:
00140         case SoKeyboardEvent::RIGHT_ALT:
00141             this->altdown = press;
00142             break;
00143         case SoKeyboardEvent::H:
00144             processed = TRUE;
00145             viewer->saveHomePosition();
00146             break;
00147         case SoKeyboardEvent::S:
00148         case SoKeyboardEvent::HOME:
00149         case SoKeyboardEvent::LEFT_ARROW:
00150         case SoKeyboardEvent::UP_ARROW:
00151         case SoKeyboardEvent::RIGHT_ARROW:
00152         case SoKeyboardEvent::DOWN_ARROW:
00153             if (!this->isViewing())
00154                 this->setViewing(true);
00155             break;
00156         default:
00157             break;
00158         }
00159     }
00160 
00161     // Mouse Button / Spaceball Button handling
00162     if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
00163         const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
00164         const int button = event->getButton();
00165         const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
00166 
00167         // SoDebugError::postInfo("processSoEvent", "button = %d", button);
00168         switch (button) {
00169         case SoMouseButtonEvent::BUTTON1:
00170             this->button1down = press;
00171             if (press && ev->wasShiftDown() &&
00172                 (this->currentmode != NavigationStyle::SELECTION)) {
00173                 this->centerTime = ev->getTime();
00174                 float ratio = vp.getViewportAspectRatio();
00175                 SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
00176                 this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
00177                 this->lockrecenter = FALSE;
00178             }
00179             else if (!press && ev->wasShiftDown() &&
00180                 (this->currentmode != NavigationStyle::SELECTION)) {
00181                 SbTime tmp = (ev->getTime() - this->centerTime);
00182                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00183                 // is it just a left click?
00184                 if (tmp.getValue() < dci && !this->lockrecenter) {
00185                     if (!this->lookAtPoint(pos)) {
00186                         panToCenter(panningplane, posn);
00187                         this->interactiveCountDec();
00188                     }
00189                     processed = TRUE;
00190                 }
00191             }
00192             else if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
00193                 newmode = NavigationStyle::SEEK_MODE;
00194                 this->seekToPoint(pos); // implicitly calls interactiveCountInc()
00195                 processed = TRUE;
00196                 this->lockrecenter = TRUE;
00197             }
00198             else if (press && (this->currentmode == NavigationStyle::IDLE)) {
00199                 this->setViewing(true);
00200                 processed = TRUE;
00201                 this->lockrecenter = TRUE;
00202             }
00203             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
00204                 this->setViewing(false);
00205                 processed = TRUE;
00206                 this->lockrecenter = TRUE;
00207             }
00208             else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
00209                 processed = TRUE;
00210                 this->lockrecenter = TRUE;
00211             }
00212             break;
00213         case SoMouseButtonEvent::BUTTON2:
00214             // If we are in edit mode then simply ignore the RMB events
00215             // to pass the event to the base class.
00216             this->lockrecenter = TRUE;
00217             if (!viewer->isEditing()) {
00218                 // If we are in zoom or pan mode ignore RMB events otherwise
00219                 // the canvas doesn't get any release events 
00220                 if (this->currentmode != NavigationStyle::ZOOMING && 
00221                     this->currentmode != NavigationStyle::PANNING) {
00222                     if (this->isPopupMenuEnabled()) {
00223                         if (!press) { // release right mouse button
00224                             this->openPopupMenu(event->getPosition());
00225                         }
00226                     }
00227                 }
00228             }
00229             break;
00230         case SoMouseButtonEvent::BUTTON3:
00231             if (press) {
00232                 this->centerTime = ev->getTime();
00233                 float ratio = vp.getViewportAspectRatio();
00234                 SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
00235                 this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
00236                 this->lockrecenter = FALSE;
00237             }
00238             else {
00239                 SbTime tmp = (ev->getTime() - this->centerTime);
00240                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00241                 // is it just a middle click?
00242                 if (tmp.getValue() < dci && !this->lockrecenter) {
00243                     if (!this->lookAtPoint(pos)) {
00244                         panToCenter(panningplane, posn);
00245                         this->interactiveCountDec();
00246                     }
00247                     processed = TRUE;
00248                 }
00249             }
00250             this->button3down = press;
00251             break;
00252         case SoMouseButtonEvent::BUTTON4:
00253             if (this->invertZoom)
00254                 zoom(viewer->getCamera(), -0.05f);
00255             else
00256                 zoom(viewer->getCamera(), 0.05f);
00257             processed = TRUE;
00258             break;
00259         case SoMouseButtonEvent::BUTTON5:
00260             if (this->invertZoom)
00261                 zoom(viewer->getCamera(), 0.05f);
00262             else
00263                 zoom(viewer->getCamera(), -0.05f);
00264             processed = TRUE;
00265             break;
00266         default:
00267             break;
00268         }
00269     }
00270 
00271     // Mouse Movement handling
00272     if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
00273         this->lockrecenter = TRUE;
00274         const SoLocation2Event * const event = (const SoLocation2Event *) ev;
00275         if (this->currentmode == NavigationStyle::ZOOMING) {
00276             this->zoomByCursor(posn, prevnormalized);
00277             processed = TRUE;
00278         }
00279         else if (this->currentmode == NavigationStyle::PANNING) {
00280             float ratio = vp.getViewportAspectRatio();
00281             panCamera(viewer->getCamera(), ratio, this->panningplane, posn, prevnormalized);
00282             processed = TRUE;
00283         }
00284         else if (this->currentmode == NavigationStyle::DRAGGING) {
00285             this->addToLog(event->getPosition(), event->getTime());
00286             this->spin(posn);
00287             processed = TRUE;
00288         }
00289     }
00290 
00291     // Spaceball & Joystick handling
00292     if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
00293         SoMotion3Event * const event = (SoMotion3Event *) ev;
00294         SoCamera * const camera = viewer->getCamera();
00295         if (camera) {
00296             SbVec3f dir = event->getTranslation();
00297             camera->orientation.getValue().multVec(dir,dir);
00298             camera->position = camera->position.getValue() + dir;
00299             camera->orientation = 
00300                 event->getRotation() * camera->orientation.getValue();
00301             processed = TRUE;
00302         }
00303     }
00304 
00305     enum {
00306         BUTTON1DOWN = 1 << 0,
00307         BUTTON3DOWN = 1 << 1,
00308         CTRLDOWN =    1 << 2,
00309         SHIFTDOWN =   1 << 3
00310     };
00311     unsigned int combo =
00312         (this->button1down ? BUTTON1DOWN : 0) |
00313         (this->button3down ? BUTTON3DOWN : 0) |
00314         (this->ctrldown ? CTRLDOWN : 0) |
00315         (this->shiftdown ? SHIFTDOWN : 0);
00316 
00317     switch (combo) {
00318     case 0:
00319         if (curmode == NavigationStyle::SPINNING) { break; }
00320         newmode = NavigationStyle::IDLE;
00321 
00322         if (curmode == NavigationStyle::DRAGGING) {
00323             if (doSpin())
00324                 newmode = NavigationStyle::SPINNING;
00325         }
00326         break;
00327     case BUTTON1DOWN:
00328         newmode = NavigationStyle::DRAGGING;
00329         break;
00330     case BUTTON3DOWN:
00331     case SHIFTDOWN|BUTTON1DOWN:
00332         newmode = NavigationStyle::PANNING;
00333         break;
00334     case CTRLDOWN:
00335     case CTRLDOWN|BUTTON1DOWN:
00336     case CTRLDOWN|SHIFTDOWN:
00337     case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN:
00338         newmode = NavigationStyle::SELECTION;
00339         break;
00340     case BUTTON1DOWN|BUTTON3DOWN:
00341     case CTRLDOWN|BUTTON3DOWN:
00342         newmode = NavigationStyle::ZOOMING;
00343         break;
00344 
00345         // There are many cases we don't handle that just falls through to
00346         // the default case, like SHIFTDOWN, CTRLDOWN, CTRLDOWN|SHIFTDOWN,
00347         // SHIFTDOWN|BUTTON3DOWN, SHIFTDOWN|CTRLDOWN|BUTTON3DOWN, etc.
00348         // This is a feature, not a bug. :-)
00349         //
00350         // mortene.
00351 
00352     default:
00353         // The default will make a spin stop and otherwise not do
00354         // anything.
00355         if ((curmode != NavigationStyle::SEEK_WAIT_MODE) &&
00356             (curmode != NavigationStyle::SEEK_MODE)) {
00357             newmode = NavigationStyle::IDLE;
00358         }
00359         break;
00360     }
00361 
00362     if (newmode != curmode) {
00363         this->setViewingMode(newmode);
00364     }
00365 
00366     // If not handled in this class, pass on upwards in the inheritance
00367     // hierarchy.
00368     if ((curmode == NavigationStyle::SELECTION || viewer->isEditing()) && !processed)
00369         processed = inherited::processSoEvent(ev);
00370     else
00371         return TRUE;
00372 
00373     return processed;
00374 }

Generated on Wed Nov 23 19:00:19 2011 for FreeCAD by  doxygen 1.6.1