The keyboardAndMouse example

keyboardAndMouse

Shows how to customize your keyboard and mouse bindings.

Use setKeyFrameKey() to change standard action bindings (axis, grid or fps display, exit...).

Use setMouseBinding() and setWheelBinding() to change standard action mouse bindings (camera rotation, translation, object selection...).

If you want to define new key or mouse actions, you have to overload keyPressEvent() and mouse(Press|Move|Release)Event to define and bind your own new actions.

Overload shortcutBindingsString() and mouseBindingsString() to update the help window binding tabs.

keyboardAndMouse.h


#include <QGLViewer/qglviewer.h>

class Viewer : public QGLViewer
{
public:
  Viewer() : wireframe_(false), flatShading_(false) {};

protected :
  virtual void draw();
  virtual void init();
  virtual void keyPressEvent(QKeyEvent *e);
  virtual void mousePressEvent(QMouseEvent* e);

  virtual QString helpString() const;
  virtual QString mouseBindingsString() const;
  virtual QString shortcutBindingsString() const;

private :
  bool wireframe_, flatShading_;
};

keyboardAndMouse.cpp


#include "keyboardAndMouse.h"
#include <qpopupmenu.h>
#include <qcursor.h>
#include <qmap.h>
#include <math.h>

using namespace std;

// Draws a spiral
void Viewer::draw()
{
  const float nbSteps = 80.0;

  glBegin(GL_QUAD_STRIP);
  for (float i=0; i<nbSteps; ++i)
    {
      float ratio = i/nbSteps;
      float angle = 21.0*ratio;
      float c = cos(angle);
      float s = sin(angle);
      float r1 = 1.0 - 0.8*ratio;
      float r2 = 0.8 - 0.8*ratio;
      float alt = ratio - 0.5;
      const float nor = .5;
      const float up = sqrt(1.0-nor*nor);
      glColor3f(fabs(c), 0.2, fabs(s));
      glNormal3f(nor*c, up, nor*s);
      glVertex3f(r1*c, alt, r1*s);
      glVertex3f(r2*c, alt+0.05, r2*s);
    }
  glEnd();
}

void Viewer::init()
{
  // Restore previous viewer state.
  restoreFromFile();


  /////////////////////////////////////////////////////
  //       Keyboard shortcut customization           //
  //      Changes standard action key bindings       //
  /////////////////////////////////////////////////////

  // Define 'CTRL+Q' as the new exit shortcut (default was 'Escape')
  setShortcutKey(QGLViewer::EXIT, Qt::Key_Q, Qt::ControlButton);

  // Set 'Control' as the FPS toggle state key (default was 'F' and becomes 'CTRL+F')
  setShortcutStateKey(QGLViewer::DISPLAY_FPS, Qt::ControlButton);

  // Disable Z-Buffer toggle shortcut (default was 'Z')
  setShortcutKey(QGLViewer::DISPLAY_Z_BUFFER, 0);



  /////////////////////////////////////////////////////
  //         Mouse bindings customization            //
  //     Changes standard action mouse bindings      //
  /////////////////////////////////////////////////////

  // Left and right buttons together make a camera zoom : emulates a mouse third button if needed.
  setMouseBinding(Qt::LeftButton | Qt::RightButton, CAMERA, ZOOM);

  // Alt+left button translates the camera (since right button will popup a menu).
  setMouseBinding(Qt::AltButton | Qt::LeftButton, CAMERA, TRANSLATE);

  // Disable previous TRANSLATE mouse binding (and remove it from help mouse tab).
  setMouseBinding(Qt::RightButton, NO_CLICK_ACTION);

  // Define Control+Shift+Right button as selection shortcut
  setMouseBinding(Qt::ControlButton | Qt::ShiftButton | Qt::RightButton, SELECT);

  // Alt + mouse wheel MOVE_FORWARD the camera.
  setWheelBinding(Qt::AltButton, CAMERA, MOVE_FORWARD);

  // Display the help window. The help window tabs are automatically updated when you define new
  // standard key or mouse bindings (as is done above). Use shortcutBindingsString() and
  // mouseBindingsString() to add the description of your own new actions.
  help();
}


///////////////////////////////////////////////
//      Define new key bindings : F & W      //
///////////////////////////////////////////////

void Viewer::keyPressEvent(QKeyEvent *e)
{
  // Get event state key
  const Qt::ButtonState state = (Qt::ButtonState)(e->state() & Qt::KeyButtonMask);
  // Bug in Qt : use 0x0f00 instead of Qt::KeyButtonMask with Qt versions < 3.1

  // A simple switch on e->key() is not sufficient if we want to take state key into account.
  // With a switch, it would have been impossible to separate 'F' from 'CTRL+F'.
  // That's why we use imbricated if...else and a "handled" boolean.
  bool handled = false;
  if ((e->key()==Qt::Key_W) && (state==Qt::NoButton))
    {
      wireframe_ = !wireframe_;
      if (wireframe_)
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
      else
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      handled = true;
      updateGL();
    }
  else
    if ((e->key()==Qt::Key_F) && (state==Qt::NoButton))
      {
	flatShading_ = !flatShading_;
	if (flatShading_)
	  glShadeModel(GL_FLAT);
	else
	  glShadeModel(GL_SMOOTH);
	handled = true;
	updateGL();
      }
  // and so on with other else if.

  if (!handled)
    QGLViewer::keyPressEvent(e);
}


///////////////////////////////////////////////////////////
//             Define new mouse bindings                 //
//   A camera viewpoint menu binded on right button      //
///////////////////////////////////////////////////////////

void Viewer::mousePressEvent(QMouseEvent* e)
{
  if ((e->button() == Qt::RightButton) && (e->state() == Qt::NoButton))
    {
      QPopupMenu menu( this );
      menu.insertItem("Camera positions");
      menu.insertSeparator();

      QMap<int, int> menuMap;
      bool atLeastOne = false;
      for (unsigned short i=0; i<camera()->nbPaths(); ++i)
	if (camera()->keyFrameInterpolator(i))
	  {
	    atLeastOne = true;
	    if (camera()->keyFrameInterpolator(i)->numberOfKeyFrames() == 1)
	      menuMap[menu.insertItem("Position "+QString::number(i+1))] = i;
	    else
	      menuMap[menu.insertItem("Path "+QString::number(i+1))] = i;
	  }

      if (!atLeastOne)
	{
	  menu.insertItem("No position defined");
	  menu.insertItem("Use to Alt+Fx to define one");
	}

      menu.setMouseTracking( true );
      int select = menu.exec( QCursor::pos() );

      if (atLeastOne && select != -1)
	camera()->playKeyFramePath(menuMap[select]);
    }
  else
    QGLViewer::mousePressEvent(e);
}

QString Viewer::helpString() const
{
  QString text("<h2>K e y b o a r d A n d M o u s e</h2>");
  text += "This example illustrates the mouse and key bindings customization.<br>";
  text += "Use setKeyFrameKey() to change standard action key bindings (axis, grid or fps display, exit...).<br>";
  text += "Use setMouseBinding() and setWheelBinding() to change standard action mouse bindings ";
  text += "(camera rotation, translation, object selection...).<br><br>";
  text += "If you want to define <b>new</b> key or mouse actions, you need to overload keyPressEvent() and/or ";
  text += "mouse(Press|Move|Release)Event to define and bind your own new actions.<br><br>";
  text += "Finally, overload shortcutBindingsString() and mouseBindingsString() to update the help window binding tabs.<br>";
  text += "See those tabs for the complete current bindings.<br>";
  text += "By the way, exit shortcut has been binded to <b>CTRL+Q</b>";
  return text;
}

// Add specific custom bindings to help window tabs
QString Viewer::mouseBindingsString() const
{
  QString text("The right mouse button opens a popup menu that displays the defined camera positions and paths.<br><br>");
  text += "The other mouse bindings are :<br>";
  text += QGLViewer::mouseBindingsString();
  return text;
}

QString Viewer::shortcutBindingsString() const
{
  QString text("Press '<b>W</b> to toggle wire frame display<br>");
  text += "Press '<b>F</b> to toggle flat shading display<br><br>";
  text += "The other standard actions are binded to:<br>";
  text += QGLViewer::shortcutBindingsString();
  return text;
}

main.cpp


#include "keyboardAndMouse.h"
#include <qapplication.h>

int main(int argc, char** argv)
{
  // Read command lines arguments.
  QApplication application(argc,argv);

  // Instantiate the viewer.
  Viewer v;

  // Make the viewer window visible on screen.
  v.show();

  // Set the viewer as the application main widget.
  application.setMainWidget(&v);

  // Run main loop.
  return application.exec();
}

Go back to the examples main page

Valid XHTML 1.0! Valid CSS! Last modified on Thursday, February 5, 2004.