diff options
Diffstat (limited to 'eel/eel-image-table.c')
-rw-r--r-- | eel/eel-image-table.c | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/eel/eel-image-table.c b/eel/eel-image-table.c new file mode 100644 index 00000000..25f67a0a --- /dev/null +++ b/eel/eel-image-table.c @@ -0,0 +1,601 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* eel-image-table.c - An image table. + + Copyright (C) 2000 Eazel, Inc. + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Ramiro Estrugo <[email protected]> +*/ + +#include <config.h> +#include "eel-image-table.h" + +#include "eel-art-extensions.h" +#include "eel-art-gtk-extensions.h" +#include "eel-debug-drawing.h" +#include "eel-gtk-extensions.h" +#include "eel-gtk-macros.h" +#include "eel-labeled-image.h" +#include "eel-marshal.h" +#include <gtk/gtk.h> + +/* Arguments */ +enum +{ + ARG_0, + ARG_CHILD_UNDER_POINTER +}; + +/* Detail member struct */ +struct EelImageTableDetails +{ + GtkWidget *child_under_pointer; + GtkWidget *child_being_pressed; + GdkGC *clear_gc; +}; + +/* Signals */ +typedef enum +{ + CHILD_ENTER, + CHILD_LEAVE, + CHILD_PRESSED, + CHILD_RELEASED, + CHILD_CLICKED, + LAST_SIGNAL +} ImageTableSignals; + +/* Signals */ +static guint image_table_signals[LAST_SIGNAL] = { 0 }; + +static void eel_image_table_class_init (EelImageTableClass *image_table_class); +static void eel_image_table_init (EelImageTable *image); + +/* GObjectClass methods */ +static void eel_image_table_finalize (GObject *object); + +/* GtkWidgetClass methods */ +static void eel_image_table_realize (GtkWidget *widget); +static void eel_image_table_unrealize (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void eel_image_table_remove (GtkContainer *container, + GtkWidget *widget); +static GType eel_image_table_child_type (GtkContainer *container); + +/* Private EelImageTable methods */ +static void image_table_emit_signal (EelImageTable *image_table, + GtkWidget *child, + guint signal_index, + int x, + int y, + int button, + guint state, + GdkEvent *event); + +/* Ancestor callbacks */ +static int ancestor_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data); +static int ancestor_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data); +static int ancestor_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer event_data); +static int ancestor_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data); +static int ancestor_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data); + +EEL_CLASS_BOILERPLATE (EelImageTable, eel_image_table, EEL_TYPE_WRAP_TABLE) + +static void +eel_image_table_class_init (EelImageTableClass *image_table_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (image_table_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (image_table_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (image_table_class); + + /* GObjectClass */ + object_class->finalize = eel_image_table_finalize; + + /* GtkWidgetClass */ + widget_class->realize = eel_image_table_realize; + widget_class->unrealize = eel_image_table_unrealize; + + /* GtkContainerClass */ + container_class->remove = eel_image_table_remove; + container_class->child_type = eel_image_table_child_type; + + /* Signals */ + image_table_signals[CHILD_ENTER] = g_signal_new ("child_enter", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_enter), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_LEAVE] = g_signal_new ("child_leave", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_leave), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_PRESSED] = g_signal_new ("child_pressed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_pressed), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_RELEASED] = g_signal_new ("child_released", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_released), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); + image_table_signals[CHILD_CLICKED] = g_signal_new ("child_clicked", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EelImageTableClass, child_clicked), + NULL, NULL, + eel_marshal_VOID__OBJECT_POINTER, + G_TYPE_NONE, + 2, + GTK_TYPE_WIDGET, + G_TYPE_POINTER); +} + +static void +eel_image_table_init (EelImageTable *image_table) +{ + gtk_widget_set_has_window (GTK_WIDGET (image_table), FALSE); + + image_table->details = g_new0 (EelImageTableDetails, 1); +} + +/* GObjectClass methods */ +static void +eel_image_table_finalize (GObject *object) +{ + EelImageTable *image_table; + + image_table = EEL_IMAGE_TABLE (object); + + g_free (image_table->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +eel_image_table_realize (GtkWidget *widget) +{ + GtkWidget *windowed_ancestor; + + g_assert (EEL_IS_IMAGE_TABLE (widget)); + + /* Chain realize */ + EEL_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget)); + + windowed_ancestor = eel_gtk_widget_find_windowed_ancestor (widget); + g_assert (GTK_IS_WIDGET (windowed_ancestor)); + + gtk_widget_add_events (windowed_ancestor, + GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_BUTTON_MOTION_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_POINTER_MOTION_MASK); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "enter_notify_event", + G_CALLBACK (ancestor_enter_notify_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "leave_notify_event", + G_CALLBACK (ancestor_leave_notify_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "motion_notify_event", + G_CALLBACK (ancestor_motion_notify_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "button_press_event", + G_CALLBACK (ancestor_button_press_event), + widget, + widget); + + eel_gtk_signal_connect_while_realized (GTK_OBJECT (windowed_ancestor), + "button_release_event", + G_CALLBACK (ancestor_button_release_event), + widget, + widget); +} + +static void +eel_image_table_unrealize (GtkWidget *widget) +{ + EelImageTable *image_table; + + g_assert (EEL_IS_IMAGE_TABLE (widget)); + + image_table = EEL_IMAGE_TABLE (widget); + + if (image_table->details->clear_gc != NULL) + { + g_object_unref (image_table->details->clear_gc); + image_table->details->clear_gc = NULL; + } + + /* Chain unrealize */ + EEL_CALL_PARENT (GTK_WIDGET_CLASS, unrealize, (widget)); +} + +/* GtkContainerClass methods */ +static void +eel_image_table_remove (GtkContainer *container, + GtkWidget *child) +{ + EelImageTable *image_table; + + g_assert (EEL_IS_IMAGE_TABLE (container)); + g_assert (EEL_IS_LABELED_IMAGE (child)); + + image_table = EEL_IMAGE_TABLE (container); + + if (child == image_table->details->child_under_pointer) + { + image_table->details->child_under_pointer = NULL; + } + + if (child == image_table->details->child_being_pressed) + { + image_table->details->child_being_pressed = NULL; + } + + EEL_CALL_PARENT (GTK_CONTAINER_CLASS, remove, (container, child)); +} + +static GType +eel_image_table_child_type (GtkContainer *container) +{ + return EEL_TYPE_LABELED_IMAGE; +} + +/* Private EelImageTable methods */ + +static void +image_table_emit_signal (EelImageTable *image_table, + GtkWidget *child, + guint signal_index, + int x, + int y, + int button, + guint state, + GdkEvent *gdk_event) +{ + EelImageTableEvent event; + + g_assert (EEL_IS_IMAGE_TABLE (image_table)); + g_assert (GTK_IS_WIDGET (child)); + g_assert (signal_index < LAST_SIGNAL); + + event.x = x; + event.y = y; + event.button = button; + event.state = state; + event.event = gdk_event; + + g_signal_emit (image_table, + image_table_signals[signal_index], + 0, + child, + &event); +} + +static void +image_table_handle_motion (EelImageTable *image_table, + int x, + int y, + GdkEvent *event) +{ + GtkWidget *child; + GtkWidget *leave_emit_child = NULL; + GtkWidget *enter_emit_child = NULL; + + g_assert (EEL_IS_IMAGE_TABLE (image_table)); + + child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), x, y); + + if (child && !gtk_widget_get_sensitive (child)) + { + return; + } + + if (child == image_table->details->child_under_pointer) + { + return; + } + + if (child != NULL) + { + if (image_table->details->child_under_pointer != NULL) + { + leave_emit_child = image_table->details->child_under_pointer; + } + + image_table->details->child_under_pointer = child; + enter_emit_child = image_table->details->child_under_pointer; + } + else + { + if (image_table->details->child_under_pointer != NULL) + { + leave_emit_child = image_table->details->child_under_pointer; + } + + image_table->details->child_under_pointer = NULL; + } + + if (leave_emit_child != NULL) + { + image_table_emit_signal (image_table, + leave_emit_child, + CHILD_LEAVE, + x, + y, + 0, + 0, + (GdkEvent *)event); + } + + if (enter_emit_child != NULL) + { + image_table_emit_signal (image_table, + enter_emit_child, + CHILD_ENTER, + x, + y, + 0, + 0, + (GdkEvent *)event); + } +} + +static int +ancestor_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data) +{ + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table_handle_motion (EEL_IMAGE_TABLE (event_data), event->x, event->y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data) +{ + EelIRect bounds; + int x = -1; + int y = -1; + + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (event_data)); + + if (eel_irect_contains_point (bounds, event->x, event->y)) + { + x = event->x; + y = event->y; + } + + image_table_handle_motion (EEL_IMAGE_TABLE (event_data), x, y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer event_data) +{ + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table_handle_motion (EEL_IMAGE_TABLE (event_data), (int) event->x, (int) event->y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data) +{ + EelImageTable *image_table; + GtkWidget *child; + + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table = EEL_IMAGE_TABLE (event_data); + + child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), event->x, event->y); + + if (child && !gtk_widget_get_sensitive (child)) + { + return FALSE; + } + + if (child != NULL) + { + if (child == image_table->details->child_under_pointer) + { + image_table->details->child_being_pressed = child; + image_table_emit_signal (image_table, + child, + CHILD_PRESSED, + event->x, + event->y, + event->button, + event->state, + (GdkEvent *)event); + } + } + + return FALSE; +} + +static int +ancestor_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data) +{ + EelImageTable *image_table; + GtkWidget *child; + GtkWidget *released_emit_child = NULL; + GtkWidget *clicked_emit_child = NULL; + + g_assert (GTK_IS_WIDGET (widget)); + g_assert (EEL_IS_IMAGE_TABLE (event_data)); + g_assert (event != NULL); + + image_table = EEL_IMAGE_TABLE (event_data); + + child = eel_wrap_table_find_child_at_event_point (EEL_WRAP_TABLE (image_table), event->x, event->y); + + if (child && !gtk_widget_get_sensitive (child)) + { + return FALSE; + } + + if (image_table->details->child_being_pressed != NULL) + { + released_emit_child = image_table->details->child_being_pressed; + } + + if (child != NULL) + { + if (child == image_table->details->child_being_pressed) + { + clicked_emit_child = child; + } + } + + image_table->details->child_being_pressed = NULL; + + if (released_emit_child != NULL) + { + image_table_emit_signal (image_table, + released_emit_child, + CHILD_RELEASED, + event->x, + event->y, + event->button, + event->state, + (GdkEvent *)event); + } + + if (clicked_emit_child != NULL) + { + + image_table_emit_signal (image_table, + clicked_emit_child, + CHILD_CLICKED, + event->x, + event->y, + event->button, + event->state, + (GdkEvent *)event); + } + + return FALSE; +} + +/** + * eel_image_table_new: + */ +GtkWidget* +eel_image_table_new (gboolean homogeneous) +{ + EelImageTable *image_table; + + image_table = EEL_IMAGE_TABLE (gtk_widget_new (eel_image_table_get_type (), NULL)); + + eel_wrap_table_set_homogeneous (EEL_WRAP_TABLE (image_table), homogeneous); + + return GTK_WIDGET (image_table); +} + +/** + * eel_image_table_add_empty_child: + * @image_table: A EelImageTable. + * + * Add a "empty" child to the table. Useful when you want to have + * empty space between 2 children. + * + * Returns: The empty child - A EelLabeledImage widget with no label + * or pixbuf. + */ +GtkWidget * +eel_image_table_add_empty_image (EelImageTable *image_table) +{ + GtkWidget *empty; + + g_return_val_if_fail (EEL_IS_IMAGE_TABLE (image_table), NULL); + + empty = eel_labeled_image_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (image_table), empty); + gtk_widget_set_sensitive (empty, FALSE); + + return empty; +} |