OpenSceneGraph/examples/osgviewerGTK/osggtkdrawingarea.h
2018-04-23 11:03:37 +01:00

208 lines
5.8 KiB
C++

#include <gtk/gtk.h>
#include <gtk/gtkgl.h>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
// This is an implementation of SimpleViewer that is designed to be subclassed
// and used as a GtkDrawingArea in a GTK application. Because of the implementation
// of GTK, I was unable to derive from GtkWidget and instead had to "wrap" it.
// Conceptually, however, you can think of an OSGGTKDrawingArea as both an OSG
// Viewer AND GtkDrawingArea.
//
// While it is possible to use this class directly, it won't end up doing anything
// interesting without calls to queueDraw, which ideally are done in the user's
// subclass implementation (see: osgviewerGTK).
class OSGGTKDrawingArea : public osgViewer::Viewer {
GtkWidget* _widget;
GdkGLConfig* _glconfig;
GdkGLContext* _context;
GdkGLDrawable* _drawable;
osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> _gw;
unsigned int _state;
osgGA::EventQueue& _queue;
static OSGGTKDrawingArea* _self(gpointer self) {
return static_cast<OSGGTKDrawingArea*>(self);
}
// A simple helper function to connect us to the various GTK signals.
void _connect(const char* name, GCallback callback) {
g_signal_connect(G_OBJECT(_widget), name, callback, this);
}
void _realize (GtkWidget*);
void _unrealize (GtkWidget*);
bool _expose_event (GtkWidget*, GdkEventExpose*);
bool _configure_event (GtkWidget*, GdkEventConfigure*);
bool _motion_notify_event (GtkWidget*, GdkEventMotion*);
bool _button_press_event (GtkWidget*, GdkEventButton*);
bool _key_press_event (GtkWidget*, GdkEventKey*);
// The following functions are static "wrappers" so that we can invoke the
// bound methods of a class instance by passing the "this" pointer as the
// self argument and invoking it explicitly.
static void _srealize(GtkWidget* widget, gpointer self) {
_self(self)->_realize(widget);
}
static void _sunrealize(GtkWidget* widget, gpointer self) {
_self(self)->_unrealize(widget);
}
static bool _sexpose_event(GtkWidget* widget, GdkEventExpose* expose, gpointer self) {
return _self(self)->_expose_event(widget, expose);
}
static bool _sconfigure_event(
GtkWidget* widget,
GdkEventConfigure* event,
gpointer self
) {
return _self(self)->_configure_event(widget, event);
}
static bool _smotion_notify_event(
GtkWidget* widget,
GdkEventMotion* event,
gpointer self
) {
return _self(self)->_motion_notify_event(widget, event);
}
static bool _sbutton_press_event(
GtkWidget* widget,
GdkEventButton* event,
gpointer self
) {
return _self(self)->_button_press_event(widget, event);
}
static bool _skey_press_event(
GtkWidget* widget,
GdkEventKey* event,
gpointer self
) {
return _self(self)->_key_press_event(widget, event);
}
protected:
// You can override these in your subclass if you'd like. :)
// Right now they're fairly uninformative, but they could be easily extended.
// Note that the "state" information isn't passed around to each function
// but is instead stored and abstracted internally. See below.
virtual void gtkRealize () {};
virtual void gtkUnrealize () {};
virtual bool gtkExpose () {
return true;
};
// The new width and height.
virtual bool gtkConfigure(int, int) {
return true;
};
// The "normalized" coordinates of the mouse.
virtual bool gtkMotionNotify(double, double) {
return true;
};
// The "normalized" coordinates of the mouse and the mouse button code on down.
virtual bool gtkButtonPress(double, double, unsigned int) {
return true;
};
// The "normalized" coordinates of the mouse and mouse button code on release.
virtual bool gtkButtonRelease(double, double, unsigned int) {
return true;
}
// The X key value on down.
virtual bool gtkKeyPress(unsigned int) {
return true;
};
// The X key value on release.
virtual bool gtkKeyRelease(unsigned int) {
return true;
};
// These functions wrap state tests of the most recent state in the
// GtkDrawingArea.
inline bool stateShift() {
return _state & GDK_SHIFT_MASK;
}
inline bool stateLock() {
return _state & GDK_LOCK_MASK;
}
inline bool stateControl() {
return _state & GDK_CONTROL_MASK;
}
inline bool stateMod() {
return _state & (
GDK_MOD1_MASK |
GDK_MOD2_MASK |
GDK_MOD3_MASK |
GDK_MOD4_MASK |
GDK_MOD5_MASK
);
}
inline bool stateButton() {
return _state & (
GDK_BUTTON1_MASK |
GDK_BUTTON2_MASK |
GDK_BUTTON3_MASK |
GDK_BUTTON4_MASK |
GDK_BUTTON5_MASK
);
}
public:
OSGGTKDrawingArea ();
~OSGGTKDrawingArea ();
bool createWidget(int, int);
GtkWidget* getWidget() {
return _widget;
}
bool gtkGLBegin() {
if(_drawable and _context) return gdk_gl_drawable_gl_begin(_drawable, _context);
else return false;
}
void gtkGLEnd() {
if(_drawable) gdk_gl_drawable_gl_end(_drawable);
}
// Because of GTK's internal double buffering, I'm not sure if we're really
// taking advantage of OpenGL's internal swapping.
bool gtkGLSwap() {
if(_drawable and gdk_gl_drawable_is_double_buffered(_drawable)) {
gdk_gl_drawable_swap_buffers(_drawable);
return true;
}
else {
glFlush();
return false;
}
}
void queueDraw() {
gtk_widget_queue_draw(_widget);
}
};