osgGtk logo

osgviewerGtkmm/osgviewerGtkmm.cpp

This example illustrates how to use ViewerGtkmm and GraphicsWindowGtkmm to display an OSG scenegraph in a Gtk-- application. Additionally, this example incorporates several Gtk-- widgets to demonstrate several aspects of ViewerGtkmm control as well as how to connect your own functions to GraphicsWindowGtkmm mouse events.

/***************************************************************************
 *   Copyright (C) 2003 by Rick L. Vinyard, Jr.                            *
 *   rvinyard@cs.nmsu.edu                                                  *
 *                                                                         *
 *   This file is part of the osgGtk library.                              *
 *                                                                         *
 *   The osgGtk library is free software; you can redistribute it and/or   *
 *   modify it under the terms of the GNU General Public License           *
 *   version 3 as published by the Free Software Foundation.               *
 *                                                                         *
 *   The osgGtk library is distributed in the hope that it will be         *
 *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty   *
 *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   *
 *   General Public License for more details.                              *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this software. If not see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/

// Of course, we need the gtkmm headers
#include <gtkmm.h>

// We'll need this to load the command line argument
// as well as the handling the file load button
#include <osgDB/ReadFile>

#include <osgGA/TrackballManipulator>

// And we'll need this for the Gtkmm OSG viewer
#include <osgGtkmm/ViewerGtkmm.h>

const char* HELP_TEXT =
    "<b><i>Right-click</i></b> while holding <b><i>CTRL</i></b> <u>or</u> <b><i>SHIFT</i></b> to pop up a fake Gtkmm menu.\n"
    "\n"
    "Use the standard OSG TrackballManipulator keys and mouse actions to\n"
    "rotate, zoom and move the loaded model.\n"
    "\n"
    "<i>Note:\n"
    "<small>\tIf the viewer is stopped, user actions won't be processed until the viewer is restarted.\n"
    "\tIn this example events are only processed when the viewer is running.</small></i>\n"
;

// This is global so that the callbacks can see it as well
// Alternatively, we could use sigc::bind, but making this
// global simplifies the example.
osgViewer::ViewerGtkmm* viewer = NULL;

// This is also global so the callback function can check to see the
// state of the toggle button
Gtk::ToggleButton* fps_button;

// Callback to handle mouse button events
// This is what will look for right-clicks and pop up the menu
bool on_button_event(GdkEventButton* event);

// Callback that loads a selected scene as the root node of the scenegraph
void on_open_file_clicked();

// Callback that runs the viewer a specific number of frames
void on_run_frames_button_clicked();

// Callback that starts/stops the viewer
void on_fps_toggled();

int main( int argc, char** argv )
{
  // We'll set a basic size of 800x600, but the user can resize larger if desired (but not smaller)
  int width=800, height=600;

  // This is some gtkmm housekeeping... we need the main loop and we also need to initialize the OpenGL system
  Gtk::Main gtkmm_main( argc, argv );
  Gtk::GL::init( argc, argv );

  // Now, let's create our viewer using ViewerGtkmm so we can use the gtkmm convenience method later
  //
  // We'll also set desired frame rate of 60 fps and load the first command line
  // argument as the scene
  viewer = new osgViewer::ViewerGtkmm();
  viewer->setCameraManipulator(new osgGA::TrackballManipulator);
  viewer->set_fps(60);

  if ( argc >= 2 ) {
    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile(argv[1]);
    if ( model.valid() ) viewer->setSceneData(model.get());
  }

  // Now we'll setup the viewer in a gtkmm window using the setup_viewer_in_gtkmm_window()
  // convenience method
  //
  // The return type is a Gtkmm widget (subclassed from Gtk::DrawingArea) that we can
  // use anywhere we want
  osgViewer::GraphicsWindowGtkmm* gw = viewer->setup_viewer_in_gtkmm_window(width, height);

  // All Gtk apps need a toplevel window
  //
  // We'll also set the title, add our widget created by the viewer and make sure it's visible
  Gtk::Window window(Gtk::WINDOW_TOPLEVEL);
  window.set_title("osgviewerGtkmm");

  // Almost all of this is just gtkmm code... creating the various
  // layouts and other UI widgets
  Gtk::VBox main_vbox;
  Gtk::HBox bottom_hbox;
  Gtk::VBox button_vbox;
  Gtk::Label help_text(HELP_TEXT);
  Gtk::Button file_button("Open File");
  Gtk::Button run_frames_button("Run 120 frames");
  Gtk::Button close_button("Close");

  fps_button = Gtk::manage(new Gtk::ToggleButton());

  window.add(main_vbox);
  main_vbox.pack_start(*gw);
  main_vbox.pack_start(bottom_hbox);
  bottom_hbox.pack_start(button_vbox);
  help_text.set_use_markup();
  bottom_hbox.pack_start(help_text);
  button_vbox.pack_start(file_button);
  button_vbox.pack_start(run_frames_button);
  button_vbox.pack_start(*fps_button);
  button_vbox.pack_start(close_button);
  window.show_all();

  // Even though we won't do anything except popup the menu on button release
  // we still need to handle the case where the button is pressed with the
  // shift or control key. Otherwise the button press will be passed on to
  // the gtk handler.
  gw->signal_button_press_event().connect(&on_button_event);
  gw->signal_button_release_event().connect(&on_button_event);
  
  // Let's connect the other Gtk buttons to their callbacks
  file_button.signal_clicked().connect(&on_open_file_clicked);
  run_frames_button.signal_clicked().connect(&on_run_frames_button_clicked);
  fps_button->signal_toggled().connect(&on_fps_toggled);
  close_button.signal_clicked().connect(&Gtk::Main::quit);

  // And, just before we kick things off, let's start the viewer running
  // by setting the fps button to active, allowing the connected callback
  // to start things off.
  fps_button->set_active(true);
  
  // This is boilerplate for all gtkmm apps... start the gtkmm main loop
  Gtk::Main::run(window);

  // If we got here, gtkmm exited it's main loop, so we'll exit cleanly
  return 0;
}

// This function is called every time there is a button press or button
// release event that occurs in the OSG graphics window
//
// Even though it is only the button release that we're concerned with,
// we still handle the button press event since anything that we don't
// handle is passed along to OSG. We don't want button press events
// to be passed into OSG when the user is holding down the shift
// key or the control key, so we stop that by returning true
// when either key is held down and the right mouse button is clicked.
bool on_button_event(GdkEventButton* event)
{
  if ( event->button == 3 and ( event->state & GDK_SHIFT_MASK or event->state & GDK_CONTROL_MASK ) )
  {
    // We get here if it's either a button press or release, but we'll
    // only pop up the menu on a release
    if ( event->type == GDK_BUTTON_RELEASE )
    {
      Gtk::Menu* menu = Gtk::manage(new Gtk::Menu());
      menu->append(*Gtk::manage(new Gtk::MenuItem("Option")));
      menu->append(*Gtk::manage(new Gtk::MenuItem("Another Option")));
      menu->append(*Gtk::manage(new Gtk::MenuItem("Still More Options")));
      menu->show_all();
      menu->popup(event->button, event->time);
    }

    // Whether it's press or release, if it's a right mouse event with
    // control or shift held down we return true, stopping it from
    // going on to OSG
    //
    // If we wanted to handled it _and_ let it pass into OSG we
    // could simply return false here.
    return true;
  }

  // But, since this was something other than a right mouse event with
  // a ctrl/shift key pressed, we'll just let it pass into OSG
  return false;
}

void on_open_file_clicked()
{
  Gtk::FileChooserDialog fc("Please select an OSG file to load...",
                            Gtk::FILE_CHOOSER_ACTION_OPEN);

  fc.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  fc.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
  
  if ( fc.run() == Gtk::RESPONSE_ACCEPT )
  {
    Glib::ustring file = fc.get_filename();
    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile(file);
    if ( model.valid() )
      viewer->setSceneData(model.get());
  }
}

void on_run_frames_button_clicked()
{
  fps_button->set_active(false);
  if ( viewer ) viewer->run_frames(120);
}

void on_fps_toggled()
{
  if ( fps_button->get_active() )
  {
    if ( viewer ) viewer->run();
    fps_button->set_label("Click to stop");
  }
  else
  {
    if ( viewer ) viewer->stop();
    fps_button->set_label("Click to run at 60fps");
  }
}

Generated on Thu Mar 19 10:06:41 2009 for osgGtk by doxygen 1.5.7.1