BlenderNavigationStyle.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::BlenderNavigationStyle */
00053 
00054 TYPESYSTEM_SOURCE(Gui::BlenderNavigationStyle, Gui::UserNavigationStyle);
00055 
00056 BlenderNavigationStyle::BlenderNavigationStyle() : lockButton1(FALSE)
00057 {
00058 }
00059 
00060 BlenderNavigationStyle::~BlenderNavigationStyle()
00061 {
00062 }
00063 
00064 const char* BlenderNavigationStyle::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 SHIFT and middle mouse button");
00071     case NavigationStyle::DRAGGING:
00072         return QT_TR_NOOP("Press 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 BlenderNavigationStyle::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->lockrecenter = TRUE;
00171             this->button1down = press;
00172             if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
00173                 newmode = NavigationStyle::SEEK_MODE;
00174                 this->seekToPoint(pos); // implicitly calls interactiveCountInc()
00175                 processed = TRUE;
00176             }
00177             //else if (press && (this->currentmode == NavigationStyle::IDLE)) {
00178             //    this->setViewing(true);
00179             //    processed = TRUE;
00180             //}
00181             else if (press && (this->currentmode == NavigationStyle::PANNING ||
00182                                this->currentmode == NavigationStyle::ZOOMING)) {
00183                 newmode = NavigationStyle::DRAGGING;
00184                 this->centerTime = ev->getTime();
00185                 processed = TRUE;
00186             }
00187             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
00188                 SbTime tmp = (ev->getTime() - this->centerTime);
00189                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00190                 if (tmp.getValue() < dci) {
00191                     newmode = NavigationStyle::ZOOMING;
00192                 }
00193                 processed = TRUE;
00194             }
00195             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
00196                 this->setViewing(false);
00197                 processed = TRUE;
00198             }
00199             else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
00200                 processed = TRUE;
00201             }
00202             break;
00203         case SoMouseButtonEvent::BUTTON2:
00204             // If we are in edit mode then simply ignore the RMB events
00205             // to pass the event to the base class.
00206             this->lockrecenter = TRUE;
00207             if (!viewer->isEditing()) {
00208                 // If we are in zoom or pan mode ignore RMB events otherwise
00209                 // the canvas doesn't get any release events 
00210                 if (this->currentmode != NavigationStyle::ZOOMING && 
00211                     this->currentmode != NavigationStyle::PANNING &&
00212                     this->currentmode != NavigationStyle::DRAGGING) {
00213                     if (this->isPopupMenuEnabled()) {
00214                         if (!press) { // release right mouse button
00215                             this->openPopupMenu(event->getPosition());
00216                         }
00217                     }
00218                 }
00219             }
00220             // Alternative way of rotating & zooming
00221             if (press && (this->currentmode == NavigationStyle::PANNING ||
00222                           this->currentmode == NavigationStyle::ZOOMING)) {
00223                 newmode = NavigationStyle::DRAGGING;
00224                 this->centerTime = ev->getTime();
00225                 processed = TRUE;
00226             }
00227             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
00228                 SbTime tmp = (ev->getTime() - this->centerTime);
00229                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00230                 if (tmp.getValue() < dci) {
00231                     newmode = NavigationStyle::ZOOMING;
00232                 }
00233                 processed = TRUE;
00234             }
00235             this->button2down = press;
00236             break;
00237         case SoMouseButtonEvent::BUTTON3:
00238             if (press) {
00239                 this->centerTime = ev->getTime();
00240                 float ratio = vp.getViewportAspectRatio();
00241                 SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
00242                 this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
00243                 this->lockrecenter = FALSE;
00244             }
00245             else {
00246                 SbTime tmp = (ev->getTime() - this->centerTime);
00247                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
00248                 // is it just a middle click?
00249                 if (tmp.getValue() < dci && !this->lockrecenter) {
00250                     if (!this->lookAtPoint(pos)) {
00251                         panToCenter(panningplane, posn);
00252                         this->interactiveCountDec();
00253                     }
00254                     processed = TRUE;
00255                 }
00256             }
00257             this->button3down = press;
00258             break;
00259         case SoMouseButtonEvent::BUTTON4:
00260             if (this->invertZoom)
00261                 zoom(viewer->getCamera(), -0.05f);
00262             else
00263                 zoom(viewer->getCamera(), 0.05f);
00264             processed = TRUE;
00265             break;
00266         case SoMouseButtonEvent::BUTTON5:
00267             if (this->invertZoom)
00268                 zoom(viewer->getCamera(), 0.05f);
00269             else
00270                 zoom(viewer->getCamera(), -0.05f);
00271             processed = TRUE;
00272             break;
00273         default:
00274             break;
00275         }
00276     }
00277 
00278     // Mouse Movement handling
00279     if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
00280         this->lockrecenter = TRUE;
00281         const SoLocation2Event * const event = (const SoLocation2Event *) ev;
00282         if (this->currentmode == NavigationStyle::ZOOMING) {
00283             this->zoomByCursor(posn, prevnormalized);
00284             processed = TRUE;
00285         }
00286         else if (this->currentmode == NavigationStyle::PANNING) {
00287             float ratio = vp.getViewportAspectRatio();
00288             panCamera(viewer->getCamera(), ratio, this->panningplane, posn, prevnormalized);
00289             processed = TRUE;
00290         }
00291         else if (this->currentmode == NavigationStyle::DRAGGING) {
00292             this->addToLog(event->getPosition(), event->getTime());
00293             this->spin(posn);
00294             processed = TRUE;
00295         }
00296     }
00297 
00298     // Spaceball & Joystick handling
00299     if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
00300         SoMotion3Event * const event = (SoMotion3Event *) ev;
00301         SoCamera * const camera = viewer->getCamera();
00302 
00303         SbVec3f dir = event->getTranslation();
00304         if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())){
00305             static float zoomConstant(-.03f);
00306             dir[2] = 0.0;//don't move the cam for z translation.
00307 
00308             SoOrthographicCamera *oCam = static_cast<SoOrthographicCamera *>(camera);
00309             oCam->scaleHeight(1.0-event->getTranslation()[2] * zoomConstant);
00310         }
00311         camera->orientation.getValue().multVec(dir,dir);
00312         camera->position = camera->position.getValue() + dir;
00313         camera->orientation = event->getRotation() * camera->orientation.getValue();
00314         processed = TRUE;
00315     }
00316 
00317     enum {
00318         BUTTON1DOWN = 1 << 0,
00319         BUTTON3DOWN = 1 << 1,
00320         CTRLDOWN =    1 << 2,
00321         SHIFTDOWN =   1 << 3,
00322         BUTTON2DOWN = 1 << 4
00323     };
00324     unsigned int combo =
00325         (this->button1down ? BUTTON1DOWN : 0) |
00326         (this->button2down ? BUTTON2DOWN : 0) |
00327         (this->button3down ? BUTTON3DOWN : 0) |
00328         (this->ctrldown ? CTRLDOWN : 0) |
00329         (this->shiftdown ? SHIFTDOWN : 0);
00330 
00331     switch (combo) {
00332     case 0:
00333         if (curmode == NavigationStyle::SPINNING) { break; }
00334         newmode = NavigationStyle::IDLE;
00335         // The left mouse button has been released right now but
00336         // we want to avoid that the event is procesed elsewhere
00337         if (this->lockButton1) {
00338             this->lockButton1 = FALSE;
00339             processed = TRUE;
00340         }
00341 
00342         //if (curmode == NavigationStyle::DRAGGING) {
00343         //    if (doSpin())
00344         //        newmode = NavigationStyle::SPINNING;
00345         //}
00346         break;
00347     case BUTTON1DOWN:
00348         // make sure not to change the selection when stopping spinning
00349         if (curmode == NavigationStyle::SPINNING || this->lockButton1)
00350             newmode = NavigationStyle::IDLE;
00351         else
00352             newmode = NavigationStyle::SELECTION;
00353         break;
00354     case SHIFTDOWN|BUTTON3DOWN:
00355         newmode = NavigationStyle::PANNING;
00356         break;
00357     case BUTTON3DOWN:
00358         newmode = NavigationStyle::DRAGGING;
00359         break;
00360     case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
00361         newmode = NavigationStyle::ZOOMING;
00362         break;
00363 
00364     default:
00365         break;
00366     }
00367 
00368     if (newmode != curmode) {
00369         this->setViewingMode(newmode);
00370     }
00371 
00372     // If for dragging the buttons 1 and 3 are pressed
00373     // but then button 3 is relaesed we shouldn't switch
00374     // into selection mode.
00375     if (this->button1down && this->button3down)
00376         this->lockButton1 = TRUE;
00377 
00378     // If not handled in this class, pass on upwards in the inheritance
00379     // hierarchy.
00380     if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed)
00381         processed = inherited::processSoEvent(ev);
00382     else
00383         return TRUE;
00384 
00385     return processed;
00386 }

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