diff options
author | Ramiro Estrugo <ramiro@src.gnome.org> | 2001-02-08 07:02:39 +0000 |
---|---|---|
committer | Ramiro Estrugo <ramiro@src.gnome.org> | 2001-02-08 07:02:39 +0000 |
commit | 6767f2921b8965d0a34314a42be3e905f6561756 (patch) | |
tree | b009863187c62631a289e9af76fc49a7769e38bc | |
parent | b99145c84e6328d5f8060500474ab416caf9ed6d (diff) | |
download | nautilus-6767f2921b8965d0a34314a42be3e905f6561756.tar.gz |
reviewed by: Mike Fleming <mfleming@eazel.com>
Minus the 2 new widgets.
* libnautilus-extensions/Makefile.am:
New files.
* libnautilus-extensions/nautilus-labeled-image.h:
* libnautilus-extensions/nautilus-labeled-image.c:
(button_leave_callback), (button_focus_out_event_callback),
(nautilus_labeled_image_check_button_new): Add workaround for
rendering problems with GtkCheckButton.
(nautilus_labeled_image_set_label_never_smooth): New function to
make the label part possibly never smooth.
* libnautilus-extensions/nautilus-clickable-image.h:
* libnautilus-extensions/nautilus-clickable-image.c:
(ancestor_button_press_event), (ancestor_button_release_event),
(nautilus_clickable_image_new),
(nautilus_clickable_image_new_from_file_name): New function to
create clickable images from image files. Add grab/ungrab calls
to match the logic in GtkButton.
* libnautilus-extensions/nautilus-wrap-table.h:
* libnautilus-extensions/nautilus-wrap-table.c:
New class.
* libnautilus-extensions/nautilus-image-table.c:
* libnautilus-extensions/nautilus-image-table.h:
New class.
* test/test-nautilus-image-table.c:
* test/.cvsignore:
* test/Makefile.am:
Image table test.
22 files changed, 3790 insertions, 36 deletions
@@ -1,3 +1,40 @@ +2001-02-07 Ramiro Estrugo <ramiro@eazel.com> + + reviewed by: Mike Fleming <mfleming@eazel.com> + Minus the 2 new widgets. + + * libnautilus-extensions/Makefile.am: + New files. + + * libnautilus-extensions/nautilus-labeled-image.h: + * libnautilus-extensions/nautilus-labeled-image.c: + (button_leave_callback), (button_focus_out_event_callback), + (nautilus_labeled_image_check_button_new): Add workaround for + rendering problems with GtkCheckButton. + (nautilus_labeled_image_set_label_never_smooth): New function to + make the label part possibly never smooth. + + * libnautilus-extensions/nautilus-clickable-image.h: + * libnautilus-extensions/nautilus-clickable-image.c: + (ancestor_button_press_event), (ancestor_button_release_event), + (nautilus_clickable_image_new), + (nautilus_clickable_image_new_from_file_name): New function to + create clickable images from image files. Add grab/ungrab calls + to match the logic in GtkButton. + + * libnautilus-extensions/nautilus-wrap-table.h: + * libnautilus-extensions/nautilus-wrap-table.c: + New class. + + * libnautilus-extensions/nautilus-image-table.c: + * libnautilus-extensions/nautilus-image-table.h: + New class. + + * test/test-nautilus-image-table.c: + * test/.cvsignore: + * test/Makefile.am: + Image table test. + 2001-02-07 Robey Pointer <robey@eazel.com> * components/services/install/lib/eazel-install-object.c: diff --git a/libnautilus-extensions/Makefile.am b/libnautilus-extensions/Makefile.am index 1361bea3b..ade8ebef8 100644 --- a/libnautilus-extensions/Makefile.am +++ b/libnautilus-extensions/Makefile.am @@ -107,6 +107,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-icon-dnd.c \ nautilus-icon-factory.c \ nautilus-icon-text-item.c \ + nautilus-image-table.c \ nautilus-image-with-background.c \ nautilus-image.c \ nautilus-keep-last-vertical-box.c \ @@ -119,8 +120,8 @@ libnautilus_extensions_la_SOURCES = \ nautilus-list-column-title.c \ nautilus-list.c \ nautilus-merged-directory.c \ - nautilus-metafile.c \ nautilus-metafile-factory.c \ + nautilus-metafile.c \ nautilus-mime-actions.c \ nautilus-password-dialog.c \ nautilus-preferences-box.c \ @@ -157,6 +158,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-view-identifier.c \ nautilus-viewport.c \ nautilus-volume-monitor.c \ + nautilus-wrap-table.c \ nautilus-xml-extensions.c \ $(NULL) @@ -218,6 +220,7 @@ noinst_HEADERS = \ nautilus-icon-factory.h \ nautilus-icon-private.h \ nautilus-icon-text-item.h \ + nautilus-image-table.h \ nautilus-image-with-background.h \ nautilus-image.h \ nautilus-iso9660.h \ @@ -232,8 +235,8 @@ noinst_HEADERS = \ nautilus-list.h \ nautilus-merged-directory.h \ nautilus-metadata.h \ - nautilus-metafile.h \ nautilus-metafile-factory.h \ + nautilus-metafile.h \ nautilus-mime-actions.h \ nautilus-password-dialog.h \ nautilus-preferences-box.h \ @@ -273,6 +276,7 @@ noinst_HEADERS = \ nautilus-view-identifier.h \ nautilus-viewport.h \ nautilus-volume-monitor.h \ + nautilus-wrap-table.h \ nautilus-xml-extensions.h \ $(NULL) diff --git a/libnautilus-extensions/nautilus-clickable-image.c b/libnautilus-extensions/nautilus-clickable-image.c index 5f6dd066f..4dfb7ddf1 100644 --- a/libnautilus-extensions/nautilus-clickable-image.c +++ b/libnautilus-extensions/nautilus-clickable-image.c @@ -30,6 +30,8 @@ #include "nautilus-gtk-extensions.h" #include "nautilus-art-gtk-extensions.h" +#include <gtk/gtkmain.h> + /* Arguments */ enum { @@ -409,6 +411,8 @@ ancestor_button_press_event (GtkWidget *widget, clickable_image = NAUTILUS_CLICKABLE_IMAGE (event_data); + gtk_grab_add (widget); + if (clickable_image->details->pointer_inside) { label_handle_button_press (NAUTILUS_CLICKABLE_IMAGE (event_data)); } @@ -429,6 +433,8 @@ ancestor_button_release_event (GtkWidget *widget, clickable_image = NAUTILUS_CLICKABLE_IMAGE (event_data); + gtk_grab_remove (widget); + if (clickable_image->details->pointer_inside) { label_handle_button_release (NAUTILUS_CLICKABLE_IMAGE (event_data)); } @@ -485,6 +491,21 @@ nautilus_clickable_image_new (const char *text, return GTK_WIDGET (clickable_image); } +GtkWidget* +nautilus_clickable_image_new_from_file_name (const char *text, + const char *pixbuf_file_name) +{ + NautilusClickableImage *clickable_image; + + g_return_val_if_fail (pixbuf_file_name != NULL, NULL); + + clickable_image = NAUTILUS_CLICKABLE_IMAGE (nautilus_clickable_image_new (text, NULL)); + + nautilus_labeled_image_set_pixbuf_from_file_name (NAUTILUS_LABELED_IMAGE (clickable_image), pixbuf_file_name); + + return GTK_WIDGET (clickable_image); +} + /** * nautilus_clickable_image_new_solid: * diff --git a/libnautilus-extensions/nautilus-clickable-image.h b/libnautilus-extensions/nautilus-clickable-image.h index b9ee915bc..f4c49efc2 100644 --- a/libnautilus-extensions/nautilus-clickable-image.h +++ b/libnautilus-extensions/nautilus-clickable-image.h @@ -72,20 +72,22 @@ struct _NautilusClickableImageClass void (*leave) (NautilusClickableImage *image); }; -GtkType nautilus_clickable_image_get_type (void); -GtkWidget *nautilus_clickable_image_new (const char *text, - GdkPixbuf *pixbuf); -GtkWidget *nautilus_clickable_image_new_solid (const char *text, - GdkPixbuf *pixbuf, - guint drop_shadow_offset, - guint32 drop_shadow_color, - guint32 text_color, - float x_alignment, - float y_alignment, - int x_padding, - int y_padding, - guint32 background_color, - GdkPixbuf *tile_pixbuf); +GtkType nautilus_clickable_image_get_type (void); +GtkWidget *nautilus_clickable_image_new (const char *text, + GdkPixbuf *pixbuf); +GtkWidget *nautilus_clickable_image_new_from_file_name (const char *text, + const char *pixbuf_file_name); +GtkWidget *nautilus_clickable_image_new_solid (const char *text, + GdkPixbuf *pixbuf, + guint drop_shadow_offset, + guint32 drop_shadow_color, + guint32 text_color, + float x_alignment, + float y_alignment, + int x_padding, + int y_padding, + guint32 background_color, + GdkPixbuf *tile_pixbuf); END_GNOME_DECLS diff --git a/libnautilus-extensions/nautilus-image-table.c b/libnautilus-extensions/nautilus-image-table.c new file mode 100644 index 000000000..0c4f0cdd7 --- /dev/null +++ b/libnautilus-extensions/nautilus-image-table.c @@ -0,0 +1,529 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-image-table.c - An image table. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#include <config.h> + +#include "nautilus-image-table.h" + +#include "nautilus-gtk-macros.h" +#include "nautilus-gtk-extensions.h" +#include "nautilus-art-extensions.h" +#include "nautilus-art-gtk-extensions.h" + +#include <gtk/gtkmain.h> + +/* Arguments */ +enum +{ + ARG_0, + ARG_CHILD_UNDER_POINTER +}; + +/* Detail member struct */ +struct NautilusImageTableDetails +{ + GtkWidget *windowed_ancestor; + guint enter_notify_connection_id; + guint leave_notify_connection_id; + guint motion_notify_connection_id; + guint button_press_connection_id; + guint button_release_connection_id; + GtkWidget *child_under_pointer; + GtkWidget *child_being_pressed; +}; + +/* 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 }; + +/* GtkObjectClass methods */ +static void nautilus_image_table_initialize_class (NautilusImageTableClass *image_table_class); +static void nautilus_image_table_initialize (NautilusImageTable *image); +static void nautilus_image_table_destroy (GtkObject *object); + +/* GtkWidgetClass methods */ +static void nautilus_image_table_realize (GtkWidget *widget); +static void nautilus_image_table_unrealize (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void nautilus_image_table_add (GtkContainer *container, + GtkWidget *widget); +static void nautilus_image_table_remove (GtkContainer *container, + GtkWidget *widget); +static GtkType nautilus_image_table_child_type (GtkContainer *container); + +/* Private NautilusImageTable methods */ + +/* 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); + +NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusImageTable, nautilus_image_table, NAUTILUS_TYPE_WRAP_TABLE) + +/* Class init methods */ +static void +nautilus_image_table_initialize_class (NautilusImageTableClass *image_table_class) +{ + GtkObjectClass *object_class = GTK_OBJECT_CLASS (image_table_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (image_table_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (image_table_class); + + /* GtkObjectClass */ + object_class->destroy = nautilus_image_table_destroy; + + /* GtkWidgetClass */ + widget_class->realize = nautilus_image_table_realize; + widget_class->unrealize = nautilus_image_table_unrealize; + + /* GtkContainerClass */ + container_class->add = nautilus_image_table_add; + container_class->remove = nautilus_image_table_remove; + container_class->child_type = nautilus_image_table_child_type; + + /* Signals */ + image_table_signals[CHILD_ENTER] = gtk_signal_new ("child_enter", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_LEAVE] = gtk_signal_new ("child_leave", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_PRESSED] = gtk_signal_new ("child_pressed", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_RELEASED] = gtk_signal_new ("child_released", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_CLICKED] = gtk_signal_new ("child_clicked", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + + gtk_object_class_add_signals (object_class, image_table_signals, LAST_SIGNAL); +} + +void +nautilus_image_table_initialize (NautilusImageTable *image_table) +{ + GTK_WIDGET_SET_FLAGS (image_table, GTK_NO_WINDOW); + + image_table->details = g_new0 (NautilusImageTableDetails, 1); +} + +/* GtkObjectClass methods */ +static void +nautilus_image_table_destroy (GtkObject *object) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (object)); + + image_table = NAUTILUS_IMAGE_TABLE (object); + + g_free (image_table->details); + + /* Chain destroy */ + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); +} + +/* GtkWidgetClass methods */ +static void +nautilus_image_table_realize (GtkWidget *widget) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (widget)); + + image_table = NAUTILUS_IMAGE_TABLE (widget); + + /* Chain realize */ + NAUTILUS_CALL_PARENT_CLASS (GTK_WIDGET_CLASS, realize, (widget)); + + image_table->details->windowed_ancestor = nautilus_gtk_widget_find_windowed_ancestor (widget); + g_assert (GTK_IS_WIDGET (image_table->details->windowed_ancestor)); + + gtk_widget_add_events (image_table->details->windowed_ancestor, + GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_POINTER_MOTION_MASK); + + image_table->details->enter_notify_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "enter_notify_event", + GTK_SIGNAL_FUNC (ancestor_enter_notify_event), + widget); + + image_table->details->leave_notify_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "leave_notify_event", + GTK_SIGNAL_FUNC (ancestor_leave_notify_event), + widget); + + image_table->details->motion_notify_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "motion_notify_event", + GTK_SIGNAL_FUNC (ancestor_motion_notify_event), + widget); + + image_table->details->button_press_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "button_press_event", + GTK_SIGNAL_FUNC (ancestor_button_press_event), + widget); + + image_table->details->button_release_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "button_release_event", + GTK_SIGNAL_FUNC (ancestor_button_release_event), + widget); +} + +static void +nautilus_image_table_unrealize (GtkWidget *widget) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (widget)); + + image_table = NAUTILUS_IMAGE_TABLE (widget); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->enter_notify_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->leave_notify_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->motion_notify_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->button_press_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->button_release_connection_id); + + image_table->details->windowed_ancestor = NULL; + image_table->details->enter_notify_connection_id = 0; + image_table->details->leave_notify_connection_id = 0; + image_table->details->motion_notify_connection_id = 0; + image_table->details->button_press_connection_id = 0; + image_table->details->button_release_connection_id = 0; + + /* Chain unrealize */ + NAUTILUS_CALL_PARENT_CLASS (GTK_WIDGET_CLASS, unrealize, (widget)); +} + +/* GtkContainerClass methods */ +static void +nautilus_image_table_add (GtkContainer *container, + GtkWidget *child) +{ + NautilusImageTable *image_table; + + g_return_if_fail (container != NULL); + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (container)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (child)); + + image_table = NAUTILUS_IMAGE_TABLE (container); + + NAUTILUS_CALL_PARENT_CLASS (GTK_CONTAINER_CLASS, add, (container, child)); +} + +static void +nautilus_image_table_remove (GtkContainer *container, + GtkWidget *child) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (container)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (child)); + + image_table = NAUTILUS_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; + } + + NAUTILUS_CALL_PARENT_CLASS (GTK_CONTAINER_CLASS, remove, (container, child)); +} + +static GtkType +nautilus_image_table_child_type (GtkContainer *container) +{ + return NAUTILUS_TYPE_LABELED_IMAGE; +} + +/* Private NautilusImageTable methods */ +static void +image_table_handle_motion (NautilusImageTable *image_table, + int x, + int y, + GdkEvent *event) +{ + GtkWidget *child; + GtkWidget *leave_emit_child = NULL; + GtkWidget *enter_emit_child = NULL; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (image_table)); + + child = nautilus_wrap_table_find_child_at_event_point (NAUTILUS_WRAP_TABLE (image_table), x, y); + + 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) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_LEAVE], + leave_emit_child, + event); + } + + if (enter_emit_child != NULL) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_ENTER], + enter_emit_child, + event); + } +} + +static int +ancestor_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table_handle_motion (NAUTILUS_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) +{ + ArtIRect bounds; + int x = -1; + int y = -1; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + bounds = nautilus_irect_gtk_widget_get_bounds (GTK_WIDGET (event_data)); + + if (nautilus_art_irect_contains_point (&bounds, event->x, event->y)) { + x = event->x; + y = event->y; + } + + image_table_handle_motion (NAUTILUS_IMAGE_TABLE (event_data), x, y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer event_data) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table_handle_motion (NAUTILUS_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) +{ + NautilusImageTable *image_table; + GtkWidget *child; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table = NAUTILUS_IMAGE_TABLE (event_data); + + gtk_grab_add (widget); + + child = nautilus_wrap_table_find_child_at_event_point (NAUTILUS_WRAP_TABLE (image_table), event->x, event->y); + + if (child != NULL) { + if (child == image_table->details->child_under_pointer) { + image_table->details->child_being_pressed = child; + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_PRESSED], + child, + event); + } + } + + return FALSE; +} + +static int +ancestor_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data) +{ + NautilusImageTable *image_table; + GtkWidget *child; + GtkWidget *released_emit_child = NULL; + GtkWidget *clicked_emit_child = NULL; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table = NAUTILUS_IMAGE_TABLE (event_data); + + gtk_grab_remove (widget); + + child = nautilus_wrap_table_find_child_at_event_point (NAUTILUS_WRAP_TABLE (image_table), event->x, event->y); + + 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) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_RELEASED], + released_emit_child, + event); + } + + if (clicked_emit_child != NULL) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_CLICKED], + clicked_emit_child, + event); + } + + return FALSE; +} + +/** + * nautilus_image_table_new: + */ +GtkWidget* +nautilus_image_table_new (gboolean homogeneous) +{ + NautilusImageTable *image_table; + + image_table = NAUTILUS_IMAGE_TABLE (gtk_widget_new (nautilus_image_table_get_type (), NULL)); + + nautilus_wrap_table_set_homogeneous (NAUTILUS_WRAP_TABLE (image_table), homogeneous); + + return GTK_WIDGET (image_table); +} diff --git a/libnautilus-extensions/nautilus-image-table.h b/libnautilus-extensions/nautilus-image-table.h new file mode 100644 index 000000000..9397f7b89 --- /dev/null +++ b/libnautilus-extensions/nautilus-image-table.h @@ -0,0 +1,73 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-image-table.h - An image table. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#ifndef NAUTILUS_IMAGE_TABLE_H +#define NAUTILUS_IMAGE_TABLE_H + +#include <libnautilus-extensions/nautilus-wrap-table.h> +#include <libnautilus-extensions/nautilus-labeled-image.h> + +BEGIN_GNOME_DECLS + +#define NAUTILUS_TYPE_IMAGE_TABLE (nautilus_image_table_get_type ()) +#define NAUTILUS_IMAGE_TABLE(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_IMAGE_TABLE, NautilusImageTable)) +#define NAUTILUS_IMAGE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_IMAGE_TABLE, NautilusImageTableClass)) +#define NAUTILUS_IS_IMAGE_TABLE(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_IMAGE_TABLE)) +#define NAUTILUS_IS_IMAGE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_IMAGE_TABLE)) + +typedef struct NautilusImageTable NautilusImageTable; +typedef struct NautilusImageTableClass NautilusImageTableClass; +typedef struct NautilusImageTableDetails NautilusImageTableDetails; + +struct NautilusImageTable +{ + /* Superclass */ + NautilusWrapTable wrap_table; + + /* Private things */ + NautilusImageTableDetails *details; +}; + +struct NautilusImageTableClass +{ + NautilusWrapTableClass parent_class; +}; + +typedef struct +{ + int x; + int y; + int button; + guint state; +} NautilusImageTableEvent; + +/* Public GtkImageTable methods */ +GtkType nautilus_image_table_get_type (void); +GtkWidget *nautilus_image_table_new (gboolean homogeneous); + +END_GNOME_DECLS + +#endif /* NAUTILUS_IMAGE_TABLE_H */ + + diff --git a/libnautilus-extensions/nautilus-labeled-image.c b/libnautilus-extensions/nautilus-labeled-image.c index a0feab5e9..47f3a768a 100644 --- a/libnautilus-extensions/nautilus-labeled-image.c +++ b/libnautilus-extensions/nautilus-labeled-image.c @@ -32,13 +32,12 @@ #include "nautilus-art-gtk-extensions.h" #include "nautilus-label.h" #include "nautilus-image.h" +#include "nautilus-debug-drawing.h" #include <gtk/gtkbutton.h> #include <gtk/gtktogglebutton.h> #include <gtk/gtkcheckbutton.h> -#include "nautilus-debug-drawing.h" - #define DEFAULT_SPACING 0 #define DEFAULT_X_PADDING 0 #define DEFAULT_Y_PADDING 0 @@ -1631,6 +1630,51 @@ nautilus_labeled_image_toggle_button_new_from_file_name (const char *text, return toggle_button; } +/* + * Workaround some bugs in GtkCheckButton where the widget + * does not redraw properly after leave or focus out events + * + * The workaround is to draw a little bit more than the + * widget itself - 4 pixels worth. For some reason the + * widget does not properly redraw its edges. + */ +static void +button_leave_callback (GtkWidget *widget, + gpointer callback_data) +{ + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) { + const int fudge = 4; + ArtIRect bounds; + + bounds = nautilus_irect_gtk_widget_get_bounds (widget); + + bounds.x0 -= fudge; + bounds.y0 -= fudge; + bounds.x1 += fudge; + bounds.y1 += fudge; + + gtk_widget_queue_draw_area (widget->parent, + bounds.x0, + bounds.y0, + nautilus_art_irect_get_width (&bounds), + nautilus_art_irect_get_height (&bounds)); + } +} + +static gint +button_focus_out_event_callback (GtkWidget *widget, + GdkEventFocus *event, + gpointer callback_data) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + button_leave_callback (widget, callback_data); + + return FALSE; +} + /** * nautilus_labeled_image_check_button_new: * @text: Text to use for label or NULL. @@ -1651,6 +1695,21 @@ nautilus_labeled_image_check_button_new (const char *text, gtk_container_add (GTK_CONTAINER (check_button), labeled_image); gtk_widget_show (labeled_image); + /* + * Workaround some bugs in GtkCheckButton where the widget + * does not redraw properly after leave or focus out events + */ + gtk_signal_connect_while_alive (GTK_OBJECT (check_button), + "leave", + GTK_SIGNAL_FUNC (button_leave_callback), + NULL, + GTK_OBJECT (check_button)); + gtk_signal_connect_while_alive (GTK_OBJECT (check_button), + "focus_out_event", + GTK_SIGNAL_FUNC (button_focus_out_event_callback), + NULL, + GTK_OBJECT (check_button)); + return check_button; } @@ -1965,3 +2024,14 @@ nautilus_labeled_image_set_text_color (NautilusLabeledImage *labeled_image, } } +void +nautilus_labeled_image_set_label_never_smooth (NautilusLabeledImage *labeled_image, + gboolean never_smooth) +{ + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->label != NULL) { + nautilus_label_set_never_smooth (NAUTILUS_LABEL (labeled_image->details->label), + never_smooth); + } +} diff --git a/libnautilus-extensions/nautilus-labeled-image.h b/libnautilus-extensions/nautilus-labeled-image.h index 26d9491e0..9be437b68 100644 --- a/libnautilus-extensions/nautilus-labeled-image.h +++ b/libnautilus-extensions/nautilus-labeled-image.h @@ -158,6 +158,8 @@ void nautilus_labeled_image_set_smooth_drop_shadow_color (Nautilu guint32 drop_shadow_color); void nautilus_labeled_image_set_text_color (NautilusLabeledImage *labeled_image, guint32 text_color); +void nautilus_labeled_image_set_label_never_smooth (NautilusLabeledImage *labeled_image, + gboolean never_smooth); END_GNOME_DECLS diff --git a/libnautilus-extensions/nautilus-wrap-table.c b/libnautilus-extensions/nautilus-wrap-table.c new file mode 100644 index 000000000..fb51a881f --- /dev/null +++ b/libnautilus-extensions/nautilus-wrap-table.c @@ -0,0 +1,939 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-wrap-box.c - A table that can wrap its contents as needed. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#include <config.h> + +#include "nautilus-wrap-table.h" + +#include "nautilus-gtk-macros.h" +#include "nautilus-gtk-extensions.h" +#include "nautilus-art-extensions.h" +#include "nautilus-art-gtk-extensions.h" + +#include <gtk/gtkmain.h> +#include <gtk/gtkviewport.h> + +/* Arguments */ +enum +{ + ARG_0, + ARG_X_SPACING, + ARG_Y_SPACING, + ARG_X_JUSTIFICATION, + ARG_Y_JUSTIFICATION, + ARG_HOMOGENEOUS, +}; + +/* Detail member struct */ +struct NautilusWrapTableDetails +{ + guint x_spacing; + guint y_spacing; + NautilusJustification x_justification; + NautilusJustification y_justification; + gboolean homogeneous; + GList *items; +}; + +/* GtkObjectClass methods */ +static void nautilus_wrap_table_initialize_class (NautilusWrapTableClass *wrap_table_class); +static void nautilus_wrap_table_initialize (NautilusWrapTable *wrap); +static void nautilus_wrap_table_destroy (GtkObject *object); +static void nautilus_wrap_table_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void nautilus_wrap_table_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +/* GtkWidgetClass methods */ +static void nautilus_wrap_table_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static int nautilus_wrap_table_expose_event (GtkWidget *widget, + GdkEventExpose *event); +static void nautilus_wrap_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void nautilus_wrap_table_map (GtkWidget *widget); +static void nautilus_wrap_table_unmap (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void nautilus_wrap_table_add (GtkContainer *container, + GtkWidget *widget); +static void nautilus_wrap_table_remove (GtkContainer *container, + GtkWidget *widget); +static void nautilus_wrap_table_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GtkType nautilus_wrap_table_child_type (GtkContainer *container); + + +/* Private NautilusWrapTable methods */ +static ArtIRect wrap_table_art_irect_max_frame (const ArtIRect *one, + const ArtIRect *two); +static ArtIRect wrap_table_get_max_child_frame (const NautilusWrapTable *wrap_table); +static ArtIRect wrap_table_get_content_frame (const NautilusWrapTable *wrap_table); +static ArtIRect wrap_table_get_content_bounds (const NautilusWrapTable *wrap_table); +static NautilusArtIPoint wrap_table_get_scroll_offset (const NautilusWrapTable *wrap_table); +static GtkWidget * wrap_table_find_child_at_point (const NautilusWrapTable *wrap_table, + int x, + int y); +static void wrap_table_layout (NautilusWrapTable *wrap_table); + +NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusWrapTable, nautilus_wrap_table, GTK_TYPE_CONTAINER) + +/* Class init methods */ +static void +nautilus_wrap_table_initialize_class (NautilusWrapTableClass *wrap_table_class) +{ + GtkObjectClass *object_class = GTK_OBJECT_CLASS (wrap_table_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (wrap_table_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (wrap_table_class); + + /* GtkObjectClass */ + object_class->destroy = nautilus_wrap_table_destroy; + object_class->set_arg = nautilus_wrap_table_set_arg; + object_class->get_arg = nautilus_wrap_table_get_arg; + + /* GtkWidgetClass */ + widget_class->size_request = nautilus_wrap_table_size_request; + widget_class->size_allocate = nautilus_wrap_table_size_allocate; + widget_class->expose_event = nautilus_wrap_table_expose_event; + widget_class->map = nautilus_wrap_table_map; + widget_class->unmap = nautilus_wrap_table_unmap; + + /* GtkContainerClass */ + container_class->add = nautilus_wrap_table_add; + container_class->remove = nautilus_wrap_table_remove; + container_class->forall = nautilus_wrap_table_forall; + container_class->child_type = nautilus_wrap_table_child_type; + + /* Arguments */ + gtk_object_add_arg_type ("NautilusWrapTable::x_spacing", + GTK_TYPE_UINT, + GTK_ARG_READWRITE, + ARG_X_SPACING); + gtk_object_add_arg_type ("NautilusWrapTable::y_spacing", + GTK_TYPE_UINT, + GTK_ARG_READWRITE, + ARG_Y_SPACING); + gtk_object_add_arg_type ("NautilusWrapTable::x_justification", + GTK_TYPE_ENUM, + GTK_ARG_READWRITE, + ARG_X_JUSTIFICATION); + gtk_object_add_arg_type ("NautilusWrapTable::y_justification", + GTK_TYPE_ENUM, + GTK_ARG_READWRITE, + ARG_Y_JUSTIFICATION); + gtk_object_add_arg_type ("NautilusWrapTable::homogeneous", + GTK_TYPE_BOOL, + GTK_ARG_READWRITE, + ARG_HOMOGENEOUS); +} + +void +nautilus_wrap_table_initialize (NautilusWrapTable *wrap_table) +{ + GTK_WIDGET_SET_FLAGS (wrap_table, GTK_NO_WINDOW); + + wrap_table->details = g_new0 (NautilusWrapTableDetails, 1); + wrap_table->details->x_justification = NAUTILUS_JUSTIFICATION_BEGINNING; + wrap_table->details->y_justification = NAUTILUS_JUSTIFICATION_END; +} + +/* GtkObjectClass methods */ +static void +nautilus_wrap_table_destroy (GtkObject *object) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (object)); + + wrap_table = NAUTILUS_WRAP_TABLE (object); + + /* + * Chain destroy before freeing our details. + * The details will be used in the nautilus_wrap_box_remove () + * method as a result of the children being killed. + */ + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); + + g_list_free (wrap_table->details->items); + + g_free (wrap_table->details); +} + +static void +nautilus_wrap_table_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (object)); + + wrap_table = NAUTILUS_WRAP_TABLE (object); + + switch (arg_id) + { + case ARG_X_SPACING: + nautilus_wrap_table_set_x_spacing (wrap_table, GTK_VALUE_UINT (*arg)); + break; + + case ARG_Y_SPACING: + nautilus_wrap_table_set_y_spacing (wrap_table, GTK_VALUE_UINT (*arg)); + break; + + case ARG_X_JUSTIFICATION: + nautilus_wrap_table_set_x_justification (wrap_table, GTK_VALUE_ENUM (*arg)); + break; + + case ARG_Y_JUSTIFICATION: + nautilus_wrap_table_set_y_justification (wrap_table, GTK_VALUE_ENUM (*arg)); + break; + + case ARG_HOMOGENEOUS: + nautilus_wrap_table_set_homogeneous (wrap_table, GTK_VALUE_BOOL (*arg)); + break; + + default: + g_assert_not_reached (); + } +} + +static void +nautilus_wrap_table_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (object)); + + wrap_table = NAUTILUS_WRAP_TABLE (object); + + switch (arg_id) + { + case ARG_X_SPACING: + GTK_VALUE_UINT (*arg) = nautilus_wrap_table_get_x_spacing (wrap_table); + break; + + case ARG_Y_SPACING: + GTK_VALUE_UINT (*arg) = nautilus_wrap_table_get_y_spacing (wrap_table); + break; + + case ARG_X_JUSTIFICATION: + GTK_VALUE_ENUM (*arg) = nautilus_wrap_table_get_x_justification (wrap_table); + break; + + case ARG_Y_JUSTIFICATION: + GTK_VALUE_ENUM (*arg) = nautilus_wrap_table_get_y_justification (wrap_table); + break; + + case ARG_HOMOGENEOUS: + GTK_VALUE_BOOL (*arg) = nautilus_wrap_table_get_homogeneous (wrap_table); + break; + + default: + g_assert_not_reached (); + } +} + +/* GtkWidgetClass methods */ +static void +nautilus_wrap_table_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + NautilusWrapTable *wrap_table; + ArtIRect content_frame; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + g_return_if_fail (requisition != NULL); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + content_frame = wrap_table_get_content_frame (wrap_table); + + /* The -1 tells Satan to use as much space as is available */ + requisition->width = -1; + requisition->height = content_frame.y1 + GTK_CONTAINER (widget)->border_width * 2; +} + +static void +nautilus_wrap_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + g_return_if_fail (allocation != NULL); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + widget->allocation = *allocation; + + wrap_table_layout (wrap_table); +} + +static int +nautilus_wrap_table_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + NautilusWrapTable *wrap_table; + GList *iterator; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (widget), TRUE); + g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), TRUE); + g_return_val_if_fail (event != NULL, TRUE); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + GdkEventExpose item_event; + + item = iterator->data; + item_event = *event; + + if (GTK_WIDGET_DRAWABLE (item) && + GTK_WIDGET_NO_WINDOW (item) && + gtk_widget_intersect (item, &event->area, &item_event.area)) { + gtk_widget_event (item, (GdkEvent *) &item_event); + } + } + + return FALSE; +} + +static void +nautilus_wrap_table_map (GtkWidget *widget) +{ + NautilusWrapTable *wrap_table; + GList *iterator; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + + item = iterator->data; + + if (GTK_WIDGET_VISIBLE (item) && !GTK_WIDGET_MAPPED (item)) { + gtk_widget_map (item); + } + } +} + +static void +nautilus_wrap_table_unmap (GtkWidget *widget) +{ + NautilusWrapTable *wrap_table; + GList *iterator; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + + item = iterator->data; + + if (GTK_WIDGET_VISIBLE (item) && GTK_WIDGET_MAPPED (item)) { + gtk_widget_unmap (item); + } + } +} + +/* GtkContainerClass methods */ +static void +nautilus_wrap_table_add (GtkContainer *container, + GtkWidget *child) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (container != NULL); + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + wrap_table = NAUTILUS_WRAP_TABLE (container); + + gtk_widget_set_parent (child, GTK_WIDGET (container)); + + wrap_table->details->items = g_list_append (wrap_table->details->items, child); + + if (GTK_WIDGET_REALIZED (container)) { + gtk_widget_realize (child); + } + + if (GTK_WIDGET_VISIBLE (container) && GTK_WIDGET_VISIBLE (child)) { + if (GTK_WIDGET_MAPPED (container)) { + gtk_widget_map (child); + } + + gtk_widget_queue_resize (child); + } +} + +static void +nautilus_wrap_table_remove (GtkContainer *container, + GtkWidget *child) +{ + NautilusWrapTable *wrap_table; + gboolean child_was_visible; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + wrap_table = NAUTILUS_WRAP_TABLE (container);; + + child_was_visible = GTK_WIDGET_VISIBLE (child); + gtk_widget_unparent (child); + wrap_table->details->items = g_list_remove (wrap_table->details->items, child); + + if (child_was_visible) { + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +nautilus_wrap_table_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + NautilusWrapTable *wrap_table; + GList *node; + GList *next; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (container)); + g_return_if_fail (callback != NULL); + + wrap_table = NAUTILUS_WRAP_TABLE (container);; + + for (node = wrap_table->details->items; node != NULL; node = next) { + g_assert (GTK_IS_WIDGET (node->data)); + next = node->next; + (* callback) (GTK_WIDGET (node->data), callback_data); + } +} + +static GtkType +nautilus_wrap_table_child_type (GtkContainer *container) +{ + return GTK_TYPE_WIDGET; +} + +/* Private NautilusWrapTable methods */ +static void +wrap_table_layout (NautilusWrapTable *wrap_table) +{ + GList *iterator; + NautilusArtIPoint pos; + ArtIRect max_child_frame; + ArtIRect content_bounds; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + max_child_frame = wrap_table_get_max_child_frame (wrap_table); + content_bounds = wrap_table_get_content_bounds (wrap_table); + pos.x = content_bounds.x0; + pos.y = content_bounds.y0; + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + + item = iterator->data; + + if (GTK_WIDGET_VISIBLE (item)) { + GtkAllocation item_allocation; + + if (wrap_table->details->homogeneous) { + item_allocation.x = pos.x; + item_allocation.y = pos.y; + item_allocation.width = max_child_frame.x1; + item_allocation.height = max_child_frame.y1; + + if ((pos.x + max_child_frame.x1) > content_bounds.x1) { + pos.x = content_bounds.x0 + wrap_table->details->x_spacing + max_child_frame.x1; + pos.y += (max_child_frame.y1 + wrap_table->details->y_spacing); + item_allocation.x = content_bounds.x0; + item_allocation.y = pos.y; + } else { + pos.x += (wrap_table->details->x_spacing + max_child_frame.x1); + } + } else { + GtkRequisition item_requisition; + + gtk_widget_size_request (item, &item_requisition); + + item_allocation.x = pos.x; + item_allocation.y = pos.y; + item_allocation.width = item_requisition.width; + item_allocation.height = item_requisition.height; + + g_assert (item_allocation.width <= max_child_frame.x1); + g_assert (item_allocation.height <= max_child_frame.y1); + + if ((pos.x + max_child_frame.x1) > content_bounds.x1) { + pos.x = content_bounds.x0 + wrap_table->details->x_spacing + max_child_frame.x1; + pos.y += (max_child_frame.y1 + wrap_table->details->y_spacing); + item_allocation.x = content_bounds.x0; + item_allocation.y = pos.y; + } else { + pos.x += (wrap_table->details->x_spacing + max_child_frame.x1); + } + + switch (wrap_table->details->x_justification) { + case NAUTILUS_JUSTIFICATION_MIDDLE: + item_allocation.x += (max_child_frame.x1 - (int) item_allocation.width) / 2; + break; + case NAUTILUS_JUSTIFICATION_END: + item_allocation.x += (max_child_frame.x1 - (int) item_allocation.width); + break; + default: + } + + switch (wrap_table->details->y_justification) { + case NAUTILUS_JUSTIFICATION_MIDDLE: + item_allocation.y += (max_child_frame.y1 - (int) item_allocation.height) / 2; + break; + case NAUTILUS_JUSTIFICATION_END: + item_allocation.y += (max_child_frame.y1 - (int) item_allocation.height); + break; + default: + } + } + + gtk_widget_size_allocate (item, &item_allocation); + } + } +} + +static ArtIRect +wrap_table_art_irect_max_frame (const ArtIRect *one, + const ArtIRect *two) +{ + ArtIRect max; + + g_return_val_if_fail (one != NULL, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (two != NULL, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (one->x0 == 0, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (one->y0 == 0, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (two->x0 == 0, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (two->y0 == 0, NAUTILUS_ART_IRECT_EMPTY); + + max.x0 = 0; + max.y0 = 0; + max.x1 = MAX (one->x1, two->x1); + max.y1 = MAX (one->y1, two->y1); + + return max; +} + +static ArtIRect +wrap_table_get_max_child_frame (const NautilusWrapTable *wrap_table) +{ + ArtIRect max; + GList *iterator; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IRECT_EMPTY); + + max = NAUTILUS_ART_IRECT_EMPTY; + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *child; + + child = iterator->data; + + if (GTK_WIDGET_VISIBLE (child)) { + GtkRequisition child_requisition; + ArtIRect child_frame; + + gtk_widget_size_request (child, &child_requisition); + + child_frame.x0 = 0; + child_frame.y0 = 0; + child_frame.x1 = child_requisition.width; + child_frame.y1 = child_requisition.height; + + max = wrap_table_art_irect_max_frame (&child_frame, &max); + } + } + + return max; +} + +static int +wrap_table_get_num_fitting (int available, + int spacing, + int max_child_size) +{ + int num; + + g_return_val_if_fail (available >= 0, 0); + g_return_val_if_fail (max_child_size > 0, 0); + g_return_val_if_fail (spacing >= 0, 0); + + num = (available + spacing) / (max_child_size + spacing); + num = MAX (num, 1); + + return num; +} + +static ArtIRect +wrap_table_get_content_frame (const NautilusWrapTable *wrap_table) +{ + ArtIRect content_frame; + guint num_children; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IRECT_EMPTY); + + content_frame = NAUTILUS_ART_IRECT_EMPTY; + + num_children = g_list_length (wrap_table->details->items); + + if (num_children > 0) { + ArtIRect max_child_frame; + ArtIRect frame; + int num_cols; + int num_rows; + + frame = nautilus_irect_gtk_widget_get_frame (GTK_WIDGET (wrap_table)); + max_child_frame = wrap_table_get_max_child_frame (wrap_table); + + max_child_frame.x1 = MAX (max_child_frame.x1, 1); + max_child_frame.y1 = MAX (max_child_frame.y1, 1); + + num_cols = wrap_table_get_num_fitting (frame.x1, + wrap_table->details->x_spacing, + max_child_frame.x1); + num_rows = num_children / num_cols; + + if ((num_children % num_rows) > 0) { + num_rows++; + } + + content_frame.x1 = frame.x1; + content_frame.y1 = num_rows * max_child_frame.y1; + } + + return content_frame; +} + +static ArtIRect +wrap_table_get_content_bounds (const NautilusWrapTable *wrap_table) +{ + ArtIRect content_bounds; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IRECT_EMPTY); + + content_bounds = nautilus_irect_gtk_widget_get_bounds (GTK_WIDGET (wrap_table)); + + content_bounds.x0 += GTK_CONTAINER (wrap_table)->border_width; + content_bounds.y0 += GTK_CONTAINER (wrap_table)->border_width; + content_bounds.x1 -= GTK_CONTAINER (wrap_table)->border_width; + content_bounds.y1 -= GTK_CONTAINER (wrap_table)->border_width; + + return content_bounds; +} + +static NautilusArtIPoint +wrap_table_get_scroll_offset (const NautilusWrapTable *wrap_table) +{ + NautilusArtIPoint scroll_offset; + GtkWidget *parent; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IPOINT_ZERO); + + scroll_offset = NAUTILUS_ART_IPOINT_ZERO; + + parent = GTK_WIDGET (wrap_table)->parent; + + /* + * FIXME: It lame we have to hardcode for a possible viewport + * parent here. Theres probably a better way to do this + */ + if (GTK_IS_VIEWPORT (parent)) { + GtkViewport *viewport; + + viewport = GTK_VIEWPORT (parent); + + gdk_window_get_position (viewport->bin_window, + &scroll_offset.x, + &scroll_offset.y); + } + + return scroll_offset; +} + +static GtkWidget * +wrap_table_find_child_at_point (const NautilusWrapTable *wrap_table, + int x, + int y) +{ + GList *iterator; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NULL); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *child; + + child = iterator->data; + + if (GTK_WIDGET_VISIBLE (child)) { + ArtIRect child_bounds; + + child_bounds = nautilus_irect_gtk_widget_get_bounds (child); + + if (nautilus_art_irect_contains_point (&child_bounds, x, y)) { + return child; + } + } + } + + return NULL; +} + +/** + * nautilus_wrap_table_new: + * + */ +GtkWidget* +nautilus_wrap_table_new (gboolean homogeneous) +{ + NautilusWrapTable *wrap_table; + + wrap_table = NAUTILUS_WRAP_TABLE (gtk_widget_new (nautilus_wrap_table_get_type (), NULL)); + + nautilus_wrap_table_set_homogeneous (wrap_table, homogeneous); + + return GTK_WIDGET (wrap_table); +} + +/** + * nautilus_wrap_table_set_x_spacing: + * @wrap_table: A NautilusWrapTable. + * @x_spacing: The new horizontal spacing between wraps. + * + */ +void +nautilus_wrap_table_set_x_spacing (NautilusWrapTable *wrap_table, + guint x_spacing) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->x_spacing == x_spacing) { + return; + } + + wrap_table->details->x_spacing = x_spacing; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_spacing: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +guint +nautilus_wrap_table_get_x_spacing (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->x_spacing; +} + +/** + * nautilus_wrap_table_set_y_spacing: + * @wrap_table: A NautilusWrapTable. + * @y_spacing: The new horizontal spacing between wraps. + * + */ +void +nautilus_wrap_table_set_y_spacing (NautilusWrapTable *wrap_table, + guint y_spacing) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->y_spacing == y_spacing) { + return; + } + + wrap_table->details->y_spacing = y_spacing; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_spacing: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +guint +nautilus_wrap_table_get_y_spacing (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->y_spacing; +} + +/** + * nautilus_wrap_table_find_child_at_event_point: + * @wrap_table: A NautilusWrapTable. + * @x: Event x; + * @y: Event y; + * + * Returns: Child found at given coordinates or NULL of no child is found. + */ +GtkWidget * +nautilus_wrap_table_find_child_at_event_point (const NautilusWrapTable *wrap_table, + int x, + int y) +{ + NautilusArtIPoint scroll_offset; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NULL); + + scroll_offset = wrap_table_get_scroll_offset (wrap_table); + + return wrap_table_find_child_at_point (wrap_table, + x + ABS (scroll_offset.x), + y + ABS (scroll_offset.y)); +} + +/** + * nautilus_wrap_table_set_x_justification: + * @wrap_table: A NautilusWrapTable. + * @x_justification: The new horizontal justification between wraps. + * + */ +void +nautilus_wrap_table_set_x_justification (NautilusWrapTable *wrap_table, + NautilusJustification x_justification) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + g_return_if_fail (x_justification >= NAUTILUS_JUSTIFICATION_BEGINNING); + g_return_if_fail (x_justification <= NAUTILUS_JUSTIFICATION_END); + + if (wrap_table->details->x_justification == x_justification) { + return; + } + + wrap_table->details->x_justification = x_justification; + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_justification: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal justification between wraps. + */ +NautilusJustification +nautilus_wrap_table_get_x_justification (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->x_justification; +} + +/** + * nautilus_wrap_table_set_y_justification: + * @wrap_table: A NautilusWrapTable. + * @y_justification: The new horizontal justification between wraps. + * + */ +void +nautilus_wrap_table_set_y_justification (NautilusWrapTable *wrap_table, + NautilusJustification y_justification) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + g_return_if_fail (y_justification >= NAUTILUS_JUSTIFICATION_BEGINNING); + g_return_if_fail (y_justification <= NAUTILUS_JUSTIFICATION_END); + + if (wrap_table->details->y_justification == y_justification) { + return; + } + + wrap_table->details->y_justification = y_justification; + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_justification: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal justification between wraps. + */ +NautilusJustification +nautilus_wrap_table_get_y_justification (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->y_justification; +} + +/** + * nautilus_wrap_table_set_homogeneous: + * @wrap_table: A NautilusWrapTable. + * @homogeneous: The new horizontal spacing between wraps. + * + */ +void +nautilus_wrap_table_set_homogeneous (NautilusWrapTable *wrap_table, + gboolean homogeneous) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->homogeneous == homogeneous) { + return; + } + + wrap_table->details->homogeneous = homogeneous; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_spacing: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +gboolean +nautilus_wrap_table_get_homogeneous (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->homogeneous; +} diff --git a/libnautilus-extensions/nautilus-wrap-table.h b/libnautilus-extensions/nautilus-wrap-table.h new file mode 100644 index 000000000..0a18a6724 --- /dev/null +++ b/libnautilus-extensions/nautilus-wrap-table.h @@ -0,0 +1,90 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-wrap-table.h - A table that can wrap its contents as needed. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#ifndef NAUTILUS_WRAP_TABLE_H +#define NAUTILUS_WRAP_TABLE_H + +#include <gtk/gtkcontainer.h> +#include <libgnome/gnome-defs.h> + +BEGIN_GNOME_DECLS + +#define NAUTILUS_TYPE_WRAP_TABLE (nautilus_wrap_table_get_type ()) +#define NAUTILUS_WRAP_TABLE(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_WRAP_TABLE, NautilusWrapTable)) +#define NAUTILUS_WRAP_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_WRAP_TABLE, NautilusWrapTableClass)) +#define NAUTILUS_IS_WRAP_TABLE(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_WRAP_TABLE)) +#define NAUTILUS_IS_WRAP_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_WRAP_TABLE)) + +typedef struct NautilusWrapTable NautilusWrapTable; +typedef struct NautilusWrapTableClass NautilusWrapTableClass; +typedef struct NautilusWrapTableDetails NautilusWrapTableDetails; + +struct NautilusWrapTable +{ + /* Superclass */ + GtkContainer container; + + /* Private things */ + NautilusWrapTableDetails *details; +}; + +struct NautilusWrapTableClass +{ + GtkContainerClass parent_class; +}; + +typedef enum +{ + NAUTILUS_JUSTIFICATION_BEGINNING, + NAUTILUS_JUSTIFICATION_MIDDLE, + NAUTILUS_JUSTIFICATION_END +} NautilusJustification; + +/* Public GtkWrapTable methods */ +GtkType nautilus_wrap_table_get_type (void); +GtkWidget * nautilus_wrap_table_new (gboolean homogeneous); +void nautilus_wrap_table_set_x_spacing (NautilusWrapTable *wrap_table, + guint x_spacing); +guint nautilus_wrap_table_get_x_spacing (const NautilusWrapTable *wrap_table); +void nautilus_wrap_table_set_y_spacing (NautilusWrapTable *wrap_table, + guint y_spacing); +guint nautilus_wrap_table_get_y_spacing (const NautilusWrapTable *wrap_table); +GtkWidget * nautilus_wrap_table_find_child_at_event_point (const NautilusWrapTable *wrap_table, + int x, + int y); +void nautilus_wrap_table_set_x_justification (NautilusWrapTable *wrap_table, + GtkJustification justification); +NautilusJustification nautilus_wrap_table_get_x_justification (const NautilusWrapTable *wrap_table); +void nautilus_wrap_table_set_y_justification (NautilusWrapTable *wrap_table, + NautilusJustification justification); +NautilusJustification nautilus_wrap_table_get_y_justification (const NautilusWrapTable *wrap_table); +void nautilus_wrap_table_set_homogeneous (NautilusWrapTable *wrap_table, + gboolean homogeneous); +gboolean nautilus_wrap_table_get_homogeneous (const NautilusWrapTable *wrap_table); + +END_GNOME_DECLS + +#endif /* NAUTILUS_WRAP_TABLE_H */ + + diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am index 1361bea3b..ade8ebef8 100644 --- a/libnautilus-private/Makefile.am +++ b/libnautilus-private/Makefile.am @@ -107,6 +107,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-icon-dnd.c \ nautilus-icon-factory.c \ nautilus-icon-text-item.c \ + nautilus-image-table.c \ nautilus-image-with-background.c \ nautilus-image.c \ nautilus-keep-last-vertical-box.c \ @@ -119,8 +120,8 @@ libnautilus_extensions_la_SOURCES = \ nautilus-list-column-title.c \ nautilus-list.c \ nautilus-merged-directory.c \ - nautilus-metafile.c \ nautilus-metafile-factory.c \ + nautilus-metafile.c \ nautilus-mime-actions.c \ nautilus-password-dialog.c \ nautilus-preferences-box.c \ @@ -157,6 +158,7 @@ libnautilus_extensions_la_SOURCES = \ nautilus-view-identifier.c \ nautilus-viewport.c \ nautilus-volume-monitor.c \ + nautilus-wrap-table.c \ nautilus-xml-extensions.c \ $(NULL) @@ -218,6 +220,7 @@ noinst_HEADERS = \ nautilus-icon-factory.h \ nautilus-icon-private.h \ nautilus-icon-text-item.h \ + nautilus-image-table.h \ nautilus-image-with-background.h \ nautilus-image.h \ nautilus-iso9660.h \ @@ -232,8 +235,8 @@ noinst_HEADERS = \ nautilus-list.h \ nautilus-merged-directory.h \ nautilus-metadata.h \ - nautilus-metafile.h \ nautilus-metafile-factory.h \ + nautilus-metafile.h \ nautilus-mime-actions.h \ nautilus-password-dialog.h \ nautilus-preferences-box.h \ @@ -273,6 +276,7 @@ noinst_HEADERS = \ nautilus-view-identifier.h \ nautilus-viewport.h \ nautilus-volume-monitor.h \ + nautilus-wrap-table.h \ nautilus-xml-extensions.h \ $(NULL) diff --git a/libnautilus-private/nautilus-clickable-image.c b/libnautilus-private/nautilus-clickable-image.c index 5f6dd066f..4dfb7ddf1 100644 --- a/libnautilus-private/nautilus-clickable-image.c +++ b/libnautilus-private/nautilus-clickable-image.c @@ -30,6 +30,8 @@ #include "nautilus-gtk-extensions.h" #include "nautilus-art-gtk-extensions.h" +#include <gtk/gtkmain.h> + /* Arguments */ enum { @@ -409,6 +411,8 @@ ancestor_button_press_event (GtkWidget *widget, clickable_image = NAUTILUS_CLICKABLE_IMAGE (event_data); + gtk_grab_add (widget); + if (clickable_image->details->pointer_inside) { label_handle_button_press (NAUTILUS_CLICKABLE_IMAGE (event_data)); } @@ -429,6 +433,8 @@ ancestor_button_release_event (GtkWidget *widget, clickable_image = NAUTILUS_CLICKABLE_IMAGE (event_data); + gtk_grab_remove (widget); + if (clickable_image->details->pointer_inside) { label_handle_button_release (NAUTILUS_CLICKABLE_IMAGE (event_data)); } @@ -485,6 +491,21 @@ nautilus_clickable_image_new (const char *text, return GTK_WIDGET (clickable_image); } +GtkWidget* +nautilus_clickable_image_new_from_file_name (const char *text, + const char *pixbuf_file_name) +{ + NautilusClickableImage *clickable_image; + + g_return_val_if_fail (pixbuf_file_name != NULL, NULL); + + clickable_image = NAUTILUS_CLICKABLE_IMAGE (nautilus_clickable_image_new (text, NULL)); + + nautilus_labeled_image_set_pixbuf_from_file_name (NAUTILUS_LABELED_IMAGE (clickable_image), pixbuf_file_name); + + return GTK_WIDGET (clickable_image); +} + /** * nautilus_clickable_image_new_solid: * diff --git a/libnautilus-private/nautilus-clickable-image.h b/libnautilus-private/nautilus-clickable-image.h index b9ee915bc..f4c49efc2 100644 --- a/libnautilus-private/nautilus-clickable-image.h +++ b/libnautilus-private/nautilus-clickable-image.h @@ -72,20 +72,22 @@ struct _NautilusClickableImageClass void (*leave) (NautilusClickableImage *image); }; -GtkType nautilus_clickable_image_get_type (void); -GtkWidget *nautilus_clickable_image_new (const char *text, - GdkPixbuf *pixbuf); -GtkWidget *nautilus_clickable_image_new_solid (const char *text, - GdkPixbuf *pixbuf, - guint drop_shadow_offset, - guint32 drop_shadow_color, - guint32 text_color, - float x_alignment, - float y_alignment, - int x_padding, - int y_padding, - guint32 background_color, - GdkPixbuf *tile_pixbuf); +GtkType nautilus_clickable_image_get_type (void); +GtkWidget *nautilus_clickable_image_new (const char *text, + GdkPixbuf *pixbuf); +GtkWidget *nautilus_clickable_image_new_from_file_name (const char *text, + const char *pixbuf_file_name); +GtkWidget *nautilus_clickable_image_new_solid (const char *text, + GdkPixbuf *pixbuf, + guint drop_shadow_offset, + guint32 drop_shadow_color, + guint32 text_color, + float x_alignment, + float y_alignment, + int x_padding, + int y_padding, + guint32 background_color, + GdkPixbuf *tile_pixbuf); END_GNOME_DECLS diff --git a/libnautilus-private/nautilus-image-table.c b/libnautilus-private/nautilus-image-table.c new file mode 100644 index 000000000..0c4f0cdd7 --- /dev/null +++ b/libnautilus-private/nautilus-image-table.c @@ -0,0 +1,529 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-image-table.c - An image table. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#include <config.h> + +#include "nautilus-image-table.h" + +#include "nautilus-gtk-macros.h" +#include "nautilus-gtk-extensions.h" +#include "nautilus-art-extensions.h" +#include "nautilus-art-gtk-extensions.h" + +#include <gtk/gtkmain.h> + +/* Arguments */ +enum +{ + ARG_0, + ARG_CHILD_UNDER_POINTER +}; + +/* Detail member struct */ +struct NautilusImageTableDetails +{ + GtkWidget *windowed_ancestor; + guint enter_notify_connection_id; + guint leave_notify_connection_id; + guint motion_notify_connection_id; + guint button_press_connection_id; + guint button_release_connection_id; + GtkWidget *child_under_pointer; + GtkWidget *child_being_pressed; +}; + +/* 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 }; + +/* GtkObjectClass methods */ +static void nautilus_image_table_initialize_class (NautilusImageTableClass *image_table_class); +static void nautilus_image_table_initialize (NautilusImageTable *image); +static void nautilus_image_table_destroy (GtkObject *object); + +/* GtkWidgetClass methods */ +static void nautilus_image_table_realize (GtkWidget *widget); +static void nautilus_image_table_unrealize (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void nautilus_image_table_add (GtkContainer *container, + GtkWidget *widget); +static void nautilus_image_table_remove (GtkContainer *container, + GtkWidget *widget); +static GtkType nautilus_image_table_child_type (GtkContainer *container); + +/* Private NautilusImageTable methods */ + +/* 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); + +NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusImageTable, nautilus_image_table, NAUTILUS_TYPE_WRAP_TABLE) + +/* Class init methods */ +static void +nautilus_image_table_initialize_class (NautilusImageTableClass *image_table_class) +{ + GtkObjectClass *object_class = GTK_OBJECT_CLASS (image_table_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (image_table_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (image_table_class); + + /* GtkObjectClass */ + object_class->destroy = nautilus_image_table_destroy; + + /* GtkWidgetClass */ + widget_class->realize = nautilus_image_table_realize; + widget_class->unrealize = nautilus_image_table_unrealize; + + /* GtkContainerClass */ + container_class->add = nautilus_image_table_add; + container_class->remove = nautilus_image_table_remove; + container_class->child_type = nautilus_image_table_child_type; + + /* Signals */ + image_table_signals[CHILD_ENTER] = gtk_signal_new ("child_enter", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_LEAVE] = gtk_signal_new ("child_leave", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_PRESSED] = gtk_signal_new ("child_pressed", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_RELEASED] = gtk_signal_new ("child_released", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + image_table_signals[CHILD_CLICKED] = gtk_signal_new ("child_clicked", + GTK_RUN_LAST, + object_class->type, + 0, + gtk_marshal_NONE__POINTER_POINTER, + GTK_TYPE_NONE, + 2, + GTK_TYPE_POINTER, + GTK_TYPE_POINTER); + + gtk_object_class_add_signals (object_class, image_table_signals, LAST_SIGNAL); +} + +void +nautilus_image_table_initialize (NautilusImageTable *image_table) +{ + GTK_WIDGET_SET_FLAGS (image_table, GTK_NO_WINDOW); + + image_table->details = g_new0 (NautilusImageTableDetails, 1); +} + +/* GtkObjectClass methods */ +static void +nautilus_image_table_destroy (GtkObject *object) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (object)); + + image_table = NAUTILUS_IMAGE_TABLE (object); + + g_free (image_table->details); + + /* Chain destroy */ + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); +} + +/* GtkWidgetClass methods */ +static void +nautilus_image_table_realize (GtkWidget *widget) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (widget)); + + image_table = NAUTILUS_IMAGE_TABLE (widget); + + /* Chain realize */ + NAUTILUS_CALL_PARENT_CLASS (GTK_WIDGET_CLASS, realize, (widget)); + + image_table->details->windowed_ancestor = nautilus_gtk_widget_find_windowed_ancestor (widget); + g_assert (GTK_IS_WIDGET (image_table->details->windowed_ancestor)); + + gtk_widget_add_events (image_table->details->windowed_ancestor, + GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_POINTER_MOTION_MASK); + + image_table->details->enter_notify_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "enter_notify_event", + GTK_SIGNAL_FUNC (ancestor_enter_notify_event), + widget); + + image_table->details->leave_notify_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "leave_notify_event", + GTK_SIGNAL_FUNC (ancestor_leave_notify_event), + widget); + + image_table->details->motion_notify_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "motion_notify_event", + GTK_SIGNAL_FUNC (ancestor_motion_notify_event), + widget); + + image_table->details->button_press_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "button_press_event", + GTK_SIGNAL_FUNC (ancestor_button_press_event), + widget); + + image_table->details->button_release_connection_id = + gtk_signal_connect (GTK_OBJECT (image_table->details->windowed_ancestor), + "button_release_event", + GTK_SIGNAL_FUNC (ancestor_button_release_event), + widget); +} + +static void +nautilus_image_table_unrealize (GtkWidget *widget) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (widget)); + + image_table = NAUTILUS_IMAGE_TABLE (widget); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->enter_notify_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->leave_notify_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->motion_notify_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->button_press_connection_id); + + gtk_signal_disconnect (GTK_OBJECT (image_table->details->windowed_ancestor), + image_table->details->button_release_connection_id); + + image_table->details->windowed_ancestor = NULL; + image_table->details->enter_notify_connection_id = 0; + image_table->details->leave_notify_connection_id = 0; + image_table->details->motion_notify_connection_id = 0; + image_table->details->button_press_connection_id = 0; + image_table->details->button_release_connection_id = 0; + + /* Chain unrealize */ + NAUTILUS_CALL_PARENT_CLASS (GTK_WIDGET_CLASS, unrealize, (widget)); +} + +/* GtkContainerClass methods */ +static void +nautilus_image_table_add (GtkContainer *container, + GtkWidget *child) +{ + NautilusImageTable *image_table; + + g_return_if_fail (container != NULL); + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (container)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (child)); + + image_table = NAUTILUS_IMAGE_TABLE (container); + + NAUTILUS_CALL_PARENT_CLASS (GTK_CONTAINER_CLASS, add, (container, child)); +} + +static void +nautilus_image_table_remove (GtkContainer *container, + GtkWidget *child) +{ + NautilusImageTable *image_table; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (container)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (child)); + + image_table = NAUTILUS_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; + } + + NAUTILUS_CALL_PARENT_CLASS (GTK_CONTAINER_CLASS, remove, (container, child)); +} + +static GtkType +nautilus_image_table_child_type (GtkContainer *container) +{ + return NAUTILUS_TYPE_LABELED_IMAGE; +} + +/* Private NautilusImageTable methods */ +static void +image_table_handle_motion (NautilusImageTable *image_table, + int x, + int y, + GdkEvent *event) +{ + GtkWidget *child; + GtkWidget *leave_emit_child = NULL; + GtkWidget *enter_emit_child = NULL; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (image_table)); + + child = nautilus_wrap_table_find_child_at_event_point (NAUTILUS_WRAP_TABLE (image_table), x, y); + + 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) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_LEAVE], + leave_emit_child, + event); + } + + if (enter_emit_child != NULL) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_ENTER], + enter_emit_child, + event); + } +} + +static int +ancestor_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event, + gpointer event_data) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table_handle_motion (NAUTILUS_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) +{ + ArtIRect bounds; + int x = -1; + int y = -1; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + bounds = nautilus_irect_gtk_widget_get_bounds (GTK_WIDGET (event_data)); + + if (nautilus_art_irect_contains_point (&bounds, event->x, event->y)) { + x = event->x; + y = event->y; + } + + image_table_handle_motion (NAUTILUS_IMAGE_TABLE (event_data), x, y, (GdkEvent *) event); + + return FALSE; +} + +static int +ancestor_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer event_data) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table_handle_motion (NAUTILUS_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) +{ + NautilusImageTable *image_table; + GtkWidget *child; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table = NAUTILUS_IMAGE_TABLE (event_data); + + gtk_grab_add (widget); + + child = nautilus_wrap_table_find_child_at_event_point (NAUTILUS_WRAP_TABLE (image_table), event->x, event->y); + + if (child != NULL) { + if (child == image_table->details->child_under_pointer) { + image_table->details->child_being_pressed = child; + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_PRESSED], + child, + event); + } + } + + return FALSE; +} + +static int +ancestor_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer event_data) +{ + NautilusImageTable *image_table; + GtkWidget *child; + GtkWidget *released_emit_child = NULL; + GtkWidget *clicked_emit_child = NULL; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (NAUTILUS_IS_IMAGE_TABLE (event_data), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + image_table = NAUTILUS_IMAGE_TABLE (event_data); + + gtk_grab_remove (widget); + + child = nautilus_wrap_table_find_child_at_event_point (NAUTILUS_WRAP_TABLE (image_table), event->x, event->y); + + 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) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_RELEASED], + released_emit_child, + event); + } + + if (clicked_emit_child != NULL) { + gtk_signal_emit (GTK_OBJECT (image_table), + image_table_signals[CHILD_CLICKED], + clicked_emit_child, + event); + } + + return FALSE; +} + +/** + * nautilus_image_table_new: + */ +GtkWidget* +nautilus_image_table_new (gboolean homogeneous) +{ + NautilusImageTable *image_table; + + image_table = NAUTILUS_IMAGE_TABLE (gtk_widget_new (nautilus_image_table_get_type (), NULL)); + + nautilus_wrap_table_set_homogeneous (NAUTILUS_WRAP_TABLE (image_table), homogeneous); + + return GTK_WIDGET (image_table); +} diff --git a/libnautilus-private/nautilus-image-table.h b/libnautilus-private/nautilus-image-table.h new file mode 100644 index 000000000..9397f7b89 --- /dev/null +++ b/libnautilus-private/nautilus-image-table.h @@ -0,0 +1,73 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-image-table.h - An image table. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#ifndef NAUTILUS_IMAGE_TABLE_H +#define NAUTILUS_IMAGE_TABLE_H + +#include <libnautilus-extensions/nautilus-wrap-table.h> +#include <libnautilus-extensions/nautilus-labeled-image.h> + +BEGIN_GNOME_DECLS + +#define NAUTILUS_TYPE_IMAGE_TABLE (nautilus_image_table_get_type ()) +#define NAUTILUS_IMAGE_TABLE(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_IMAGE_TABLE, NautilusImageTable)) +#define NAUTILUS_IMAGE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_IMAGE_TABLE, NautilusImageTableClass)) +#define NAUTILUS_IS_IMAGE_TABLE(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_IMAGE_TABLE)) +#define NAUTILUS_IS_IMAGE_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_IMAGE_TABLE)) + +typedef struct NautilusImageTable NautilusImageTable; +typedef struct NautilusImageTableClass NautilusImageTableClass; +typedef struct NautilusImageTableDetails NautilusImageTableDetails; + +struct NautilusImageTable +{ + /* Superclass */ + NautilusWrapTable wrap_table; + + /* Private things */ + NautilusImageTableDetails *details; +}; + +struct NautilusImageTableClass +{ + NautilusWrapTableClass parent_class; +}; + +typedef struct +{ + int x; + int y; + int button; + guint state; +} NautilusImageTableEvent; + +/* Public GtkImageTable methods */ +GtkType nautilus_image_table_get_type (void); +GtkWidget *nautilus_image_table_new (gboolean homogeneous); + +END_GNOME_DECLS + +#endif /* NAUTILUS_IMAGE_TABLE_H */ + + diff --git a/libnautilus-private/nautilus-labeled-image.c b/libnautilus-private/nautilus-labeled-image.c index a0feab5e9..47f3a768a 100644 --- a/libnautilus-private/nautilus-labeled-image.c +++ b/libnautilus-private/nautilus-labeled-image.c @@ -32,13 +32,12 @@ #include "nautilus-art-gtk-extensions.h" #include "nautilus-label.h" #include "nautilus-image.h" +#include "nautilus-debug-drawing.h" #include <gtk/gtkbutton.h> #include <gtk/gtktogglebutton.h> #include <gtk/gtkcheckbutton.h> -#include "nautilus-debug-drawing.h" - #define DEFAULT_SPACING 0 #define DEFAULT_X_PADDING 0 #define DEFAULT_Y_PADDING 0 @@ -1631,6 +1630,51 @@ nautilus_labeled_image_toggle_button_new_from_file_name (const char *text, return toggle_button; } +/* + * Workaround some bugs in GtkCheckButton where the widget + * does not redraw properly after leave or focus out events + * + * The workaround is to draw a little bit more than the + * widget itself - 4 pixels worth. For some reason the + * widget does not properly redraw its edges. + */ +static void +button_leave_callback (GtkWidget *widget, + gpointer callback_data) +{ + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) { + const int fudge = 4; + ArtIRect bounds; + + bounds = nautilus_irect_gtk_widget_get_bounds (widget); + + bounds.x0 -= fudge; + bounds.y0 -= fudge; + bounds.x1 += fudge; + bounds.y1 += fudge; + + gtk_widget_queue_draw_area (widget->parent, + bounds.x0, + bounds.y0, + nautilus_art_irect_get_width (&bounds), + nautilus_art_irect_get_height (&bounds)); + } +} + +static gint +button_focus_out_event_callback (GtkWidget *widget, + GdkEventFocus *event, + gpointer callback_data) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + button_leave_callback (widget, callback_data); + + return FALSE; +} + /** * nautilus_labeled_image_check_button_new: * @text: Text to use for label or NULL. @@ -1651,6 +1695,21 @@ nautilus_labeled_image_check_button_new (const char *text, gtk_container_add (GTK_CONTAINER (check_button), labeled_image); gtk_widget_show (labeled_image); + /* + * Workaround some bugs in GtkCheckButton where the widget + * does not redraw properly after leave or focus out events + */ + gtk_signal_connect_while_alive (GTK_OBJECT (check_button), + "leave", + GTK_SIGNAL_FUNC (button_leave_callback), + NULL, + GTK_OBJECT (check_button)); + gtk_signal_connect_while_alive (GTK_OBJECT (check_button), + "focus_out_event", + GTK_SIGNAL_FUNC (button_focus_out_event_callback), + NULL, + GTK_OBJECT (check_button)); + return check_button; } @@ -1965,3 +2024,14 @@ nautilus_labeled_image_set_text_color (NautilusLabeledImage *labeled_image, } } +void +nautilus_labeled_image_set_label_never_smooth (NautilusLabeledImage *labeled_image, + gboolean never_smooth) +{ + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (labeled_image)); + + if (labeled_image->details->label != NULL) { + nautilus_label_set_never_smooth (NAUTILUS_LABEL (labeled_image->details->label), + never_smooth); + } +} diff --git a/libnautilus-private/nautilus-labeled-image.h b/libnautilus-private/nautilus-labeled-image.h index 26d9491e0..9be437b68 100644 --- a/libnautilus-private/nautilus-labeled-image.h +++ b/libnautilus-private/nautilus-labeled-image.h @@ -158,6 +158,8 @@ void nautilus_labeled_image_set_smooth_drop_shadow_color (Nautilu guint32 drop_shadow_color); void nautilus_labeled_image_set_text_color (NautilusLabeledImage *labeled_image, guint32 text_color); +void nautilus_labeled_image_set_label_never_smooth (NautilusLabeledImage *labeled_image, + gboolean never_smooth); END_GNOME_DECLS diff --git a/libnautilus-private/nautilus-wrap-table.c b/libnautilus-private/nautilus-wrap-table.c new file mode 100644 index 000000000..fb51a881f --- /dev/null +++ b/libnautilus-private/nautilus-wrap-table.c @@ -0,0 +1,939 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-wrap-box.c - A table that can wrap its contents as needed. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#include <config.h> + +#include "nautilus-wrap-table.h" + +#include "nautilus-gtk-macros.h" +#include "nautilus-gtk-extensions.h" +#include "nautilus-art-extensions.h" +#include "nautilus-art-gtk-extensions.h" + +#include <gtk/gtkmain.h> +#include <gtk/gtkviewport.h> + +/* Arguments */ +enum +{ + ARG_0, + ARG_X_SPACING, + ARG_Y_SPACING, + ARG_X_JUSTIFICATION, + ARG_Y_JUSTIFICATION, + ARG_HOMOGENEOUS, +}; + +/* Detail member struct */ +struct NautilusWrapTableDetails +{ + guint x_spacing; + guint y_spacing; + NautilusJustification x_justification; + NautilusJustification y_justification; + gboolean homogeneous; + GList *items; +}; + +/* GtkObjectClass methods */ +static void nautilus_wrap_table_initialize_class (NautilusWrapTableClass *wrap_table_class); +static void nautilus_wrap_table_initialize (NautilusWrapTable *wrap); +static void nautilus_wrap_table_destroy (GtkObject *object); +static void nautilus_wrap_table_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void nautilus_wrap_table_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +/* GtkWidgetClass methods */ +static void nautilus_wrap_table_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static int nautilus_wrap_table_expose_event (GtkWidget *widget, + GdkEventExpose *event); +static void nautilus_wrap_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void nautilus_wrap_table_map (GtkWidget *widget); +static void nautilus_wrap_table_unmap (GtkWidget *widget); + +/* GtkContainerClass methods */ +static void nautilus_wrap_table_add (GtkContainer *container, + GtkWidget *widget); +static void nautilus_wrap_table_remove (GtkContainer *container, + GtkWidget *widget); +static void nautilus_wrap_table_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GtkType nautilus_wrap_table_child_type (GtkContainer *container); + + +/* Private NautilusWrapTable methods */ +static ArtIRect wrap_table_art_irect_max_frame (const ArtIRect *one, + const ArtIRect *two); +static ArtIRect wrap_table_get_max_child_frame (const NautilusWrapTable *wrap_table); +static ArtIRect wrap_table_get_content_frame (const NautilusWrapTable *wrap_table); +static ArtIRect wrap_table_get_content_bounds (const NautilusWrapTable *wrap_table); +static NautilusArtIPoint wrap_table_get_scroll_offset (const NautilusWrapTable *wrap_table); +static GtkWidget * wrap_table_find_child_at_point (const NautilusWrapTable *wrap_table, + int x, + int y); +static void wrap_table_layout (NautilusWrapTable *wrap_table); + +NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusWrapTable, nautilus_wrap_table, GTK_TYPE_CONTAINER) + +/* Class init methods */ +static void +nautilus_wrap_table_initialize_class (NautilusWrapTableClass *wrap_table_class) +{ + GtkObjectClass *object_class = GTK_OBJECT_CLASS (wrap_table_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (wrap_table_class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (wrap_table_class); + + /* GtkObjectClass */ + object_class->destroy = nautilus_wrap_table_destroy; + object_class->set_arg = nautilus_wrap_table_set_arg; + object_class->get_arg = nautilus_wrap_table_get_arg; + + /* GtkWidgetClass */ + widget_class->size_request = nautilus_wrap_table_size_request; + widget_class->size_allocate = nautilus_wrap_table_size_allocate; + widget_class->expose_event = nautilus_wrap_table_expose_event; + widget_class->map = nautilus_wrap_table_map; + widget_class->unmap = nautilus_wrap_table_unmap; + + /* GtkContainerClass */ + container_class->add = nautilus_wrap_table_add; + container_class->remove = nautilus_wrap_table_remove; + container_class->forall = nautilus_wrap_table_forall; + container_class->child_type = nautilus_wrap_table_child_type; + + /* Arguments */ + gtk_object_add_arg_type ("NautilusWrapTable::x_spacing", + GTK_TYPE_UINT, + GTK_ARG_READWRITE, + ARG_X_SPACING); + gtk_object_add_arg_type ("NautilusWrapTable::y_spacing", + GTK_TYPE_UINT, + GTK_ARG_READWRITE, + ARG_Y_SPACING); + gtk_object_add_arg_type ("NautilusWrapTable::x_justification", + GTK_TYPE_ENUM, + GTK_ARG_READWRITE, + ARG_X_JUSTIFICATION); + gtk_object_add_arg_type ("NautilusWrapTable::y_justification", + GTK_TYPE_ENUM, + GTK_ARG_READWRITE, + ARG_Y_JUSTIFICATION); + gtk_object_add_arg_type ("NautilusWrapTable::homogeneous", + GTK_TYPE_BOOL, + GTK_ARG_READWRITE, + ARG_HOMOGENEOUS); +} + +void +nautilus_wrap_table_initialize (NautilusWrapTable *wrap_table) +{ + GTK_WIDGET_SET_FLAGS (wrap_table, GTK_NO_WINDOW); + + wrap_table->details = g_new0 (NautilusWrapTableDetails, 1); + wrap_table->details->x_justification = NAUTILUS_JUSTIFICATION_BEGINNING; + wrap_table->details->y_justification = NAUTILUS_JUSTIFICATION_END; +} + +/* GtkObjectClass methods */ +static void +nautilus_wrap_table_destroy (GtkObject *object) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (object)); + + wrap_table = NAUTILUS_WRAP_TABLE (object); + + /* + * Chain destroy before freeing our details. + * The details will be used in the nautilus_wrap_box_remove () + * method as a result of the children being killed. + */ + NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); + + g_list_free (wrap_table->details->items); + + g_free (wrap_table->details); +} + +static void +nautilus_wrap_table_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (object)); + + wrap_table = NAUTILUS_WRAP_TABLE (object); + + switch (arg_id) + { + case ARG_X_SPACING: + nautilus_wrap_table_set_x_spacing (wrap_table, GTK_VALUE_UINT (*arg)); + break; + + case ARG_Y_SPACING: + nautilus_wrap_table_set_y_spacing (wrap_table, GTK_VALUE_UINT (*arg)); + break; + + case ARG_X_JUSTIFICATION: + nautilus_wrap_table_set_x_justification (wrap_table, GTK_VALUE_ENUM (*arg)); + break; + + case ARG_Y_JUSTIFICATION: + nautilus_wrap_table_set_y_justification (wrap_table, GTK_VALUE_ENUM (*arg)); + break; + + case ARG_HOMOGENEOUS: + nautilus_wrap_table_set_homogeneous (wrap_table, GTK_VALUE_BOOL (*arg)); + break; + + default: + g_assert_not_reached (); + } +} + +static void +nautilus_wrap_table_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (object)); + + wrap_table = NAUTILUS_WRAP_TABLE (object); + + switch (arg_id) + { + case ARG_X_SPACING: + GTK_VALUE_UINT (*arg) = nautilus_wrap_table_get_x_spacing (wrap_table); + break; + + case ARG_Y_SPACING: + GTK_VALUE_UINT (*arg) = nautilus_wrap_table_get_y_spacing (wrap_table); + break; + + case ARG_X_JUSTIFICATION: + GTK_VALUE_ENUM (*arg) = nautilus_wrap_table_get_x_justification (wrap_table); + break; + + case ARG_Y_JUSTIFICATION: + GTK_VALUE_ENUM (*arg) = nautilus_wrap_table_get_y_justification (wrap_table); + break; + + case ARG_HOMOGENEOUS: + GTK_VALUE_BOOL (*arg) = nautilus_wrap_table_get_homogeneous (wrap_table); + break; + + default: + g_assert_not_reached (); + } +} + +/* GtkWidgetClass methods */ +static void +nautilus_wrap_table_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + NautilusWrapTable *wrap_table; + ArtIRect content_frame; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + g_return_if_fail (requisition != NULL); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + content_frame = wrap_table_get_content_frame (wrap_table); + + /* The -1 tells Satan to use as much space as is available */ + requisition->width = -1; + requisition->height = content_frame.y1 + GTK_CONTAINER (widget)->border_width * 2; +} + +static void +nautilus_wrap_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + g_return_if_fail (allocation != NULL); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + widget->allocation = *allocation; + + wrap_table_layout (wrap_table); +} + +static int +nautilus_wrap_table_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + NautilusWrapTable *wrap_table; + GList *iterator; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (widget), TRUE); + g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), TRUE); + g_return_val_if_fail (event != NULL, TRUE); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + GdkEventExpose item_event; + + item = iterator->data; + item_event = *event; + + if (GTK_WIDGET_DRAWABLE (item) && + GTK_WIDGET_NO_WINDOW (item) && + gtk_widget_intersect (item, &event->area, &item_event.area)) { + gtk_widget_event (item, (GdkEvent *) &item_event); + } + } + + return FALSE; +} + +static void +nautilus_wrap_table_map (GtkWidget *widget) +{ + NautilusWrapTable *wrap_table; + GList *iterator; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + + item = iterator->data; + + if (GTK_WIDGET_VISIBLE (item) && !GTK_WIDGET_MAPPED (item)) { + gtk_widget_map (item); + } + } +} + +static void +nautilus_wrap_table_unmap (GtkWidget *widget) +{ + NautilusWrapTable *wrap_table; + GList *iterator; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (widget)); + + wrap_table = NAUTILUS_WRAP_TABLE (widget); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + + item = iterator->data; + + if (GTK_WIDGET_VISIBLE (item) && GTK_WIDGET_MAPPED (item)) { + gtk_widget_unmap (item); + } + } +} + +/* GtkContainerClass methods */ +static void +nautilus_wrap_table_add (GtkContainer *container, + GtkWidget *child) +{ + NautilusWrapTable *wrap_table; + + g_return_if_fail (container != NULL); + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + wrap_table = NAUTILUS_WRAP_TABLE (container); + + gtk_widget_set_parent (child, GTK_WIDGET (container)); + + wrap_table->details->items = g_list_append (wrap_table->details->items, child); + + if (GTK_WIDGET_REALIZED (container)) { + gtk_widget_realize (child); + } + + if (GTK_WIDGET_VISIBLE (container) && GTK_WIDGET_VISIBLE (child)) { + if (GTK_WIDGET_MAPPED (container)) { + gtk_widget_map (child); + } + + gtk_widget_queue_resize (child); + } +} + +static void +nautilus_wrap_table_remove (GtkContainer *container, + GtkWidget *child) +{ + NautilusWrapTable *wrap_table; + gboolean child_was_visible; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + wrap_table = NAUTILUS_WRAP_TABLE (container);; + + child_was_visible = GTK_WIDGET_VISIBLE (child); + gtk_widget_unparent (child); + wrap_table->details->items = g_list_remove (wrap_table->details->items, child); + + if (child_was_visible) { + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +nautilus_wrap_table_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + NautilusWrapTable *wrap_table; + GList *node; + GList *next; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (container)); + g_return_if_fail (callback != NULL); + + wrap_table = NAUTILUS_WRAP_TABLE (container);; + + for (node = wrap_table->details->items; node != NULL; node = next) { + g_assert (GTK_IS_WIDGET (node->data)); + next = node->next; + (* callback) (GTK_WIDGET (node->data), callback_data); + } +} + +static GtkType +nautilus_wrap_table_child_type (GtkContainer *container) +{ + return GTK_TYPE_WIDGET; +} + +/* Private NautilusWrapTable methods */ +static void +wrap_table_layout (NautilusWrapTable *wrap_table) +{ + GList *iterator; + NautilusArtIPoint pos; + ArtIRect max_child_frame; + ArtIRect content_bounds; + + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + max_child_frame = wrap_table_get_max_child_frame (wrap_table); + content_bounds = wrap_table_get_content_bounds (wrap_table); + pos.x = content_bounds.x0; + pos.y = content_bounds.y0; + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *item; + + item = iterator->data; + + if (GTK_WIDGET_VISIBLE (item)) { + GtkAllocation item_allocation; + + if (wrap_table->details->homogeneous) { + item_allocation.x = pos.x; + item_allocation.y = pos.y; + item_allocation.width = max_child_frame.x1; + item_allocation.height = max_child_frame.y1; + + if ((pos.x + max_child_frame.x1) > content_bounds.x1) { + pos.x = content_bounds.x0 + wrap_table->details->x_spacing + max_child_frame.x1; + pos.y += (max_child_frame.y1 + wrap_table->details->y_spacing); + item_allocation.x = content_bounds.x0; + item_allocation.y = pos.y; + } else { + pos.x += (wrap_table->details->x_spacing + max_child_frame.x1); + } + } else { + GtkRequisition item_requisition; + + gtk_widget_size_request (item, &item_requisition); + + item_allocation.x = pos.x; + item_allocation.y = pos.y; + item_allocation.width = item_requisition.width; + item_allocation.height = item_requisition.height; + + g_assert (item_allocation.width <= max_child_frame.x1); + g_assert (item_allocation.height <= max_child_frame.y1); + + if ((pos.x + max_child_frame.x1) > content_bounds.x1) { + pos.x = content_bounds.x0 + wrap_table->details->x_spacing + max_child_frame.x1; + pos.y += (max_child_frame.y1 + wrap_table->details->y_spacing); + item_allocation.x = content_bounds.x0; + item_allocation.y = pos.y; + } else { + pos.x += (wrap_table->details->x_spacing + max_child_frame.x1); + } + + switch (wrap_table->details->x_justification) { + case NAUTILUS_JUSTIFICATION_MIDDLE: + item_allocation.x += (max_child_frame.x1 - (int) item_allocation.width) / 2; + break; + case NAUTILUS_JUSTIFICATION_END: + item_allocation.x += (max_child_frame.x1 - (int) item_allocation.width); + break; + default: + } + + switch (wrap_table->details->y_justification) { + case NAUTILUS_JUSTIFICATION_MIDDLE: + item_allocation.y += (max_child_frame.y1 - (int) item_allocation.height) / 2; + break; + case NAUTILUS_JUSTIFICATION_END: + item_allocation.y += (max_child_frame.y1 - (int) item_allocation.height); + break; + default: + } + } + + gtk_widget_size_allocate (item, &item_allocation); + } + } +} + +static ArtIRect +wrap_table_art_irect_max_frame (const ArtIRect *one, + const ArtIRect *two) +{ + ArtIRect max; + + g_return_val_if_fail (one != NULL, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (two != NULL, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (one->x0 == 0, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (one->y0 == 0, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (two->x0 == 0, NAUTILUS_ART_IRECT_EMPTY); + g_return_val_if_fail (two->y0 == 0, NAUTILUS_ART_IRECT_EMPTY); + + max.x0 = 0; + max.y0 = 0; + max.x1 = MAX (one->x1, two->x1); + max.y1 = MAX (one->y1, two->y1); + + return max; +} + +static ArtIRect +wrap_table_get_max_child_frame (const NautilusWrapTable *wrap_table) +{ + ArtIRect max; + GList *iterator; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IRECT_EMPTY); + + max = NAUTILUS_ART_IRECT_EMPTY; + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *child; + + child = iterator->data; + + if (GTK_WIDGET_VISIBLE (child)) { + GtkRequisition child_requisition; + ArtIRect child_frame; + + gtk_widget_size_request (child, &child_requisition); + + child_frame.x0 = 0; + child_frame.y0 = 0; + child_frame.x1 = child_requisition.width; + child_frame.y1 = child_requisition.height; + + max = wrap_table_art_irect_max_frame (&child_frame, &max); + } + } + + return max; +} + +static int +wrap_table_get_num_fitting (int available, + int spacing, + int max_child_size) +{ + int num; + + g_return_val_if_fail (available >= 0, 0); + g_return_val_if_fail (max_child_size > 0, 0); + g_return_val_if_fail (spacing >= 0, 0); + + num = (available + spacing) / (max_child_size + spacing); + num = MAX (num, 1); + + return num; +} + +static ArtIRect +wrap_table_get_content_frame (const NautilusWrapTable *wrap_table) +{ + ArtIRect content_frame; + guint num_children; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IRECT_EMPTY); + + content_frame = NAUTILUS_ART_IRECT_EMPTY; + + num_children = g_list_length (wrap_table->details->items); + + if (num_children > 0) { + ArtIRect max_child_frame; + ArtIRect frame; + int num_cols; + int num_rows; + + frame = nautilus_irect_gtk_widget_get_frame (GTK_WIDGET (wrap_table)); + max_child_frame = wrap_table_get_max_child_frame (wrap_table); + + max_child_frame.x1 = MAX (max_child_frame.x1, 1); + max_child_frame.y1 = MAX (max_child_frame.y1, 1); + + num_cols = wrap_table_get_num_fitting (frame.x1, + wrap_table->details->x_spacing, + max_child_frame.x1); + num_rows = num_children / num_cols; + + if ((num_children % num_rows) > 0) { + num_rows++; + } + + content_frame.x1 = frame.x1; + content_frame.y1 = num_rows * max_child_frame.y1; + } + + return content_frame; +} + +static ArtIRect +wrap_table_get_content_bounds (const NautilusWrapTable *wrap_table) +{ + ArtIRect content_bounds; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IRECT_EMPTY); + + content_bounds = nautilus_irect_gtk_widget_get_bounds (GTK_WIDGET (wrap_table)); + + content_bounds.x0 += GTK_CONTAINER (wrap_table)->border_width; + content_bounds.y0 += GTK_CONTAINER (wrap_table)->border_width; + content_bounds.x1 -= GTK_CONTAINER (wrap_table)->border_width; + content_bounds.y1 -= GTK_CONTAINER (wrap_table)->border_width; + + return content_bounds; +} + +static NautilusArtIPoint +wrap_table_get_scroll_offset (const NautilusWrapTable *wrap_table) +{ + NautilusArtIPoint scroll_offset; + GtkWidget *parent; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NAUTILUS_ART_IPOINT_ZERO); + + scroll_offset = NAUTILUS_ART_IPOINT_ZERO; + + parent = GTK_WIDGET (wrap_table)->parent; + + /* + * FIXME: It lame we have to hardcode for a possible viewport + * parent here. Theres probably a better way to do this + */ + if (GTK_IS_VIEWPORT (parent)) { + GtkViewport *viewport; + + viewport = GTK_VIEWPORT (parent); + + gdk_window_get_position (viewport->bin_window, + &scroll_offset.x, + &scroll_offset.y); + } + + return scroll_offset; +} + +static GtkWidget * +wrap_table_find_child_at_point (const NautilusWrapTable *wrap_table, + int x, + int y) +{ + GList *iterator; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NULL); + + for (iterator = wrap_table->details->items; iterator; iterator = iterator->next) { + GtkWidget *child; + + child = iterator->data; + + if (GTK_WIDGET_VISIBLE (child)) { + ArtIRect child_bounds; + + child_bounds = nautilus_irect_gtk_widget_get_bounds (child); + + if (nautilus_art_irect_contains_point (&child_bounds, x, y)) { + return child; + } + } + } + + return NULL; +} + +/** + * nautilus_wrap_table_new: + * + */ +GtkWidget* +nautilus_wrap_table_new (gboolean homogeneous) +{ + NautilusWrapTable *wrap_table; + + wrap_table = NAUTILUS_WRAP_TABLE (gtk_widget_new (nautilus_wrap_table_get_type (), NULL)); + + nautilus_wrap_table_set_homogeneous (wrap_table, homogeneous); + + return GTK_WIDGET (wrap_table); +} + +/** + * nautilus_wrap_table_set_x_spacing: + * @wrap_table: A NautilusWrapTable. + * @x_spacing: The new horizontal spacing between wraps. + * + */ +void +nautilus_wrap_table_set_x_spacing (NautilusWrapTable *wrap_table, + guint x_spacing) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->x_spacing == x_spacing) { + return; + } + + wrap_table->details->x_spacing = x_spacing; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_spacing: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +guint +nautilus_wrap_table_get_x_spacing (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->x_spacing; +} + +/** + * nautilus_wrap_table_set_y_spacing: + * @wrap_table: A NautilusWrapTable. + * @y_spacing: The new horizontal spacing between wraps. + * + */ +void +nautilus_wrap_table_set_y_spacing (NautilusWrapTable *wrap_table, + guint y_spacing) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->y_spacing == y_spacing) { + return; + } + + wrap_table->details->y_spacing = y_spacing; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_spacing: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +guint +nautilus_wrap_table_get_y_spacing (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->y_spacing; +} + +/** + * nautilus_wrap_table_find_child_at_event_point: + * @wrap_table: A NautilusWrapTable. + * @x: Event x; + * @y: Event y; + * + * Returns: Child found at given coordinates or NULL of no child is found. + */ +GtkWidget * +nautilus_wrap_table_find_child_at_event_point (const NautilusWrapTable *wrap_table, + int x, + int y) +{ + NautilusArtIPoint scroll_offset; + + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), NULL); + + scroll_offset = wrap_table_get_scroll_offset (wrap_table); + + return wrap_table_find_child_at_point (wrap_table, + x + ABS (scroll_offset.x), + y + ABS (scroll_offset.y)); +} + +/** + * nautilus_wrap_table_set_x_justification: + * @wrap_table: A NautilusWrapTable. + * @x_justification: The new horizontal justification between wraps. + * + */ +void +nautilus_wrap_table_set_x_justification (NautilusWrapTable *wrap_table, + NautilusJustification x_justification) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + g_return_if_fail (x_justification >= NAUTILUS_JUSTIFICATION_BEGINNING); + g_return_if_fail (x_justification <= NAUTILUS_JUSTIFICATION_END); + + if (wrap_table->details->x_justification == x_justification) { + return; + } + + wrap_table->details->x_justification = x_justification; + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_justification: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal justification between wraps. + */ +NautilusJustification +nautilus_wrap_table_get_x_justification (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->x_justification; +} + +/** + * nautilus_wrap_table_set_y_justification: + * @wrap_table: A NautilusWrapTable. + * @y_justification: The new horizontal justification between wraps. + * + */ +void +nautilus_wrap_table_set_y_justification (NautilusWrapTable *wrap_table, + NautilusJustification y_justification) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + g_return_if_fail (y_justification >= NAUTILUS_JUSTIFICATION_BEGINNING); + g_return_if_fail (y_justification <= NAUTILUS_JUSTIFICATION_END); + + if (wrap_table->details->y_justification == y_justification) { + return; + } + + wrap_table->details->y_justification = y_justification; + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_justification: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal justification between wraps. + */ +NautilusJustification +nautilus_wrap_table_get_y_justification (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->y_justification; +} + +/** + * nautilus_wrap_table_set_homogeneous: + * @wrap_table: A NautilusWrapTable. + * @homogeneous: The new horizontal spacing between wraps. + * + */ +void +nautilus_wrap_table_set_homogeneous (NautilusWrapTable *wrap_table, + gboolean homogeneous) +{ + g_return_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table)); + + if (wrap_table->details->homogeneous == homogeneous) { + return; + } + + wrap_table->details->homogeneous = homogeneous; + + gtk_widget_queue_resize (GTK_WIDGET (wrap_table)); +} + +/** + * nautilus_wrap_table_get_item_spacing: + * @wrap_table: A NautilusWrapTable. + * + * Returns: The horizontal spacing between wraps. + */ +gboolean +nautilus_wrap_table_get_homogeneous (const NautilusWrapTable *wrap_table) +{ + g_return_val_if_fail (NAUTILUS_IS_WRAP_TABLE (wrap_table), 0); + + return wrap_table->details->homogeneous; +} diff --git a/libnautilus-private/nautilus-wrap-table.h b/libnautilus-private/nautilus-wrap-table.h new file mode 100644 index 000000000..0a18a6724 --- /dev/null +++ b/libnautilus-private/nautilus-wrap-table.h @@ -0,0 +1,90 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* nautilus-wrap-table.h - A table that can wrap its contents as needed. + + Copyright (C) 2000 Eazel, Inc. + + The Gnome 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 Gnome 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 Gnome 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 <ramiro@eazel.com> +*/ + +#ifndef NAUTILUS_WRAP_TABLE_H +#define NAUTILUS_WRAP_TABLE_H + +#include <gtk/gtkcontainer.h> +#include <libgnome/gnome-defs.h> + +BEGIN_GNOME_DECLS + +#define NAUTILUS_TYPE_WRAP_TABLE (nautilus_wrap_table_get_type ()) +#define NAUTILUS_WRAP_TABLE(obj) (GTK_CHECK_CAST ((obj), NAUTILUS_TYPE_WRAP_TABLE, NautilusWrapTable)) +#define NAUTILUS_WRAP_TABLE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_WRAP_TABLE, NautilusWrapTableClass)) +#define NAUTILUS_IS_WRAP_TABLE(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_WRAP_TABLE)) +#define NAUTILUS_IS_WRAP_TABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_WRAP_TABLE)) + +typedef struct NautilusWrapTable NautilusWrapTable; +typedef struct NautilusWrapTableClass NautilusWrapTableClass; +typedef struct NautilusWrapTableDetails NautilusWrapTableDetails; + +struct NautilusWrapTable +{ + /* Superclass */ + GtkContainer container; + + /* Private things */ + NautilusWrapTableDetails *details; +}; + +struct NautilusWrapTableClass +{ + GtkContainerClass parent_class; +}; + +typedef enum +{ + NAUTILUS_JUSTIFICATION_BEGINNING, + NAUTILUS_JUSTIFICATION_MIDDLE, + NAUTILUS_JUSTIFICATION_END +} NautilusJustification; + +/* Public GtkWrapTable methods */ +GtkType nautilus_wrap_table_get_type (void); +GtkWidget * nautilus_wrap_table_new (gboolean homogeneous); +void nautilus_wrap_table_set_x_spacing (NautilusWrapTable *wrap_table, + guint x_spacing); +guint nautilus_wrap_table_get_x_spacing (const NautilusWrapTable *wrap_table); +void nautilus_wrap_table_set_y_spacing (NautilusWrapTable *wrap_table, + guint y_spacing); +guint nautilus_wrap_table_get_y_spacing (const NautilusWrapTable *wrap_table); +GtkWidget * nautilus_wrap_table_find_child_at_event_point (const NautilusWrapTable *wrap_table, + int x, + int y); +void nautilus_wrap_table_set_x_justification (NautilusWrapTable *wrap_table, + GtkJustification justification); +NautilusJustification nautilus_wrap_table_get_x_justification (const NautilusWrapTable *wrap_table); +void nautilus_wrap_table_set_y_justification (NautilusWrapTable *wrap_table, + NautilusJustification justification); +NautilusJustification nautilus_wrap_table_get_y_justification (const NautilusWrapTable *wrap_table); +void nautilus_wrap_table_set_homogeneous (NautilusWrapTable *wrap_table, + gboolean homogeneous); +gboolean nautilus_wrap_table_get_homogeneous (const NautilusWrapTable *wrap_table); + +END_GNOME_DECLS + +#endif /* NAUTILUS_WRAP_TABLE_H */ + + diff --git a/test/.cvsignore b/test/.cvsignore index 617de9093..3a3c9e4bb 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -11,6 +11,7 @@ test-nautilus-font test-nautilus-font-picker test-nautilus-font-simple test-nautilus-image +test-nautilus-image-table test-nautilus-image-background test-nautilus-image-scrolled test-nautilus-image-simple diff --git a/test/Makefile.am b/test/Makefile.am index 1eff0a8ff..4a27d2ac3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -4,6 +4,7 @@ INCLUDES =\ -I$(top_srcdir) \ -I$(top_builddir) \ -I$(top_builddir)/libnautilus \ + -I$(top_srcdir)/cut-n-paste-code\ $(BONOBO_CFLAGS) \ $(OAF_CFLAGS) \ $(GCONF_CFLAGS) \ @@ -39,6 +40,7 @@ noinst_PROGRAMS =\ test-nautilus-image-scrolled \ test-nautilus-image-simple \ test-nautilus-image-tile \ + test-nautilus-image-table \ test-nautilus-label \ test-nautilus-label-background \ test-nautilus-label-flavorful \ @@ -65,6 +67,7 @@ test_nautilus_font_picker_SOURCES = test-nautilus-font-picker.c test_nautilus_font_simple_SOURCES = test-nautilus-font-simple.c test.c test_nautilus_image_SOURCES = test-nautilus-image.c test_nautilus_image_background_SOURCES = test-nautilus-image-background.c test.c +test_nautilus_image_table_SOURCES = test-nautilus-image-table.c test.c test_nautilus_image_scrolled_SOURCES = test-nautilus-image-scrolled.c test.c test_nautilus_image_simple_SOURCES = test-nautilus-image-simple.c test_nautilus_image_tile_SOURCES = test-nautilus-image-tile.c test.c diff --git a/test/test-nautilus-image-table.c b/test/test-nautilus-image-table.c new file mode 100644 index 000000000..53fb7c1b3 --- /dev/null +++ b/test/test-nautilus-image-table.c @@ -0,0 +1,253 @@ +#include "test.h" + +#include <libnautilus-extensions/nautilus-image-table.h> +#include <libnautilus-extensions/nautilus-viewport.h> + +static const char pixbuf_name[] = "/usr/share/pixmaps/gnome-globe.png"; + +static const char *names[] = +{ + "Tomaso Albinoni", + "Isaac Albéniz", + "Georges Bizet", + "Luigi Boccherini", + "Alexander Borodin", + "Johannes Brahms", + "Max Bruch", + "Anton Bruckner", + "Frédéric Chopin", + "Aaron Copland", + "John Corigliano", + "Claude Debussy", + "Léo Delibes", + "Antonín Dvorák", + "Edward Elgar", + "Manuel de Falla", + "George Gershwin", + "Alexander Glazunov", + "Mikhail Glinka", + "Enrique Granados", + "Edvard Grieg", + "Joseph Haydn", + "Scott Joplin", + "Franz Liszt", + "Gustav Mahler", + "Igor Markevitch", + "Felix Mendelssohn", + "Modest Mussorgsky", + "Sergei Prokofiev", + "Giacomo Puccini", + "Maurice Ravel", + "Ottorino Respighi", + "Joaquin Rodrigo", + "Gioachino Rossini", + "Domenico Scarlatti", + "Franz Schubert", + "Robert Schumann", + "Jean Sibelius", + "Bedrich Smetana", + "Johann Strauss", + "Igor Stravinsky", + "Giuseppe Verdi", + "Antonio Vivaldi", + "Richard Wagner", +}; + +static GtkWidget * +labeled_image_new (const char *text, + const char *icon_name) +{ + GtkWidget *image; + GdkPixbuf *pixbuf = NULL; + + if (icon_name) { + const float sizes[] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0 }; + pixbuf = test_pixbuf_new_named (icon_name, sizes[random () % NAUTILUS_N_ELEMENTS (sizes)]); + } + + image = nautilus_labeled_image_new (text, pixbuf); + + nautilus_labeled_image_set_background_mode (NAUTILUS_LABELED_IMAGE (image), + NAUTILUS_SMOOTH_BACKGROUND_SOLID_COLOR); + nautilus_labeled_image_set_solid_background_color (NAUTILUS_LABELED_IMAGE (image), + 0xFFFFFF); + + nautilus_gdk_pixbuf_unref_if_not_null (pixbuf); + + return image; +} + + +static void +image_table_child_enter_callback (GtkWidget *image_table, + GtkWidget *item, + gpointer callback_data) +{ + char *text; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (image_table)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (item)); + + text = nautilus_labeled_image_get_text (NAUTILUS_LABELED_IMAGE (item)); + +// g_print ("%s(%s)\n", __FUNCTION__, text); +} + +static void +image_table_child_leave_callback (GtkWidget *image_table, + GtkWidget *item, + gpointer callback_data) +{ + char *text; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (image_table)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (item)); + + text = nautilus_labeled_image_get_text (NAUTILUS_LABELED_IMAGE (item)); + +// g_print ("%s(%s)\n", __FUNCTION__, text); +} + +static void +image_table_child_pressed_callback (GtkWidget *image_table, + GtkWidget *item, + gpointer callback_data) +{ + char *text; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (image_table)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (item)); + + text = nautilus_labeled_image_get_text (NAUTILUS_LABELED_IMAGE (item)); + + g_print ("%s(%s)\n", __FUNCTION__, text); +} + +static void +image_table_child_released_callback (GtkWidget *image_table, + GtkWidget *item, + gpointer callback_data) +{ + char *text; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (image_table)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (item)); + + text = nautilus_labeled_image_get_text (NAUTILUS_LABELED_IMAGE (item)); + + g_print ("%s(%s)\n", __FUNCTION__, text); +} + +static void +image_table_child_clicked_callback (GtkWidget *image_table, + GtkWidget *item, + gpointer callback_data) +{ + char *text; + + g_return_if_fail (NAUTILUS_IS_IMAGE_TABLE (image_table)); + g_return_if_fail (NAUTILUS_IS_LABELED_IMAGE (item)); + + text = nautilus_labeled_image_get_text (NAUTILUS_LABELED_IMAGE (item)); + + g_print ("%s(%s)\n", __FUNCTION__, text); +} + +static GtkWidget * +image_table_new_scrolled (void) +{ + GtkWidget *scrolled; + GtkWidget *viewport; + GtkWidget *window; + GtkWidget *image_table; + int i; + + window = test_window_new ("Image Table Test", 10); + + gtk_window_set_default_size (GTK_WINDOW (window), 400, 300); + + /* Scrolled window */ + scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (window), scrolled); + + /* Viewport */ + viewport = nautilus_viewport_new (NULL, NULL); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (scrolled), viewport); + + image_table = nautilus_image_table_new (FALSE); + nautilus_wrap_table_set_x_justification (NAUTILUS_WRAP_TABLE (image_table), + NAUTILUS_JUSTIFICATION_MIDDLE); + nautilus_wrap_table_set_y_justification (NAUTILUS_WRAP_TABLE (image_table), + NAUTILUS_JUSTIFICATION_END); + + gtk_container_add (GTK_CONTAINER (viewport), image_table); + + gtk_signal_connect (GTK_OBJECT (image_table), + "child_enter", + GTK_SIGNAL_FUNC (image_table_child_enter_callback), + NULL); + + gtk_signal_connect (GTK_OBJECT (image_table), + "child_leave", + GTK_SIGNAL_FUNC (image_table_child_leave_callback), + NULL); + + gtk_signal_connect (GTK_OBJECT (image_table), + "child_pressed", + GTK_SIGNAL_FUNC (image_table_child_pressed_callback), + NULL); + + gtk_signal_connect (GTK_OBJECT (image_table), + "child_released", + GTK_SIGNAL_FUNC (image_table_child_released_callback), + NULL); + + gtk_signal_connect (GTK_OBJECT (image_table), + "child_clicked", + GTK_SIGNAL_FUNC (image_table_child_clicked_callback), + NULL); + + //test_gtk_widget_set_background_color (viewport, "white"); + nautilus_gtk_widget_set_background_color (viewport, "white:red"); + + for (i = 0; i < 100; i++) { + char *text; + GtkWidget *image; + + text = g_strdup_printf ("%s %d", + names[random () % NAUTILUS_N_ELEMENTS (names)], + i); + image = labeled_image_new (text, pixbuf_name); + g_free (text); + + gtk_container_add (GTK_CONTAINER (image_table), image); + gtk_widget_show (image); + } + + gtk_widget_show (viewport); + gtk_widget_show (scrolled); + gtk_widget_show (image_table); + + return window; +} + +int +main (int argc, char* argv[]) +{ + GtkWidget *window = NULL; + + test_init (&argc, &argv); + + window = image_table_new_scrolled (); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} |