qglviewer.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 
3  Copyright (C) 2002-2013 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.4.0.
6 
7  http://www.libqglviewer.com - contact@libqglviewer.com
8 
9  This file may be used under the terms of the GNU General Public License
10  versions 2.0 or 3.0 as published by the Free Software Foundation and
11  appearing in the LICENSE file included in the packaging of this file.
12  In addition, as a special exception, Gilles Debunne gives you certain
13  additional rights, described in the file GPL_EXCEPTION in this package.
14 
15  libQGLViewer uses dual licensing. Commercial/proprietary software must
16  purchase a libQGLViewer Commercial License.
17 
18  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
19  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 
21 *****************************************************************************/
22 
23 #include "domUtils.h"
24 #include "qglviewer.h"
25 #include "camera.h"
26 #include "keyFrameInterpolator.h"
27 
28 #if QT_VERSION >= 0x040000
29 # include <QtAlgorithms>
30 # include <QTextEdit>
31 # include <QApplication>
32 # include <QFileInfo>
33 # include <QDateTime>
34 # include <QMessageBox>
35 # include <QPushButton>
36 # include <QTabWidget>
37 # include <QTextStream>
38 # include <QMouseEvent>
39 # include <QTimer>
40 # include <QImage>
41 # include <QDir>
42 # include <QUrl>
43 #else
44 # include <qapplication.h>
45 # include <qfileinfo.h>
46 # include <qdatetime.h>
47 # include <qmessagebox.h>
48 # include <qpushbutton.h>
49 # include <qtabwidget.h>
50 # include <qtextstream.h>
51 # include <qtimer.h>
52 # include <qimage.h>
53 # include <qtextedit.h>
54 # include <qkeysequence.h>
55 # include <qdir.h>
56  // Patch for enums names change
57 # define KeyboardModifierMask KeyButtonMask
58  // Patch for QMap API change
59 # define value data
60 #endif
61 
62 using namespace std;
63 using namespace qglviewer;
64 
65 // Static private variable
66 #if QT_VERSION >= 0x040000
67 QList<QGLViewer*> QGLViewer::QGLViewerPool_;
68 #else
69 QPtrList<QGLViewer> QGLViewer::QGLViewerPool_;
70 #endif
71 
72 
91 {
92  // - - - W A R N I N G - - -
93  // This method should not call initializeGL(). Otherwise, as we are in the
94  // base class constructor, the user-defined init() would never be called.
95  // The different QGLViewer::setXXX are hence protected, so that updateGL is not called.
96  // The different constructor code should then be EMPTY.
97  updateGLOK_ = false;
98 
99  // Test OpenGL context
100  // if (glGetString(GL_VERSION) == 0)
101  // qWarning("Unable to get OpenGL version, context may not be available - Check your configuration");
102 
103 #if QT_VERSION >= 0x040000
104  int poolIndex = QGLViewer::QGLViewerPool_.indexOf(NULL);
105  setFocusPolicy(Qt::StrongFocus);
106 #else
107  int poolIndex = QGLViewer::QGLViewerPool_.findRef(NULL);
108  setFocusPolicy(QWidget::StrongFocus);
109 #endif
110 
111  if (poolIndex >= 0)
112  QGLViewer::QGLViewerPool_.replace(poolIndex, this);
113  else
114  QGLViewer::QGLViewerPool_.append(this);
115 
116  camera_ = new Camera();
117  setCamera(camera());
118 
119  setDefaultShortcuts();
120  setDefaultMouseBindings();
121 
122  setSnapshotFileName(tr("snapshot", "Default snapshot file name"));
123  initializeSnapshotFormats();
124  setSnapshotCounter(0);
125  setSnapshotQuality(95);
126 
127  fpsTime_.start();
128  fpsCounter_ = 0;
129  f_p_s_ = 0.0;
130  fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg("?");
131  visualHint_ = 0;
132  previousPathId_ = 0;
133  // prevPos_ is not initialized since pos() is not meaningful here. It will be set by setFullScreen().
134 
135  // #CONNECTION# default values in initFromDOMElement()
136  manipulatedFrame_ = NULL;
137  manipulatedFrameIsACamera_ = false;
138  mouseGrabberIsAManipulatedFrame_ = false;
139  mouseGrabberIsAManipulatedCameraFrame_ = false;
140  displayMessage_ = false;
141  connect(&messageTimer_, SIGNAL(timeout()), SLOT(hideMessage()));
142 #if QT_VERSION >= 0x040000
143  messageTimer_.setSingleShot(true);
144 #endif
145  helpWidget_ = NULL;
146  setMouseGrabber(NULL);
147 
148  setSceneRadius(1.0);
149  showEntireScene();
150  setStateFileName(".qglviewer.xml");
151 
152  // #CONNECTION# default values in initFromDOMElement()
153  setAxisIsDrawn(false);
154  setGridIsDrawn(false);
155  setFPSIsDisplayed(false);
156  setCameraIsEdited(false);
157  setTextIsEnabled(true);
158  setStereoDisplay(false);
159  setFullScreen(false);
160 
161  animationTimerId_ = 0;
162  stopAnimation();
163  setAnimationPeriod(40); // 25Hz
164 
165  selectBuffer_ = NULL;
166  setSelectBufferSize(4*1000);
167  setSelectRegionWidth(3);
168  setSelectRegionHeight(3);
169  setSelectedName(-1);
170 
171  bufferTextureId_ = 0;
172  bufferTextureMaxU_ = 0.0;
173  bufferTextureMaxV_ = 0.0;
174  bufferTextureWidth_ = 0;
175  bufferTextureHeight_ = 0;
176  previousBufferTextureFormat_ = 0;
177  previousBufferTextureInternalFormat_ = 0;
178 
179 #if QT_VERSION >= 0x040000
180  setAttribute(Qt::WA_NoSystemBackground);
181 #endif
182 
183  tileRegion_ = NULL;
184 }
185 
186 #if QT_VERSION >= 0x040000 && !defined QT3_SUPPORT
187 
194 QGLViewer::QGLViewer(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags)
195 : QGLWidget(parent, shareWidget, flags)
196 { defaultConstructor(); }
197 
203 QGLViewer::QGLViewer(QGLContext *context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags)
204 : QGLWidget(context, parent, shareWidget, flags)
205 { defaultConstructor(); }
206 
211 QGLViewer::QGLViewer(const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags)
212 : QGLWidget(format, parent, shareWidget, flags)
213 { defaultConstructor(); }
214 #endif
215 
221 {
222  // See closeEvent comment. Destructor is called (and not closeEvent) only when the widget is embedded.
223  // Hence we saveToFile here. It is however a bad idea if virtual domElement() has been overloaded !
224  // if (parent())
225  // saveStateToFileForAllViewers();
226 
227 #if QT_VERSION >= 0x040000
228  QGLViewer::QGLViewerPool_.replace(QGLViewer::QGLViewerPool_.indexOf(this), NULL);
229 #else
230  QGLViewer::QGLViewerPool_.replace(QGLViewer::QGLViewerPool_.findRef(this), NULL);
231 #endif
232 
233  delete camera();
234  delete[] selectBuffer_;
235  if (helpWidget())
236  {
237  // Needed for Qt 4 which has no main widget.
238  helpWidget()->close();
239  delete helpWidget_;
240  }
241 }
242 
243 
244 static QString QGLViewerVersionString()
245 {
246  return QString::number((QGLVIEWER_VERSION & 0xff0000) >> 16) + "." +
247  QString::number((QGLVIEWER_VERSION & 0x00ff00) >> 8) + "." +
248  QString::number(QGLVIEWER_VERSION & 0x0000ff);
249 }
250 
251 static int convertToKeyboardModifiers(int state)
252 {
253 #if QT_VERSION < 0x040000
254  // Qt 2 & 3 have different values for ButtonState and Modifiers.
255  // Converts CTRL,SHIFT... to ControlButton, ShiftButton...
256  if (state & Qt::MODIFIER_MASK)
257  {
258  if (state & Qt::CTRL) { state &= ~Qt::CTRL; state |= Qt::ControlButton; }
259  if (state & Qt::SHIFT) { state &= ~Qt::SHIFT; state |= Qt::ShiftButton; }
260  if (state & Qt::ALT) { state &= ~Qt::ALT; state |= Qt::AltButton; }
261 # if QT_VERSION >= 0x030100
262  if (state & Qt::META) { state &= ~Qt::META; state |= Qt::MetaButton; }
263 # endif
264  }
265 #endif
266  return state;
267 }
268 
269 static Qt::KeyboardModifiers convertKeyboardModifiers(Qt::KeyboardModifiers modifiers)
270 {
271 #if QT_VERSION < 0x040000
272  return Qt::KeyboardModifiers(convertToKeyboardModifiers(modifiers));
273 #else
274  return modifiers;
275 #endif
276 }
277 
278 static int convertToShortModifier(int state)
279 {
280  // Converts ControlButton, ShiftButton... to CTRL,SHIFT...
281  // convertToKeyboardModifiers does the opposite
282 #if QT_VERSION < 0x040000
283  if (state & Qt::KeyButtonMask)
284  {
285  if (state & Qt::ControlButton) { state &= ~Qt::ControlButton; state |= Qt::CTRL; }
286  if (state & Qt::ShiftButton) { state &= ~Qt::ShiftButton; state |= Qt::SHIFT; }
287  if (state & Qt::AltButton) { state &= ~Qt::AltButton; state |= Qt::ALT; }
288 # if QT_VERSION >= 0x030100
289  if (state & Qt::MetaButton) { state &= ~Qt::MetaButton; state |= Qt::META; }
290 # endif
291  }
292 #endif
293  return state;
294 }
295 
315 {
316  if (updateGLOK_)
317  qWarning("Internal debug: initializeGL() is called in QGLViewer constructor.");
318 
319  glEnable(GL_LIGHT0);
320  glEnable(GL_LIGHTING);
321  glEnable(GL_DEPTH_TEST);
322  glEnable(GL_COLOR_MATERIAL);
323 
324  // Default colors
325  setForegroundColor(QColor(180, 180, 180));
326  setBackgroundColor(QColor(51, 51, 51));
327 
328  // Clear the buffer where we're going to draw
329  if (format().stereo())
330  {
331  glDrawBuffer(GL_BACK_RIGHT);
332  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
333  glDrawBuffer(GL_BACK_LEFT);
334  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
335  }
336  else
337  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
338 
339  // Calls user defined method. Default emits a signal.
340  init();
341 
342  // Give time to glInit to finish and then call setFullScreen().
343  if (isFullScreen())
344  QTimer::singleShot( 100, this, SLOT(delayedFullScreen()) );
345 
346  updateGLOK_ = true;
347 }
348 
356 {
357  updateGLOK_ = false;
358  if (displaysInStereo())
359  {
360  for (int view=1; view>=0; --view)
361  {
362  // Clears screen, set model view matrix with shifted matrix for ith buffer
363  preDrawStereo(view);
364  // Used defined method. Default is empty
365  if (camera()->frame()->isManipulated())
366  fastDraw();
367  else
368  draw();
369  postDraw();
370  }
371  }
372  else
373  {
374  // Clears screen, set model view matrix...
375  preDraw();
376  // Used defined method. Default calls draw()
377  if (camera()->frame()->isManipulated())
378  fastDraw();
379  else
380  draw();
381  // Add visual hints: axis, camera, grid...
382  postDraw();
383  }
384  updateGLOK_ = true;
385  Q_EMIT drawFinished(true);
386 }
387 
400 {
401  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
402 
403  // GL_PROJECTION matrix
404  camera()->loadProjectionMatrix();
405  // GL_MODELVIEW matrix
406  camera()->loadModelViewMatrix();
407 
408  Q_EMIT drawNeeded();
409 }
410 
422 {
423  // Reset model view matrix to world coordinates origin
424  glMatrixMode(GL_MODELVIEW);
425  glPushMatrix();
426  camera()->loadModelViewMatrix();
427  // TODO restore model loadProjectionMatrixStereo
428 
429  // Save OpenGL state
430  glPushAttrib(GL_ALL_ATTRIB_BITS);
431 
432  // Set neutral GL state
433  glDisable(GL_TEXTURE_1D);
434  glDisable(GL_TEXTURE_2D);
435 #ifdef GL_TEXTURE_3D // OpenGL 1.2 Only...
436  glDisable(GL_TEXTURE_3D);
437 #endif
438 
439  glDisable(GL_TEXTURE_GEN_Q);
440  glDisable(GL_TEXTURE_GEN_R);
441  glDisable(GL_TEXTURE_GEN_S);
442  glDisable(GL_TEXTURE_GEN_T);
443 
444 #ifdef GL_RESCALE_NORMAL // OpenGL 1.2 Only...
445  glEnable(GL_RESCALE_NORMAL);
446 #endif
447 
448  glDisable(GL_COLOR_MATERIAL);
449  qglColor(foregroundColor());
450 
451  if (cameraIsEdited())
452  camera()->drawAllPaths();
453 
454  // Revolve Around Point, line when camera rolls, zoom region
455  drawVisualHints();
456 
457  if (gridIsDrawn()) { glLineWidth(1.0); drawGrid(camera()->sceneRadius()); }
458  if (axisIsDrawn()) { glLineWidth(2.0); drawAxis(camera()->sceneRadius()); }
459 
460  // FPS computation
461  const unsigned int maxCounter = 20;
462  if (++fpsCounter_ == maxCounter)
463  {
464  f_p_s_ = 1000.0 * maxCounter / fpsTime_.restart();
465  fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg(f_p_s_, 0, 'f', ((f_p_s_ < 10.0)?1:0));
466  fpsCounter_ = 0;
467  }
468 
469  // Restore foregroundColor
470  float color[4];
471  color[0] = foregroundColor().red() / 255.0;
472  color[1] = foregroundColor().green() / 255.0;
473  color[2] = foregroundColor().blue() / 255.0;
474  color[3] = 1.0;
475  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
476  glDisable(GL_LIGHTING);
477  glDisable(GL_DEPTH_TEST);
478 
479  if (FPSIsDisplayed()) displayFPS();
480  if (displayMessage_) drawText(10, height()-10, message_);
481 
482  // Restore GL state
483  glPopAttrib();
484  glPopMatrix();
485 }
486 
492 void QGLViewer::preDrawStereo(bool leftBuffer)
493 {
494  // Set buffer to draw in
495  // Seems that SGI and Crystal Eyes are not synchronized correctly !
496  // That's why we don't draw in the appropriate buffer...
497  if (!leftBuffer)
498  glDrawBuffer(GL_BACK_LEFT);
499  else
500  glDrawBuffer(GL_BACK_RIGHT);
501 
502  // Clear the buffer where we're going to draw
503  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
504  // GL_PROJECTION matrix
505  camera()->loadProjectionMatrixStereo(leftBuffer);
506  // GL_MODELVIEW matrix
507  camera()->loadModelViewMatrixStereo(leftBuffer);
508 
509  Q_EMIT drawNeeded();
510 }
511 
520 {
521  draw();
522 }
523 
532 {
533  cameraIsEdited_ = edit;
534  if (edit)
535  {
536  previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient();
537  // #CONNECTION# 5.0 also used in domElement() and in initFromDOMElement().
538  camera()->setZClippingCoefficient(5.0);
539  }
540  else
541  camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_);
542 
543  Q_EMIT cameraIsEditedChanged(edit);
544 
545  if (updateGLOK_)
546  updateGL();
547 }
548 
549 // Key bindings. 0 means not defined
551 {
552  // D e f a u l t a c c e l e r a t o r s
553  setShortcut(DRAW_AXIS, Qt::Key_A);
554  setShortcut(DRAW_GRID, Qt::Key_G);
555  setShortcut(DISPLAY_FPS, Qt::Key_F);
556  setShortcut(ENABLE_TEXT, Qt::SHIFT+Qt::Key_Question);
557  setShortcut(EXIT_VIEWER, Qt::Key_Escape);
558  setShortcut(SAVE_SCREENSHOT, Qt::CTRL+Qt::Key_S);
559  setShortcut(CAMERA_MODE, Qt::Key_Space);
560  setShortcut(FULL_SCREEN, Qt::ALT+Qt::Key_Return);
561  setShortcut(STEREO, Qt::Key_S);
562  setShortcut(ANIMATION, Qt::Key_Return);
563  setShortcut(HELP, Qt::Key_H);
564  setShortcut(EDIT_CAMERA, Qt::Key_C);
565  setShortcut(MOVE_CAMERA_LEFT, Qt::Key_Left);
566  setShortcut(MOVE_CAMERA_RIGHT,Qt::Key_Right);
567  setShortcut(MOVE_CAMERA_UP, Qt::Key_Up);
568  setShortcut(MOVE_CAMERA_DOWN, Qt::Key_Down);
569  setShortcut(INCREASE_FLYSPEED,Qt::Key_Plus);
570  setShortcut(DECREASE_FLYSPEED,Qt::Key_Minus);
571  setShortcut(SNAPSHOT_TO_CLIPBOARD,Qt::CTRL+Qt::Key_C);
572 
573  keyboardActionDescription_[DISPLAY_FPS] = tr("Toggles the display of the FPS", "DISPLAY_FPS action description");
574  keyboardActionDescription_[SAVE_SCREENSHOT] = tr("Saves a screenshot", "SAVE_SCREENSHOT action description");
575  keyboardActionDescription_[FULL_SCREEN] = tr("Toggles full screen display", "FULL_SCREEN action description");
576  keyboardActionDescription_[DRAW_AXIS] = tr("Toggles the display of the world axis", "DRAW_AXIS action description");
577  keyboardActionDescription_[DRAW_GRID] = tr("Toggles the display of the XY grid", "DRAW_GRID action description");
578  keyboardActionDescription_[CAMERA_MODE] = tr("Changes camera mode (revolve or fly)", "CAMERA_MODE action description");
579  keyboardActionDescription_[STEREO] = tr("Toggles stereo display", "STEREO action description");
580  keyboardActionDescription_[HELP] = tr("Opens this help window", "HELP action description");
581  keyboardActionDescription_[ANIMATION] = tr("Starts/stops the animation", "ANIMATION action description");
582  keyboardActionDescription_[EDIT_CAMERA] = tr("Toggles camera paths display", "EDIT_CAMERA action description"); // TODO change
583  keyboardActionDescription_[ENABLE_TEXT] = tr("Toggles the display of the text", "ENABLE_TEXT action description");
584  keyboardActionDescription_[EXIT_VIEWER] = tr("Exits program", "EXIT_VIEWER action description");
585  keyboardActionDescription_[MOVE_CAMERA_LEFT] = tr("Moves camera left", "MOVE_CAMERA_LEFT action description");
586  keyboardActionDescription_[MOVE_CAMERA_RIGHT] = tr("Moves camera right", "MOVE_CAMERA_RIGHT action description");
587  keyboardActionDescription_[MOVE_CAMERA_UP] = tr("Moves camera up", "MOVE_CAMERA_UP action description");
588  keyboardActionDescription_[MOVE_CAMERA_DOWN] = tr("Moves camera down", "MOVE_CAMERA_DOWN action description");
589  keyboardActionDescription_[INCREASE_FLYSPEED] = tr("Increases fly speed", "INCREASE_FLYSPEED action description");
590  keyboardActionDescription_[DECREASE_FLYSPEED] = tr("Decreases fly speed", "DECREASE_FLYSPEED action description");
591  keyboardActionDescription_[SNAPSHOT_TO_CLIPBOARD] = tr("Copies a snapshot to clipboard", "SNAPSHOT_TO_CLIPBOARD action description");
592 
593  // K e y f r a m e s s h o r t c u t k e y s
594  setPathKey(Qt::Key_F1, 1);
595  setPathKey(Qt::Key_F2, 2);
596  setPathKey(Qt::Key_F3, 3);
597  setPathKey(Qt::Key_F4, 4);
598  setPathKey(Qt::Key_F5, 5);
599  setPathKey(Qt::Key_F6, 6);
600  setPathKey(Qt::Key_F7, 7);
601  setPathKey(Qt::Key_F8, 8);
602  setPathKey(Qt::Key_F9, 9);
603  setPathKey(Qt::Key_F10, 10);
604  setPathKey(Qt::Key_F11, 11);
605  setPathKey(Qt::Key_F12, 12);
606 
607 #if QT_VERSION >= 0x040000
608  setAddKeyFrameKeyboardModifiers(Qt::AltModifier);
609  setPlayPathKeyboardModifiers(Qt::NoModifier);
610 #else
611  setAddKeyFrameKeyboardModifiers(Qt::AltButton);
612  setPlayPathKeyboardModifiers(Qt::NoButton);
613 #endif
614 }
615 
616 // M o u s e b e h a v i o r
618 {
619 #if QT_VERSION >= 0x040000
620  const Qt::KeyboardModifiers cameraKeyboardModifiers = Qt::NoModifier;
621  const Qt::KeyboardModifiers frameKeyboardModifiers = Qt::ControlModifier;
622 #else
623  const Qt::KeyboardModifiers cameraKeyboardModifiers = Qt::NoButton;
624  const Qt::KeyboardModifiers frameKeyboardModifiers = Qt::ControlButton;
625 #endif
626  //#CONNECTION# toggleCameraMode()
627  for (int handler=0; handler<2; ++handler)
628  {
629  MouseHandler mh = (MouseHandler)(handler);
630  Qt::KeyboardModifiers modifiers = (mh == FRAME) ? frameKeyboardModifiers : cameraKeyboardModifiers;
631 
632  setMouseBinding(modifiers | Qt::LeftButton, mh, ROTATE);
633  setMouseBinding(modifiers | Qt::MidButton, mh, ZOOM);
634  setMouseBinding(modifiers | Qt::RightButton, mh, TRANSLATE);
635 
636  setMouseBinding(modifiers | Qt::LeftButton | Qt::MidButton, mh, SCREEN_ROTATE);
637  // 2.2.4 setMouseBinding(modifiers | Qt::RightButton | Qt::MidButton, mh, SCREEN_TRANSLATE);
638 
639  setWheelBinding(modifiers, mh, ZOOM);
640  }
641 
642 #if QT_VERSION >= 0x040000
643  // Z o o m o n r e g i o n
644  setMouseBinding(Qt::SHIFT + Qt::MidButton, CAMERA, ZOOM_ON_REGION);
645  // S e l e c t
646  setMouseBinding(Qt::SHIFT + Qt::LeftButton, SELECT);
647 #else
648  setMouseBinding(Qt::SHIFT + Qt::MidButton, CAMERA, ZOOM_ON_REGION);
649  setMouseBinding(Qt::SHIFT + Qt::LeftButton, SELECT);
650 #endif
651 
652  // D o u b l e c l i c k
653  setMouseBinding(Qt::LeftButton, ALIGN_CAMERA, true);
654  setMouseBinding(Qt::MidButton, SHOW_ENTIRE_SCENE, true);
655  setMouseBinding(Qt::RightButton, CENTER_SCENE, true);
656 
657  setMouseBinding(frameKeyboardModifiers | Qt::LeftButton, ALIGN_FRAME, true);
658  setMouseBinding(frameKeyboardModifiers | Qt::RightButton, CENTER_FRAME, true);
659 
660  // S p e c i f i c d o u b l e c l i c k s
661  setMouseBinding(Qt::LeftButton, RAP_FROM_PIXEL, true, Qt::RightButton);
662  setMouseBinding(Qt::RightButton, RAP_IS_CENTER, true, Qt::LeftButton);
663  setMouseBinding(Qt::LeftButton, ZOOM_ON_PIXEL, true, Qt::MidButton);
664  setMouseBinding(Qt::RightButton, ZOOM_TO_FIT, true, Qt::MidButton);
665 
666 #ifdef Q_OS_MAC
667  // Specific Mac bindings. Double finger emulates a wheelEvent which zooms.
668  // Make Option + left emulate the right button. Other bindings should be changed accordingly.
669  // Done at the end to override previous settings.
670 # if QT_VERSION >= 0x040000
671  const Qt::KeyboardModifiers macKeyboardModifiers = Qt::AltModifier;
672 # else
673  const Qt::KeyboardModifiers macKeyboardModifiers = Qt::AltButton;
674 # endif
675 
676  setMouseBinding(macKeyboardModifiers | Qt::LeftButton, CAMERA, TRANSLATE);
677  setMouseBinding(macKeyboardModifiers | Qt::LeftButton, CENTER_SCENE, true);
678  setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers | Qt::LeftButton, CENTER_FRAME, true);
679  setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers | Qt::LeftButton, FRAME, TRANSLATE);
680 
681  // S p e c i f i c d o u b l e c l i c k s
682  // A single tap is actually seen as a left followed by a right button click.
683  setMouseBinding(Qt::META + Qt::RightButton, RAP_FROM_PIXEL, true, Qt::LeftButton);
684  setMouseBinding(Qt::SHIFT + Qt::META + Qt::RightButton, RAP_IS_CENTER, true, Qt::LeftButton);
685  // A tap with two fingers is actually considered a rightButton.
686  setMouseBinding(Qt::META + Qt::RightButton, ZOOM_ON_PIXEL, false);
687  setMouseBinding(Qt::SHIFT + Qt::MetaModifier | Qt::RightButton, ZOOM_TO_FIT, false);
688 #endif
689 }
690 
707 void QGLViewer::setCamera(Camera* const camera)
708 {
709  if (!camera)
710  return;
711 
712  camera->setSceneRadius(sceneRadius());
713  camera->setSceneCenter(sceneCenter());
714  camera->setScreenWidthAndHeight(width(),height());
715 
716  // Disconnect current camera to this viewer.
717  disconnect(this->camera()->frame(), SIGNAL(manipulated()), this, SLOT(updateGL()));
718  disconnect(this->camera()->frame(), SIGNAL(spun()), this, SLOT(updateGL()));
719 
720  // Connect camera frame to this viewer.
721  connect(camera->frame(), SIGNAL(manipulated()), SLOT(updateGL()));
722  connect(camera->frame(), SIGNAL(spun()), SLOT(updateGL()));
723 
724  connectAllCameraKFIInterpolatedSignals(false);
725  camera_ = camera;
726  connectAllCameraKFIInterpolatedSignals();
727 
728  previousCameraZClippingCoefficient_ = this->camera()->zClippingCoefficient();
729 }
730 
732 {
733  for (QMap<int, KeyFrameInterpolator*>::ConstIterator it = camera()->kfi_.begin(), end=camera()->kfi_.end(); it != end; ++it)
734  {
735  if (connection)
736  connect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), SLOT(updateGL()));
737  else
738  disconnect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), this, SLOT(updateGL()));
739  }
740 
741  if (connection)
742  connect(camera()->interpolationKfi_, SIGNAL(interpolated()), SLOT(updateGL()));
743  else
744  disconnect(camera()->interpolationKfi_, SIGNAL(interpolated()), this, SLOT(updateGL()));
745 }
746 
763 void QGLViewer::drawLight(GLenum light, float scale) const
764 {
765  static GLUquadric* quadric = gluNewQuadric();
766 
767  const float length = sceneRadius() / 5.0 * scale;
768 
769  GLboolean lightIsOn;
770  glGetBooleanv(light, &lightIsOn);
771 
772  if (lightIsOn)
773  {
774  // All light values are given in eye coordinates
775  glPushMatrix();
776  glLoadIdentity();
777 
778  float color[4];
779  glGetLightfv(light, GL_DIFFUSE, color);
780  glColor4fv(color);
781 
782  float pos[4];
783  glGetLightfv(light, GL_POSITION, pos);
784 
785  if (pos[3] != 0.0)
786  {
787  glTranslatef(pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3]);
788 
789  GLfloat cutOff;
790  glGetLightfv(light, GL_SPOT_CUTOFF, &cutOff);
791  if (cutOff != 180.0)
792  {
793  GLfloat dir[4];
794  glGetLightfv(light, GL_SPOT_DIRECTION, dir);
795  glMultMatrixd(Quaternion(Vec(0,0,1), Vec(dir)).matrix());
796  QGLViewer::drawArrow(length);
797  gluCylinder(quadric, 0.0, 0.7 * length * sin(cutOff * M_PI / 180.0), 0.7 * length * cos(cutOff * M_PI / 180.0), 12, 1);
798  }
799  else
800  gluSphere(quadric, 0.2*length, 10, 10);
801  }
802  else
803  {
804  // Directional light.
805  Vec dir(pos[0], pos[1], pos[2]);
806  dir.normalize();
807  Frame fr=Frame(camera()->cameraCoordinatesOf(4.0 * length * camera()->frame()->inverseTransformOf(dir)),
808  Quaternion(Vec(0,0,-1), dir));
809  glMultMatrixd(fr.matrix());
810  drawArrow(length);
811  }
812 
813  glPopMatrix();
814  }
815 }
816 
817 
860 void QGLViewer::drawText(int x, int y, const QString& text, const QFont& fnt)
861 {
862  if (!textIsEnabled())
863  return;
864 
865 #if QT_VERSION < QGLVIEWER_QT_VERSION_WITHOUT_GLUT
866  const GLfloat font_scale = 119.05f - 33.33f; // see glutStrokeCharacter man page
867 
868  startScreenCoordinatesSystem();
869 
870  // Anti-aliased characters
871  glPushAttrib(GL_ALL_ATTRIB_BITS);
872  glDisable(GL_LIGHTING);
873  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
874  glEnable(GL_BLEND);
875  glDisable(GL_DEPTH_TEST);
876  glEnable(GL_LINE_SMOOTH);
877  glLineWidth(1.0);
878 
879  glTranslatef((GLfloat)x, (GLfloat)y, 0.0);
880  const GLfloat scale = ((fnt.pixelSize()>0)?fnt.pixelSize():fnt.pointSize()) / font_scale;
881  glScalef(scale, -scale, scale);
882 
883  for (uint i=0; i<text.length(); ++i)
884  glutStrokeCharacter(GLUT_STROKE_ROMAN, text.at(i));
885 
886  glPopAttrib();
887 
888  stopScreenCoordinatesSystem();
889 #else
890 
891 # if QT_VERSION < 0x030300 && defined Q_OS_UNIX
892  // Fix bug with anti-aliased fonts on nVidia driver
893  QFont newFont(fnt);
894  newFont.setFamily("fixed");
895  newFont.setRawMode(true);
896  newFont.setPixelSize(10);
897  newFont.setFixedPitch(true);
898 # if QT_VERSION >= 0x030200
899  newFont.setStyleStrategy(QFont::OpenGLCompatible);
900 # endif
901  newFont.setStyleHint(QFont::AnyStyle, QFont::PreferBitmap);
902  renderText(x, y, text, newFont);
903 # else
904  if (tileRegion_ != NULL) {
905  renderText((x-tileRegion_->xMin) * width() / (tileRegion_->xMax - tileRegion_->xMin),
906  (y-tileRegion_->yMin) * height() / (tileRegion_->yMax - tileRegion_->yMin), text, scaledFont(fnt));
907  } else
908  renderText(x, y, text, fnt);
909 # endif
910 
911 #endif
912 }
913 
914 /* Similar to drawText(), but the text is handled as a classical 3D object of the scene.
915 
916 Although useful, this method is deprecated with recent Qt versions. Indeed, Qt renders text as
917 pixmaps that cannot be oriented. However, when GLUT is used instead of Qt (when your Qt version is
918 lower than 3.1, see drawText() documentation) orientated characters are possible and this method will work.
919 
920 \p pos and \p normal respectively represent the 3D coordinate of the text and the normal to the text
921 plane. They are expressed with respect to the \e current \c GL_MODELVIEW matrix.
922 
923 If you want your text to always face the camera (normal parallel to camera()->viewDirection), use
924 QGLWidget::renderText(x,y,z).
925 
926 See the <a href="../examples/draw3DText.html">draw3DText example</a> for an illustration. */
927 /*
928 void QGLViewer::draw3DText(const Vec& pos, const Vec& normal, const QString& text, GLfloat height)
929 {
930 #if QT_VERSION < QGLVIEWER_QT_VERSION_WITHOUT_GLUT
931 if (!textIsEnabled())
932 return;
933 
934 glMatrixMode(GL_MODELVIEW) ;
935 glPushMatrix() ;
936 
937 const GLfloat font_scale = (119.05f - 33.33f) / 8; // see glutStrokeCharacter man page
938 // const GLfloat font_scale = (119.05f - 33.33f) * 15.0f; // see glutStrokeCharacter man page
939 
940 static GLfloat lineWidth;
941 glGetFloatv(GL_LINE_WIDTH, &lineWidth);
942 
943 glTranslatef(pos.x, pos.y, pos.z);
944 glMultMatrixd(Quaternion(Vec(0.0, 0.0, 1.0), normal).matrix());
945 
946 glLineWidth(2.0);
947 
948 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
949 glEnable(GL_BLEND);
950 glEnable(GL_LINE_SMOOTH);
951 
952 const GLfloat scale = height / font_scale;
953 glScalef(scale, scale, scale);
954 
955 for (uint i=0; i<text.length(); ++i)
956 glutStrokeCharacter(GLUT_STROKE_ROMAN, text.at(i));
957 
958 glLineWidth(lineWidth);
959 
960 glMatrixMode(GL_MODELVIEW);
961 glPopMatrix() ;
962 #else
963 static bool displayed = false;
964 
965 if (!displayed)
966 {
967 qWarning("draw3DText is not supported with Qt >= 3.1.");
968 qWarning("Use QGLWidget::renderText() instead,");
969 qWarning("or use the glut glutStrokeCharacter() method.");
970 displayed = true;
971 }
972 
973 Q_UNUSED(pos)
974 Q_UNUSED(normal)
975 Q_UNUSED(text)
976 Q_UNUSED(height)
977 #endif
978 }
979 */
980 
992 void QGLViewer::displayMessage(const QString& message, int delay)
993 {
994  message_ = message;
995  displayMessage_ = true;
996 #if QT_VERSION >= 0x040000
997  // Was set to single shot in defaultConstructor.
998  messageTimer_.start(delay);
999 #else
1000  if (messageTimer_.isActive())
1001  messageTimer_.changeInterval(delay);
1002  else
1003  messageTimer_.start(delay, true);
1004 #endif
1005  if (textIsEnabled() && updateGLOK_)
1006  updateGL();
1007 }
1008 
1010 {
1011  displayMessage_ = false;
1012  if (textIsEnabled())
1013  updateGL();
1014 }
1015 
1016 
1027 {
1028  drawText(10, int(1.5*((QApplication::font().pixelSize()>0)?QApplication::font().pixelSize():QApplication::font().pointSize())), fpsString_);
1029 }
1030 
1063 {
1064  glMatrixMode(GL_PROJECTION);
1065  glPushMatrix();
1066  glLoadIdentity();
1067  if (tileRegion_ != NULL)
1068  if (upward)
1069  glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMin, tileRegion_->yMax, 0.0, -1.0);
1070  else
1071  glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMax, tileRegion_->yMin, 0.0, -1.0);
1072  else
1073  if (upward)
1074  glOrtho(0, width(), 0, height(), 0.0, -1.0);
1075  else
1076  glOrtho(0, width(), height(), 0, 0.0, -1.0);
1077 
1078  glMatrixMode(GL_MODELVIEW);
1079  glPushMatrix();
1080  glLoadIdentity();
1081 }
1082 
1088 {
1089  glMatrixMode(GL_PROJECTION);
1090  glPopMatrix();
1091 
1092  glMatrixMode(GL_MODELVIEW);
1093  glPopMatrix();
1094 }
1095 
1099 void QGLViewer::timerEvent(QTimerEvent *)
1100 {
1101  if (animationIsStarted())
1102  {
1103  animate();
1104  updateGL();
1105  }
1106 }
1107 
1110 {
1111  animationTimerId_ = startTimer(animationPeriod());
1112  animationStarted_ = true;
1113 }
1114 
1117 {
1118  animationStarted_ = false;
1119  if (animationTimerId_ != 0)
1120  killTimer(animationTimerId_);
1121 }
1122 
1126 void QGLViewer::closeEvent(QCloseEvent *e)
1127 {
1128  // When the user clicks on the window close (x) button:
1129  // - If the viewer is a top level window, closeEvent is called and then saves to file.
1130  // - Otherwise, nothing happen s:(
1131  // When the user press the EXIT_VIEWER keyboard shortcut:
1132  // - If the viewer is a top level window, saveStateToFile() is also called
1133  // - Otherwise, closeEvent is NOT called and keyPressEvent does the job.
1134 
1135  /* After tests:
1136  E : Embedded widget
1137  N : Widget created with new
1138  C : closeEvent called
1139  D : destructor called
1140 
1141  E N C D
1142  y y
1143  y n y
1144  n y y
1145  n n y y
1146 
1147  closeEvent is called iif the widget is NOT embedded.
1148 
1149  Destructor is called iif the widget is created on the stack
1150  or if widget (resp. parent if embedded) is created with WDestructiveClose flag.
1151 
1152  closeEvent always before destructor.
1153 
1154  Close using qApp->closeAllWindows or (x) is identical.
1155  */
1156 
1157  // #CONNECTION# Also done for EXIT_VIEWER in keyPressEvent().
1158  saveStateToFile();
1159  QGLWidget::closeEvent(e);
1160 }
1161 
1171 void QGLViewer::select(const QMouseEvent* event)
1172 {
1173  // For those who don't derive but rather rely on the signal-slot mechanism.
1174  Q_EMIT pointSelected(event);
1175  select(event->pos());
1176 }
1177 
1228 void QGLViewer::select(const QPoint& point)
1229 {
1230  beginSelection(point);
1231  drawWithNames();
1232  endSelection(point);
1233  postSelection(point);
1234 }
1235 
1247 void QGLViewer::beginSelection(const QPoint& point)
1248 {
1249  // Make OpenGL context current (may be needed with several viewers ?)
1250  makeCurrent();
1251 
1252  // Prepare the selection mode
1253  glSelectBuffer(selectBufferSize(), selectBuffer());
1254  glRenderMode(GL_SELECT);
1255  glInitNames();
1256 
1257  // Loads the matrices
1258  glMatrixMode(GL_PROJECTION);
1259  glLoadIdentity();
1260  static GLint viewport[4];
1261  camera()->getViewport(viewport);
1262  gluPickMatrix(point.x(), point.y(), selectRegionWidth(), selectRegionHeight(), viewport);
1263 
1264  // loadProjectionMatrix() first resets the GL_PROJECTION matrix with a glLoadIdentity().
1265  // The false parameter prevents this and hence multiplies the matrices.
1266  camera()->loadProjectionMatrix(false);
1267  // Reset the original (world coordinates) modelview matrix
1268  camera()->loadModelViewMatrix();
1269 }
1270 
1307 void QGLViewer::endSelection(const QPoint& point)
1308 {
1309  Q_UNUSED(point);
1310 
1311  // Flush GL buffers
1312  glFlush();
1313 
1314  // Get the number of objects that were seen through the pick matrix frustum. Reset GL_RENDER mode.
1315  GLint nbHits = glRenderMode(GL_RENDER);
1316 
1317  if (nbHits <= 0)
1318  setSelectedName(-1);
1319  else
1320  {
1321  // Interpret results: each object created 4 values in the selectBuffer().
1322  // selectBuffer[4*i+1] is the object minimum depth value, while selectBuffer[4*i+3] is the id pushed on the stack.
1323  // Of all the objects that were projected in the pick region, we select the closest one (zMin comparison).
1324  // This code needs to be modified if you use several stack levels. See glSelectBuffer() man page.
1325  GLuint zMin = (selectBuffer())[1];
1326  setSelectedName((selectBuffer())[3]);
1327  for (int i=1; i<nbHits; ++i)
1328  if ((selectBuffer())[4*i+1] < zMin)
1329  {
1330  zMin = (selectBuffer())[4*i+1];
1331  setSelectedName((selectBuffer())[4*i+3]);
1332  }
1333  }
1334 }
1335 
1340 {
1341  if (selectBuffer_)
1342  delete[] selectBuffer_;
1343  selectBufferSize_ = size;
1344  selectBuffer_ = new GLuint[selectBufferSize()];
1345 }
1346 
1347 void QGLViewer::performClickAction(ClickAction ca, const QMouseEvent* const e)
1348 {
1349  // Note: action that need it should updateGL().
1350  switch (ca)
1351  {
1352  // # CONNECTION setMouseBinding prevents adding NO_CLICK_ACTION in clickBinding_
1353  // This case should hence not be possible. Prevents unused case warning.
1354  case NO_CLICK_ACTION :
1355  break;
1356  case ZOOM_ON_PIXEL :
1357  camera()->interpolateToZoomOnPixel(e->pos());
1358  break;
1359  case ZOOM_TO_FIT :
1360  camera()->interpolateToFitScene();
1361  break;
1362  case SELECT :
1363  select(e);
1364  updateGL();
1365  break;
1366  case RAP_FROM_PIXEL :
1367  if (camera()->setRevolveAroundPointFromPixel(e->pos()))
1368  {
1369  setVisualHintsMask(1);
1370  updateGL();
1371  }
1372  break;
1373  case RAP_IS_CENTER :
1374  camera()->setRevolveAroundPoint(sceneCenter());
1375  setVisualHintsMask(1);
1376  updateGL();
1377  break;
1378  case CENTER_FRAME :
1379  if (manipulatedFrame())
1380  manipulatedFrame()->projectOnLine(camera()->position(), camera()->viewDirection());
1381  break;
1382  case CENTER_SCENE :
1383  camera()->centerScene();
1384  break;
1385  case SHOW_ENTIRE_SCENE :
1386  camera()->showEntireScene();
1387  break;
1388  case ALIGN_FRAME :
1389  if (manipulatedFrame())
1390  manipulatedFrame()->alignWithFrame(camera()->frame());
1391  break;
1392  case ALIGN_CAMERA :
1393  camera()->frame()->alignWithFrame(NULL, true);
1394  break;
1395  }
1396 }
1397 
1414 void QGLViewer::mousePressEvent(QMouseEvent* e)
1415 {
1416  //#CONNECTION# mouseDoubleClickEvent has the same structure
1417  //#CONNECTION# mouseString() concatenates bindings description in inverse order.
1418  ClickActionPrivate cap;
1419  cap.doubleClick = false;
1420 #if QT_VERSION >= 0x040000
1421  cap.modifiers = e->modifiers();
1422  cap.button = e->button();
1423  cap.buttonsBefore = (Qt::MouseButtons)(e->buttons() & ~(e->button()));
1424 #else
1425  cap.modifiers = (Qt::KeyboardModifiers)(e->state() & Qt::KeyboardModifierMask);
1426  cap.button = (Qt::MouseButtons)((e->stateAfter() & Qt::MouseButtonMask) & (~(e->state() & Qt::MouseButtonMask)));
1427  cap.buttonsBefore = (Qt::MouseButtons)(e->state() & Qt::MouseButtonMask);
1428 #endif
1429 
1430  if (clickBinding_.contains(cap))
1431  performClickAction(clickBinding_[cap], e);
1432  else
1433  if (mouseGrabber())
1434  {
1435  if (mouseGrabberIsAManipulatedFrame_)
1436  {
1437  for (QMap<int, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it!=end; ++it)
1438 #if QT_VERSION >= 0x040000
1439  if ((it.value().handler == FRAME) && ((it.key() & Qt::MouseButtonMask) == e->buttons()))
1440 #else
1441  if ((it.data().handler == FRAME) && ((it.key() & Qt::MouseButtonMask) == (e->stateAfter() & Qt::MouseButtonMask)))
1442 #endif
1443  {
1444  ManipulatedFrame* mf = dynamic_cast<ManipulatedFrame*>(mouseGrabber());
1445  if (mouseGrabberIsAManipulatedCameraFrame_)
1446  {
1447  mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint);
1448  mf->ManipulatedFrame::mousePressEvent(e, camera());
1449  }
1450  else
1451  {
1452  mf->startAction(it.value().action, it.value().withConstraint);
1453  mf->mousePressEvent(e, camera());
1454  }
1455  break;
1456  }
1457  }
1458  else
1459  mouseGrabber()->mousePressEvent(e, camera());
1460  updateGL();
1461  }
1462  else
1463  {
1464  //#CONNECTION# wheelEvent has the same structure
1465 #if QT_VERSION >= 0x040000
1466  const int state = e->modifiers() | e->buttons();
1467 #else
1468  const int state = e->stateAfter();
1469 #endif
1470 
1471  if (mouseBinding_.contains(state))
1472  {
1473  MouseActionPrivate map = mouseBinding_[state];
1474  switch (map.handler)
1475  {
1476  case CAMERA :
1477  camera()->frame()->startAction(map.action, map.withConstraint);
1478  camera()->frame()->mousePressEvent(e, camera());
1479  break;
1480  case FRAME :
1481  if (manipulatedFrame())
1482  {
1483  if (manipulatedFrameIsACamera_)
1484  {
1485  manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
1486  manipulatedFrame()->ManipulatedFrame::mousePressEvent(e, camera());
1487  }
1488  else
1489  {
1490  manipulatedFrame()->startAction(map.action, map.withConstraint);
1491  manipulatedFrame()->mousePressEvent(e, camera());
1492  }
1493  }
1494  break;
1495  }
1496  if (map.action == SCREEN_ROTATE)
1497  // Display visual hint line
1498  updateGL();
1499  }
1500 #if QT_VERSION >= 0x030000
1501  else
1502  e->ignore();
1503 #endif
1504  }
1505 }
1506 
1546 void QGLViewer::mouseMoveEvent(QMouseEvent* e)
1547 {
1548  if (mouseGrabber())
1549  {
1550  mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera());
1551  if (mouseGrabber()->grabsMouse())
1552  if (mouseGrabberIsAManipulatedCameraFrame_)
1553  (dynamic_cast<ManipulatedFrame*>(mouseGrabber()))->ManipulatedFrame::mouseMoveEvent(e, camera());
1554  else
1555  mouseGrabber()->mouseMoveEvent(e, camera());
1556  else
1557  setMouseGrabber(NULL);
1558  updateGL();
1559  }
1560 
1561  if (!mouseGrabber())
1562  {
1563  //#CONNECTION# mouseReleaseEvent has the same structure
1564  if (camera()->frame()->isManipulated())
1565  {
1566  camera()->frame()->mouseMoveEvent(e, camera());
1567  // #CONNECTION# manipulatedCameraFrame::mouseMoveEvent specific if at the beginning
1568  if (camera()->frame()->action_ == ZOOM_ON_REGION)
1569  updateGL();
1570  }
1571  else // !
1572  if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated()))
1573  if (manipulatedFrameIsACamera_)
1574  manipulatedFrame()->ManipulatedFrame::mouseMoveEvent(e, camera());
1575  else
1576  manipulatedFrame()->mouseMoveEvent(e, camera());
1577  else
1578  if (hasMouseTracking())
1579  {
1580 #if QT_VERSION >= 0x040000
1581  Q_FOREACH (MouseGrabber* mg, MouseGrabber::MouseGrabberPool())
1582  {
1583 #else
1584  QPtrListIterator<MouseGrabber> it(MouseGrabber::MouseGrabberPool());
1585  for (MouseGrabber* mg; (mg = it.current()); ++it)
1586  {
1587 #endif
1588  mg->checkIfGrabsMouse(e->x(), e->y(), camera());
1589  if (mg->grabsMouse())
1590  {
1591  setMouseGrabber(mg);
1592  // Check that MouseGrabber is not disabled
1593  if (mouseGrabber() == mg)
1594  {
1595  updateGL();
1596  break;
1597  }
1598  }
1599  }
1600  }
1601  }
1602 }
1603 
1609 void QGLViewer::mouseReleaseEvent(QMouseEvent* e)
1610 {
1611  if (mouseGrabber())
1612  {
1613  if (mouseGrabberIsAManipulatedCameraFrame_)
1614  (dynamic_cast<ManipulatedFrame*>(mouseGrabber()))->ManipulatedFrame::mouseReleaseEvent(e, camera());
1615  else
1616  mouseGrabber()->mouseReleaseEvent(e, camera());
1617  mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera());
1618  if (!(mouseGrabber()->grabsMouse()))
1619  setMouseGrabber(NULL);
1620  // updateGL();
1621  }
1622  else
1623  //#CONNECTION# mouseMoveEvent has the same structure
1624  if (camera()->frame()->isManipulated())
1625  {
1626  // bool updateGLNeeded = ((camera()->frame()->action_ == ZOOM_ON_REGION) ||
1627  // (camera()->frame()->action_ == SCREEN_ROTATE));
1628  camera()->frame()->mouseReleaseEvent(e, camera());
1629  // if (updateGLNeeded)
1630  // Needed in all cases because of fastDraw().
1631  // updateGL();
1632  }
1633  else
1634  if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated()))
1635  {
1636  // bool updateGLNeeded = (manipulatedFrame()->action_ == SCREEN_ROTATE);
1637  if (manipulatedFrameIsACamera_)
1638  manipulatedFrame()->ManipulatedFrame::mouseReleaseEvent(e, camera());
1639  else
1640  manipulatedFrame()->mouseReleaseEvent(e, camera());
1641  // if (updateGLNeeded)
1642  // updateGL();
1643  }
1644 #if QT_VERSION >= 0x030000
1645  else
1646  e->ignore();
1647 #endif
1648 
1649  // Not absolutely needed (see above commented code for the optimal version), but may reveal
1650  // useful for specific applications.
1651  updateGL();
1652 }
1653 
1658 void QGLViewer::wheelEvent(QWheelEvent* e)
1659 {
1660  if (mouseGrabber())
1661  {
1662  if (mouseGrabberIsAManipulatedFrame_)
1663  {
1664  for (QMap<Qt::KeyboardModifiers, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it)
1665  if (it.value().handler == FRAME)
1666  {
1667  ManipulatedFrame* mf = dynamic_cast<ManipulatedFrame*>(mouseGrabber());
1668  if (mouseGrabberIsAManipulatedCameraFrame_)
1669  {
1670  mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint);
1671  mf->ManipulatedFrame::wheelEvent(e, camera());
1672  }
1673  else
1674  {
1675  mf->startAction(it.value().action, it.value().withConstraint);
1676  mf->wheelEvent(e, camera());
1677  }
1678  break;
1679  }
1680  }
1681  else
1682  mouseGrabber()->wheelEvent(e, camera());
1683  updateGL();
1684  }
1685  else
1686  {
1687  //#CONNECTION# mousePressEvent has the same structure
1688 #if QT_VERSION >= 0x040000
1689  const Qt::KeyboardModifiers modifiers = e->modifiers();
1690 #else
1691  const Qt::KeyboardModifiers modifiers = e->state();
1692 #endif
1693  if (wheelBinding_.contains(modifiers))
1694  {
1695  MouseActionPrivate map = wheelBinding_[modifiers];
1696  switch (map.handler)
1697  {
1698  case CAMERA :
1699  camera()->frame()->startAction(map.action, map.withConstraint);
1700  camera()->frame()->wheelEvent(e, camera());
1701  break;
1702  case FRAME :
1703  if (manipulatedFrame()) {
1704  if (manipulatedFrameIsACamera_)
1705  {
1706  manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
1707  manipulatedFrame()->ManipulatedFrame::wheelEvent(e, camera());
1708  }
1709  else
1710  {
1711  manipulatedFrame()->startAction(map.action, map.withConstraint);
1712  manipulatedFrame()->wheelEvent(e, camera());
1713  }
1714  }
1715  break;
1716  }
1717  }
1718 #if QT_VERSION >= 0x030000
1719  else
1720  e->ignore();
1721 #endif
1722  }
1723 }
1724 
1730 {
1731  //#CONNECTION# mousePressEvent has the same structure
1732  ClickActionPrivate cap;
1733  cap.doubleClick = true;
1734 #if QT_VERSION >= 0x040000
1735  cap.modifiers = e->modifiers();
1736  cap.button = e->button();
1737  cap.buttonsBefore = (Qt::MouseButtons)(e->buttons() & ~(e->button()));
1738 #else
1739  cap.modifiers = (Qt::KeyboardModifiers)(e->state() & Qt::KeyboardModifierMask);
1740  cap.button = (Qt::MouseButtons)((e->stateAfter() & Qt::MouseButtonMask) & (~(e->state() & Qt::MouseButtonMask)));
1741  cap.buttonsBefore = (Qt::MouseButtons)(e->state() & Qt::MouseButtonMask);
1742 #endif
1743  if (clickBinding_.contains(cap))
1744  performClickAction(clickBinding_[cap], e);
1745  else
1746  if (mouseGrabber())
1747  mouseGrabber()->mouseDoubleClickEvent(e, camera());
1748 #if QT_VERSION >= 0x030000
1749  else
1750  e->ignore();
1751 #endif
1752 }
1753 
1759 {
1760  if (format().stereo())
1761  {
1762  stereo_ = stereo;
1763  if (!displaysInStereo())
1764  {
1765  glDrawBuffer(GL_BACK_LEFT);
1766  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1767  glDrawBuffer(GL_BACK_RIGHT);
1768  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1769  }
1770 
1771  Q_EMIT stereoChanged(stereo_);
1772 
1773  if (updateGLOK_)
1774  updateGL();
1775  }
1776  else
1777  if (stereo)
1778  QMessageBox::warning(this, tr("Stereo not supported", "Message box window title"), tr("Stereo is not supported on this display."));
1779  else
1780  stereo_ = false;
1781 }
1782 
1787 void QGLViewer::setFullScreen(bool fullScreen)
1788 {
1789  fullScreen_ = fullScreen;
1790 
1791  // Tricky. A timer does it later if !updateGLOK_.
1792  if (!updateGLOK_)
1793  return;
1794 
1795  QWidget* tlw = topLevelWidget();
1796 
1797  if (isFullScreen())
1798  {
1799  prevPos_ = topLevelWidget()->pos();
1800  tlw->showFullScreen();
1801  tlw->move(0,0);
1802  }
1803  else
1804  {
1805  tlw->showNormal();
1806  tlw->move(prevPos_);
1807  }
1808 }
1809 
1817 {
1818  if (!mouseGrabberIsEnabled(mouseGrabber))
1819  return;
1820 
1821  mouseGrabber_ = mouseGrabber;
1822 
1823  mouseGrabberIsAManipulatedFrame_ = (dynamic_cast<ManipulatedFrame*>(mouseGrabber) != NULL);
1824  mouseGrabberIsAManipulatedCameraFrame_ = ((dynamic_cast<ManipulatedCameraFrame*>(mouseGrabber) != NULL) &&
1825  (mouseGrabber != camera()->frame()));
1826  Q_EMIT mouseGrabberChanged(mouseGrabber);
1827 }
1828 
1830 void QGLViewer::setMouseGrabberIsEnabled(const qglviewer::MouseGrabber* const mouseGrabber, bool enabled)
1831 {
1832  if (enabled)
1833  disabledMouseGrabbers_.remove(reinterpret_cast<size_t>(mouseGrabber));
1834  else
1835  disabledMouseGrabbers_[reinterpret_cast<size_t>(mouseGrabber)];
1836 }
1837 
1838 static QString keyboardModifiersString(Qt::KeyboardModifiers m, bool noButton=false)
1839 {
1840 #if QT_VERSION >= 0x040000
1841  if (noButton && (m==Qt::NoModifier))
1842 #else
1843  if (noButton && (m==Qt::NoButton))
1844 #endif
1845  return QGLViewer::tr("(no button)");
1846 
1847  QString keySequence = "";
1848 
1849 #if QT_VERSION >= 0x040000
1850  if (m & Qt::ControlModifier) keySequence += "Ctrl+";
1851  if (m & Qt::AltModifier) keySequence += "Alt+";
1852  if (m & Qt::ShiftModifier) keySequence += "Shift+";
1853  if (m & Qt::MetaModifier) keySequence += "Meta+";
1854 #else
1855  if (m & Qt::ControlButton) keySequence += "Ctrl+";
1856  if (m & Qt::AltButton) keySequence += "Alt+";
1857  if (m & Qt::ShiftButton) keySequence += "Shift+";
1858 # if QT_VERSION >= 0x030000
1859  if (m & Qt::MetaButton) keySequence += "Meta+";
1860 # endif
1861 #endif
1862 
1863  if (keySequence.length() > 0)
1864 #if QT_VERSION >= 0x040000
1865  return QKeySequence(keySequence+"X").toString(QKeySequence::NativeText).replace("X", "");
1866 #else
1867  return QString(QKeySequence(keySequence+"X")).replace("X", "");
1868 #endif
1869  else
1870  return QString();
1871 }
1872 
1873 static QString mouseButtonsString(Qt::MouseButtons b)
1874 {
1875  QString result("");
1876  bool addAmpersand = false;
1877  if (b & Qt::LeftButton) { result += QGLViewer::tr("Left", "left mouse button"); addAmpersand=true; }
1878  if (b & Qt::MidButton) { if (addAmpersand) result += " & "; result += QGLViewer::tr("Middle", "middle mouse button"); addAmpersand=true; }
1879  if (b & Qt::RightButton) { if (addAmpersand) result += " & "; result += QGLViewer::tr("Right", "right mouse button"); }
1880  return result;
1881 }
1882 
1884 {
1885  switch (ma)
1886  {
1887  case QGLViewer::NO_MOUSE_ACTION : return QString::null;
1888  case QGLViewer::ROTATE : return QGLViewer::tr("Rotates", "ROTATE mouse action");
1889  case QGLViewer::ZOOM : return QGLViewer::tr("Zooms", "ZOOM mouse action");
1890  case QGLViewer::TRANSLATE : return QGLViewer::tr("Translates", "TRANSLATE mouse action");
1891  case QGLViewer::MOVE_FORWARD : return QGLViewer::tr("Moves forward", "MOVE_FORWARD mouse action");
1892  case QGLViewer::LOOK_AROUND : return QGLViewer::tr("Looks around", "LOOK_AROUND mouse action");
1893  case QGLViewer::MOVE_BACKWARD : return QGLViewer::tr("Moves backward", "MOVE_BACKWARD mouse action");
1894  case QGLViewer::SCREEN_ROTATE : return QGLViewer::tr("Rotates in screen plane", "SCREEN_ROTATE mouse action");
1895  case QGLViewer::ROLL : return QGLViewer::tr("Rolls", "ROLL mouse action");
1896  case QGLViewer::DRIVE : return QGLViewer::tr("Drives", "DRIVE mouse action");
1897  case QGLViewer::SCREEN_TRANSLATE : return QGLViewer::tr("Horizontally/Vertically translates", "SCREEN_TRANSLATE mouse action");
1898  case QGLViewer::ZOOM_ON_REGION : return QGLViewer::tr("Zooms on region for", "ZOOM_ON_REGION mouse action");
1899  }
1900  return QString::null;
1901 }
1902 
1904 {
1905  switch (ca)
1906  {
1907  case QGLViewer::NO_CLICK_ACTION : return QString::null;
1908  case QGLViewer::ZOOM_ON_PIXEL : return QGLViewer::tr("Zooms on pixel", "ZOOM_ON_PIXEL click action");
1909  case QGLViewer::ZOOM_TO_FIT : return QGLViewer::tr("Zooms to fit scene", "ZOOM_TO_FIT click action");
1910  case QGLViewer::SELECT : return QGLViewer::tr("Selects", "SELECT click action");
1911  case QGLViewer::RAP_FROM_PIXEL : return QGLViewer::tr("Sets revolve around point", "RAP_FROM_PIXEL click action");
1912  case QGLViewer::RAP_IS_CENTER : return QGLViewer::tr("Resets revolve around point", "RAP_IS_CENTER click action");
1913  case QGLViewer::CENTER_FRAME : return QGLViewer::tr("Centers frame", "CENTER_FRAME click action");
1914  case QGLViewer::CENTER_SCENE : return QGLViewer::tr("Centers scene", "CENTER_SCENE click action");
1915  case QGLViewer::SHOW_ENTIRE_SCENE : return QGLViewer::tr("Shows entire scene", "SHOW_ENTIRE_SCENE click action");
1916  case QGLViewer::ALIGN_FRAME : return QGLViewer::tr("Aligns frame", "ALIGN_FRAME click action");
1917  case QGLViewer::ALIGN_CAMERA : return QGLViewer::tr("Aligns camera", "ALIGN_CAMERA click action");
1918  }
1919  return QString::null;
1920 }
1921 
1923 {
1924  bool buttonsBefore = cap.buttonsBefore != Qt::NoButton;
1925  return tr("%1%2%3%4%5%6", "Modifier / button or wheel / double click / with / button / pressed")
1927  .arg(mouseButtonsString(cap.button)+(cap.button == Qt::NoButton ? tr("Wheel", "Mouse wheel") : ""))
1928  .arg(cap.doubleClick ? tr(" double click", "Suffix after mouse button") : "")
1929  .arg(buttonsBefore ? tr(" with ", "As in : Left button with Ctrl pressed") : "")
1930  .arg(buttonsBefore ? mouseButtonsString(cap.buttonsBefore) : "")
1931  .arg(buttonsBefore ? tr(" pressed", "As in : Left button with Ctrl pressed") : "");
1932 }
1933 
1968 void QGLViewer::setMouseBindingDescription(int state, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore)
1969 {
1970  ClickActionPrivate cap;
1971  cap.modifiers = Qt::KeyboardModifiers(convertToKeyboardModifiers(state) & Qt::KeyboardModifierMask);
1972  cap.button = Qt::MouseButtons(state & Qt::MouseButtonMask);
1973  cap.doubleClick = doubleClick;
1974  cap.buttonsBefore = buttonsBefore;
1975 
1976  if (description.isEmpty())
1977  mouseDescription_.remove(cap);
1978  else
1979  mouseDescription_[cap] = description;
1980 }
1981 
1982 static QString tableLine(const QString& left, const QString& right)
1983 {
1984  static bool even = false;
1985  const QString tdtd("</b></td><td>");
1986  const QString tdtr("</td></tr>\n");
1987 
1988  QString res("<tr bgcolor=\"");
1989 
1990  if (even)
1991  res += "#eeeeff\">";
1992  else
1993  res += "#ffffff\">";
1994  res += "<td><b>" + left + tdtd + right + tdtr;
1995  even = !even;
1996 
1997  return res;
1998 }
1999 
2009 QString QGLViewer::mouseString() const
2010 {
2011  QString text("<center><table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n");
2012  const QString trtd("<tr><td>");
2013  const QString tdtr("</td></tr>\n");
2014  const QString tdtd("</td><td>");
2015 
2016  text += QString("<tr bgcolor=\"#aaaacc\"><th align=\"center\">%1</th><th align=\"center\">%2</th></tr>\n").
2017  arg(tr("Button(s)", "Buttons column header in help window mouse tab")).arg(tr("Description", "Description column header in help window mouse tab"));
2018 
2019  QMap<ClickActionPrivate, QString> mouseBinding;
2020 
2021  // User-defined mouse bindings come first.
2022  for (QMap<ClickActionPrivate, QString>::ConstIterator itm=mouseDescription_.begin(), endm=mouseDescription_.end(); itm!=endm; ++itm)
2023  mouseBinding[itm.key()] = itm.value();
2024 
2025  for (QMap<ClickActionPrivate, QString>::ConstIterator it=mouseBinding.begin(), end=mouseBinding.end(); it != end; ++it)
2026  {
2027  // Should not be needed (see setMouseBindingDescription())
2028  if (it.value().isNull())
2029  continue;
2030 
2031  text += tableLine(formatClickActionPrivate(it.key()), it.value());
2032  }
2033 
2034  // Optionnal separator line
2035  if (!mouseBinding.isEmpty())
2036  {
2037  mouseBinding.clear();
2038  text += QString("<tr bgcolor=\"#aaaacc\"><td colspan=2>%1</td></tr>\n").arg(tr("Standard mouse bindings", "In help window mouse tab"));
2039  }
2040 
2041  // Then concatenates the descriptions of wheelBinding_, mouseBinding_ and clickBinding_.
2042  // The order is significant and corresponds to the priorities set in mousePressEvent() (reverse priority order, last one overwrites previous)
2043  // #CONNECTION# mousePressEvent() order
2044  for (QMap<Qt::KeyboardModifiers, MouseActionPrivate>::ConstIterator itw=wheelBinding_.begin(), endw=wheelBinding_.end(); itw != endw; ++itw)
2045  {
2046  ClickActionPrivate cap;
2047  cap.doubleClick = false;
2048  cap.modifiers = itw.key();
2049  cap.button = Qt::NoButton;
2050  cap.buttonsBefore = Qt::NoButton;
2051 
2052  QString text = mouseActionString(itw.value().action);
2053 
2054  if (!text.isNull())
2055  {
2056  switch (itw.value().handler)
2057  {
2058  case CAMERA: text += " " + tr("camera", "Suffix after action"); break;
2059  case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break;
2060  }
2061  if (!(itw.value().withConstraint))
2062  text += "*";
2063  }
2064 
2065  mouseBinding[cap] = text;
2066  }
2067 
2068  for (QMap<int, MouseActionPrivate>::ConstIterator itmb=mouseBinding_.begin(), endmb=mouseBinding_.end();
2069  itmb != endmb; ++itmb)
2070  {
2071  ClickActionPrivate cap;
2072  cap.doubleClick = false;
2073  cap.modifiers = Qt::KeyboardModifiers(itmb.key() & Qt::KeyboardModifierMask);
2074  cap.button = Qt::MouseButtons(itmb.key() & Qt::MouseButtonMask);
2075  cap.buttonsBefore = Qt::NoButton;
2076 
2077  QString text = mouseActionString(itmb.value().action);
2078 
2079  if (!text.isNull())
2080  {
2081  switch (itmb.value().handler)
2082  {
2083  case CAMERA: text += " " + tr("camera", "Suffix after action"); break;
2084  case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break;
2085  }
2086  if (!(itmb.value().withConstraint))
2087  text += "*";
2088  }
2089  mouseBinding[cap] = text;
2090  }
2091 
2092  for (QMap<ClickActionPrivate, ClickAction>::ConstIterator itcb=clickBinding_.begin(), endcb=clickBinding_.end(); itcb!=endcb; ++itcb)
2093  mouseBinding[itcb.key()] = clickActionString(itcb.value());
2094 
2095  for (QMap<ClickActionPrivate, QString>::ConstIterator it2=mouseBinding.begin(), end2=mouseBinding.end(); it2 != end2; ++it2)
2096  {
2097  if (it2.value().isNull())
2098  continue;
2099 
2100  text += tableLine(formatClickActionPrivate(it2.key()), it2.value());
2101  }
2102 
2103  text += "</table></center>";
2104 
2105  return text;
2106 }
2107 
2122 void QGLViewer::setKeyDescription(int key, QString description)
2123 {
2124 #if QT_VERSION >= 0x030000
2125  // #CONNECTION# keyString. In Qt 2.3, longs modifier overlap with key codes.
2126  key = convertToKeyboardModifiers(key);
2127 #endif
2128  if (description.isEmpty())
2129  keyDescription_.remove(key);
2130  else
2131  keyDescription_[key] = description;
2132 }
2133 
2134 static QString keyString(int key)
2135 {
2136 #if QT_VERSION >= 0x030000
2137 # if QT_VERSION >= 0x040100
2138  return QKeySequence(convertToShortModifier(key)).toString();
2139 # else
2140  return QString(QKeySequence(convertToShortModifier(key)));
2141 # endif
2142 #else
2143  // #CONNECTION# setKeyDescription. In Qt 2.3, long modifiers overlap with key codes.
2144  return QString(QKeySequence(key));
2145 #endif
2146 }
2147 
2149 {
2150  if (pathIndex_.isEmpty())
2151  return QString::null;
2152 
2153 #if QT_VERSION >= 0x040000 || QT_VERSION < 0x030000
2154  QVector<int> keys;
2155 #else
2156  QValueVector<int> keys;
2157 #endif
2158  keys.reserve(pathIndex_.count());
2159  for (QMap<Qt::Key, int>::ConstIterator i = pathIndex_.begin(), endi=pathIndex_.end(); i != endi; ++i)
2160  keys.push_back(i.key());
2161 #if QT_VERSION >= 0x040000
2162  qSort(keys);
2163 #else
2164 # if QT_VERSION >= 0x030000
2165  qHeapSort(keys);
2166 # else
2167  sort(keys.begin(), keys.end());
2168 # endif
2169 #endif
2170 
2171 #if QT_VERSION >= 0x040000 || QT_VERSION < 0x030000
2172  QVector<int>::const_iterator it = keys.begin(), end = keys.end();
2173 #else
2174  QValueVector<int>::const_iterator it = keys.begin(), end = keys.end();
2175 #endif
2176  QString res = keyString(*it);
2177 
2178  const int maxDisplayedKeys = 6;
2179  int nbDisplayedKeys = 0;
2180  int previousKey = (*it);
2181  int state = 0;
2182  ++it;
2183  while ((it != end) && (nbDisplayedKeys < maxDisplayedKeys-1))
2184  {
2185  switch (state)
2186  {
2187  case 0 :
2188  if ((*it) == previousKey + 1)
2189  state++;
2190  else
2191  {
2192  res += ", " + keyString(*it);
2193  nbDisplayedKeys++;
2194  }
2195  break;
2196  case 1 :
2197  if ((*it) == previousKey + 1)
2198  state++;
2199  else
2200  {
2201  res += ", " + keyString(previousKey);
2202  res += ", " + keyString(*it);
2203  nbDisplayedKeys += 2;
2204  state = 0;
2205  }
2206  break;
2207  default :
2208  if ((*it) != previousKey + 1)
2209  {
2210  res += ".." + keyString(previousKey);
2211  res += ", " + keyString(*it);
2212  nbDisplayedKeys += 2;
2213  state = 0;
2214  }
2215  break;
2216  }
2217  previousKey = *it;
2218  ++it;
2219  }
2220 
2221  if (state == 1)
2222  res += ", " + keyString(previousKey);
2223  if (state == 2)
2224  res += ".." + keyString(previousKey);
2225  if (it != end)
2226  res += "...";
2227 
2228  return res;
2229 }
2230 
2240 {
2241  QString text("<center><table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n");
2242  text += QString("<tr bgcolor=\"#aaaacc\"><th align=\"center\">%1</th><th align=\"center\">%2</th></tr>\n").
2243  arg(QGLViewer::tr("Key(s)", "Keys column header in help window mouse tab")).arg(QGLViewer::tr("Description", "Description column header in help window mouse tab"));
2244 
2245  QMap<int, QString> keyDescription;
2246 
2247  // 1 - User defined key descriptions
2248  for (QMap<int, QString>::ConstIterator kd=keyDescription_.begin(), kdend=keyDescription_.end(); kd!=kdend; ++kd)
2249  keyDescription[kd.key()] = kd.value();
2250 
2251  // Add to text in sorted order
2252  for (QMap<int, QString>::ConstIterator kb=keyDescription.begin(), endb=keyDescription.end(); kb!=endb; ++kb)
2253  text += tableLine(keyString(kb.key()), kb.value());
2254 
2255 
2256  // 2 - Optional separator line
2257  if (!keyDescription.isEmpty())
2258  {
2259  keyDescription.clear();
2260  text += QString("<tr bgcolor=\"#aaaacc\"><td colspan=2>%1</td></tr>\n").arg(QGLViewer::tr("Standard viewer keys", "In help window keys tab"));
2261  }
2262 
2263 
2264  // 3 - KeyboardAction bindings description
2265  for (QMap<KeyboardAction, unsigned int>::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end(); it != end; ++it)
2266  if ((it.value() != 0) && ((!cameraIsInRevolveMode()) || ((it.key() != INCREASE_FLYSPEED) && (it.key() != DECREASE_FLYSPEED))))
2267  keyDescription[it.value()] = keyboardActionDescription_[it.key()];
2268 
2269  // Add to text in sorted order
2270  for (QMap<int, QString>::ConstIterator kb2=keyDescription.begin(), endb2=keyDescription.end(); kb2!=endb2; ++kb2)
2271  text += tableLine(keyString(kb2.key()), kb2.value());
2272 
2273 
2274  // 4 - Camera paths keys description
2275  const QString cpks = cameraPathKeysString();
2276  if (!cpks.isNull())
2277  {
2278  text += "<tr bgcolor=\"#ccccff\"><td colspan=2>\n";
2279  text += QGLViewer::tr("Camera paths are controlled using %1 (noted <i>Fx</i> below):", "Help window key tab camera keys").arg(cpks) + "</td></tr>\n";
2280  text += tableLine(keyboardModifiersString(playPathKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
2281  QGLViewer::tr("Plays path (or resets saved position)"));
2282  text += tableLine(keyboardModifiersString(addKeyFrameKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
2283  QGLViewer::tr("Adds a key frame to path (or defines a position)"));
2284  text += tableLine(keyboardModifiersString(addKeyFrameKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>+<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
2285  QGLViewer::tr("Deletes path (or saved position)"));
2286  }
2287  text += "</table></center>";
2288 
2289  return text;
2290 }
2291 
2294  help();
2295 #if QT_VERSION >= 0x040000
2296  helpWidget()->setCurrentIndex(3);
2297 #else
2298  helpWidget()->setCurrentPage(3);
2299 #endif
2300 }
2301 
2302 
2313 {
2314  Q_EMIT helpRequired();
2315 
2316  bool resize = false;
2317  int width=600;
2318  int height=400;
2319 
2320  static QString label[] = {tr("&Help", "Help window tab title"), tr("&Keyboard", "Help window tab title"), tr("&Mouse", "Help window tab title"), tr("&About", "Help window about title")};
2321 
2322  if (!helpWidget())
2323  {
2324  // Qt4 requires a NULL parent...
2325  helpWidget_ = new QTabWidget(NULL);
2326 #if QT_VERSION >= 0x040000
2327  helpWidget()->setWindowTitle(tr("Help", "Help window title"));
2328 #else
2329  helpWidget()->setCaption(tr("Help", "Help window title"));
2330 #endif
2331 
2332  resize = true;
2333  for (int i=0; i<4; ++i)
2334  {
2335  QTextEdit* tab = new QTextEdit(NULL);
2336 #if QT_VERSION >= 0x030000
2337  tab->setReadOnly(true);
2338 #endif
2339 
2340 #if QT_VERSION >= 0x040000
2341  helpWidget()->insertTab(i, tab, label[i]);
2342  if (i==3) {
2343 # include "qglviewer-icon.xpm"
2344  QPixmap pixmap(qglviewer_icon);
2345  tab->document()->addResource(QTextDocument::ImageResource,
2346  QUrl("mydata://qglviewer-icon.xpm"), QVariant(pixmap));
2347  }
2348 #else
2349  tab->setTextFormat(Qt::RichText);
2350  helpWidget()->insertTab(tab, label[i]);
2351 #endif
2352  }
2353  }
2354 
2355 
2356 #if QT_VERSION < 0x030000
2357  const int currentPageIndex = helpWidget()->currentPageIndex();
2358 #endif
2359 
2360  for (int i=0; i<4; ++i)
2361  {
2362  QString text;
2363  switch (i)
2364  {
2365  case 0 : text = helpString(); break;
2366  case 1 : text = keyboardString(); break;
2367  case 2 : text = mouseString(); break;
2368  case 3 : text = QString("<center><br><img src=\"mydata://qglviewer-icon.xpm\">") + tr(
2369  "<h1>libQGLViewer</h1>"
2370  "<h3>Version %1</h3><br>"
2371  "A versatile 3D viewer based on OpenGL and Qt<br>"
2372  "Copyright 2002-%2 Gilles Debunne<br>"
2373  "<code>%3</code>").arg(QGLViewerVersionString()).arg("2012").arg("http://www.libqglviewer.com") +
2374  QString("</center>");
2375  break;
2376  default : break;
2377  }
2378 
2379 #if QT_VERSION >= 0x040000
2380  QTextEdit* textEdit = (QTextEdit*)(helpWidget()->widget(i));
2381  textEdit->setHtml(text);
2382 #else
2383 # if QT_VERSION < 0x030000
2384  helpWidget()->setCurrentPage(i);
2385  QTextEdit* textEdit = (QTextEdit*)(helpWidget()->currentPage());
2386 # else
2387  QTextEdit* textEdit = (QTextEdit*)(helpWidget()->page(i));
2388 # endif
2389  textEdit->setText(text);
2390 #endif
2391 
2392 #if QT_VERSION < 0x040000
2393  if (resize && (textEdit->heightForWidth(width) > height))
2394  height = textEdit->heightForWidth(width);
2395 #else
2396  if (resize && (textEdit->height() > height))
2397  height = textEdit->height();
2398 #endif
2399  }
2400 
2401 #if QT_VERSION < 0x030000
2402  helpWidget()->setCurrentPage(currentPageIndex);
2403 #endif
2404 
2405  if (resize)
2406  helpWidget()->resize(width, height+40); // 40 pixels is ~ tabs' height
2407  helpWidget()->show();
2408  helpWidget()->raise();
2409 }
2410 
2437 void QGLViewer::keyPressEvent(QKeyEvent *e)
2438 {
2439  if (e->key() == 0)
2440  {
2441  e->ignore();
2442  return;
2443  }
2444 
2445  const Qt::Key key = Qt::Key(e->key());
2446 #if QT_VERSION >= 0x040000
2447  const Qt::KeyboardModifiers modifiers = e->modifiers();
2448 #else
2449  const Qt::KeyboardModifiers modifiers = (Qt::KeyboardModifiers)(e->state() & Qt::KeyboardModifierMask);
2450 #endif
2451 
2452  QMap<KeyboardAction, unsigned int>::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end();
2453  const unsigned int target = key | modifiers;
2454  while ((it != end) && (it.value() != target))
2455  ++it;
2456 
2457  if (it != end)
2458  handleKeyboardAction(it.key());
2459  else
2460  if (pathIndex_.contains(Qt::Key(key)))
2461  {
2462  // Camera paths
2463  int index = pathIndex_[Qt::Key(key)];
2464 
2465  static QTime doublePress; // try to double press on two viewers at the same time !
2466 
2467  if (modifiers == playPathKeyboardModifiers())
2468  {
2469  int elapsed = doublePress.restart();
2470  if ((elapsed < 250) && (index==previousPathId_))
2471  camera()->resetPath(index);
2472  else
2473  {
2474  // Stop previous interpolation before starting a new one.
2475  if (index != previousPathId_)
2476  {
2477  KeyFrameInterpolator* previous = camera()->keyFrameInterpolator(previousPathId_);
2478  if ((previous) && (previous->interpolationIsStarted()))
2479  previous->resetInterpolation();
2480  }
2481  camera()->playPath(index);
2482  }
2483  previousPathId_ = index;
2484  }
2485  else if (modifiers == addKeyFrameKeyboardModifiers())
2486  {
2487  int elapsed = doublePress.restart();
2488  if ((elapsed < 250) && (index==previousPathId_))
2489  {
2490  if (camera()->keyFrameInterpolator(index))
2491  {
2492  disconnect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), this, SLOT(updateGL()));
2493  if (camera()->keyFrameInterpolator(index)->numberOfKeyFrames() > 1)
2494  displayMessage(tr("Path %1 deleted", "Feedback message").arg(index));
2495  else
2496  displayMessage(tr("Position %1 deleted", "Feedback message").arg(index));
2497  camera()->deletePath(index);
2498  }
2499  }
2500  else
2501  {
2502  bool nullBefore = (camera()->keyFrameInterpolator(index) == NULL);
2503  camera()->addKeyFrameToPath(index);
2504  if (nullBefore)
2505  connect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), SLOT(updateGL()));
2506  int nbKF = camera()->keyFrameInterpolator(index)->numberOfKeyFrames();
2507  if (nbKF > 1)
2508  displayMessage(tr("Path %1, position %2 added", "Feedback message").arg(index).arg(nbKF));
2509  else
2510  displayMessage(tr("Position %1 saved", "Feedback message").arg(index));
2511  }
2512  previousPathId_ = index;
2513  }
2514  updateGL();
2515  }
2516  else
2517  e->ignore();
2518 }
2519 
2521 {
2522  switch (id)
2523  {
2524  case DRAW_AXIS : toggleAxisIsDrawn(); break;
2525  case DRAW_GRID : toggleGridIsDrawn(); break;
2526  case DISPLAY_FPS : toggleFPSIsDisplayed(); break;
2527  case ENABLE_TEXT : toggleTextIsEnabled(); break;
2528  case EXIT_VIEWER : saveStateToFileForAllViewers(); qApp->closeAllWindows(); break;
2529  case SAVE_SCREENSHOT : saveSnapshot(false, false); break;
2530  case FULL_SCREEN : toggleFullScreen(); break;
2531  case STEREO : toggleStereoDisplay(); break;
2532  case ANIMATION : toggleAnimation(); break;
2533  case HELP : help(); break;
2534  case EDIT_CAMERA : toggleCameraIsEdited(); break;
2535  case SNAPSHOT_TO_CLIPBOARD : snapshotToClipboard(); break;
2536  case CAMERA_MODE :
2537  toggleCameraMode();
2538  displayMessage(cameraIsInRevolveMode()?tr("Camera in revolve around mode", "Feedback message"):tr("Camera in fly mode", "Feedback message"));
2539  break;
2540 
2541  case MOVE_CAMERA_LEFT :
2542  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(-10.0*camera()->flySpeed(), 0.0, 0.0)));
2543  updateGL();
2544  break;
2545  case MOVE_CAMERA_RIGHT :
2546  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec( 10.0*camera()->flySpeed(), 0.0, 0.0)));
2547  updateGL();
2548  break;
2549  case MOVE_CAMERA_UP :
2550  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, 10.0*camera()->flySpeed(), 0.0)));
2551  updateGL();
2552  break;
2553  case MOVE_CAMERA_DOWN :
2554  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, -10.0*camera()->flySpeed(), 0.0)));
2555  updateGL();
2556  break;
2557 
2558  case INCREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() * 1.5); break;
2559  case DECREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() / 1.5); break;
2560  }
2561 }
2562 
2567 void QGLViewer::resizeGL(int width, int height)
2568 {
2569  QGLWidget::resizeGL(width, height);
2570  glViewport( 0, 0, GLint(width), GLint(height) );
2571  camera()->setScreenWidthAndHeight(this->width(), this->height());
2572 }
2573 
2575 // K e y b o a r d s h o r t c u t s //
2577 
2595 void QGLViewer::setShortcut(KeyboardAction action, unsigned int key)
2596 {
2597  keyboardBinding_[action] = convertToKeyboardModifiers(key);
2598 }
2599 
2615 unsigned int QGLViewer::shortcut(KeyboardAction action) const
2616 {
2617  if (keyboardBinding_.contains(action))
2618  return convertToShortModifier(keyboardBinding_[action]);
2619  else
2620  return 0;
2621 }
2622 
2623 #ifndef DOXYGEN
2625 {
2626  qWarning("setKeyboardAccelerator is deprecated. Use setShortcut instead.");
2627  setShortcut(action, key);
2628 }
2629 
2631 {
2632  qWarning("keyboardAccelerator is deprecated. Use shortcut instead.");
2633  return shortcut(action);
2634 }
2635 #endif
2636 
2638 
2654 Qt::Key QGLViewer::pathKey(int index) const
2655 {
2656  for (QMap<Qt::Key, int>::ConstIterator it = pathIndex_.begin(), end=pathIndex_.end(); it != end; ++it)
2657  if (it.value() == index)
2658  return it.key();
2659  return Qt::Key(0);
2660 }
2661 
2673 void QGLViewer::setPathKey(int key, int index)
2674 {
2675  if (key < 0)
2676  pathIndex_.remove(Qt::Key(-key));
2677  else
2678  pathIndex_[Qt::Key(key)] = index;
2679 }
2680 
2682 void QGLViewer::setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers)
2683 {
2684  playPathKeyboardModifiers_ = convertKeyboardModifiers(modifiers);
2685 }
2686 
2688 void QGLViewer::setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers)
2689 {
2690  addKeyFrameKeyboardModifiers_ = convertKeyboardModifiers(modifiers);
2691 }
2692 
2706 Qt::KeyboardModifiers QGLViewer::addKeyFrameKeyboardModifiers() const
2707 {
2708  return addKeyFrameKeyboardModifiers_;
2709 }
2710 
2723 Qt::KeyboardModifiers QGLViewer::playPathKeyboardModifiers() const
2724 {
2725  return playPathKeyboardModifiers_;
2726 }
2727 
2728 #ifndef DOXYGEN
2729 // Deprecated methods
2730 Qt::KeyboardModifiers QGLViewer::addKeyFrameStateKey() const
2731 {
2732  qWarning("addKeyFrameStateKey has been renamed addKeyFrameKeyboardModifiers");
2733  return addKeyFrameKeyboardModifiers(); }
2734 
2735 Qt::KeyboardModifiers QGLViewer::playPathStateKey() const
2736 {
2737  qWarning("playPathStateKey has been renamed playPathKeyboardModifiers");
2738  return playPathKeyboardModifiers();
2739 }
2740 
2742 {
2743  qWarning("setAddKeyFrameStateKey has been renamed setAddKeyFrameKeyboardModifiers");
2744  setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
2745 }
2746 
2747 void QGLViewer::setPlayPathStateKey(int buttonState)
2748 {
2749  qWarning("setPlayPathStateKey has been renamed setPlayPathKeyboardModifiers");
2750  setPlayPathKeyboardModifiers(Qt::KeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
2751 }
2752 
2753 Qt::Key QGLViewer::keyFrameKey(int index) const
2754 {
2755  qWarning("keyFrameKey has been renamed pathKey.");
2756  return pathKey(index);
2757 }
2758 
2759 Qt::KeyboardModifiers QGLViewer::playKeyFramePathStateKey() const
2760 {
2761  qWarning("playKeyFramePathStateKey has been renamed playPathKeyboardModifiers.");
2762  return playPathKeyboardModifiers();
2763 }
2764 
2765 void QGLViewer::setKeyFrameKey(int index, int key)
2766 {
2767  qWarning("setKeyFrameKey is deprecated, use setPathKey instead, with swapped parameters.");
2768  setPathKey(key, index);
2769 }
2770 
2772 {
2773  qWarning("setPlayKeyFramePathStateKey has been renamed setPlayPathKeyboardModifiers.");
2774  setPlayPathKeyboardModifiers(Qt::KeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
2775 }
2776 #endif
2777 
2779 // M o u s e b e h a v i o r s t a t e k e y s //
2781 
2822 void QGLViewer::setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers)
2823 {
2824  QMap<int, MouseActionPrivate> newMouseBinding;
2825  QMap<Qt::KeyboardModifiers, MouseActionPrivate> newWheelBinding;
2826  QMap<ClickActionPrivate, ClickAction> newClickBinding_;
2827 
2828  QMap<int, MouseActionPrivate>::Iterator mit;
2829  QMap<Qt::KeyboardModifiers, MouseActionPrivate>::Iterator wit;
2830 
2831  // First copy unchanged bindings.
2832  for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
2833  if ((mit.value().handler != handler) || (mit.value().action == ZOOM_ON_REGION))
2834  newMouseBinding[mit.key()] = mit.value();
2835 
2836  for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
2837  if (wit.value().handler != handler)
2838  newWheelBinding[wit.key()] = wit.value();
2839 
2840  // Then, add modified bindings, that can overwrite the previous ones.
2841  modifiers = convertKeyboardModifiers(modifiers);
2842  for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
2843  if ((mit.value().handler == handler) && (mit.value().action != ZOOM_ON_REGION))
2844  {
2845  int newState = modifiers | (mit.key() & Qt::MouseButtonMask);
2846  newMouseBinding[newState] = mit.value();
2847  }
2848 
2849  for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
2850  if (wit.value().handler == handler)
2851  {
2852  Qt::KeyboardModifiers newState = modifiers;
2853  newWheelBinding[newState] = wit.value();
2854  }
2855 
2856  // Same for button bindings
2857  for (QMap<ClickActionPrivate, ClickAction>::ConstIterator cb=clickBinding_.begin(), end=clickBinding_.end(); cb != end; ++cb)
2858  if (((handler==CAMERA) && ((cb.value() == CENTER_SCENE) || (cb.value() == ALIGN_CAMERA))) ||
2859  ((handler==FRAME) && ((cb.value() == CENTER_FRAME) || (cb.value() == ALIGN_FRAME))))
2860  {
2861  ClickActionPrivate cap;
2862  cap.modifiers = modifiers;
2863  cap.button = cb.key().button;
2864  cap.doubleClick = cb.key().doubleClick;
2865  cap.buttonsBefore = cb.key().buttonsBefore;
2866  newClickBinding_[cap] = cb.value();
2867  }
2868  else
2869  newClickBinding_[cb.key()] = cb.value();
2870 
2871  mouseBinding_ = newMouseBinding;
2872  wheelBinding_ = newWheelBinding;
2873  clickBinding_ = newClickBinding_;
2874 }
2875 
2876 
2877 #ifndef DOXYGEN
2878 void QGLViewer::setHandlerStateKey(MouseHandler handler, int buttonState)
2879 {
2880  qWarning("setHandlerStateKey has been renamed setHandlerKeyboardModifiers");
2881  setHandlerKeyboardModifiers(handler, Qt::KeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
2882 }
2883 
2884 void QGLViewer::setMouseStateKey(MouseHandler handler, int buttonState)
2885 {
2886  qWarning("setMouseStateKey has been renamed setHandlerKeyboardModifiers.");
2887  setHandlerKeyboardModifiers(handler, Qt::KeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
2888 }
2889 #endif
2890 
2922 void QGLViewer::setMouseBinding(int state, MouseHandler handler, MouseAction action, bool withConstraint)
2923 {
2924  if ((handler == FRAME) && ((action == MOVE_FORWARD) || (action == MOVE_BACKWARD) ||
2925  (action == ROLL) || (action == LOOK_AROUND) ||
2926  (action == ZOOM_ON_REGION)))
2927  {
2928 #if QT_VERSION >= 0x040000
2929  qWarning("Cannot bind %s to FRAME", mouseActionString(action).toLatin1().constData());
2930 #else
2931  qWarning("Cannot bind %s to FRAME", mouseActionString(action).latin1());
2932 #endif
2933  }
2934  else
2935  if ((state & Qt::MouseButtonMask) == 0)
2936  qWarning("No mouse button specified in setMouseBinding");
2937  else
2938  {
2939  MouseActionPrivate map;
2940  map.handler = handler;
2941  map.action = action;
2942  map.withConstraint = withConstraint;
2943  state = convertToKeyboardModifiers(state);
2944 
2945  mouseBinding_.remove(state);
2946 
2947  if (action != NO_MOUSE_ACTION)
2948  mouseBinding_.insert(state, map);
2949 
2950  ClickActionPrivate cap;
2951  cap.modifiers = Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask);
2952  cap.button = Qt::MouseButtons(state & Qt::MouseButtonMask);
2953  cap.doubleClick = false;
2954  cap.buttonsBefore = Qt::NoButton;
2955  clickBinding_.remove(cap);
2956  }
2957 }
2958 
2959 
2984 void QGLViewer::setMouseBinding(int state, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore)
2985 {
2986  if ((buttonsBefore != Qt::NoButton) && !doubleClick)
2987  qWarning("Buttons before is only meaningful when doubleClick is true in setMouseBinding().");
2988  else
2989  if ((state & Qt::MouseButtonMask) == 0)
2990  qWarning("No mouse button specified in setMouseBinding");
2991  else
2992  {
2993  ClickActionPrivate cap;
2994  state = convertToKeyboardModifiers(state);
2995  cap.modifiers = Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask);
2996  cap.button = Qt::MouseButtons(state & Qt::MouseButtonMask);
2997  cap.doubleClick = doubleClick;
2998  cap.buttonsBefore = buttonsBefore;
2999  clickBinding_.remove(cap);
3000 
3001  // #CONNECTION performClickAction comment on NO_CLICK_ACTION
3002  if (action != NO_CLICK_ACTION)
3003  clickBinding_.insert(cap, action);
3004 
3005  if ((!doubleClick) && (buttonsBefore == Qt::NoButton))
3006  mouseBinding_.remove(state);
3007  }
3008 }
3009 
3020 void QGLViewer::setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint)
3021 {
3022  //#CONNECTION# ManipulatedFrame::wheelEvent and ManipulatedCameraFrame::wheelEvent switches
3023  if ((action != ZOOM) && (action != MOVE_FORWARD) && (action != MOVE_BACKWARD) && (action != NO_MOUSE_ACTION))
3024 #if QT_VERSION >= 0x040000
3025  qWarning("Cannot bind %s to wheel", mouseActionString(action).toLatin1().constData());
3026 #else
3027  qWarning("Cannot bind %s to wheel", + mouseActionString(action).latin1());
3028 #endif
3029  else
3030  if ((handler == FRAME) && (action != ZOOM) && (action != NO_MOUSE_ACTION))
3031 #if QT_VERSION >= 0x040000
3032  qWarning("Cannot bind %s to FRAME wheel", mouseActionString(action).toLatin1().constData());
3033 #else
3034  qWarning("Cannot bind %s to FRAME wheel", mouseActionString(action).latin1());
3035 #endif
3036  else
3037  {
3038  MouseActionPrivate map;
3039  map.handler = handler;
3040  map.action = action;
3041  map.withConstraint = withConstraint;
3042  modifiers = convertKeyboardModifiers(modifiers);
3043  wheelBinding_.remove(modifiers);
3044 
3045  if (action != NO_MOUSE_ACTION)
3046  wheelBinding_.insert(modifiers, map);
3047  }
3048 }
3049 
3062 {
3063  state = convertToKeyboardModifiers(state);
3064  if (mouseBinding_.contains(state))
3065  return mouseBinding_[state].action;
3066  else
3067  return NO_MOUSE_ACTION;
3068 }
3069 
3080 int QGLViewer::mouseHandler(int state) const
3081 {
3082  state = convertToKeyboardModifiers(state);
3083  if (mouseBinding_.contains(state))
3084  return mouseBinding_[state].handler;
3085  else
3086  return -1;
3087 }
3088 
3106 int QGLViewer::mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const
3107 {
3108  for (QMap<int, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it)
3109  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
3110  return it.key();
3111 
3112  return Qt::NoButton;
3113 }
3114 
3120 QGLViewer::MouseAction QGLViewer::wheelAction(Qt::KeyboardModifiers modifiers) const
3121 {
3122  modifiers = convertKeyboardModifiers(modifiers);
3123  if (wheelBinding_.contains(modifiers))
3124  return wheelBinding_[modifiers].action;
3125  else
3126  return NO_MOUSE_ACTION;
3127 }
3128 
3130 int QGLViewer::wheelHandler(Qt::KeyboardModifiers modifiers) const
3131 {
3132  modifiers = convertKeyboardModifiers(modifiers);
3133  if (wheelBinding_.contains(modifiers))
3134  return wheelBinding_[modifiers].handler;
3135  else
3136  return -1;
3137 }
3138 
3143 int QGLViewer::wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const
3144 {
3145  for (QMap<Qt::KeyboardModifiers, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it)
3146  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
3147  return it.key();
3148 
3149  return -1;
3150 }
3151 
3153 QGLViewer::ClickAction QGLViewer::clickAction(int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const
3154 {
3155  ClickActionPrivate cap;
3156  cap.modifiers = Qt::KeyboardModifiers(convertToKeyboardModifiers(state) & Qt::KeyboardModifierMask);
3157  cap.button = Qt::MouseButtons(state & Qt::MouseButtonMask);
3158  cap.doubleClick = doubleClick;
3159  cap.buttonsBefore = buttonsBefore;
3160  if (clickBinding_.contains(cap))
3161  return clickBinding_[cap];
3162  else
3163  return NO_CLICK_ACTION;
3164 }
3165 
3171 void QGLViewer::getClickButtonState(ClickAction ca, int& state, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const
3172 {
3173  for (QMap<ClickActionPrivate, ClickAction>::ConstIterator it=clickBinding_.begin(), end=clickBinding_.end(); it != end; ++it)
3174  if (it.value() == ca)
3175  {
3176  state = it.key().modifiers | it.key().button;
3177  doubleClick = it.key().doubleClick;
3178  buttonsBefore = it.key().buttonsBefore;
3179  return;
3180  }
3181 
3182  state = Qt::NoButton;
3183 }
3184 
3189 {
3190  //#CONNECTION# used in toggleCameraMode() and keyboardString()
3191  return mouseButtonState(CAMERA, ROTATE) != Qt::NoButton;
3192 }
3193 
3208 {
3209  bool revolveMode = cameraIsInRevolveMode();
3210  int bs;
3211  if (revolveMode)
3212  bs = mouseButtonState(CAMERA, ROTATE);
3213  else
3214  bs = mouseButtonState(CAMERA, MOVE_FORWARD);
3215  Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(bs & Qt::KeyboardModifierMask);
3216 
3217  //#CONNECTION# setDefaultMouseBindings()
3218  if (revolveMode)
3219  {
3220  camera()->frame()->updateFlyUpVector();
3221  camera()->frame()->stopSpinning();
3222 
3223  setMouseBinding(modifiers | Qt::LeftButton, CAMERA, MOVE_FORWARD);
3224  setMouseBinding(modifiers | Qt::MidButton, CAMERA, LOOK_AROUND);
3225  setMouseBinding(modifiers | Qt::RightButton, CAMERA, MOVE_BACKWARD);
3226 
3227  setMouseBinding(modifiers | Qt::LeftButton | Qt::MidButton, CAMERA, ROLL);
3228  // 2.2.4 setMouseBinding(modifiers | Qt::RightButton | Qt::MidButton, CAMERA, SCREEN_TRANSLATE);
3229 
3230  setMouseBinding(Qt::LeftButton, NO_CLICK_ACTION, true);
3231  setMouseBinding(Qt::MidButton, NO_CLICK_ACTION, true);
3232  setMouseBinding(Qt::RightButton, NO_CLICK_ACTION, true);
3233 
3234  setWheelBinding(modifiers, CAMERA, MOVE_FORWARD);
3235  }
3236  else
3237  {
3238  // Should stop flyTimer. But unlikely and not easy.
3239  setMouseBinding(modifiers | Qt::LeftButton, CAMERA, ROTATE);
3240  setMouseBinding(modifiers | Qt::MidButton, CAMERA, ZOOM);
3241  setMouseBinding(modifiers | Qt::RightButton, CAMERA, TRANSLATE);
3242 
3243  setMouseBinding(modifiers | Qt::LeftButton | Qt::MidButton, CAMERA, SCREEN_ROTATE);
3244  // 2.2.4 setMouseBinding(modifiers | Qt::RightButton | Qt::MidButton, CAMERA, SCREEN_TRANSLATE);
3245 
3246  setMouseBinding(Qt::LeftButton, ALIGN_CAMERA, true);
3247  setMouseBinding(Qt::MidButton, SHOW_ENTIRE_SCENE, true);
3248  setMouseBinding(Qt::RightButton, CENTER_SCENE, true);
3249 
3250  setWheelBinding(modifiers, CAMERA, ZOOM);
3251  }
3252 }
3253 
3255 // M a n i p u l a t e d f r a m e s //
3257 
3270 {
3271  if (manipulatedFrame())
3272  {
3273  manipulatedFrame()->stopSpinning();
3274 
3275  if (manipulatedFrame() != camera()->frame())
3276  {
3277  disconnect(manipulatedFrame(), SIGNAL(manipulated()), this, SLOT(updateGL()));
3278  disconnect(manipulatedFrame(), SIGNAL(spun()), this, SLOT(updateGL()));
3279  }
3280  }
3281 
3282  manipulatedFrame_ = frame;
3283 
3284  manipulatedFrameIsACamera_ = ((manipulatedFrame() != camera()->frame()) &&
3285  (dynamic_cast<ManipulatedCameraFrame*>(manipulatedFrame()) != NULL));
3286 
3287  if (manipulatedFrame())
3288  {
3289  // Prevent multiple connections, that would result in useless display updates
3290  if (manipulatedFrame() != camera()->frame())
3291  {
3292  connect(manipulatedFrame(), SIGNAL(manipulated()), SLOT(updateGL()));
3293  connect(manipulatedFrame(), SIGNAL(spun()), SLOT(updateGL()));
3294  }
3295  }
3296 }
3297 
3298 #ifndef DOXYGEN
3299 // V i s u a l H i n t s //
3302 
3318 {
3319  // Revolve Around point cross
3320  if (visualHint_ & 1)
3321  {
3322  const float size = 15.0;
3323  Vec proj = camera()->projectedCoordinatesOf(camera()->revolveAroundPoint());
3324  startScreenCoordinatesSystem();
3325  glDisable(GL_LIGHTING);
3326  glDisable(GL_DEPTH_TEST);
3327  glLineWidth(3.0);
3328  glBegin(GL_LINES);
3329  glVertex2f(proj.x - size, proj.y);
3330  glVertex2f(proj.x + size, proj.y);
3331  glVertex2f(proj.x, proj.y - size);
3332  glVertex2f(proj.x, proj.y + size);
3333  glEnd();
3334  glEnable(GL_DEPTH_TEST);
3335  stopScreenCoordinatesSystem();
3336  }
3337 
3338  // if (visualHint_ & 2)
3339  // drawText(80, 10, "Play");
3340 
3341  // Screen rotate line
3342  ManipulatedFrame* mf = NULL;
3343  Vec pnt;
3344  if (camera()->frame()->action_ == SCREEN_ROTATE)
3345  {
3346  mf = camera()->frame();
3347  pnt = camera()->revolveAroundPoint();
3348  }
3349  if (manipulatedFrame() && (manipulatedFrame()->action_ == SCREEN_ROTATE))
3350  {
3351  mf = manipulatedFrame();
3352  // Maybe useful if the mf is a manipCameraFrame...
3353  // pnt = manipulatedFrame()->revolveAroundPoint();
3354  pnt = manipulatedFrame()->position();
3355  }
3356 
3357  if (mf)
3358  {
3359  pnt = camera()->projectedCoordinatesOf(pnt);
3360  startScreenCoordinatesSystem();
3361  glDisable(GL_LIGHTING);
3362  glDisable(GL_DEPTH_TEST);
3363  glLineWidth(3.0);
3364  glBegin(GL_LINES);
3365  glVertex2f(pnt.x, pnt.y);
3366  glVertex2f(mf->prevPos_.x(), mf->prevPos_.y());
3367  glEnd();
3368  glEnable(GL_DEPTH_TEST);
3369  stopScreenCoordinatesSystem();
3370  }
3371 
3372  // Zoom on region: draw a rectangle
3373  if (camera()->frame()->action_ == ZOOM_ON_REGION)
3374  {
3375  startScreenCoordinatesSystem();
3376  glDisable(GL_LIGHTING);
3377  glDisable(GL_DEPTH_TEST);
3378  glLineWidth(2.0);
3379  glBegin(GL_LINE_LOOP);
3380  glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->pressPos_.y());
3381  glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->pressPos_.y());
3382  glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->prevPos_.y());
3383  glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->prevPos_.y());
3384  glEnd();
3385  glEnable(GL_DEPTH_TEST);
3386  stopScreenCoordinatesSystem();
3387  }
3388 }
3389 
3393 void QGLViewer::setVisualHintsMask(int mask, int delay)
3394 {
3395  visualHint_ = visualHint_ | mask;
3396  QTimer::singleShot(delay, this, SLOT(resetVisualHints()));
3397 }
3398 
3401 {
3402  visualHint_ = 0;
3403 }
3404 #endif
3405 
3407 // A x i s a n d G r i d d i s p l a y l i s t s //
3409 
3419 void QGLViewer::drawArrow(float length, float radius, int nbSubdivisions)
3420 {
3421  static GLUquadric* quadric = gluNewQuadric();
3422 
3423  if (radius < 0.0)
3424  radius = 0.05 * length;
3425 
3426  const float head = 2.5*(radius / length) + 0.1;
3427  const float coneRadiusCoef = 4.0 - 5.0 * head;
3428 
3429  gluCylinder(quadric, radius, radius, length * (1.0 - head/coneRadiusCoef), nbSubdivisions, 1);
3430  glTranslatef(0.0, 0.0, length * (1.0 - head));
3431  gluCylinder(quadric, coneRadiusCoef * radius, 0.0, head * length, nbSubdivisions, 1);
3432  glTranslatef(0.0, 0.0, -length * (1.0 - head));
3433 }
3434 
3439 void QGLViewer::drawArrow(const Vec& from, const Vec& to, float radius, int nbSubdivisions)
3440 {
3441  glPushMatrix();
3442  glTranslatef(from[0],from[1],from[2]);
3443  const Vec dir = to-from;
3444  glMultMatrixd(Quaternion(Vec(0,0,1), dir).matrix());
3445  QGLViewer::drawArrow(dir.norm(), radius, nbSubdivisions);
3446  glPopMatrix();
3447 }
3448 
3467 void QGLViewer::drawAxis(float length)
3468 {
3469  const float charWidth = length / 40.0;
3470  const float charHeight = length / 30.0;
3471  const float charShift = 1.04 * length;
3472 
3473  GLboolean lighting, colorMaterial;
3474  glGetBooleanv(GL_LIGHTING, &lighting);
3475  glGetBooleanv(GL_COLOR_MATERIAL, &colorMaterial);
3476 
3477  glDisable(GL_LIGHTING);
3478 
3479  glBegin(GL_LINES);
3480  // The X
3481  glVertex3f(charShift, charWidth, -charHeight);
3482  glVertex3f(charShift, -charWidth, charHeight);
3483  glVertex3f(charShift, -charWidth, -charHeight);
3484  glVertex3f(charShift, charWidth, charHeight);
3485  // The Y
3486  glVertex3f( charWidth, charShift, charHeight);
3487  glVertex3f(0.0, charShift, 0.0);
3488  glVertex3f(-charWidth, charShift, charHeight);
3489  glVertex3f(0.0, charShift, 0.0);
3490  glVertex3f(0.0, charShift, 0.0);
3491  glVertex3f(0.0, charShift, -charHeight);
3492  // The Z
3493  glVertex3f(-charWidth, charHeight, charShift);
3494  glVertex3f( charWidth, charHeight, charShift);
3495  glVertex3f( charWidth, charHeight, charShift);
3496  glVertex3f(-charWidth, -charHeight, charShift);
3497  glVertex3f(-charWidth, -charHeight, charShift);
3498  glVertex3f( charWidth, -charHeight, charShift);
3499  glEnd();
3500 
3501  glEnable(GL_LIGHTING);
3502  glDisable(GL_COLOR_MATERIAL);
3503 
3504  float color[4];
3505  color[0] = 0.7f; color[1] = 0.7f; color[2] = 1.0f; color[3] = 1.0f;
3506  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3507  QGLViewer::drawArrow(length, 0.01*length);
3508 
3509  color[0] = 1.0f; color[1] = 0.7f; color[2] = 0.7f; color[3] = 1.0f;
3510  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3511  glPushMatrix();
3512  glRotatef(90.0, 0.0, 1.0, 0.0);
3513  QGLViewer::drawArrow(length, 0.01*length);
3514  glPopMatrix();
3515 
3516  color[0] = 0.7f; color[1] = 1.0f; color[2] = 0.7f; color[3] = 1.0f;
3517  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3518  glPushMatrix();
3519  glRotatef(-90.0, 1.0, 0.0, 0.0);
3520  QGLViewer::drawArrow(length, 0.01*length);
3521  glPopMatrix();
3522 
3523  if (colorMaterial)
3524  glEnable(GL_COLOR_MATERIAL);
3525  if (!lighting)
3526  glDisable(GL_LIGHTING);
3527 }
3528 
3535 void QGLViewer::drawGrid(float size, int nbSubdivisions)
3536 {
3537  GLboolean lighting;
3538  glGetBooleanv(GL_LIGHTING, &lighting);
3539 
3540  glDisable(GL_LIGHTING);
3541 
3542  glBegin(GL_LINES);
3543  for (int i=0; i<=nbSubdivisions; ++i)
3544  {
3545  const float pos = size*(2.0*i/nbSubdivisions-1.0);
3546  glVertex2f(pos, -size);
3547  glVertex2f(pos, +size);
3548  glVertex2f(-size, pos);
3549  glVertex2f( size, pos);
3550  }
3551  glEnd();
3552 
3553  if (lighting)
3554  glEnable(GL_LIGHTING);
3555 }
3556 
3558 // S t a t i c m e t h o d s : Q G L V i e w e r P o o l //
3560 
3563 {
3564 #if QT_VERSION >= 0x040000
3565  Q_FOREACH (QGLViewer* viewer, QGLViewer::QGLViewerPool())
3566  {
3567 #else
3568  QPtrListIterator<QGLViewer> it(QGLViewer::QGLViewerPool());
3569  for (QGLViewer* viewer; (viewer = it.current()) != 0; ++it)
3570  {
3571 #endif
3572  if (viewer)
3573  viewer->saveStateToFile();
3574  }
3575 }
3576 
3578 // S a v e s t a t e b e t w e e n s e s s i o n s //
3580 
3595 {
3596  QString name = stateFileName_;
3597 
3598  if (!name.isEmpty() && QGLViewer::QGLViewerIndex(this) > 0)
3599  {
3600  QFileInfo fi(name);
3601 #if QT_VERSION >= 0x040000
3602  if (fi.suffix().isEmpty())
3603 #else
3604  if (fi.extension(false).isEmpty())
3605 #endif
3606  name += QString::number(QGLViewer::QGLViewerIndex(this));
3607  else
3608 #if QT_VERSION >= 0x040000
3609  name = fi.absolutePath() + '/' + fi.completeBaseName() + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.suffix();
3610 #else
3611 # if QT_VERSION >= 0x030000
3612  name = fi.dirPath() + '/' + fi.baseName(true) + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.extension(false);
3613 # else
3614  name = fi.dirPath() + '/' + fi.baseName() + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.extension();
3615 # endif
3616 #endif
3617  }
3618 
3619  return name;
3620 }
3621 
3630 {
3631  QString name = stateFileName();
3632 
3633  if (name.isEmpty())
3634  return;
3635 
3636  QFileInfo fileInfo(name);
3637 
3638  if (fileInfo.isDir())
3639  {
3640  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("State file name (%1) references a directory instead of a file.").arg(name));
3641  return;
3642  }
3643 
3644 #if QT_VERSION >= 0x040000
3645  const QString dirName = fileInfo.absolutePath();
3646 #else
3647  const QString dirName = fileInfo.dirPath();
3648 #endif
3649  if (!QFileInfo(dirName).exists())
3650  {
3651  QDir dir;
3652 #if QT_VERSION >= 0x040000
3653  if (!(dir.mkdir(dirName)))
3654 #else
3655  if (!(dir.mkdir(dirName, true)))
3656 #endif
3657  {
3658  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to create directory %1").arg(dirName));
3659  return;
3660  }
3661  }
3662 
3663  // Write the DOM tree to file
3664  QFile f(name);
3665 #if QT_VERSION >= 0x040000
3666  if (f.open(QIODevice::WriteOnly))
3667 #else
3668  if (f.open(IO_WriteOnly))
3669 #endif
3670  {
3671  QTextStream out(&f);
3672  QDomDocument doc("QGLVIEWER");
3673  doc.appendChild(domElement("QGLViewer", doc));
3674  doc.save(out, 2);
3675  f.flush();
3676  f.close();
3677  }
3678  else
3679 #if QT_VERSION < 0x030200
3680  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to save to file %1").arg(name));
3681 #else
3682  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to save to file %1").arg(name) + ":\n" + f.errorString());
3683 #endif
3684 }
3685 
3707 {
3708  QString name = stateFileName();
3709 
3710  if (name.isEmpty())
3711  return false;
3712 
3713  QFileInfo fileInfo(name);
3714 
3715  if (!fileInfo.isFile())
3716  // No warning since it would be displayed at first start.
3717  return false;
3718 
3719  if (!fileInfo.isReadable())
3720  {
3721  QMessageBox::warning(this, tr("Problem in state restoration", "Message box window title"), tr("File %1 is not readable.").arg(name));
3722  return false;
3723  }
3724 
3725  // Read the DOM tree form file
3726  QFile f(name);
3727 #if QT_VERSION >= 0x040000
3728  if (f.open(QIODevice::ReadOnly) == true)
3729 #else
3730  if (f.open(IO_ReadOnly) == true)
3731 #endif
3732  {
3733  QDomDocument doc;
3734  doc.setContent(&f);
3735  f.close();
3736  QDomElement main = doc.documentElement();
3737  initFromDOMElement(main);
3738  }
3739  else
3740  {
3741 #if QT_VERSION < 0x030200
3742  QMessageBox::warning(this, tr("Open file error", "Message box window title"), tr("Unable to open file %1").arg(name));
3743 #else
3744  QMessageBox::warning(this, tr("Open file error", "Message box window title"), tr("Unable to open file %1").arg(name) + ":\n" + f.errorString());
3745 #endif
3746  return false;
3747  }
3748 
3749  return true;
3750 }
3751 
3784 QDomElement QGLViewer::domElement(const QString& name, QDomDocument& document) const
3785 {
3786  QDomElement de = document.createElement(name);
3787  de.setAttribute("version", QGLViewerVersionString());
3788 
3789  QDomElement stateNode = document.createElement("State");
3790  // stateNode.setAttribute("mouseTracking", (hasMouseTracking()?"true":"false"));
3791  stateNode.appendChild(DomUtils::QColorDomElement(foregroundColor(), "foregroundColor", document));
3792  stateNode.appendChild(DomUtils::QColorDomElement(backgroundColor(), "backgroundColor", document));
3793  stateNode.setAttribute("stereo", (displaysInStereo()?"true":"false"));
3794  stateNode.setAttribute("cameraMode", (cameraIsInRevolveMode()?"revolve":"fly"));
3795  de.appendChild(stateNode);
3796 
3797  QDomElement displayNode = document.createElement("Display");
3798  displayNode.setAttribute("axisIsDrawn", (axisIsDrawn()?"true":"false"));
3799  displayNode.setAttribute("gridIsDrawn", (gridIsDrawn()?"true":"false"));
3800  displayNode.setAttribute("FPSIsDisplayed", (FPSIsDisplayed()?"true":"false"));
3801  displayNode.setAttribute("cameraIsEdited", (cameraIsEdited()?"true":"false"));
3802  // displayNode.setAttribute("textIsEnabled", (textIsEnabled()?"true":"false"));
3803  de.appendChild(displayNode);
3804 
3805  QDomElement geometryNode = document.createElement("Geometry");
3806  geometryNode.setAttribute("fullScreen", (isFullScreen()?"true":"false"));
3807  if (isFullScreen())
3808  {
3809  geometryNode.setAttribute("prevPosX", QString::number(prevPos_.x()));
3810  geometryNode.setAttribute("prevPosY", QString::number(prevPos_.y()));
3811  }
3812  else
3813  {
3814  QWidget* tlw = topLevelWidget();
3815  geometryNode.setAttribute("width", QString::number(tlw->width()));
3816  geometryNode.setAttribute("height", QString::number(tlw->height()));
3817  geometryNode.setAttribute("posX", QString::number(tlw->pos().x()));
3818  geometryNode.setAttribute("posY", QString::number(tlw->pos().y()));
3819  }
3820  de.appendChild(geometryNode);
3821 
3822  // Restore original Camera zClippingCoefficient before saving.
3823  if (cameraIsEdited())
3824  camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_);
3825  de.appendChild(camera()->domElement("Camera", document));
3826  if (cameraIsEdited())
3827  // #CONNECTION# 5.0 from setCameraIsEdited()
3828  camera()->setZClippingCoefficient(5.0);
3829 
3830  if (manipulatedFrame())
3831  de.appendChild(manipulatedFrame()->domElement("ManipulatedFrame", document));
3832 
3833  return de;
3834 }
3835 
3870 void QGLViewer::initFromDOMElement(const QDomElement& element)
3871 {
3872  const QString version = element.attribute("version");
3873  // if (version != QGLViewerVersionString())
3874  if (version[0] != '2')
3875  // Patches for previous versions should go here when the state file syntax is modified.
3876 #if QT_VERSION >= 0x040000
3877  qWarning("State file created using QGLViewer version %s may not be correctly read.", version.toLatin1().constData());
3878 #else
3879  qWarning("State file created using QGLViewer version %s may not be correctly read.", version.latin1());
3880 #endif
3881 
3882  QDomElement child=element.firstChild().toElement();
3883  bool tmpCameraIsEdited = cameraIsEdited();
3884  while (!child.isNull())
3885  {
3886  if (child.tagName() == "State")
3887  {
3888  // #CONNECTION# default values from defaultConstructor()
3889  // setMouseTracking(DomUtils::boolFromDom(child, "mouseTracking", false));
3890  setStereoDisplay(DomUtils::boolFromDom(child, "stereo", false));
3891  if ((child.attribute("cameraMode", "revolve") == "fly") && (cameraIsInRevolveMode()))
3892  toggleCameraMode();
3893 
3894  QDomElement ch=child.firstChild().toElement();
3895  while (!ch.isNull())
3896  {
3897  if (ch.tagName() == "foregroundColor")
3898  setForegroundColor(DomUtils::QColorFromDom(ch));
3899  if (ch.tagName() == "backgroundColor")
3900  setBackgroundColor(DomUtils::QColorFromDom(ch));
3901  ch = ch.nextSibling().toElement();
3902  }
3903  }
3904 
3905  if (child.tagName() == "Display")
3906  {
3907  // #CONNECTION# default values from defaultConstructor()
3908  setAxisIsDrawn(DomUtils::boolFromDom(child, "axisIsDrawn", false));
3909  setGridIsDrawn(DomUtils::boolFromDom(child, "gridIsDrawn", false));
3910  setFPSIsDisplayed(DomUtils::boolFromDom(child, "FPSIsDisplayed", false));
3911  // See comment below.
3912  tmpCameraIsEdited = DomUtils::boolFromDom(child, "cameraIsEdited", false);
3913  // setTextIsEnabled(DomUtils::boolFromDom(child, "textIsEnabled", true));
3914  }
3915 
3916  if (child.tagName() == "Geometry")
3917  {
3918  setFullScreen(DomUtils::boolFromDom(child, "fullScreen", false));
3919 
3920  if (isFullScreen())
3921  {
3922  prevPos_.setX(DomUtils::intFromDom(child, "prevPosX", 0));
3923  prevPos_.setY(DomUtils::intFromDom(child, "prevPosY", 0));
3924  }
3925  else
3926  {
3927  int width = DomUtils::intFromDom(child, "width", 600);
3928  int height = DomUtils::intFromDom(child, "height", 400);
3929  topLevelWidget()->resize(width, height);
3930  camera()->setScreenWidthAndHeight(this->width(), this->height());
3931 
3932  QPoint pos;
3933  pos.setX(DomUtils::intFromDom(child, "posX", 0));
3934  pos.setY(DomUtils::intFromDom(child, "posY", 0));
3935  topLevelWidget()->move(pos);
3936  }
3937  }
3938 
3939  if (child.tagName() == "Camera")
3940  {
3941  connectAllCameraKFIInterpolatedSignals(false);
3942  camera()->initFromDOMElement(child);
3943  connectAllCameraKFIInterpolatedSignals();
3944  }
3945 
3946  if ((child.tagName() == "ManipulatedFrame") && (manipulatedFrame()))
3947  manipulatedFrame()->initFromDOMElement(child);
3948 
3949  child = child.nextSibling().toElement();
3950  }
3951 
3952  // The Camera always stores its "real" zClippingCoef in domElement(). If it is edited,
3953  // its "real" coef must be saved and the coef set to 5.0, as is done in setCameraIsEdited().
3954  // BUT : Camera and Display are read in an arbitrary order. We must initialize Camera's
3955  // "real" coef BEFORE calling setCameraIsEdited. Hence this temp cameraIsEdited and delayed call
3956  cameraIsEdited_ = tmpCameraIsEdited;
3957  if (cameraIsEdited_)
3958  {
3959  previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient();
3960  // #CONNECTION# 5.0 from setCameraIsEdited.
3961  camera()->setZClippingCoefficient(5.0);
3962  }
3963 }
3964 
3965 #ifndef DOXYGEN
3966 
3968 void QGLViewer::saveToFile(const QString& fileName)
3969 {
3970  if (!fileName.isEmpty())
3971  setStateFileName(fileName);
3972 
3973  qWarning("saveToFile() is deprecated, use saveStateToFile() instead.");
3974  saveStateToFile();
3975 }
3976 
3979 bool QGLViewer::restoreFromFile(const QString& fileName)
3980 {
3981  if (!fileName.isEmpty())
3982  setStateFileName(fileName);
3983 
3984  qWarning("restoreFromFile() is deprecated, use restoreStateFromFile() instead.");
3985  return restoreStateFromFile();
3986 }
3987 #endif
3988 
4042 void QGLViewer::copyBufferToTexture(GLint internalFormat, GLenum format)
4043 {
4044  int h = 16;
4045  int w = 16;
4046  // Todo compare performance with qt code.
4047  while (w < width())
4048  w <<= 1;
4049  while (h < height())
4050  h <<= 1;
4051 
4052  bool init = false;
4053 
4054  if ((w != bufferTextureWidth_) || (h != bufferTextureHeight_))
4055  {
4056  bufferTextureWidth_ = w;
4057  bufferTextureHeight_ = h;
4058  bufferTextureMaxU_ = width() / float(bufferTextureWidth_);
4059  bufferTextureMaxV_ = height() / float(bufferTextureHeight_);
4060  init = true;
4061  }
4062 
4063  if (bufferTextureId() == 0)
4064  {
4065  glGenTextures(1, &bufferTextureId_);
4066  glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
4067  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
4068  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
4069  init = true;
4070  }
4071  else
4072  glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
4073 
4074  if ((format != previousBufferTextureFormat_) ||
4075  (internalFormat != previousBufferTextureInternalFormat_))
4076  {
4077  previousBufferTextureFormat_ = format;
4078  previousBufferTextureInternalFormat_ = internalFormat;
4079  init = true;
4080  }
4081 
4082  if (init)
4083  {
4084  if (format == GL_NONE)
4085  format = internalFormat;
4086 
4087  glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, bufferTextureWidth_, bufferTextureHeight_, 0, format, GL_UNSIGNED_BYTE, NULL);
4088  }
4089 
4090  glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width(), height());
4091 }
4092 
4100 {
4101  if (glIsTexture(bufferTextureId_))
4102  return bufferTextureId_;
4103  else
4104  return 0;
4105 }
virtual QString mouseString() const
Definition: qglviewer.cpp:2009
virtual void postDraw()
Definition: qglviewer.cpp:421
virtual void aboutQGLViewer()
Definition: qglviewer.cpp:2293
Qt::KeyboardModifiers playPathKeyboardModifiers() const
Definition: qglviewer.cpp:2723
virtual void wheelEvent(QWheelEvent *)
Definition: qglviewer.cpp:1658
void setScreenWidthAndHeight(int width, int height)
Definition: camera.cpp:164
static QPtrList< QGLViewer > QGLViewerPool_
Definition: qglviewer.h:1259
void setDefaultMouseBindings()
Definition: qglviewer.cpp:617
A keyFrame Catmull-Rom Frame interpolator.
virtual void timerEvent(QTimerEvent *)
Definition: qglviewer.cpp:1099
void displayFPS()
Definition: qglviewer.cpp:1026
void setCamera(qglviewer::Camera *const camera)
Definition: qglviewer.cpp:707
Qt::KeyboardModifiers addKeyFrameStateKey() const
Definition: qglviewer.cpp:2730
ClickAction clickAction(int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const
Definition: qglviewer.cpp:3153
static QDomElement QColorDomElement(const QColor &color, const QString &name, QDomDocument &doc)
Definition: domUtils.h:151
The ManipulatedCameraFrame class represents a ManipulatedFrame with Camera specific mouse bindings...
virtual void resetVisualHints()
Definition: qglviewer.cpp:3400
float zClippingCoefficient() const
Definition: camera.h:267
static QString mouseActionString(QGLViewer::MouseAction ma)
Definition: qglviewer.cpp:1883
static void drawArrow(float length=1.0f, float radius=-1.0f, int nbSubdivisions=12)
Definition: qglviewer.cpp:3419
virtual void setKeyFrameKey(int index, int key)
Definition: qglviewer.cpp:2765
A ManipulatedFrame is a Frame that can be rotated and translated using the mouse. ...
QString stateFileName() const
Definition: qglviewer.cpp:3594
void setMouseBindingDescription(int state, QString description, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton)
Definition: qglviewer.cpp:1968
virtual void setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers)
Definition: qglviewer.cpp:2682
virtual void checkIfGrabsMouse(int x, int y, const Camera *const camera)=0
virtual void fastDraw()
Definition: qglviewer.cpp:519
static int convertToShortModifier(int state)
Definition: qglviewer.cpp:278
#define Qt
Definition: qglviewer.h:45
Qt::MouseButtons buttonsBefore
Definition: qglviewer.h:1220
virtual void stopAnimation()
Definition: qglviewer.cpp:1116
virtual ~QGLViewer()
Definition: qglviewer.cpp:220
virtual void stopScreenCoordinatesSystem() const
Definition: qglviewer.cpp:1087
static QString keyString(int key)
Definition: qglviewer.cpp:2134
void hideMessage()
Definition: qglviewer.cpp:1009
int wheelHandler(Qt::KeyboardModifiers modifiers) const
Definition: qglviewer.cpp:3130
void setSceneCenter(const Vec &center)
Definition: camera.cpp:694
virtual void saveStateToFile()
Definition: qglviewer.cpp:3629
void defaultConstructor()
Definition: qglviewer.cpp:90
void setHandlerStateKey(MouseHandler handler, int buttonState)
Definition: qglviewer.cpp:2878
QGLViewer(QWidget *parent=NULL, const char *name=0, const QGLWidget *shareWidget=0, Qt::WindowFlags flags=0)
Definition: qglviewer.h:78
double norm() const
Definition: vec.h:339
void setMouseGrabberIsEnabled(const qglviewer::MouseGrabber *const mouseGrabber, bool enabled=true)
Definition: qglviewer.cpp:1830
void drawText(int x, int y, const QString &text, const QFont &fnt=QFont())
Definition: qglviewer.cpp:860
#define M_PI
#define QGLVIEWER_VERSION
Definition: config.h:31
virtual void closeEvent(QCloseEvent *)
Definition: qglviewer.cpp:1126
int mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const
Definition: qglviewer.cpp:3106
void setStereoDisplay(bool stereo=true)
Definition: qglviewer.cpp:1758
Qt::KeyboardModifiers playKeyFramePathStateKey() const
Definition: qglviewer.cpp:2759
bool restoreFromFile(const QString &fileName=QString::null)
Definition: qglviewer.cpp:3979
static QString clickActionString(QGLViewer::ClickAction ca)
Definition: qglviewer.cpp:1903
Qt::KeyboardModifiers playPathStateKey() const
Definition: qglviewer.cpp:2735
Abstract class for objects that grab mouse focus in a QGLViewer.
Definition: mouseGrabber.h:134
static int QGLViewerIndex(const QGLViewer *const viewer)
Definition: qglviewer.h:1103
bool grabsMouse() const
Definition: mouseGrabber.h:187
virtual void endSelection(const QPoint &point)
Definition: qglviewer.cpp:1307
static QString QGLViewerVersionString()
Definition: qglviewer.cpp:244
void setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers)
Definition: qglviewer.cpp:2822
ManipulatedCameraFrame * frame() const
Definition: camera.h:372
virtual void mouseMoveEvent(QMouseEvent *)
Definition: qglviewer.cpp:1546
virtual void select(const QMouseEvent *event)
Definition: qglviewer.cpp:1171
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera)
virtual void setPlayKeyFramePathStateKey(int buttonState)
Definition: qglviewer.cpp:2771
void setKeyDescription(int key, QString description)
Definition: qglviewer.cpp:2122
void setShortcut(KeyboardAction action, unsigned int key)
Definition: qglviewer.cpp:2595
The Vec class represents 3D positions and 3D vectors.
Definition: vec.h:69
const GLdouble * matrix() const
Definition: frame.cpp:123
virtual void startScreenCoordinatesSystem(bool upward=false) const
Definition: qglviewer.cpp:1062
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
virtual void setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers)
Definition: qglviewer.cpp:2688
void setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint=true)
Definition: qglviewer.cpp:3020
Qt::KeyboardModifiers addKeyFrameKeyboardModifiers() const
Definition: qglviewer.cpp:2706
virtual void setPathKey(int key, int index=0)
Definition: qglviewer.cpp:2673
void setKeyboardAccelerator(KeyboardAction action, int key)
Definition: qglviewer.cpp:2624
bool cameraIsInRevolveMode() const
Definition: qglviewer.cpp:3188
void connectAllCameraKFIInterpolatedSignals(bool connection=true)
Definition: qglviewer.cpp:731
void copyBufferToTexture(GLint internalFormat, GLenum format=GL_NONE)
Definition: qglviewer.cpp:4042
virtual void initFromDOMElement(const QDomElement &element)
Definition: qglviewer.cpp:3870
static void saveStateToFileForAllViewers()
Definition: qglviewer.cpp:3562
void setManipulatedFrame(qglviewer::ManipulatedFrame *frame)
Definition: qglviewer.cpp:3269
int keyboardAccelerator(KeyboardAction action) const
Definition: qglviewer.cpp:2630
void setDefaultShortcuts()
Definition: qglviewer.cpp:550
static QString formatClickActionPrivate(ClickActionPrivate cap)
Definition: qglviewer.cpp:1922
GLuint bufferTextureId() const
Definition: qglviewer.cpp:4099
void setSelectBufferSize(int size)
Definition: qglviewer.cpp:1339
virtual QString keyboardString() const
Definition: qglviewer.cpp:2239
static Qt::KeyboardModifiers convertKeyboardModifiers(Qt::KeyboardModifiers modifiers)
Definition: qglviewer.cpp:269
double normalize()
Definition: vec.h:344
static QString mouseButtonsString(Qt::MouseButtons b)
Definition: qglviewer.cpp:1873
void setFullScreen(bool fullScreen=true)
Definition: qglviewer.cpp:1787
virtual void startAnimation()
Definition: qglviewer.cpp:1109
static void drawGrid(float size=1.0f, int nbSubdivisions=10)
Definition: qglviewer.cpp:3535
virtual void setAddKeyFrameStateKey(int buttonState)
Definition: qglviewer.cpp:2741
int wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const
Definition: qglviewer.cpp:3143
static const QPtrList< QGLViewer > & QGLViewerPool()
Definition: qglviewer.h:1089
void setMouseGrabber(qglviewer::MouseGrabber *mouseGrabber)
Definition: qglviewer.cpp:1816
void setMouseBinding(int state, MouseHandler handler, MouseAction action, bool withConstraint=true)
Definition: qglviewer.cpp:2922
virtual void mouseDoubleClickEvent(QMouseEvent *)
Definition: qglviewer.cpp:1729
#define KeyboardModifierMask
Definition: qglviewer.cpp:57
#define Q_EMIT
Definition: config.h:121
static QColor QColorFromDom(const QDomElement &e)
Definition: domUtils.h:160
A versatile 3D OpenGL viewer based on QGLWidget.
Definition: qglviewer.h:70
void setCameraIsEdited(bool edit=true)
Definition: qglviewer.cpp:531
virtual void paintGL()
Definition: qglviewer.cpp:355
MouseAction wheelAction(Qt::KeyboardModifiers modifiers) const
Definition: qglviewer.cpp:3120
virtual void preDrawStereo(bool leftBuffer=true)
Definition: qglviewer.cpp:492
QString cameraPathKeysString() const
Definition: qglviewer.cpp:2148
static void drawAxis(float length=1.0f)
Definition: qglviewer.cpp:3467
A perspective or orthographic camera.
Definition: camera.h:81
static int convertToKeyboardModifiers(int state)
Definition: qglviewer.cpp:251
The Quaternion class represents 3D rotations and orientations.
Definition: quaternion.h:66
Qt::KeyboardModifiers modifiers
Definition: qglviewer.h:1217
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
Definition: qglviewer.cpp:3784
virtual bool restoreStateFromFile()
Definition: qglviewer.cpp:3706
void performClickAction(ClickAction ca, const QMouseEvent *const e)
Definition: qglviewer.cpp:1347
virtual void drawVisualHints()
Definition: qglviewer.cpp:3317
virtual void keyPressEvent(QKeyEvent *)
Definition: qglviewer.cpp:2437
Qt::Key keyFrameKey(int index) const
Definition: qglviewer.cpp:2753
MouseAction mouseAction(int state) const
Definition: qglviewer.cpp:3061
static bool boolFromDom(const QDomElement &e, const QString &attribute, bool defValue)
Definition: domUtils.h:122
void toggleCameraMode()
Definition: qglviewer.cpp:3207
virtual void preDraw()
Definition: qglviewer.cpp:399
void setSceneRadius(float radius)
Definition: camera.cpp:667
The Frame class represents a coordinate system, defined by a position and an orientation.
Definition: frame.h:126
void setMouseStateKey(MouseHandler handler, int buttonState)
Definition: qglviewer.cpp:2884
static int intFromDom(const QDomElement &e, const QString &attribute, int defValue)
Definition: domUtils.h:104
void getClickButtonState(ClickAction action, int &state, bool &doubleClick, Qt::MouseButtons &buttonsBefore) const
Definition: qglviewer.cpp:3171
static QString keyboardModifiersString(Qt::KeyboardModifiers m, bool noButton=false)
Definition: qglviewer.cpp:1838
virtual void setVisualHintsMask(int mask, int delay=2000)
Definition: qglviewer.cpp:3393
static QString tableLine(const QString &left, const QString &right)
Definition: qglviewer.cpp:1982
int main(int argc, char *argv[])
Definition: main.cpp:29
void handleKeyboardAction(KeyboardAction id)
Definition: qglviewer.cpp:2520
virtual void drawLight(GLenum light, float scale=1.0f) const
Definition: qglviewer.cpp:763
virtual void help()
Definition: qglviewer.cpp:2312
double y
Definition: vec.h:85
virtual void resizeGL(int width, int height)
Definition: qglviewer.cpp:2567
unsigned int shortcut(KeyboardAction action) const
Definition: qglviewer.cpp:2615
int mouseHandler(int state) const
Definition: qglviewer.cpp:3080
Qt::Key pathKey(int index) const
Definition: qglviewer.cpp:2654
virtual void initializeGL()
Definition: qglviewer.cpp:314
void saveToFile(const QString &fileName=QString::null)
Definition: qglviewer.cpp:3968
virtual void mouseReleaseEvent(QMouseEvent *)
Definition: qglviewer.cpp:1609
virtual void setPlayPathStateKey(int buttonState)
Definition: qglviewer.cpp:2747
virtual void beginSelection(const QPoint &point)
Definition: qglviewer.cpp:1247
virtual void startAction(int ma, bool withConstraint=true)
virtual void mousePressEvent(QMouseEvent *)
Definition: qglviewer.cpp:1414
void displayMessage(const QString &message, int delay=2000)
Definition: qglviewer.cpp:992
double x
Definition: vec.h:85


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Mon Jun 10 2019 14:00:25