summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamiro Estrugo <ramiro@src.gnome.org>2001-02-08 07:02:39 +0000
committerRamiro Estrugo <ramiro@src.gnome.org>2001-02-08 07:02:39 +0000
commit6767f2921b8965d0a34314a42be3e905f6561756 (patch)
treeb009863187c62631a289e9af76fc49a7769e38bc
parentb99145c84e6328d5f8060500474ab416caf9ed6d (diff)
downloadnautilus-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.
-rw-r--r--ChangeLog37
-rw-r--r--libnautilus-extensions/Makefile.am8
-rw-r--r--libnautilus-extensions/nautilus-clickable-image.c21
-rw-r--r--libnautilus-extensions/nautilus-clickable-image.h30
-rw-r--r--libnautilus-extensions/nautilus-image-table.c529
-rw-r--r--libnautilus-extensions/nautilus-image-table.h73
-rw-r--r--libnautilus-extensions/nautilus-labeled-image.c74
-rw-r--r--libnautilus-extensions/nautilus-labeled-image.h2
-rw-r--r--libnautilus-extensions/nautilus-wrap-table.c939
-rw-r--r--libnautilus-extensions/nautilus-wrap-table.h90
-rw-r--r--libnautilus-private/Makefile.am8
-rw-r--r--libnautilus-private/nautilus-clickable-image.c21
-rw-r--r--libnautilus-private/nautilus-clickable-image.h30
-rw-r--r--libnautilus-private/nautilus-image-table.c529
-rw-r--r--libnautilus-private/nautilus-image-table.h73
-rw-r--r--libnautilus-private/nautilus-labeled-image.c74
-rw-r--r--libnautilus-private/nautilus-labeled-image.h2
-rw-r--r--libnautilus-private/nautilus-wrap-table.c939
-rw-r--r--libnautilus-private/nautilus-wrap-table.h90
-rw-r--r--test/.cvsignore1
-rw-r--r--test/Makefile.am3
-rw-r--r--test/test-nautilus-image-table.c253
22 files changed, 3790 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index c8fc16a90..4fb56955d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;
+}