CADNavigationStyle.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::CADNavigationStyle */
00053 
00054 TYPESYSTEM_SOURCE(Gui::CADNavigationStyle, Gui::UserNavigationStyle);
00055 
00056 CADNavigationStyle::CADNavigationStyle() : lockButton1(FALSE)
00057 {
00058 }
00059 
00060 CADNavigationStyle::~CADNavigationStyle()
00061 {
00062 }
00063 
00064 const char* CADNavigationStyle::mouseButtons(ViewerMode mode)
00065 {
00066     switch (mode) {
00067     case NavigationStyle::SELECTION:
00068         return QT_TR_NOOP("Press 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 and middle 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 CADNavigationStyle::processSoEvent(const SoEvent * const ev)
00081 {
00082 #if 0
00083     // Events when in "ready-to-seek" mode are ignored, except those
00084     // which influence the seek mode itself -- these are handled further
00085     // up the inheritance hierarchy.
00086     if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
00087 #else
00088     if (!this->isSeekMode() && this->isViewing())
00089         this->setViewing(false); // by default disable viewing mode to render the scene
00090 #endif
00091 
00092     const SoType type(ev->getTypeId());
00093 
00094     const SbViewportRegion & vp = viewer->getViewportRegion();
00095     const SbVec2s size(vp.getViewportSizePixels());
00096     const SbVec2f prevnormalized = this->lastmouseposition;
00097     const SbVec2s pos(ev->getPosition());
00098     const SbVec2f posn((float) pos[0] / (float) SoQtMax((int)(size[0] - 1), 1),
00099                        (float) pos[1] / (float) SoQtMax((int)(size[1] - 1), 1));
00100 
00101     this->lastmouseposition = posn;
00102 
00103     // Set to TRUE if any event processing happened. Note that it is not
00104     // necessary to restrict ourselves to only do one "action" for an
00105     // event, we only need this flag to see if any processing happened
00106     // at all.
00107     SbBool processed = FALSE;
00108 
00109     const ViewerMode curmode = this->currentmode;
00110     ViewerMode newmode = curmode;
00111 
00112     // Mismatches in state of the modifier keys happens if the user
00113     // presses or releases them outside the viewer window.
00114     if (this->ctrldown != ev->wasCtrlDown()) {
00115         this->ctrldown = ev->wasCtrlDown();
00116     }
00117     if (this->shiftdown != ev->wasShiftDown()) {
00118         this->shiftdown = ev->wasShiftDown();
00119     }
00120     if (this->altdown != ev->wasAltDown()) {
00121         this->altdown = ev->wasAltDown();
00122     }
00123 
00124     // give the nodes in the foreground root the chance to handle events (e.g color bar)
00125     if (!processed && !viewer->isEditing()) {
00126         processed = handleEventInForeground(ev);
00127         if (processed)
00128             return TRUE;
00129     }
00130 
00131     // Keyboard handling
00132     if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
00133         const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
00134         const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
00135         switch (event->getKey()) {
00136         case SoKeyboardEvent::LEFT_CONTROL:
00137         case SoKeyboardEvent::RIGHT_CONTROL:
00138             this->ctrldown = press;
00139             break;
00140         case SoKeyboardEvent::LEFT_SHIFT:
00141         case SoKeyboardEvent::RIGHT_SHIFT:
00142             this->shiftdown = press;
00143             break;
00144         case SoKeyboardEvent::LEFT_ALT:
00145         case SoKeyboardEvent::RIGHT_ALT:
00146             this->altdown = press;
00147             break;
00148         case SoKeyboardEvent::H:
00149             processed = TRUE;
00150             viewer->saveHomePosition();
00151             break;
00152         case SoKeyboardEvent::S:
00153         case SoKeyboardEvent::HOME:
00154         case SoKeyboardEvent::LEFT_ARROW:
00155         case SoKeyboardEvent::UP_ARROW:
00156         case SoKeyboardEvent::RIGHT_ARROW:
00157         case SoKeyboardEvent::DOWN_ARROW:
00158             if (!this->isViewing())
00159                 this->setViewing(true);
00160             break;
00161         default:
00162             break;
00163         }
00164     }
00165 
00166     // Mouse Button / Spaceball Button handling
00167     if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
00168         const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
00169         const int button = event->getButton();
00170         const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
00171 
00172         // SoDebugError::postInfo("processSoEvent", "button = %d", button);
00173         switch (button) {
00174         case SoMouseButtonEvent::BUTTON1:
00175             this->lockrecenter = TRUE;
00176             this->button1down = press;
00177 #if 0 // disable to avoid interferences where this key combination is used, too
00178             if (press && ev->wasShiftDown() &&
00179                 (this->currentmode != NavigationStyle::SELECTION)) {
00180                 this->centerTime = ev->getTime();
00181                 float ratio = vp.getViewportAspectRatio();
00182                 SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
00183                 this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
00184                 this->lockrecenter = FALSE;
00185             }
00186             else if (!press && ev->wasShiftDown() &&
00187                 (this->currentmode != NavigationStyle::SELECTION)) {
00188                 SbTime tmp = (ev->getTime() - this->centerTime);
00189                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00190                 // is it just a left click?
00191                 if (tmp.getValue() < dci && !this->lockrecenter) {
00192                     if (!this->moveToPoint(pos)) {
00193                         panToCenter(panningplane, posn);
00194                         this->interactiveCountDec();
00195                     }
00196                     processed = TRUE;
00197                 }
00198             }
00199             else
00200 #endif
00201             if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
00202                 newmode = NavigationStyle::SEEK_MODE;
00203                 this->seekToPoint(pos); // implicitly calls interactiveCountInc()
00204                 processed = TRUE;
00205             }
00206             //else if (press && (this->currentmode == NavigationStyle::IDLE)) {
00207             //    this->setViewing(true);
00208             //    processed = TRUE;
00209             //}
00210             else if (press && (this->currentmode == NavigationStyle::PANNING ||
00211                                this->currentmode == NavigationStyle::ZOOMING)) {
00212                 newmode = NavigationStyle::DRAGGING;
00213                 this->centerTime = ev->getTime();
00214                 processed = TRUE;
00215             }
00216             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
00217                 SbTime tmp = (ev->getTime() - this->centerTime);
00218                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00219                 if (tmp.getValue() < dci) {
00220                     newmode = NavigationStyle::ZOOMING;
00221                 }
00222                 processed = TRUE;
00223             }
00224             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
00225                 this->setViewing(false);
00226                 processed = TRUE;
00227             }
00228             else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
00229                 processed = TRUE;
00230             }
00231             break;
00232         case SoMouseButtonEvent::BUTTON2:
00233             // If we are in edit mode then simply ignore the RMB events
00234             // to pass the event to the base class.
00235             this->lockrecenter = TRUE;
00236             if (!viewer->isEditing()) {
00237                 // If we are in zoom or pan mode ignore RMB events otherwise
00238                 // the canvas doesn't get any release events 
00239                 if (this->currentmode != NavigationStyle::ZOOMING && 
00240                     this->currentmode != NavigationStyle::PANNING &&
00241                     this->currentmode != NavigationStyle::DRAGGING) {
00242                     if (this->isPopupMenuEnabled()) {
00243                         if (!press) { // release right mouse button
00244                             this->openPopupMenu(event->getPosition());
00245                         }
00246                     }
00247                 }
00248             }
00249             // Alternative way of rotating & zooming
00250             if (press && (this->currentmode == NavigationStyle::PANNING ||
00251                           this->currentmode == NavigationStyle::ZOOMING)) {
00252                 newmode = NavigationStyle::DRAGGING;
00253                 this->centerTime = ev->getTime();
00254                 processed = TRUE;
00255             }
00256             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
00257                 SbTime tmp = (ev->getTime() - this->centerTime);
00258                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00259                 if (tmp.getValue() < dci) {
00260                     newmode = NavigationStyle::ZOOMING;
00261                 }
00262                 processed = TRUE;
00263             }
00264             this->button2down = press;
00265             break;
00266         case SoMouseButtonEvent::BUTTON3:
00267             if (press) {
00268                 this->centerTime = ev->getTime();
00269                 float ratio = vp.getViewportAspectRatio();
00270                 SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
00271                 this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
00272                 this->lockrecenter = FALSE;
00273             }
00274             else {
00275                 SbTime tmp = (ev->getTime() - this->centerTime);
00276                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00277                 // is it just a middle click?
00278                 if (tmp.getValue() < dci && !this->lockrecenter) {
00279                     if (!this->lookAtPoint(pos)) {
00280                         panToCenter(panningplane, posn);
00281                         this->interactiveCountDec();
00282                     }
00283                     processed = TRUE;
00284                 }
00285             }
00286             this->button3down = press;
00287             break;
00288         case SoMouseButtonEvent::BUTTON4:
00289             if (this->invertZoom)
00290                 zoom(viewer->getCamera(), -0.05f);
00291             else
00292                 zoom(viewer->getCamera(), 0.05f);
00293             processed = TRUE;
00294             break;
00295         case SoMouseButtonEvent::BUTTON5:
00296             if (this->invertZoom)
00297                 zoom(viewer->getCamera(), 0.05f);
00298             else
00299                 zoom(viewer->getCamera(), -0.05f);
00300             processed = TRUE;
00301             break;
00302         default:
00303             break;
00304         }
00305     }
00306 
00307     // Mouse Movement handling
00308     if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
00309         this->lockrecenter = TRUE;
00310         const SoLocation2Event * const event = (const SoLocation2Event *) ev;
00311         if (this->currentmode == NavigationStyle::ZOOMING) {
00312             this->zoomByCursor(posn, prevnormalized);
00313             processed = TRUE;
00314         }
00315         else if (this->currentmode == NavigationStyle::PANNING) {
00316             float ratio = vp.getViewportAspectRatio();
00317             panCamera(viewer->getCamera(), ratio, this->panningplane, posn, prevnormalized);
00318             processed = TRUE;
00319         }
00320         else if (this->currentmode == NavigationStyle::DRAGGING) {
00321             this->addToLog(event->getPosition(), event->getTime());
00322             this->spin(posn);
00323             processed = TRUE;
00324         }
00325     }
00326 
00327     // Spaceball & Joystick handling
00328     if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
00329         SoMotion3Event * const event = (SoMotion3Event *) ev;
00330         SoCamera * const camera = viewer->getCamera();
00331 
00332         SbVec3f dir = event->getTranslation();
00333         if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())){
00334             static float zoomConstant(-.03f);
00335             dir[2] = 0.0;//don't move the cam for z translation.
00336 
00337             SoOrthographicCamera *oCam = static_cast<SoOrthographicCamera *>(camera);
00338             oCam->scaleHeight(1.0-event->getTranslation()[2] * zoomConstant);
00339         }
00340         camera->orientation.getValue().multVec(dir,dir);
00341         camera->position = camera->position.getValue() + dir;
00342         camera->orientation = event->getRotation() * camera->orientation.getValue();
00343         processed = TRUE;
00344     }
00345 
00346     enum {
00347         BUTTON1DOWN = 1 << 0,
00348         BUTTON3DOWN = 1 << 1,
00349         CTRLDOWN =    1 << 2,
00350         SHIFTDOWN =   1 << 3,
00351         BUTTON2DOWN = 1 << 4
00352     };
00353     unsigned int combo =
00354         (this->button1down ? BUTTON1DOWN : 0) |
00355         (this->button2down ? BUTTON2DOWN : 0) |
00356         (this->button3down ? BUTTON3DOWN : 0) |
00357         (this->ctrldown ? CTRLDOWN : 0) |
00358         (this->shiftdown ? SHIFTDOWN : 0);
00359 
00360     switch (combo) {
00361     case 0:
00362         if (curmode == NavigationStyle::SPINNING) { break; }
00363         newmode = NavigationStyle::IDLE;
00364         // The left mouse button has been released right now but
00365         // we want to avoid that the event is procesed elsewhere
00366         if (this->lockButton1) {
00367             this->lockButton1 = FALSE;
00368             processed = TRUE;
00369         }
00370 
00371         //if (curmode == NavigationStyle::DRAGGING) {
00372         //    if (doSpin())
00373         //        newmode = NavigationStyle::SPINNING;
00374         //}
00375         break;
00376     case BUTTON1DOWN:
00377         // make sure not to change the selection when stopping spinning
00378         if (curmode == NavigationStyle::SPINNING || this->lockButton1)
00379             newmode = NavigationStyle::IDLE;
00380         else
00381             newmode = NavigationStyle::SELECTION;
00382         break;
00383     case BUTTON3DOWN:
00384         if (curmode == NavigationStyle::SPINNING) { break; }
00385         else if (newmode == NavigationStyle::ZOOMING) { break; }
00386         newmode = NavigationStyle::PANNING;
00387 
00388         if (curmode == NavigationStyle::DRAGGING) {
00389             if (doSpin()) {
00390                 newmode = NavigationStyle::SPINNING;
00391                 break;
00392             }
00393         }
00394         break;
00395     case CTRLDOWN|BUTTON2DOWN:
00396         newmode = NavigationStyle::PANNING;
00397         break;
00398     case SHIFTDOWN|BUTTON2DOWN:
00399         newmode = NavigationStyle::DRAGGING;
00400         break;
00401     case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
00402         newmode = NavigationStyle::ZOOMING;
00403         break;
00404     //case CTRLDOWN:
00405     //case CTRLDOWN|BUTTON1DOWN:
00406     //case CTRLDOWN|SHIFTDOWN:
00407     //case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN:
00408     //    newmode = NavigationStyle::SELECTION;
00409     //    break;
00410     //case BUTTON1DOWN|BUTTON3DOWN:
00411     //case CTRLDOWN|BUTTON3DOWN:
00412     //    newmode = NavigationStyle::ZOOMING;
00413     //    break;
00414 
00415         // There are many cases we don't handle that just falls through to
00416         // the default case, like SHIFTDOWN, CTRLDOWN, CTRLDOWN|SHIFTDOWN,
00417         // SHIFTDOWN|BUTTON3DOWN, SHIFTDOWN|CTRLDOWN|BUTTON3DOWN, etc.
00418         // This is a feature, not a bug. :-)
00419         //
00420         // mortene.
00421 
00422     default:
00423         // The default will make a spin stop and otherwise not do
00424         // anything.
00425         //if ((curmode != NavigationStyle::SEEK_WAIT_MODE) &&
00426         //    (curmode != NavigationStyle::SEEK_MODE)) {
00427         //    newmode = NavigationStyle::IDLE;
00428         //}
00429         break;
00430     }
00431 
00432     if (newmode != curmode) {
00433         this->setViewingMode(newmode);
00434     }
00435 
00436     // If for dragging the buttons 1 and 3 are pressed
00437     // but then button 3 is relaesed we shouldn't switch
00438     // into selection mode.
00439     if (this->button1down && this->button3down)
00440         this->lockButton1 = TRUE;
00441 
00442     // If not handled in this class, pass on upwards in the inheritance
00443     // hierarchy.
00444     if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed)
00445         processed = inherited::processSoEvent(ev);
00446     else
00447         return TRUE;
00448 
00449     return processed;
00450 }

Generated on Wed Nov 23 18:59:59 2011 for FreeCAD by  doxygen 1.6.1