X-Git-Url: http://pileus.org/git/?p=grits;a=blobdiff_plain;f=src%2Fobjects%2Fgrits-object.c;h=2812b9e3d647e72a9919b77936e3e4849237b367;hp=6abc4eb26f3ba70b3ff25a945f2af5918cd38d44;hb=d55c77bbf477e582a8525ac831ad97b035b8185d;hpb=1d0635977583ad84faaa1978f1fd78fa3ec83052 diff --git a/src/objects/grits-object.c b/src/objects/grits-object.c index 6abc4eb..2812b9e 100644 --- a/src/objects/grits-object.c +++ b/src/objects/grits-object.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 Andy Spencer + * Copyright (C) 2009-2011 Andy Spencer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,14 +30,21 @@ #include #include -#include +#include "gtkgl.h" #include "grits-object.h" +#include "grits-marshal.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]; @@ -45,6 +52,7 @@ static guint signals[NUM_SIGNALS]; void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pick) { GritsObjectClass *klass = GRITS_OBJECT_GET_CLASS(object); + if (!klass->draw) { g_warning("GritsObject: draw - Unimplemented"); return; @@ -54,6 +62,14 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi if (object->hidden) return; + /* Skip object with no signals when picking */ + for (int i = 0; pick; i++) { + if (i == NUM_SIGNALS) + return; + if (g_signal_has_handler_pending(object, signals[i], 0, FALSE)) + break; + } + /* Support GritsTester */ if (!GRITS_IS_OPENGL(opengl)) { g_debug("GritsObject: draw - drawing raw object"); @@ -61,7 +77,7 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi return; } - /* Calculae distance for LOD and horizon tests */ + /* Calculate distance for LOD and horizon tests */ GritsPoint *center = &object->center; if ((!(object->skip & GRITS_SKIP_LOD) || !(object->skip & GRITS_SKIP_HORIZON)) && @@ -95,7 +111,7 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi } /* Save state, draw, restore state */ - g_mutex_lock(opengl->sphere_lock); + g_mutex_lock(&opengl->sphere_lock); if (!(object->skip & GRITS_SKIP_STATE)) { glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -118,7 +134,7 @@ void grits_object_pickdraw(GritsObject *object, GritsOpenGL *opengl, gboolean pi glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } - g_mutex_unlock(opengl->sphere_lock); + g_mutex_unlock(&opengl->sphere_lock); } /** @@ -147,42 +163,72 @@ void grits_object_hide(GritsObject *object, gboolean hidden) void grits_object_queue_draw(GritsObject *object) { if (object->viewer) - gtk_widget_queue_draw(GTK_WIDGET(object->viewer)); + grits_viewer_queue_draw(object->viewer); } -/* Event handling */ -void grits_object_pick_begin(GritsObject *object, GritsOpenGL *opengl) +void grits_object_set_cursor(GritsObject *object, GdkCursorType cursor) { - 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; - } - } + // Used by grits OpenGL + object->cursor = gdk_cursor_new(cursor); } -void grits_object_pick_pointer(GritsObject *object, double x, double y) +/* Event handling */ +void grits_object_pick(GritsObject *object, GritsOpenGL *opengl) { - object->state.picked = TRUE; + grits_object_pickdraw(object, opengl, TRUE); } -void grits_object_pick_end(GritsObject *object) +gboolean grits_object_set_pointer(GritsObject *object, GdkEvent *event, gboolean selected) { - if (object->state.picked) { + gboolean rval = FALSE; + if (selected) { if (!object->state.selected) - g_signal_emit(object, signals[SIG_ENTER], 0); + g_signal_emit(object, signals[SIG_ENTER], 0, event, &rval); object->state.selected = TRUE; } else { if (object->state.selected) - g_signal_emit(object, signals[SIG_LEAVE], 0); + g_signal_emit(object, signals[SIG_LEAVE], 0, event, &rval); object->state.selected = FALSE; } + return rval; +} + +gboolean 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 FALSE; + guint sig = map[event->type]; + gboolean rval = FALSE; + + /* Handle button click */ + if (sig == SIG_BUTTON_PRESS) + object->state.clicking = GRITS_CLICK_THRESHOLD; + if (sig == SIG_MOTION && object->state.clicking) + object->state.clicking -= 1; + if (sig == SIG_BUTTON_RELEASE && object->state.clicking) + g_signal_emit(object, signals[SIG_CLICKED], 0, event, &rval); + if (sig == SIG_BUTTON_RELEASE) + object->state.clicking = 0; + + /* Emit this signal */ + if (rval == FALSE) { + if (!g_signal_has_handler_pending(object, signals[sig], 0, FALSE)) + return FALSE; + g_signal_emit(object, signals[sig], 0, event, &rval); + } + + if (rval == TRUE) + g_debug("GritsObject: breaking chained event"); + return rval; } /* GObject stuff */ @@ -211,9 +257,10 @@ static void grits_object_class_init(GritsObjectClass *klass) 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 1, + G_TYPE_POINTER); /** * GritsViewer::leave: @@ -229,7 +276,123 @@ static void grits_object_class_init(GritsObjectClass *klass) 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 1, + G_TYPE_POINTER); + + /** + * 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, + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 1, + G_TYPE_POINTER); + + /** + * 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, + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 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, + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 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, + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 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, + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 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, + grits_cclosure_marshal_BOOLEAN__POINTER, + G_TYPE_BOOLEAN, + 1, + G_TYPE_POINTER); }