X-Git-Url: http://pileus.org/git/?p=grits;a=blobdiff_plain;f=src%2Fobjects%2Fgrits-object.c;h=65d7b420aae2e44e55e6585b327a385d104a273f;hp=b321b6e994493a3ff71e1abb732870f7cf5256d7;hb=7940344c1faea5b80fb39b44419b508568d3a6fc;hpb=3ea7566fadf5490c46e04cb3a2a6cc8e02ac05e6 diff --git a/src/objects/grits-object.c b/src/objects/grits-object.c index b321b6e..65d7b42 100644 --- a/src/objects/grits-object.c +++ b/src/objects/grits-object.c @@ -34,18 +34,21 @@ #include "grits-object.h" +/* Constants */ +enum { + SIG_ENTER, + SIG_LEAVE, + SIG_CLICKED, + SIG_BUTTON_PRESS, + SIG_BUTTON_RELEASE, + SIG_KEY_PRESS, + SIG_KEY_RELEASE, + SIG_MOTION, + NUM_SIGNALS, +}; +static guint signals[NUM_SIGNALS]; -/** - * grits_object_draw: - * @object: the object - * @opengl: the viewer the object is being displayed in - * - * Perform any OpenGL commands necessasairy to draw the object. - * - * The GL_PROJECTION and GL_MODELVIEW matricies and GL_ALL_ATTRIB_BITS will be - * restored to the default state after the call to draw. - */ -void grits_object_draw(GritsObject *object, GritsOpenGL *opengl) +void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick) { GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object); if (!klass->draw) { @@ -111,7 +114,10 @@ void grits_object_draw(GritsObject *object, GritsOpenGL *opengl) object->center.lon, object->center.elev); - klass->draw(object, opengl); + if (pick && klass->pick) + klass->pick(object, opengl); + else + klass->draw(object, opengl); if (!(object->skip & GRITS_SKIP_STATE)) { glPopAttrib(); @@ -121,12 +127,99 @@ void grits_object_draw(GritsObject *object, GritsOpenGL *opengl) g_mutex_unlock(opengl->sphere_lock); } +/** + * grits_object_draw: + * @object: the object + * @opengl: the viewer the object is being displayed in + * + * Perform any OpenGL commands necessasairy to draw the object. + * + * The GL_PROJECTION and GL_MODELVIEW matricies and GL_ALL_ATTRIB_BITS will be + * restored to the default state after the call to draw. + */ +void grits_object_draw(GritsObject *object, GritsOpenGL *opengl) +{ + grits_object_pickdraw(object, opengl, FALSE); +} + +void grits_object_hide(GritsObject *object, gboolean hidden) +{ + GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object); + object->hidden = hidden; + if (klass->hide) + klass->hide(object, hidden); +} + void grits_object_queue_draw(GritsObject *object) { if (object->viewer) gtk_widget_queue_draw(GTK_WIDGET(object->viewer)); } +/* Event handling */ +void grits_object_pick_begin(GritsObject *object, GritsOpenGL *opengl) +{ + object->state.picked = FALSE; + + /* Check for connected signals */ + for (int i = 0; i < NUM_SIGNALS; i++) { + if (g_signal_has_handler_pending(object, signals[i], 0, FALSE)) { + /* Someone is watching, render the object _once_ */ + glPushName((guint)object); + grits_object_pickdraw(object, opengl, TRUE); + glPopName(); + return; + } + } +} + +void grits_object_pick_pointer(GritsObject *object, double x, double y) +{ + object->state.picked = TRUE; +} + +void grits_object_pick_end(GritsObject *object) +{ + if (object->state.picked) { + if (!object->state.selected) + g_signal_emit(object, signals[SIG_ENTER], 0); + object->state.selected = TRUE; + } else { + if (object->state.selected) + g_signal_emit(object, signals[SIG_LEAVE], 0); + object->state.selected = FALSE; + } +} + +void grits_object_event(GritsObject *object, GdkEvent *event) +{ + const int map[GDK_EVENT_LAST] = { + [GDK_BUTTON_PRESS ] SIG_BUTTON_PRESS, + [GDK_2BUTTON_PRESS ] SIG_BUTTON_PRESS, + [GDK_3BUTTON_PRESS ] SIG_BUTTON_PRESS, + [GDK_BUTTON_RELEASE] SIG_BUTTON_RELEASE, + [GDK_KEY_PRESS ] SIG_KEY_PRESS, + [GDK_KEY_RELEASE ] SIG_KEY_RELEASE, + [GDK_MOTION_NOTIFY ] SIG_MOTION, + }; + if (!object->state.selected) + return; + guint sig = map[event->type]; + + /* Handle button click */ + if (sig == SIG_BUTTON_PRESS) + object->state.clicking = TRUE; + if (sig == SIG_BUTTON_RELEASE && object->state.clicking) + g_signal_emit(object, signals[SIG_CLICKED], 0, event); + if (sig == SIG_BUTTON_RELEASE || sig == SIG_MOTION) + object->state.clicking = FALSE; + + /* Emit this signal */ + if (!g_signal_has_handler_pending(object, signals[sig], 0, FALSE)) + return; + g_signal_emit(object, signals[sig], 0, event); +} + /* GObject stuff */ G_DEFINE_ABSTRACT_TYPE(GritsObject, grits_object, G_TYPE_OBJECT); static void grits_object_init(GritsObject *object) @@ -138,4 +231,154 @@ static void grits_object_init(GritsObject *object) static void grits_object_class_init(GritsObjectClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + /** + * GritsObject::enter: + * @object: the object. + * + * The ::enter signal is emitted when the pointer moves over the object + */ + signals[SIG_ENTER] = g_signal_new( + "enter", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * GritsViewer::leave: + * @object: the object. + * + * The ::leave signal is emitted when the pointer moves away from the + * object + */ + signals[SIG_LEAVE] = g_signal_new( + "leave", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * GritsViewer::clicked: + * @object: the object. + * + * The ::clicked signal is emitted when the user clicks on the object + */ + signals[SIG_CLICKED] = g_signal_new( + "clicked", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * GritsViewer::button-press: + * @object: the object. + * @event: the GdkEventButton which triggered this signal + * + * The ::button-press signal is emitted when a button (typically from a + * mouse) is pressed. + */ + signals[SIG_BUTTON_PRESS] = g_signal_new( + "button-press", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::button-release: + * @object: the object. + * @event: the GdkEventButton which triggered this signal + * + * The ::button-release signal is emitted when a button (typically from + * a mouse) is released. + */ + signals[SIG_BUTTON_RELEASE] = g_signal_new( + "button-release", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::key-press: + * @object: the object. + * @event: the GdkEventKey which triggered this signal + * + * The ::key-press signal is emitted when a key is pressed. + */ + signals[SIG_KEY_PRESS] = g_signal_new( + "key-press", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::key-release: + * @object: the object. + * @event: the GdkEventKey which triggered this signal + * + * The ::key-release signal is emitted when a key is released. + */ + signals[SIG_KEY_RELEASE] = g_signal_new( + "key-release", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + /** + * GritsViewer::motion: + * @object: the object. + * @event: the GdkEventMotion which triggered this signal + * + * The ::motion signal is emitted the pointer moves over the object + */ + signals[SIG_MOTION] = g_signal_new( + "motion", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); }