From 423b5c48178641c6ea5010d03b52fdc785188019 Mon Sep 17 00:00:00 2001 From: Darin Adler Date: Thu, 10 Feb 2000 00:33:49 +0000 Subject: [PATCH] Reworked the canvas item class used by the icon container. Straightened out the use of various coordinate systems and bounds calculations and removed much unused code inherited from the GdkPixbuf canvas item class that Andy cloned our code from. Changed the class so it doesn't scale icons any more -- we leave that to the icon factory so the scaled icons can be cached. * libnautilus/gnome-icon-container-dnd.c: * libnautilus/gnome-icon-container-private.h: * libnautilus/gnome-icon-container.c: * libnautilus/nautilus-icons-view-icon-item.c: * libnautilus/nautilus-icons-view-icon-item.h: Made extensive changes to the icon item class, including getting rid of the "x", "y", "width", and "height" attributes, adding a new "font" attribute, changing the "label" attribute name to "text" to be more consistent with other canvas items, simplifying the update logic for now (we can recomplicate it later if need be), changing the pixbuf to have a fixed size in pixels instead of being scaled with the pixels_per_unit and changing the pixbuf when we change zoom levels, and other misc. cleanup. (nautilus_icons_view_icon_item_get_arg): Fixed bug for "label" which would return a non-strdup'd piece of text. (draw_or_measure_text_box): Fixed bug where width of the selection box would be based on the length of the last line of text, not the widest, and extra GCs would be created for each line of text. * libnautilus/nautilus-icons-controller.h: * libnautilus/nautilus-icons-controller.c: (nautilus_icons_controller_get_icon_image): * src/file-manager/fm-icons-controller.c: (fm_icons_controller_get_icon_image): Changed the interface so that the icons controller specifies the icon as a NautilusScalableIcon instead of a GdkPixbuf. This lets the icon container get the appropriate icon for size as it zooms. * libnautilus/gdk-extensions.h: * libnautilus/gdk-extensions.c: (nautilus_gdk_font_equal): Added a version of gdk_font_equal that works with NULL for the font. Maybe we need a naming scheme for these NULL-tolerant variations on basic calls. * src/ntl-uri-map.c: (nautilus_navinfo_free): * src/ntl-window-msgs.c: (nautilus_window_change_location_2): Fixed a NULL dereference that would happen when @navi was NULL. * libnautilus/nautilus-directory.c: (nautilus_directory_try_to_read_metafile): Fixed error handling for case when gnome_vfs_read fails. Fixed error handling for case where metafile_info.size won't fit into a size_t. Switched back to g_malloc instead of g_alloca, since the size of a file might be too big for the stack. In the long run, we will feed the file data directly to the XML code, so this is a bit temporary. Removed the assert that Elliot added to help track down the giant files sizes coming from gnome-vfs; the failure in g_malloc will be easy to debug, unlike the failure in g_alloca. (The assert was added without a ChangeLog entry.) --- libnautilus-extensions/gdk-extensions.c | 18 + libnautilus-extensions/gdk-extensions.h | 3 + .../gnome-icon-container-dnd.c | 250 ++-- .../gnome-icon-container-private.h | 10 +- libnautilus-extensions/gnome-icon-container.c | 149 ++- .../nautilus-icons-controller.c | 2 +- .../nautilus-icons-controller.h | 27 +- .../nautilus-icons-view-icon-item.c | 1070 +++++++---------- .../nautilus-icons-view-icon-item.h | 7 +- libnautilus-private/gdk-extensions.c | 18 + libnautilus-private/gdk-extensions.h | 3 + .../gnome-icon-container-dnd.c | 250 ++-- .../gnome-icon-container-private.h | 10 +- libnautilus-private/gnome-icon-container.c | 149 ++- .../nautilus-icons-controller.c | 2 +- .../nautilus-icons-controller.h | 27 +- .../nautilus-icons-view-icon-item.c | 1070 +++++++---------- .../nautilus-icons-view-icon-item.h | 7 +- libnautilus/gdk-extensions.c | 18 + libnautilus/gdk-extensions.h | 3 + libnautilus/gnome-icon-container-dnd.c | 250 ++-- libnautilus/gnome-icon-container-private.h | 10 +- libnautilus/gnome-icon-container.c | 149 ++- libnautilus/nautilus-icons-controller.c | 2 +- libnautilus/nautilus-icons-controller.h | 27 +- libnautilus/nautilus-icons-view-icon-item.c | 1070 +++++++---------- libnautilus/nautilus-icons-view-icon-item.h | 7 +- src/file-manager/fm-icons-controller.c | 56 +- src/nautilus-window-manage-views.c | 3 +- src/ntl-window-msgs.c | 3 +- 30 files changed, 1943 insertions(+), 2727 deletions(-) diff --git a/libnautilus-extensions/gdk-extensions.c b/libnautilus-extensions/gdk-extensions.c index 73731dc41..7d7f2c286 100644 --- a/libnautilus-extensions/gdk-extensions.c +++ b/libnautilus-extensions/gdk-extensions.c @@ -393,6 +393,24 @@ nautilus_gdk_color_parse_with_white_default (const char *color_spec, } } +/** + * nautilus_gdk_font_equal + * @font_a_null_allowed: A font or NULL. + * @font_b_null_allowed: A font or NULL. + * + * Calls gdk_font_equal, unless one of the fonts is NULL. + */ +gboolean +nautilus_gdk_font_equal (GdkFont *font_a_null_allowed, + GdkFont *font_b_null_allowed) +{ + if (font_a_null_allowed == NULL) + return font_b_null_allowed == NULL; + if (font_b_null_allowed == NULL) + return FALSE; + return gdk_font_equal (font_a_null_allowed, font_b_null_allowed); +} + #if ! defined (NAUTILUS_OMIT_SELF_CHECK) static char * diff --git a/libnautilus-extensions/gdk-extensions.h b/libnautilus-extensions/gdk-extensions.h index f5dd0c27b..366303c1d 100644 --- a/libnautilus-extensions/gdk-extensions.h +++ b/libnautilus-extensions/gdk-extensions.h @@ -81,4 +81,7 @@ void nautilus_interpolate_color (gdouble ratio, const GdkColor *end_color, GdkColor *interpolated_color); +gboolean nautilus_gdk_font_equal (GdkFont *font_a_null_allowed, + GdkFont *font_b_null_allowed); + #endif /* GDK_EXTENSIONS_H */ diff --git a/libnautilus-extensions/gnome-icon-container-dnd.c b/libnautilus-extensions/gnome-icon-container-dnd.c index e01c1c43d..dd74f85ea 100644 --- a/libnautilus-extensions/gnome-icon-container-dnd.c +++ b/libnautilus-extensions/gnome-icon-container-dnd.c @@ -26,17 +26,15 @@ #include #include "gnome-icon-container-dnd.h" -#include "gnome-icon-container-private.h" -#include "nautilus-icons-view-icon-item.h" -#include "nautilus-background.h" -#include "nautilus-gtk-extensions.h" - -#include #include #include #include +#include "nautilus-glib-extensions.h" #include - +#include "nautilus-gtk-extensions.h" +#include "nautilus-background.h" +#include "gnome-icon-container-private.h" +#include typedef struct { char *uri; @@ -50,7 +48,6 @@ static GtkTargetEntry drag_types [] = { { GNOME_ICON_CONTAINER_DND_URI_LIST_TYPE, 0, GNOME_ICON_CONTAINER_DND_URI_LIST }, { GNOME_ICON_CONTAINER_DND_URL_TYPE, 0, GNOME_ICON_CONTAINER_DND_URL } }; -static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); static GtkTargetEntry drop_types [] = { { GNOME_ICON_CONTAINER_DND_GNOME_ICON_LIST_TYPE, 0, GNOME_ICON_CONTAINER_DND_GNOME_ICON_LIST }, @@ -58,7 +55,6 @@ static GtkTargetEntry drop_types [] = { { GNOME_ICON_CONTAINER_DND_URL_TYPE, 0, GNOME_ICON_CONTAINER_DND_URL }, { GNOME_ICON_CONTAINER_DND_COLOR_TYPE, 0, GNOME_ICON_CONTAINER_DND_COLOR } }; -static const int num_drop_types = sizeof (drop_types) / sizeof (drop_types[0]); static GnomeCanvasItem * create_selection_shadow (GnomeIconContainer *container, @@ -70,6 +66,7 @@ create_selection_shadow (GnomeIconContainer *container, int max_x, max_y; int min_x, min_y; GList *p; + double pixels_per_unit; if (list == NULL) return NULL; @@ -83,6 +80,7 @@ create_selection_shadow (GnomeIconContainer *container, we try to be smart and only create the maximum number of rectangles that we will need, in the vertical/horizontal directions. */ + /* FIXME: Does this work properly if the window is scrolled? */ max_x = GTK_WIDGET (container)->allocation.width; min_x = -max_x; @@ -96,10 +94,10 @@ create_selection_shadow (GnomeIconContainer *container, gnome_canvas_group_get_type (), NULL)); + pixels_per_unit = canvas->pixels_per_unit; for (p = list; p != NULL; p = p->next) { DndSelectionItem *item; - int x1, y1; - int x2, y2; + int x1, y1, x2, y2; item = p->data; @@ -111,32 +109,29 @@ create_selection_shadow (GnomeIconContainer *container, x2 = x1 + item->icon_width; y2 = y1 + item->icon_height; - if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y) { - GnomeCanvasItem *rect; - - rect = gnome_canvas_item_new + if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y) + gnome_canvas_item_new (group, gnome_canvas_rect_get_type (), - "x1", (double) x1, "y1", (double) y1, - "x2", (double) x2, "y2", (double) y2, + "x1", (double) x1 / pixels_per_unit, + "y1", (double) y1 / pixels_per_unit, + "x2", (double) x2 / pixels_per_unit, + "y2", (double) y2 / pixels_per_unit, "outline_color", "black", "outline_stipple", stipple, "width_pixels", 1, NULL); - } } return GNOME_CANVAS_ITEM (group); } -/* This is a workaround for a gnome-canvas bug: with the current (1.0.18) - gnome-libs, setting the x/y values for an existing group fails at updating - the bounds of the group. So, instead of setting the x/y values to the - current position at initialization time, we set them to (0,0) and then use a - simple affine transform. */ +/* Set the affine instead of the x and y position. + * Simple, and setting x and y was broken at one point. + */ static void set_shadow_position (GnomeCanvasItem *shadow, - gdouble x, gdouble y) + double x, double y) { double affine[6]; @@ -151,6 +146,7 @@ set_shadow_position (GnomeCanvasItem *shadow, } + /* Functions to deal with DndSelectionItems. */ static DndSelectionItem * @@ -195,7 +191,6 @@ set_gnome_icon_list_selection (GnomeIconContainer *container, GtkSelectionData *selection_data) { GnomeIconContainerDetails *details; - GnomeCanvas* canvas = GNOME_CANVAS(container); GList *p; GString *data; @@ -204,31 +199,28 @@ set_gnome_icon_list_selection (GnomeIconContainer *container, data = g_string_new (NULL); for (p = details->icons; p != NULL; p = p->next) { GnomeIconContainerIcon *icon; - gint center_offset; + ArtIRect rect; char *uri; char *s; - GdkPixbuf *pixbuf; - int icon_x, icon_y; icon = p->data; if (!icon->is_selected) continue; - center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (icon->item)); - - /* Corner of the icon relative to the cursor. */ - icon_x = icon->x - details->dnd_info->start_x + floor(center_offset / canvas->pixels_per_unit); - icon_y = icon->y - details->dnd_info->start_y; + nautilus_icons_view_icon_item_get_icon_window_rectangle + (icon->item, &rect); + uri = nautilus_icons_controller_get_icon_uri + (details->controller, icon->data); + + s = g_strdup_printf ("%s\r%d:%d:%hu:%hu\r\n", + uri, + (int) (rect.x0 - details->dnd_info->start_x), + (int) (rect.y0 - details->dnd_info->start_y), + rect.x1 - rect.x0, + rect.y1 - rect.y0); - uri = nautilus_icons_controller_get_icon_uri (details->controller, icon->data); - pixbuf = nautilus_icons_controller_get_icon_image(details->controller, icon->data); - - s = g_strdup_printf ("%s\r%d:%d:%d:%d\r\n", - uri, icon_x, icon_y, pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height); g_free (uri); - gdk_pixbuf_unref(pixbuf); - + g_string_append (data, s); g_free (s); } @@ -312,7 +304,7 @@ get_gnome_icon_list_selection (GnomeIconContainer *container, { GnomeIconContainerDndInfo *dnd_info; const guchar *p, *oldp; - gint size; + int size; dnd_info = container->details->dnd_info; @@ -401,8 +393,8 @@ gnome_icon_container_position_shadow (GnomeIconContainer *container, gnome_canvas_window_to_world (GNOME_CANVAS (container), x, y, &world_x, &world_y); - gnome_canvas_item_show (shadow); set_shadow_position (shadow, world_x, world_y); + gnome_canvas_item_show (shadow); } static void @@ -412,44 +404,31 @@ gnome_icon_container_dropped_icon_feedback (GtkWidget *widget, { GnomeIconContainer *container; GnomeIconContainerDndInfo *dnd_info; - GnomeCanvasItem *shadow; - double world_x, world_y; container = GNOME_ICON_CONTAINER (widget); dnd_info = container->details->dnd_info; - /* delete old selection list if any */ - + /* Delete old selection list if any. */ if (dnd_info->selection_list != NULL) { destroy_selection_list (dnd_info->selection_list); dnd_info->selection_list = NULL; } - /* build the selection list from the drag data */ - - get_gnome_icon_list_selection (container, data); - - shadow = create_selection_shadow (container, dnd_info->selection_list); - - gnome_canvas_item_set (shadow, "x", (gdouble) 0, "y", (gdouble) 0, - NULL); - - gnome_canvas_window_to_world (GNOME_CANVAS (widget), - x, y, &world_x, &world_y); - set_shadow_position (shadow, world_x, world_y); - - gnome_canvas_item_show (shadow); - + /* Delete old shadow if any. */ if (dnd_info->shadow != NULL) gtk_object_destroy (GTK_OBJECT (dnd_info->shadow)); - dnd_info->shadow = shadow; + + /* Build the selection list and the shadow. */ + get_gnome_icon_list_selection (container, data); + dnd_info->shadow = create_selection_shadow (container, dnd_info->selection_list); + gnome_icon_container_position_shadow (container, x, y); } static void drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, - gint x, - gint y, + int x, + int y, GtkSelectionData *data, guint info, guint32 time, @@ -535,60 +514,44 @@ gnome_icon_container_receive_dropped_icons (GnomeIconContainer *container, if (dnd_info->selection_list == NULL) return; - /* Move files in same window. - - FIXME: This won't work between windows for two reasons. - - First, we have to figure out whether we need to actually - move or copy some files. For directory views this is based - on the URIs, but that should be done by the controller, not - here in the view. - - Second, the start_x and start_y values are only good for - this window. To make dragging between multiple windows work, - we need to communicate the offset between the mouse and the - corner of the selection along with the other selection info - so we can position the icons correctly in the window they - are dropped in. The geometry that's currently included along - with the selection is not sufficient. - */ - if (context->action == GDK_ACTION_MOVE) { - double world_x, world_y; + /* Move files. */ + if (context->action != GDK_ACTION_MOVE) { + /* FIXME: We want to copy files here, I think. */ + g_warning ("non-move action not implemented yet"); + } else { GList *icons_to_select; - - gnome_canvas_window_to_world (GNOME_CANVAS (container), - x, y, &world_x, &world_y); - + icons_to_select = NULL; for (p = dnd_info->selection_list; p != NULL; p = p->next) { DndSelectionItem *item; GnomeIconContainerIcon *icon; - + item = p->data; icon = gnome_icon_container_get_icon_by_uri (container, item->uri); - + if (icon == NULL) { + /* FIXME: Do we ever get a MOVE between windows? + * If so, we need to move files here. + */ g_warning ("drag between containers not implemented yet"); continue; } - + if (item->got_icon_position) { - int icon_x, icon_y; - double scale = icon->item->canvas->pixels_per_unit; - int center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (icon->item)); - - icon_x = (int) world_x + item->icon_x - (center_offset / scale); - icon_y = (int) world_y + item->icon_y; + double world_x, world_y; + gnome_canvas_window_to_world (GNOME_CANVAS (container), + x + item->icon_x, + y + item->icon_y, + &world_x, &world_y); gnome_icon_container_move_icon - (container, icon, icon_x, icon_y, TRUE); + (container, icon, world_x, world_y, TRUE); } - + icons_to_select = g_list_prepend (icons_to_select, icon); } - + gnome_icon_container_select_list_unselect_others (container, icons_to_select); g_list_free (icons_to_select); @@ -621,8 +584,8 @@ gnome_icon_container_free_drag_data (GnomeIconContainer *container) static gboolean drag_drop_cb (GtkWidget *widget, GdkDragContext *context, - gint x, - gint y, + int x, + int y, guint32 time, gpointer data) { @@ -680,7 +643,7 @@ gnome_icon_container_dnd_init (GnomeIconContainer *container, dnd_info = g_new0 (GnomeIconContainerDndInfo, 1); dnd_info->target_list = gtk_target_list_new (drag_types, - num_drag_types); + NAUTILUS_N_ELEMENTS (drag_types)); dnd_info->stipple = gdk_bitmap_ref (stipple); @@ -691,7 +654,7 @@ gnome_icon_container_dnd_init (GnomeIconContainer *container, gtk_drag_dest_set (GTK_WIDGET (container), 0, - drop_types, num_drop_types, + drop_types, NAUTILUS_N_ELEMENTS (drop_types), GDK_ACTION_COPY | GDK_ACTION_MOVE); /* Messages for outgoing drag. */ @@ -740,30 +703,33 @@ gnome_icon_container_dnd_fini (GnomeIconContainer *container) void gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, GdkDragAction actions, - gint button, + int button, GdkEventMotion *event) { - GtkArg pixbuf_args[1]; GnomeIconContainerDndInfo *dnd_info; - GdkDragContext *context; - GnomeCanvasItem *pixbuf_item; GnomeCanvas *canvas; - GdkPixbuf *temp_pixbuf, *scaled_pixbuf; + GdkDragContext *context; + GtkArg pixbuf_arg; + GnomeCanvasItem *item; + GdkPixbuf *pixbuf; GdkPixmap *pixmap_for_dragged_file; GdkBitmap *mask_for_dragged_file; - gint x_offset, y_offset, center_offset; + int x_offset, y_offset; + ArtIRect rect; - g_return_if_fail (container != NULL); g_return_if_fail (GNOME_IS_ICON_CONTAINER (container)); g_return_if_fail (event != NULL); dnd_info = container->details->dnd_info; g_return_if_fail (dnd_info != NULL); - /* Notice that the event is already in world coordinates, because of - the way the canvas handles events! */ - dnd_info->start_x = event->x; - dnd_info->start_y = event->y; + /* Notice that the event is in world coordinates, because of + the way the canvas handles events. + */ + canvas = GNOME_CANVAS (container); + gnome_canvas_world_to_window (canvas, + event->x, event->y, + &dnd_info->start_x, &dnd_info->start_y); /* start the drag */ context = gtk_drag_begin (GTK_WIDGET (container), @@ -773,46 +739,21 @@ gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, (GdkEvent *) event); /* create a pixmap and mask to drag with */ - pixbuf_item = GNOME_CANVAS_ITEM (container->details->drag_icon->item); - pixbuf_args[0].name = "NautilusIconsViewIconItem::pixbuf"; - gtk_object_getv (GTK_OBJECT (pixbuf_item), 1, pixbuf_args); - temp_pixbuf = (GdkPixbuf *) GTK_VALUE_OBJECT (pixbuf_args[0]); - + item = GNOME_CANVAS_ITEM (container->details->drag_icon->item); + pixbuf_arg.name = "NautilusIconsViewIconItem::pixbuf"; + gtk_object_getv (GTK_OBJECT (item), 1, &pixbuf_arg); + pixbuf = GTK_VALUE_BOXED (pixbuf_arg); + gdk_pixbuf_render_pixmap_and_mask (pixbuf, + &pixmap_for_dragged_file, + &mask_for_dragged_file, + 128); + /* compute the image's offset */ - canvas = GNOME_CANVAS (container); - - x_offset = floor (event->x - pixbuf_item->x1 + .5); - y_offset = floor (event->y - pixbuf_item->y1 + .5); + nautilus_icons_view_icon_item_get_icon_window_rectangle + (container->details->drag_icon->item, &rect); + x_offset = dnd_info->start_x - rect.x0; + y_offset = dnd_info->start_y - rect.y0; - center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (container->details->drag_icon->item)); - x_offset -= center_offset; - - /* if the scale factor isn't 1.0, we have to scale the pixmap */ - /* FIXME: eventually need to get the size, if any, from the metadata here */ - - scaled_pixbuf = NULL; - if (container->details->zoom_level != NAUTILUS_ZOOM_LEVEL_STANDARD) { - gint old_width, old_height; - gint new_width, new_height; - - x_offset = floor (event->x * canvas->pixels_per_unit - center_offset - pixbuf_item->x1 + .5); - y_offset = floor (event->y * canvas->pixels_per_unit - pixbuf_item->y1 + .5); - - old_width = gdk_pixbuf_get_width (temp_pixbuf); - old_height = gdk_pixbuf_get_height (temp_pixbuf); - - new_width = floor ((old_width * canvas->pixels_per_unit) + .5); - new_height = floor ((old_height * canvas->pixels_per_unit) + .5); - - scaled_pixbuf = gdk_pixbuf_scale_simple (temp_pixbuf, new_width, new_height, ART_FILTER_BILINEAR); - temp_pixbuf = scaled_pixbuf; - } - - gdk_pixbuf_render_pixmap_and_mask (temp_pixbuf, &pixmap_for_dragged_file, &mask_for_dragged_file, 128); - if (scaled_pixbuf) - gdk_pixbuf_unref(scaled_pixbuf); - /* set the pixmap and mask for dragging */ gtk_drag_set_icon_pixmap (context, gtk_widget_get_colormap (GTK_WIDGET (container)), pixmap_for_dragged_file, mask_for_dragged_file, @@ -824,7 +765,6 @@ gnome_icon_container_dnd_end_drag (GnomeIconContainer *container) { GnomeIconContainerDndInfo *dnd_info; - g_return_if_fail (container != NULL); g_return_if_fail (GNOME_IS_ICON_CONTAINER (container)); dnd_info = container->details->dnd_info; diff --git a/libnautilus-extensions/gnome-icon-container-private.h b/libnautilus-extensions/gnome-icon-container-private.h index 1ecd0625d..abb781303 100644 --- a/libnautilus-extensions/gnome-icon-container-private.h +++ b/libnautilus-extensions/gnome-icon-container-private.h @@ -28,20 +28,20 @@ #include "gnome-icon-container.h" #include "gnome-icon-container-dnd.h" #include "nautilus-icon-factory.h" -#include +#include "nautilus-icons-view-icon-item.h" /* An Icon. */ typedef struct { /* Canvas item for the icon. */ - GnomeCanvasItem *item; + NautilusIconsViewIconItem *item; /* X/Y coordinates and size. We could use the GnomeCanvasItem * functions, but this is a lot faster */ - gdouble x, y; + double x, y; - /* Whether this item is selected (i.e. highlighted) for operation. */ + /* Whether this item is selected for operation. */ gboolean is_selected : 1; /* Whether this item is selected for keyboard navigation. */ @@ -89,7 +89,7 @@ typedef struct { typedef struct { gboolean active; - gdouble start_x, start_y; + double start_x, start_y; GnomeCanvasItem *selection_rectangle; guint timer_id; diff --git a/libnautilus-extensions/gnome-icon-container.c b/libnautilus-extensions/gnome-icon-container.c index 04e1c054d..7f144c396 100644 --- a/libnautilus-extensions/gnome-icon-container.c +++ b/libnautilus-extensions/gnome-icon-container.c @@ -37,8 +37,6 @@ #include "nautilus-gtk-macros.h" #include "gnome-icon-container-private.h" -#include "gnome-icon-container-dnd.h" -#include "nautilus-icons-view-icon-item.h" /* Interval for updating the rubberband selection, in milliseconds. */ #define RUBBERBAND_TIMEOUT_INTERVAL 10 @@ -117,10 +115,10 @@ icon_new (GnomeIconContainer *container, new->data = data; - new->item = gnome_canvas_item_new - (GNOME_CANVAS_GROUP (canvas->root), - nautilus_icons_view_icon_item_get_type (), - NULL); + new->item = NAUTILUS_ICONS_VIEW_ICON_ITEM + (gnome_canvas_item_new (GNOME_CANVAS_GROUP (canvas->root), + nautilus_icons_view_icon_item_get_type (), + NULL)); request_update_one (container, new); @@ -129,20 +127,17 @@ icon_new (GnomeIconContainer *container, static void icon_position (GnomeIconContainerIcon *icon, - GnomeIconContainer *container, - gdouble x, gdouble y) + double x, double y) { - GnomeIconContainerDetails *details; + if (icon->x == x && icon->y == y) + return; - details = container->details; + gnome_canvas_item_move (GNOME_CANVAS_ITEM (icon->item), + x - icon->x, + y - icon->y); icon->x = x; icon->y = y; - - gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "x", (gdouble) icon->x, - "y", (gdouble) icon->y, - NULL); } static void @@ -162,7 +157,7 @@ icon_toggle_selected (GnomeIconContainerIcon *icon) { icon->is_selected = !icon->is_selected; gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "selected", (gboolean) icon->is_selected, + "highlighted_for_selection", (gboolean) icon->is_selected, NULL); } @@ -187,28 +182,23 @@ icon_select (GnomeIconContainerIcon *icon, static gboolean icon_is_in_region (GnomeIconContainer *container, GnomeIconContainerIcon *icon, - int x1, int y1, - int x2, int y2) + int x0, int y0, + int x1, int y1) { - int icon_x2, icon_y2; - int size; - - size = nautilus_icon_size_for_zoom_level - (gnome_icon_container_get_zoom_level (container)); - - icon_x2 = icon->x + size; - icon_y2 = icon->y + size; + ArtDRect rect; - if (x1 >= x2 || y1 >= y2) + if (x0 >= x1 || y0 >= y1) return FALSE; - return x1 < icon_x2 && x2 >= icon->x && y1 < icon_y2 && y2 >= icon->y; + nautilus_icons_view_icon_item_get_icon_world_rectangle + (icon->item, &rect); + return x0 < rect.x1 && x1 >= rect.x0 && y0 < rect.y1 && y1 >= rect.y0; } static void icon_get_bounding_box (GnomeIconContainerIcon *icon, - guint *x1_return, guint *y1_return, - guint *x2_return, guint *y2_return) + int *x1_return, int *y1_return, + int *x2_return, int *y2_return) { double x1, y1, x2, y2; @@ -829,15 +819,15 @@ set_kbd_current (GnomeIconContainer *container, details = container->details; if (details->kbd_current != NULL) - gnome_canvas_item_set (details->kbd_current->item, - "alt_selected", 0, + gnome_canvas_item_set (GNOME_CANVAS_ITEM (details->kbd_current->item), + "highlighted_for_keyboard_selection", 0, NULL); details->kbd_current = icon; if (icon != NULL) { - gnome_canvas_item_set (icon->item, - "alt_selected", 1, + gnome_canvas_item_set (GNOME_CANVAS_ITEM (details->kbd_current->item), + "highlighted_for_keyboard_selection", 1, NULL); icon_raise (icon); } @@ -859,7 +849,7 @@ set_scroll_region (GnomeIconContainer *container) GnomeIconContainerIconGrid *grid; GtkAllocation *allocation; GtkAdjustment *vadj, *hadj; - gdouble x1, y1, x2, y2; + double x1, y1, x2, y2; guint scroll_width, scroll_height; details = container->details; @@ -883,8 +873,8 @@ set_scroll_region (GnomeIconContainer *container) gnome_canvas_set_scroll_region (GNOME_CANVAS (container), 0.0, 0.0, - (gdouble) scroll_width, - (gdouble) scroll_height); + (double) scroll_width, + (double) scroll_height); if (details->width <= allocation->width) gtk_adjustment_set_value (hadj, 0.0); @@ -1005,7 +995,7 @@ gnome_icon_container_move_icon (GnomeIconContainer *container, if (new_x_offset > 0 && new_y_offset > 0) icon_grid_add (details->grid, icon, new_grid_x + 1, new_grid_y + 1); - icon_position (icon, container, x, y); + icon_position (icon, x, y); if (raise) icon_raise (icon); @@ -1023,10 +1013,10 @@ gnome_icon_container_move_icon (GnomeIconContainer *container, static gboolean rubberband_select_in_cell (GnomeIconContainer *container, GList *cell, - gdouble curr_x1, gdouble curr_y1, - gdouble curr_x2, gdouble curr_y2, - gdouble prev_x1, gdouble prev_y1, - gdouble prev_x2, gdouble prev_y2) + double curr_x1, double curr_y1, + double curr_x2, double curr_y2, + double prev_x1, double prev_y1, + double prev_x2, double prev_y2) { GList *p; gboolean selection_changed; @@ -1061,10 +1051,10 @@ rubberband_select_in_cell (GnomeIconContainer *container, static void rubberband_select (GnomeIconContainer *container, - gdouble curr_x1, gdouble curr_y1, - gdouble curr_x2, gdouble curr_y2, - gdouble prev_x1, gdouble prev_y1, - gdouble prev_x2, gdouble prev_y2) + double curr_x1, double curr_y1, + double curr_x2, double curr_y2, + double prev_x1, double prev_y1, + double prev_x2, double prev_y2) { GList **p; GnomeIconContainerIconGrid *grid; @@ -1117,8 +1107,8 @@ rubberband_timeout_cb (gpointer data) GtkWidget *widget; GnomeIconContainerRubberbandInfo *band_info; int x, y; - gdouble x1, y1, x2, y2; - gdouble world_x, world_y; + double x1, y1, x2, y2; + double world_x, world_y; int x_scroll, y_scroll; GDK_THREADS_ENTER (); @@ -1127,6 +1117,9 @@ rubberband_timeout_cb (gpointer data) container = GNOME_ICON_CONTAINER (data); band_info = &container->details->rubberband_info; + g_assert (band_info->timer_id != 0); + g_assert (GNOME_IS_CANVAS_RECT (band_info->selection_rectangle)); + gdk_window_get_pointer (widget->window, &x, &y, NULL); if (x < 0) { @@ -1177,10 +1170,10 @@ rubberband_timeout_cb (gpointer data) } gnome_canvas_item_set (band_info->selection_rectangle, - "x1", (gdouble) x1, - "y1", (gdouble) y1, - "x2", (gdouble) x2, - "y2", (gdouble) y2, + "x1", x1, + "y1", y1, + "x2", x2, + "y2", y2, NULL); rubberband_select (container, @@ -1241,8 +1234,8 @@ start_rubberbanding (GnomeIconContainer *container, band_info->active = TRUE; band_info->timer_id = gtk_timeout_add (RUBBERBAND_TIMEOUT_INTERVAL, - rubberband_timeout_cb, - container); + rubberband_timeout_cb, + container); gnome_canvas_item_grab (band_info->selection_rectangle, (GDK_POINTER_MOTION_MASK @@ -2014,7 +2007,7 @@ gnome_icon_container_initialize (GnomeIconContainer *container) details->grid = icon_grid_new (); details->canvas_item_to_icon = g_hash_table_new (g_direct_hash, - g_direct_equal); + g_direct_equal); details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD; @@ -2277,19 +2270,28 @@ static void request_update_one (GnomeIconContainer *container, GnomeIconContainerIcon *icon) { GnomeIconContainerDetails *details; - GdkPixbuf *image; + NautilusScalableIcon *scalable_icon; + GdkPixbuf *pixbuf; char *label; + GdkFont *font; details = container->details; - image = nautilus_icons_controller_get_icon_image (details->controller, icon->data); + scalable_icon = nautilus_icons_controller_get_icon_image (details->controller, icon->data); + pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (scalable_icon, nautilus_icon_size_for_zoom_level (details->zoom_level)); + nautilus_scalable_icon_unref (scalable_icon); + label = nautilus_icons_controller_get_icon_text (details->controller, icon->data); + + font = details->label_font[details->zoom_level]; gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "pixbuf", image, - "label", label, + "pixbuf", pixbuf, + "text", label, + "font", font, NULL); + gdk_pixbuf_unref (pixbuf); g_free (label); } @@ -2308,7 +2310,7 @@ gnome_icon_container_add (GnomeIconContainer *container, details = container->details; new_icon = icon_new (container, data); - icon_position (new_icon, container, x, y); + icon_position (new_icon, x, y); world_to_grid (container, x, y, &grid_x, &grid_y); icon_grid_add (details->grid, new_icon, grid_x, grid_y); @@ -2350,7 +2352,7 @@ gnome_icon_container_add_auto (GnomeIconContainer *container, icon_grid_add_auto (container->details->grid, new_icon, &grid_x, &grid_y); grid_to_world (container, grid_x, grid_y, &x, &y); - icon_position (new_icon, container, x, y); + icon_position (new_icon, x, y); setup_icon_in_container (container, new_icon); @@ -2368,9 +2370,9 @@ gnome_icon_container_get_zoom_level(GnomeIconContainer *container) void gnome_icon_container_set_zoom_level(GnomeIconContainer *container, int new_level) { + GnomeIconContainerDetails *details; int pinned_level; double pixels_per_unit; - GnomeIconContainerDetails *details; details = container->details; @@ -2379,15 +2381,15 @@ gnome_icon_container_set_zoom_level(GnomeIconContainer *container, int new_level pinned_level = NAUTILUS_ZOOM_LEVEL_SMALLEST; else if (pinned_level > NAUTILUS_ZOOM_LEVEL_LARGEST) pinned_level = NAUTILUS_ZOOM_LEVEL_LARGEST; - + if (pinned_level == details->zoom_level) return; - + details->zoom_level = pinned_level; pixels_per_unit = (double) nautilus_icon_size_for_zoom_level (pinned_level) / NAUTILUS_ICON_SIZE_STANDARD; - gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(container), pixels_per_unit); + gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (container), pixels_per_unit); gnome_icon_container_request_update_all (container); } @@ -2403,20 +2405,13 @@ void gnome_icon_container_request_update_all (GnomeIconContainer *container) { GList *p; - GnomeIconContainerDetails *details; - details = container->details; - - for (p = details->icons; p != NULL; p = p->next) - { - GnomeIconContainerIcon *icon; - icon = p->data; - - request_update_one (container, icon); - } + for (p = container->details->icons; p != NULL; p = p->next) + request_update_one (container, p->data); } + /** * gnome_icon_container_relayout: * @container: An icon container. @@ -2492,7 +2487,7 @@ gnome_icon_container_relayout (GnomeIconContainer *container) dp[cols] = g_list_alloc (); dp[cols]->data = icon; - icon_position (icon, container, dx, dy); + icon_position (icon, dx, dy); icon->layout_done = TRUE; @@ -2631,7 +2626,7 @@ gnome_icon_container_line_up (GnomeIconContainer *container) || (icon->y >= 0 && icon->y < y)) continue; - icon_position (icon, container, dx, y); + icon_position (icon, dx, y); icon->layout_done = TRUE; q[k] = g_list_alloc (); diff --git a/libnautilus-extensions/nautilus-icons-controller.c b/libnautilus-extensions/nautilus-icons-controller.c index ac68e783c..850ffdce8 100644 --- a/libnautilus-extensions/nautilus-icons-controller.c +++ b/libnautilus-extensions/nautilus-icons-controller.c @@ -50,7 +50,7 @@ nautilus_icons_controller_initialize (NautilusIconsController *controller) { } -GdkPixbuf * +NautilusScalableIcon * nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, NautilusControllerIcon *icon) { diff --git a/libnautilus-extensions/nautilus-icons-controller.h b/libnautilus-extensions/nautilus-icons-controller.h index fa123c455..a9256dd13 100644 --- a/libnautilus-extensions/nautilus-icons-controller.h +++ b/libnautilus-extensions/nautilus-icons-controller.h @@ -28,6 +28,7 @@ #include #include +#include "nautilus-icon-factory.h" /* NautilusIconsController is an abstract class that describes the interface that a NautilusIconsView (currently named GnomeIconContainer) @@ -54,15 +55,15 @@ typedef struct NautilusControllerIconDummy NautilusControllerIcon; ((NautilusControllerIcon *)(icon)) /* Basic GtkObject requirements. */ -GtkType nautilus_icons_controller_get_type (void); +GtkType nautilus_icons_controller_get_type (void); /* Icon operations. */ -GdkPixbuf *nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, - NautilusControllerIcon *icon); -char * nautilus_icons_controller_get_icon_text (NautilusIconsController *controller, - NautilusControllerIcon *icon); -char * nautilus_icons_controller_get_icon_uri (NautilusIconsController *controller, - NautilusControllerIcon *icon); +NautilusScalableIcon *nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, + NautilusControllerIcon *icon); +char * nautilus_icons_controller_get_icon_text (NautilusIconsController *controller, + NautilusControllerIcon *icon); +char * nautilus_icons_controller_get_icon_uri (NautilusIconsController *controller, + NautilusControllerIcon *icon); struct _NautilusIconsController { @@ -73,12 +74,12 @@ struct _NautilusIconsControllerClass { GtkObjectClass parent_class; - GdkPixbuf * (*get_icon_image) (NautilusIconsController *controller, - NautilusControllerIcon *icon); - char * (* get_icon_text) (NautilusIconsController *controller, - NautilusControllerIcon *icon); - char * (* get_icon_uri) (NautilusIconsController *controller, - NautilusControllerIcon *icon); + NautilusScalableIcon * (*get_icon_image) (NautilusIconsController *controller, + NautilusControllerIcon *icon); + char * (* get_icon_text) (NautilusIconsController *controller, + NautilusControllerIcon *icon); + char * (* get_icon_uri) (NautilusIconsController *controller, + NautilusControllerIcon *icon); }; #endif /* NAUTILUS_ICONS_CONTROLLER_H */ diff --git a/libnautilus-extensions/nautilus-icons-view-icon-item.c b/libnautilus-extensions/nautilus-icons-view-icon-item.c index 027bb7901..3c83c5be0 100644 --- a/libnautilus-extensions/nautilus-icons-view-icon-item.c +++ b/libnautilus-extensions/nautilus-icons-view-icon-item.c @@ -30,50 +30,27 @@ #include #include #include +#include #include "gnome-icon-container-private.h" #include "nautilus-gtk-macros.h" #include "nautilus-string.h" +#include "gdk-extensions.h" /* Private part of the NautilusIconsViewIconItem structure */ struct _NautilusIconsViewIconItemDetails { - /* Our main gdk-pixbuf */ + /* The image, text, font. */ GdkPixbuf *pixbuf; - - /* text for our label */ - char* label; + char* text; + GdkFont *font; - /* Width value */ - double width; - - /* Height value */ - double height; - - /* X translation */ - double x; - - /* Y translation */ - double y; - - /* width in pixels of the label */ - double text_width; - - /* height in pixels of the label */ - double text_height; + /* Size of the text at current font. */ + int text_width; + int text_height; - /* boolean to indicate selection state */ - guint is_selected : 1; - - /* boolean to indicate keyboard selection state */ - guint is_alt_selected: 1; - - /* boolean to indicate highlight state (for swallow) */ - guint is_highlighted : 1; - - /* Whether the pixbuf has changed */ - guint need_pixbuf_update : 1; - - /* Whether the transformation or size have changed */ - guint need_xform_update : 1; + /* Highlight state. */ + guint is_highlighted_for_selection : 1; + guint is_highlighted_for_keyboard_selection: 1; + guint is_highlighted_for_drop : 1; }; @@ -82,60 +59,73 @@ struct _NautilusIconsViewIconItemDetails { enum { ARG_0, ARG_PIXBUF, - ARG_LABEL, - ARG_WIDTH, - ARG_HEIGHT, - ARG_X, - ARG_Y, - ARG_SELECTED, - ARG_ALT_SELECTED, - ARG_HIGHLIGHTD + ARG_TEXT, + ARG_FONT, + ARG_HIGHLIGHTED_FOR_SELECTION, + ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION, + ARG_HIGHLIGHTED_FOR_DROP }; /* constants */ -#define MAX_LABEL_WIDTH 80 +#define MAX_TEXT_WIDTH 80 /* Bitmap for stippled selection rectangles. */ static GdkBitmap *stipple; static char stipple_bits[] = { 0x02, 0x01 }; /* GtkObject */ -static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class); -static void nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *item); -static void nautilus_icons_view_icon_item_destroy (GtkObject *object); -static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); -static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class); +static void nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *item); +static void nautilus_icons_view_icon_item_destroy (GtkObject *object); +static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); /* GnomeCanvasItem */ -static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags); -static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height); -static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf); -static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item); -static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2); +static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, + double *affine, + ArtSVP *clip_path, + int flags); +static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, + GdkDrawable *drawable, + int x, + int y, + int width, + int height); +static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, + GnomeCanvasBuf *buf); +static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, + double x, + double y, + int cx, + int cy, + GnomeCanvasItem **actual_item); +static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, + double *x1, + double *y1, + double *x2, + double *y2); /* private */ -static GdkFont* get_font_for_item (GnomeCanvasItem *item); -static void draw_or_measure_text_box (GnomeCanvasItem* item, - GdkDrawable *drawable, - GdkFont *title_font, - const char* label, - int icon_left, - int icon_bottom, - gboolean do_draw); -static void nautilus_icons_view_draw_text_box (GnomeCanvasItem* item, - GdkDrawable *drawable, - GdkFont *title_font, - const char *label, - int icon_left, - int icon_bottom); -static void nautilus_icons_view_measure_text_box (GnomeCanvasItem* item, - GdkFont *title_font, - const char *label); +static void draw_or_measure_text_box (GnomeCanvasItem *item, + GdkDrawable *drawable, + int icon_left, + int icon_bottom); +static void nautilus_icons_view_draw_text_box (GnomeCanvasItem *item, + GdkDrawable *drawable, + int icon_left, + int icon_bottom); +static void nautilus_icons_view_measure_text_box (GnomeCanvasItem *item); +static void nautilus_icons_view_icon_item_get_icon_canvas_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect); NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconsViewIconItem, nautilus_icons_view_icon_item, GNOME_TYPE_CANVAS_ITEM) -/* Class initialization function for the icon canvas item */ +/* Class initialization function for the icon canvas item. */ static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class) { @@ -146,24 +136,17 @@ nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass * item_class = GNOME_CANVAS_ITEM_CLASS (class); gtk_object_add_arg_type ("NautilusIconsViewIconItem::pixbuf", - GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PIXBUF); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::label", - GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::width", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH); - - gtk_object_add_arg_type ("NautilusIconsViewIconItem::height", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::x", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::y", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::selected", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SELECTED); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::alt_selected", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ALT_SELECTED); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlightd", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTD); + GTK_TYPE_BOXED, GTK_ARG_READWRITE, ARG_PIXBUF); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::text", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TEXT); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::font", + GTK_TYPE_BOXED, GTK_ARG_READWRITE, ARG_FONT); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_selection", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_SELECTION); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_keyboard_selection", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_drop", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_DROP); object_class->destroy = nautilus_icons_view_icon_item_destroy; object_class->set_arg = nautilus_icons_view_icon_item_set_arg; @@ -178,186 +161,154 @@ nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass * stipple = gdk_bitmap_create_from_data (NULL, stipple_bits, 2, 2); } -/* Object initialization function for the icon item */ +/* Object initialization function for the icon item. */ static void -nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *icon_view_item) +nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *icon_item) { NautilusIconsViewIconItemDetails *details; details = g_new0 (NautilusIconsViewIconItemDetails, 1); - icon_view_item->details = details; + + icon_item->details = details; } -/* Destroy handler for the icon canvas item */ +/* Destroy handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_destroy (GtkObject *object) { GnomeCanvasItem *item; - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (object)); item = GNOME_CANVAS_ITEM (object); - icon_view_item = (NAUTILUS_ICONS_VIEW_ICON_ITEM (object)); - details = icon_view_item->details; + icon_item = (NAUTILUS_ICONS_VIEW_ICON_ITEM (object)); + details = icon_item->details; gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); if (details->pixbuf != NULL) gdk_pixbuf_unref (details->pixbuf); - g_free (details->label); - + g_free (details->text); + if (details->font != NULL) + gdk_font_unref (details->font); + g_free (details); NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); } -/* Set_arg handler for the icon item */ - +/* Set_arg handler for the icon item. */ static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) { - GnomeCanvasItem *item; - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; GdkPixbuf *pixbuf; - char* new_label; - double val; + GdkFont *font; - item = GNOME_CANVAS_ITEM (object); - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (object); - details = icon_view_item->details; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (object)->details; switch (arg_id) { case ARG_PIXBUF: - pixbuf = GTK_VALUE_POINTER (*arg); - if (pixbuf != details->pixbuf) { - if (pixbuf) { - g_return_if_fail (pixbuf->art_pixbuf->format == ART_PIX_RGB); - g_return_if_fail (pixbuf->art_pixbuf->n_channels == 3 - || pixbuf->art_pixbuf->n_channels == 4); - g_return_if_fail (pixbuf->art_pixbuf->bits_per_sample == 8); - - gdk_pixbuf_ref (pixbuf); - } + pixbuf = GTK_VALUE_BOXED (*arg); + if (pixbuf == details->pixbuf) + return; + + if (pixbuf != NULL) { + g_return_if_fail (pixbuf->art_pixbuf->format == ART_PIX_RGB); + g_return_if_fail (pixbuf->art_pixbuf->n_channels == 3 + || pixbuf->art_pixbuf->n_channels == 4); + g_return_if_fail (pixbuf->art_pixbuf->bits_per_sample == 8); - if (details->pixbuf) - gdk_pixbuf_unref (details->pixbuf); - - details->pixbuf = pixbuf; + gdk_pixbuf_ref (pixbuf); } - - details->need_pixbuf_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_LABEL: - new_label = GTK_VALUE_STRING (*arg); - if (details->label) - g_free(details->label); - details->label = g_strdup(new_label); - details->need_pixbuf_update = TRUE; - gnome_canvas_item_request_update (item); + if (details->pixbuf != NULL) + gdk_pixbuf_unref (details->pixbuf); + + details->pixbuf = pixbuf; break; - case ARG_WIDTH: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - details->width = val; - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; + case ARG_TEXT: + if (nautilus_strcmp (details->text, GTK_VALUE_STRING (*arg)) == 0) + return; - case ARG_HEIGHT: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - details->height = val; - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); + g_free (details->text); + details->text = g_strdup (GTK_VALUE_STRING (*arg)); break; - case ARG_X: - details->x = GTK_VALUE_DOUBLE (*arg); - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; + case ARG_FONT: + font = GTK_VALUE_BOXED (*arg); + if (nautilus_gdk_font_equal (font, details->font)) + return; - case ARG_Y: - details->y = GTK_VALUE_DOUBLE (*arg); - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); + if (font != NULL) + gdk_font_ref (font); + if (details->font != NULL) + gdk_font_unref (details->font); + details->font = font; break; - - case ARG_SELECTED: - details->is_selected = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + + case ARG_HIGHLIGHTED_FOR_SELECTION: + if (!details->is_highlighted_for_selection == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_selection = GTK_VALUE_BOOL (*arg); break; - case ARG_ALT_SELECTED: - details->is_alt_selected = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + case ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION: + if (!details->is_highlighted_for_keyboard_selection == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_keyboard_selection = GTK_VALUE_BOOL (*arg); break; - case ARG_HIGHLIGHTD: - details->is_highlighted = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + case ARG_HIGHLIGHTED_FOR_DROP: + if (!details->is_highlighted_for_drop == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_drop = GTK_VALUE_BOOL (*arg); break; - default: - break; + g_warning ("nautilus_icons_view_item_item_set_arg on unknown argument"); + return; } + + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (object)); } /* Get_arg handler for the icon item */ static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) { - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (object); - details = icon_view_item->details; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (object)->details; switch (arg_id) { case ARG_PIXBUF: - GTK_VALUE_POINTER (*arg) = details->pixbuf; - break; - - case ARG_LABEL: - GTK_VALUE_STRING (*arg) = details->label; - break; - - case ARG_WIDTH: - GTK_VALUE_DOUBLE (*arg) = details->width; - break; - - case ARG_HEIGHT: - GTK_VALUE_DOUBLE (*arg) = details->height; + GTK_VALUE_BOXED (*arg) = details->pixbuf; break; - case ARG_X: - GTK_VALUE_DOUBLE (*arg) = details->x; + case ARG_TEXT: + GTK_VALUE_STRING (*arg) = g_strdup (details->text); break; - case ARG_Y: - GTK_VALUE_DOUBLE (*arg) = details->y; + case ARG_FONT: + GTK_VALUE_BOXED (*arg) = details->font; break; - case ARG_SELECTED: - GTK_VALUE_BOOL (*arg) = details->is_selected; + case ARG_HIGHLIGHTED_FOR_SELECTION: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_selection; break; - case ARG_ALT_SELECTED: - GTK_VALUE_BOOL (*arg) = details->is_alt_selected; + case ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_keyboard_selection; break; - case ARG_HIGHLIGHTD: - GTK_VALUE_BOOL (*arg) = details->is_highlighted; + case ARG_HIGHLIGHTED_FOR_DROP: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_drop; break; default: @@ -366,324 +317,147 @@ nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg } } - -/* Bounds and utilities */ - -/* Computes the amount by which the unit horizontal and vertical vectors will be - * scaled by an affine transformation. - */ -static void -compute_xform_scaling (double *affine, ArtPoint *i_c, ArtPoint *j_c) -{ - ArtPoint orig, orig_c; - ArtPoint i, j; - - /* Origin */ - - orig.x = 0.0; - orig.y = 0.0; - art_affine_point (&orig_c, &orig, affine); - - /* Horizontal and vertical vectors */ - - i.x = 1.0; - i.y = 0.0; - art_affine_point (i_c, &i, affine); - i_c->x -= orig_c.x; - i_c->y -= orig_c.y; - - j.x = 0.0; - j.y = 1.0; - art_affine_point (j_c, &j, affine); - j_c->x -= orig_c.x; - j_c->y -= orig_c.y; -} - -/* computes the addtional resolution dependent affine needed to - * fit the image within its viewport defined by x,y,width and height - * args - */ -static void -compute_viewport_affine (NautilusIconsViewIconItem *icon_view_item, double *viewport_affine, double *i2c) -{ - NautilusIconsViewIconItemDetails *details; - ArtPoint i_c, j_c; - double i_len, j_len; - double si_len, sj_len; - double ti_len, tj_len; - double scale[6], translate[6]; - double w, h; - double x, y; - - details = icon_view_item->details; - - /* Compute scaling vectors and required width/height */ - - compute_xform_scaling (i2c, &i_c, &j_c); - - i_len = sqrt (i_c.x * i_c.x + i_c.y * i_c.y); - j_len = sqrt (j_c.x * j_c.x + j_c.y * j_c.y); - - w = details->width; - if (!w) - w = details->pixbuf->art_pixbuf->width; - - h = details->height; - if (!h) - h = details->pixbuf->art_pixbuf->height; - - x = details->x; - y = details->y; - - si_len = w / details->pixbuf->art_pixbuf->width; - sj_len = h / details->pixbuf->art_pixbuf->height; - - ti_len = x; - tj_len = y; - - /* Compute the final affine */ - - art_affine_scale (scale, si_len, sj_len); - art_affine_translate (translate, ti_len, tj_len); - art_affine_multiply (viewport_affine, scale, translate); -} - -/* Computes the affine transformation with which the pixbuf needs to be - * transformed to render it on the canvas. This is not the same as the - * item_to_canvas transformation because we may need to scale the pixbuf - * by some other amount. - */ -static void -compute_render_affine (NautilusIconsViewIconItem *icon_view_item, double *render_affine, double *i2c) -{ - double viewport_affine[6]; - - compute_viewport_affine (icon_view_item, viewport_affine, i2c); - art_affine_multiply (render_affine, viewport_affine, i2c); -} - -/* utility to return the proper font for a given item, factoring in the current zoom level */ -static GdkFont* -get_font_for_item (GnomeCanvasItem *item) -{ - GnomeIconContainer* container = GNOME_ICON_CONTAINER (item->canvas); - return container->details->label_font[container->details->zoom_level]; -} - /* Recomputes the bounding box of a icon canvas item. */ static void -recompute_bounding_box (NautilusIconsViewIconItem *icon_view_item) +recompute_bounding_box (NautilusIconsViewIconItem *icon_item) { + /* The key to understanding this function: + * You must know that the documentation for gnome-canvas.h lies. + * x1, y1, x2, and y2 are in canvas coordinates, not world. + */ + GnomeCanvasItem *item; - NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - ArtDRect rect; + ArtDRect bounds; - item = GNOME_CANVAS_ITEM (icon_view_item); - details = icon_view_item->details; + item = GNOME_CANVAS_ITEM (icon_item); - if (!details->pixbuf) { - item->x1 = item->y1 = item->x2 = item->y2 = 0.0; - return; - } + gnome_canvas_item_get_bounds (item, + &bounds.x0, &bounds.y0, + &bounds.x1, &bounds.y1); - /* add 2 pixels slop to each side for highlight margin */ - rect.x0 = 0.0; - rect.x1 = details->pixbuf->art_pixbuf->width + 4; - if ((details->text_width + 4)> rect.x1) - rect.x1 = details->text_width + 4; - - rect.y0 = 0.0; - rect.y1 = details->pixbuf->art_pixbuf->height; - rect.y1 += floor(details->text_height); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - art_drect_affine_transform (&rect, &rect, render_affine); - - item->x1 = floor (rect.x0); - item->y1 = floor (rect.y0); - item->x2 = ceil (rect.x1); - item->y2 = ceil (rect.y1); -} + gnome_canvas_w2c_d (item->canvas, + bounds.x0, bounds.y0, + &item->x1, &item->y1); -/* Update sequence */ + gnome_canvas_w2c_d (item->canvas, + bounds.x1, bounds.y1, + &item->x2, &item->y2); +} -/* Update handler for the icon canvas item */ +/* Update handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - GdkFont *title_font; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - title_font = get_font_for_item(item); + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; - /* make sure the text box measurements are set up before recalculating the bounding box */ - nautilus_icons_view_measure_text_box(item, title_font, details->label); - recompute_bounding_box(icon_view_item); + /* Make sure the text box measurements are set up + * before recalculating the bounding box. + */ + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + nautilus_icons_view_measure_text_box (item); + recompute_bounding_box (icon_item); + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); NAUTILUS_CALL_PARENT_CLASS (GNOME_CANVAS_ITEM_CLASS, update, (item, affine, clip_path, flags)); - - if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE) - || details->need_pixbuf_update - || details->need_xform_update) - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - - /* If we need a pixbuf update, or if the item changed visibility to - * shown, recompute the bounding box. - */ - if (details->need_pixbuf_update - || details->need_xform_update - || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && (GTK_OBJECT_FLAGS (icon_view_item) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE)) { - recompute_bounding_box (icon_view_item); - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - details->need_pixbuf_update = FALSE; - details->need_xform_update = FALSE; - } } /* Rendering */ -/* This is detailsate to libart, but we need it. Sigh. */ -extern void art_rgb_affine_run (int *p_x0, int *p_x1, int y, int src_width, int src_height, - const double affine[6]); - -/* Fills the specified buffer with the transformed version of a pixbuf */ -static void -transform_pixbuf (guchar *dest, int x, int y, int width, int height, int rowstride, - GdkPixbuf *pixbuf, double *affine) -{ - ArtPixBuf *apb; - int xx, yy; - double inv[6]; - guchar *src, *d; - ArtPoint src_p, dest_p; - int run_x1, run_x2; - int src_x, src_y; - int i; - - apb = pixbuf->art_pixbuf; - - art_affine_invert (inv, affine); - - for (yy = 0; yy < height; yy++) { - dest_p.y = y + yy + 0.5; - - run_x1 = x; - run_x2 = x + width; - art_rgb_affine_run (&run_x1, &run_x2, yy + y, - apb->width, apb->height, - inv); - - d = dest + yy * rowstride + (run_x1 - x) * 4; - - for (xx = run_x1; xx < run_x2; xx++) { - dest_p.x = xx + 0.5; - art_affine_point (&src_p, &dest_p, inv); - src_x = floor (src_p.x); - src_y = floor (src_p.y); - - src = apb->pixels + src_y * apb->rowstride + src_x * apb->n_channels; - - for (i = 0; i < apb->n_channels; i++) - *d++ = *src++; - - if (!apb->has_alpha) - *d++ = 255; /* opaque */ - } - } -} - -/* Draw the label in a box, using gnomelib routines. */ +/* Draw the text in a box, using gnomelib routines. */ static void draw_or_measure_text_box (GnomeCanvasItem* item, GdkDrawable *drawable, - GdkFont *title_font, - const char *label, - int icon_left, - int icon_bottom, - gboolean do_draw) + int icon_left, + int icon_bottom) { - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; int width_so_far, height_so_far; GdkGC* gc; - int max_label_width; - int item_width, box_left; + int max_text_width; + int icon_width, text_left, box_left; GnomeIconTextInfo *icon_text_info; - gchar **pieces; - const char *label_piece; - guint piece_index; + char **pieces; + const char *text_piece; + int i; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - pieces = g_strsplit (label, "\n", 0); - piece_index = 0; - label_piece = pieces[piece_index]; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (item)->details; + + if (details->font == NULL || details->text == NULL || details->text[0] == '\0') { + details->text_height = 0; + details->text_width = 0; + return; + } + width_so_far = 0; height_so_far = 0; - while (label_piece != NULL) { + + if (drawable != NULL) { + icon_width = details->pixbuf == NULL ? 0 : details->pixbuf->art_pixbuf->width; + gc = gdk_gc_new (item->canvas->layout.bin_window); + } + + max_text_width = floor (MAX_TEXT_WIDTH * item->canvas->pixels_per_unit); + + pieces = g_strsplit (details->text, "\n", 0); + for (i = 0; (text_piece = pieces[i]) != NULL; i++) { /* Replace empty string with space for measurement and drawing. - * This make empty lines appear, instead of being collapsed out. + * This makes empty lines appear, instead of being collapsed out. */ - if (strlen (label_piece) == 0) - label_piece = " "; - - if (do_draw) { - item_width = floor (item->x2 - item->x1); - gc = gdk_gc_new (item->canvas->layout.bin_window); - } + if (text_piece[0] == '\0') + text_piece = " "; - max_label_width = floor (MAX_LABEL_WIDTH * item->canvas->pixels_per_unit); - icon_text_info = gnome_icon_layout_text - (title_font, label_piece, " -_,;.:?/&", max_label_width, TRUE); + (details->font, text_piece, " -_,;.:?/&", max_text_width, TRUE); - if (do_draw) { - box_left = icon_left + (item_width - icon_text_info->width) / 2; + if (drawable != NULL) { + text_left = icon_left + (icon_width - icon_text_info->width) / 2; gnome_icon_paint_text (icon_text_info, drawable, gc, - box_left, icon_bottom + height_so_far, GTK_JUSTIFY_CENTER); + text_left, icon_bottom + height_so_far, GTK_JUSTIFY_CENTER); } - gnome_icon_text_info_free (icon_text_info); - width_so_far = MAX (width_so_far, icon_text_info->width); height_so_far += icon_text_info->height; - - label_piece = pieces[++piece_index]; + + gnome_icon_text_info_free (icon_text_info); } g_strfreev (pieces); - height_so_far += 4; /* extra slop for nicer highlighting */ + height_so_far += 2; /* extra slop for nicer highlighting */ - if (do_draw) { + if (drawable != NULL) { - /* Current calculations should match what we measured before drawing */ + /* Current calculations should match what we measured before drawing. + * This assumes that we will always make a separate call to measure + * before the call to draw. We might later decide to use this function + * differently and change these asserts. + */ g_assert (height_so_far == details->text_height); g_assert (width_so_far == details->text_width); + box_left = icon_left + (icon_width - width_so_far) / 2; + /* invert to indicate selection if necessary */ - if (details->is_selected) { - gdk_gc_set_function (gc, GDK_INVERT); - gdk_draw_rectangle (drawable, gc, TRUE, box_left, icon_bottom - 2, width_so_far, height_so_far); - gdk_gc_set_function (gc, GDK_COPY); + if (details->is_highlighted_for_selection) { + gdk_gc_set_function (gc, GDK_INVERT); + gdk_draw_rectangle (drawable, gc, TRUE, + box_left, icon_bottom - 2, + width_so_far, 2 + height_so_far); + gdk_gc_set_function (gc, GDK_COPY); } - /* indicate alt-selection by framing the text with a gray-stippled rectangle */ - if (details->is_alt_selected) { - gdk_gc_set_stipple(gc, stipple); - gdk_gc_set_fill(gc, GDK_STIPPLED); - gdk_draw_rectangle (drawable, gc, FALSE, box_left, icon_bottom - 2, width_so_far, height_so_far); + /* indicate keyboard selection by framing the text with a gray-stippled rectangle */ + if (details->is_highlighted_for_keyboard_selection) { + gdk_gc_set_stipple (gc, stipple); + gdk_gc_set_fill (gc, GDK_STIPPLED); + gdk_draw_rectangle (drawable, gc, FALSE, + box_left, icon_bottom - 2, + width_so_far, 2 + height_so_far); } gdk_gc_unref (gc); @@ -691,252 +465,262 @@ draw_or_measure_text_box (GnomeCanvasItem* item, else { /* If measuring, remember the width & height. */ - details->text_width = (double) width_so_far; - details->text_height = (double) height_so_far; + details->text_width = width_so_far; + details->text_height = height_so_far; } } static void -nautilus_icons_view_measure_text_box (GnomeCanvasItem* item, - GdkFont *title_font, - const char *label) +nautilus_icons_view_measure_text_box (GnomeCanvasItem* item) { - draw_or_measure_text_box (item, - NULL, - title_font, - label, - 0, - 0, - FALSE); + draw_or_measure_text_box (item, NULL, 0, 0); } static void nautilus_icons_view_draw_text_box (GnomeCanvasItem* item, GdkDrawable *drawable, - GdkFont *title_font, const char *label, int icon_left, int icon_bottom) { - draw_or_measure_text_box (item, - drawable, - title_font, - label, - icon_left, - icon_bottom, - TRUE); + draw_or_measure_text_box (item, drawable, icon_left, icon_bottom); } -/* draw the icon item */ - +/* Draw the icon item. */ static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - guchar *buf; - GdkPixbuf *pixbuf; - ArtIRect p_rect, a_rect, d_rect; - int w, h, icon_height; - int center_offset = 0; - GdkFont *title_font = get_font_for_item(item); - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - /* handle drawing the pixbuf */ - - if (details->pixbuf) { - center_offset = nautilus_icons_view_icon_item_center_offset (icon_view_item); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - - /* Compute the area we need to repaint */ - - p_rect.x0 = item->x1; - p_rect.y0 = item->y1; - p_rect.x1 = item->x2; - p_rect.y1 = item->y2; - - a_rect.x0 = x - center_offset; - a_rect.y0 = y; - a_rect.x1 = x + width - center_offset; - a_rect.y1 = y + height; - - art_irect_intersect (&d_rect, &p_rect, &a_rect); - if (art_irect_empty (&d_rect)) - return; - - /* Create a temporary buffer and transform the pixbuf there */ - /* FIXME: only do this if really necessary */ - - w = d_rect.x1 - d_rect.x0; - h = d_rect.y1 - d_rect.y0; - - buf = g_new0 (guchar, w * h * 4); - transform_pixbuf (buf, - d_rect.x0, d_rect.y0, - w, h, - w * 4, - details->pixbuf, render_affine); - - pixbuf = gdk_pixbuf_new_from_data (buf, ART_PIX_RGB, TRUE, w, h, w * 4, NULL, NULL); - - gdk_pixbuf_render_to_drawable_alpha (pixbuf, drawable, - 0, 0, - d_rect.x0 - x + center_offset, d_rect.y0 - y, - w, h, - GDK_PIXBUF_ALPHA_BILEVEL, - 128, - GDK_RGB_DITHER_MAX, - d_rect.x0, d_rect.y0); - gdk_pixbuf_unref (pixbuf); - g_free (buf); + ArtIRect pixbuf_rect, drawable_rect, draw_rect; + + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + + /* Compute pixbuf rectangle in canvas coordinates. */ + nautilus_icons_view_icon_item_get_icon_canvas_rectangle + (icon_item, &pixbuf_rect); + + /* Draw the pixbuf. */ + if (details->pixbuf != NULL) { + /* Compute the area we need to draw. */ + drawable_rect.x0 = x; + drawable_rect.y0 = y; + drawable_rect.x1 = x + width; + drawable_rect.y1 = y + height; + art_irect_intersect (&draw_rect, &pixbuf_rect, &drawable_rect); + if (!art_irect_empty (&draw_rect)) + gdk_pixbuf_render_to_drawable_alpha + (details->pixbuf, drawable, + draw_rect.x0 - pixbuf_rect.x0, draw_rect.y0 - pixbuf_rect.y0, + draw_rect.x0 - x, draw_rect.y0 - y, + draw_rect.x1 - draw_rect.x0, draw_rect.y1 - draw_rect.y0, + GDK_PIXBUF_ALPHA_BILEVEL, 128, GDK_RGB_DITHER_MAX, + draw_rect.x0, draw_rect.y0); } - /* now compute the position of the label and draw it */ - if (nautilus_strlen (details->label) > 0) - { - icon_height = details->pixbuf->art_pixbuf->height * item->canvas->pixels_per_unit; - nautilus_icons_view_draw_text_box(item, drawable, title_font, details->label, item->x1 - x, - item->y1 - y + icon_height); - } -} - -/* return the center offset for this icon */ -int -nautilus_icons_view_icon_item_center_offset(NautilusIconsViewIconItem *icon_view_item) -{ - GnomeCanvasItem *item; - NautilusIconsViewIconItemDetails *details; - int box_width; - int center_offset; - - g_return_val_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (icon_view_item), 0); - - item = GNOME_CANVAS_ITEM (icon_view_item); - details = icon_view_item->details; - - box_width = floor (item->x2 - item->x1); - center_offset = (box_width - floor (details->pixbuf->art_pixbuf->width * item->canvas->pixels_per_unit)) / 2; - return center_offset; + /* Draw the text. */ + nautilus_icons_view_draw_text_box + (item, drawable, + pixbuf_rect.x0 - x, pixbuf_rect.y1 - y); } -/* Render handler for the icon canvas item */ +/* Render handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) { - NautilusIconsViewIconItem *icon_view_item; - NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - if (!details->pixbuf) - return; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); + g_assert_not_reached (); +#if 0 gnome_canvas_buf_ensure_buf (buf); art_rgb_pixbuf_affine (buf->buf, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, buf->buf_rowstride, details->pixbuf->art_pixbuf, - render_affine, + i2c, ART_FILTER_BILINEAR, NULL); buf->is_bg = 0; +#endif } -/* Point handler for the icon canvas item */ +/* Point handler for the icon canvas item. */ +/* FIXME: This currently only reports a hit if the pixbuf is hit. */ static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) + GnomeCanvasItem **actual_item) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6], inv[6]; - ArtPoint c, p; - int px, py; - int center_offset; double no_hit; - ArtPixBuf *apb; - guchar *src; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - center_offset = nautilus_icons_view_icon_item_center_offset (icon_view_item); + ArtIRect rect; + ArtPixBuf *art_pixbuf; + guint8 *pixel; + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + *actual_item = item; - no_hit = item->canvas->pixels_per_unit * 2 + 10; - - if (!details->pixbuf) + + /* Check to see if it's within the item's rectangle at all. */ + nautilus_icons_view_icon_item_get_icon_canvas_rectangle (icon_item, &rect); + if (cx <= rect.x0 || cx >= rect.x1 || cy <= rect.y0 || cy >= rect.y1) return no_hit; - - apb = details->pixbuf->art_pixbuf; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - art_affine_invert (inv, render_affine); - - c.x = cx - center_offset; - c.y = cy; - art_affine_point (&p, &c, inv); - px = p.x; - py = p.y; - - if (px < 0 || px >= apb->width || py < 0 || py >= apb->height) + + /* Can't get this far without a pixbuf. */ + g_assert (details->pixbuf != NULL); + if (details->pixbuf == NULL) return no_hit; - if (!apb->has_alpha) + /* If there's no alpha channel, it's opaque and we have a hit. */ + art_pixbuf = details->pixbuf->art_pixbuf; + if (!art_pixbuf->has_alpha) return 0.0; + g_assert (art_pixbuf->n_channels == 4); - src = apb->pixels + py * apb->rowstride + px * apb->n_channels; - - if (src[3] < 128) - return no_hit; - else + /* Check the alpha channel of the pixel to see if we have a hit. */ + pixel = art_pixbuf->pixels + + (cy - rect.y0) * art_pixbuf->rowstride + + (cx - rect.x0) * 4; + if (pixel[3] >= 128) return 0.0; -} + return no_hit; +} -/* Bounds handler for the icon canvas item */ +/* Bounds handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], viewport_affine[6]; - ArtDRect rect; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; + ArtIRect rect; + int pixbuf_width, pixbuf_height; + double pixels_per_unit; + + g_assert (x1 != NULL); + g_assert (y1 != NULL); + g_assert (x2 != NULL); + g_assert (y2 != NULL); + + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + + if (details->pixbuf == NULL) { + pixbuf_width = 0; + pixbuf_height = 0; + } else { + pixbuf_width = details->pixbuf->art_pixbuf->width; + pixbuf_height = details->pixbuf->art_pixbuf->height; + } - if (!details->pixbuf) { - *x1 = *y1 = *x2 = *y2 = 0.0; - return; + /* Compute rectangle enclosing both the icon and the text. */ + if (pixbuf_width > details->text_width) { + rect.x0 = 0; + rect.x1 = pixbuf_width; + } else { + rect.x0 = (pixbuf_width - details->text_width) / 2; + rect.x1 = rect.x0 + details->text_width; } + rect.y0 = 0; + rect.y1 = pixbuf_height + details->text_height; + + /* Add 2 pixels slop to each side. */ + rect.x0 -= 2; + rect.x1 += 2; + rect.y0 -= 2; + rect.y1 += 2; + + /* Return the result. */ + pixels_per_unit = item->canvas->pixels_per_unit; + *x1 = rect.x0 / pixels_per_unit; + *y1 = rect.y0 / pixels_per_unit; + *x2 = rect.x1 / pixels_per_unit; + *y2 = rect.y1 / pixels_per_unit; +} + +/* Get the rectangle of the icon only, in world coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_world_rectangle (NautilusIconsViewIconItem *item, + ArtDRect *rect) +{ + double i2w[6]; + ArtPoint art_point; + double pixels_per_unit; + GdkPixbuf *pixbuf; - /* add 2 pixels slop to each side for highlight margin */ - rect.x0 = 0.0; - rect.x1 = details->pixbuf->art_pixbuf->width + 4; - if ((details->text_width + 4) > rect.x1) - rect.x1 = details->text_width + 4; + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2w_affine (GNOME_CANVAS_ITEM (item), i2w); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2w); - rect.y0 = 0.0; - rect.y1 = details->pixbuf->art_pixbuf->height; - rect.y1 += floor(details->text_height); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_viewport_affine (icon_view_item, viewport_affine, i2c); - art_drect_affine_transform (&rect, &rect, viewport_affine); + rect->x0 = art_point.x; + rect->y0 = art_point.y; + + pixbuf = item->details->pixbuf; + pixels_per_unit = GNOME_CANVAS_ITEM (item)->canvas->pixels_per_unit; + + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width) / pixels_per_unit; + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height) / pixels_per_unit; +} + +/* Get the rectangle of the icon only, in canvas coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_canvas_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect) +{ + double i2c[6]; + ArtPoint art_point; + GdkPixbuf *pixbuf; + + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (item), i2c); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2c); + + rect->x0 = floor (art_point.x); + rect->y0 = floor (art_point.y); + + pixbuf = item->details->pixbuf; + + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height); +} + +/* Get the rectangle of the icon only, in window coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_window_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect) +{ + double i2w[6]; + ArtPoint art_point; + GdkPixbuf *pixbuf; + + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2w_affine (GNOME_CANVAS_ITEM (item), i2w); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2w); + gnome_canvas_world_to_window (GNOME_CANVAS_ITEM (item)->canvas, + art_point.x, art_point.y, + &art_point.x, &art_point.y); + + rect->x0 = floor (art_point.x); + rect->y0 = floor (art_point.y); + + pixbuf = item->details->pixbuf; - *x1 = rect.x0; - *y1 = rect.y0; - *x2 = rect.x1; - *y2 = rect.y1; + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height); } diff --git a/libnautilus-extensions/nautilus-icons-view-icon-item.h b/libnautilus-extensions/nautilus-icons-view-icon-item.h index 4e95dcefb..03ae11862 100644 --- a/libnautilus-extensions/nautilus-icons-view-icon-item.h +++ b/libnautilus-extensions/nautilus-icons-view-icon-item.h @@ -55,8 +55,11 @@ struct _NautilusIconsViewIconItemClass { GnomeCanvasItemClass parent_class; }; -GtkType nautilus_icons_view_icon_item_get_type (void); -int nautilus_icons_view_icon_item_center_offset (NautilusIconsViewIconItem *item); +GtkType nautilus_icons_view_icon_item_get_type (void); +void nautilus_icons_view_icon_item_get_icon_world_rectangle (NautilusIconsViewIconItem *item, + ArtDRect *world_rectangle); +void nautilus_icons_view_icon_item_get_icon_window_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *window_rectangle); END_GNOME_DECLS diff --git a/libnautilus-private/gdk-extensions.c b/libnautilus-private/gdk-extensions.c index 73731dc41..7d7f2c286 100644 --- a/libnautilus-private/gdk-extensions.c +++ b/libnautilus-private/gdk-extensions.c @@ -393,6 +393,24 @@ nautilus_gdk_color_parse_with_white_default (const char *color_spec, } } +/** + * nautilus_gdk_font_equal + * @font_a_null_allowed: A font or NULL. + * @font_b_null_allowed: A font or NULL. + * + * Calls gdk_font_equal, unless one of the fonts is NULL. + */ +gboolean +nautilus_gdk_font_equal (GdkFont *font_a_null_allowed, + GdkFont *font_b_null_allowed) +{ + if (font_a_null_allowed == NULL) + return font_b_null_allowed == NULL; + if (font_b_null_allowed == NULL) + return FALSE; + return gdk_font_equal (font_a_null_allowed, font_b_null_allowed); +} + #if ! defined (NAUTILUS_OMIT_SELF_CHECK) static char * diff --git a/libnautilus-private/gdk-extensions.h b/libnautilus-private/gdk-extensions.h index f5dd0c27b..366303c1d 100644 --- a/libnautilus-private/gdk-extensions.h +++ b/libnautilus-private/gdk-extensions.h @@ -81,4 +81,7 @@ void nautilus_interpolate_color (gdouble ratio, const GdkColor *end_color, GdkColor *interpolated_color); +gboolean nautilus_gdk_font_equal (GdkFont *font_a_null_allowed, + GdkFont *font_b_null_allowed); + #endif /* GDK_EXTENSIONS_H */ diff --git a/libnautilus-private/gnome-icon-container-dnd.c b/libnautilus-private/gnome-icon-container-dnd.c index e01c1c43d..dd74f85ea 100644 --- a/libnautilus-private/gnome-icon-container-dnd.c +++ b/libnautilus-private/gnome-icon-container-dnd.c @@ -26,17 +26,15 @@ #include #include "gnome-icon-container-dnd.h" -#include "gnome-icon-container-private.h" -#include "nautilus-icons-view-icon-item.h" -#include "nautilus-background.h" -#include "nautilus-gtk-extensions.h" - -#include #include #include #include +#include "nautilus-glib-extensions.h" #include - +#include "nautilus-gtk-extensions.h" +#include "nautilus-background.h" +#include "gnome-icon-container-private.h" +#include typedef struct { char *uri; @@ -50,7 +48,6 @@ static GtkTargetEntry drag_types [] = { { GNOME_ICON_CONTAINER_DND_URI_LIST_TYPE, 0, GNOME_ICON_CONTAINER_DND_URI_LIST }, { GNOME_ICON_CONTAINER_DND_URL_TYPE, 0, GNOME_ICON_CONTAINER_DND_URL } }; -static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); static GtkTargetEntry drop_types [] = { { GNOME_ICON_CONTAINER_DND_GNOME_ICON_LIST_TYPE, 0, GNOME_ICON_CONTAINER_DND_GNOME_ICON_LIST }, @@ -58,7 +55,6 @@ static GtkTargetEntry drop_types [] = { { GNOME_ICON_CONTAINER_DND_URL_TYPE, 0, GNOME_ICON_CONTAINER_DND_URL }, { GNOME_ICON_CONTAINER_DND_COLOR_TYPE, 0, GNOME_ICON_CONTAINER_DND_COLOR } }; -static const int num_drop_types = sizeof (drop_types) / sizeof (drop_types[0]); static GnomeCanvasItem * create_selection_shadow (GnomeIconContainer *container, @@ -70,6 +66,7 @@ create_selection_shadow (GnomeIconContainer *container, int max_x, max_y; int min_x, min_y; GList *p; + double pixels_per_unit; if (list == NULL) return NULL; @@ -83,6 +80,7 @@ create_selection_shadow (GnomeIconContainer *container, we try to be smart and only create the maximum number of rectangles that we will need, in the vertical/horizontal directions. */ + /* FIXME: Does this work properly if the window is scrolled? */ max_x = GTK_WIDGET (container)->allocation.width; min_x = -max_x; @@ -96,10 +94,10 @@ create_selection_shadow (GnomeIconContainer *container, gnome_canvas_group_get_type (), NULL)); + pixels_per_unit = canvas->pixels_per_unit; for (p = list; p != NULL; p = p->next) { DndSelectionItem *item; - int x1, y1; - int x2, y2; + int x1, y1, x2, y2; item = p->data; @@ -111,32 +109,29 @@ create_selection_shadow (GnomeIconContainer *container, x2 = x1 + item->icon_width; y2 = y1 + item->icon_height; - if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y) { - GnomeCanvasItem *rect; - - rect = gnome_canvas_item_new + if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y) + gnome_canvas_item_new (group, gnome_canvas_rect_get_type (), - "x1", (double) x1, "y1", (double) y1, - "x2", (double) x2, "y2", (double) y2, + "x1", (double) x1 / pixels_per_unit, + "y1", (double) y1 / pixels_per_unit, + "x2", (double) x2 / pixels_per_unit, + "y2", (double) y2 / pixels_per_unit, "outline_color", "black", "outline_stipple", stipple, "width_pixels", 1, NULL); - } } return GNOME_CANVAS_ITEM (group); } -/* This is a workaround for a gnome-canvas bug: with the current (1.0.18) - gnome-libs, setting the x/y values for an existing group fails at updating - the bounds of the group. So, instead of setting the x/y values to the - current position at initialization time, we set them to (0,0) and then use a - simple affine transform. */ +/* Set the affine instead of the x and y position. + * Simple, and setting x and y was broken at one point. + */ static void set_shadow_position (GnomeCanvasItem *shadow, - gdouble x, gdouble y) + double x, double y) { double affine[6]; @@ -151,6 +146,7 @@ set_shadow_position (GnomeCanvasItem *shadow, } + /* Functions to deal with DndSelectionItems. */ static DndSelectionItem * @@ -195,7 +191,6 @@ set_gnome_icon_list_selection (GnomeIconContainer *container, GtkSelectionData *selection_data) { GnomeIconContainerDetails *details; - GnomeCanvas* canvas = GNOME_CANVAS(container); GList *p; GString *data; @@ -204,31 +199,28 @@ set_gnome_icon_list_selection (GnomeIconContainer *container, data = g_string_new (NULL); for (p = details->icons; p != NULL; p = p->next) { GnomeIconContainerIcon *icon; - gint center_offset; + ArtIRect rect; char *uri; char *s; - GdkPixbuf *pixbuf; - int icon_x, icon_y; icon = p->data; if (!icon->is_selected) continue; - center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (icon->item)); - - /* Corner of the icon relative to the cursor. */ - icon_x = icon->x - details->dnd_info->start_x + floor(center_offset / canvas->pixels_per_unit); - icon_y = icon->y - details->dnd_info->start_y; + nautilus_icons_view_icon_item_get_icon_window_rectangle + (icon->item, &rect); + uri = nautilus_icons_controller_get_icon_uri + (details->controller, icon->data); + + s = g_strdup_printf ("%s\r%d:%d:%hu:%hu\r\n", + uri, + (int) (rect.x0 - details->dnd_info->start_x), + (int) (rect.y0 - details->dnd_info->start_y), + rect.x1 - rect.x0, + rect.y1 - rect.y0); - uri = nautilus_icons_controller_get_icon_uri (details->controller, icon->data); - pixbuf = nautilus_icons_controller_get_icon_image(details->controller, icon->data); - - s = g_strdup_printf ("%s\r%d:%d:%d:%d\r\n", - uri, icon_x, icon_y, pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height); g_free (uri); - gdk_pixbuf_unref(pixbuf); - + g_string_append (data, s); g_free (s); } @@ -312,7 +304,7 @@ get_gnome_icon_list_selection (GnomeIconContainer *container, { GnomeIconContainerDndInfo *dnd_info; const guchar *p, *oldp; - gint size; + int size; dnd_info = container->details->dnd_info; @@ -401,8 +393,8 @@ gnome_icon_container_position_shadow (GnomeIconContainer *container, gnome_canvas_window_to_world (GNOME_CANVAS (container), x, y, &world_x, &world_y); - gnome_canvas_item_show (shadow); set_shadow_position (shadow, world_x, world_y); + gnome_canvas_item_show (shadow); } static void @@ -412,44 +404,31 @@ gnome_icon_container_dropped_icon_feedback (GtkWidget *widget, { GnomeIconContainer *container; GnomeIconContainerDndInfo *dnd_info; - GnomeCanvasItem *shadow; - double world_x, world_y; container = GNOME_ICON_CONTAINER (widget); dnd_info = container->details->dnd_info; - /* delete old selection list if any */ - + /* Delete old selection list if any. */ if (dnd_info->selection_list != NULL) { destroy_selection_list (dnd_info->selection_list); dnd_info->selection_list = NULL; } - /* build the selection list from the drag data */ - - get_gnome_icon_list_selection (container, data); - - shadow = create_selection_shadow (container, dnd_info->selection_list); - - gnome_canvas_item_set (shadow, "x", (gdouble) 0, "y", (gdouble) 0, - NULL); - - gnome_canvas_window_to_world (GNOME_CANVAS (widget), - x, y, &world_x, &world_y); - set_shadow_position (shadow, world_x, world_y); - - gnome_canvas_item_show (shadow); - + /* Delete old shadow if any. */ if (dnd_info->shadow != NULL) gtk_object_destroy (GTK_OBJECT (dnd_info->shadow)); - dnd_info->shadow = shadow; + + /* Build the selection list and the shadow. */ + get_gnome_icon_list_selection (container, data); + dnd_info->shadow = create_selection_shadow (container, dnd_info->selection_list); + gnome_icon_container_position_shadow (container, x, y); } static void drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, - gint x, - gint y, + int x, + int y, GtkSelectionData *data, guint info, guint32 time, @@ -535,60 +514,44 @@ gnome_icon_container_receive_dropped_icons (GnomeIconContainer *container, if (dnd_info->selection_list == NULL) return; - /* Move files in same window. - - FIXME: This won't work between windows for two reasons. - - First, we have to figure out whether we need to actually - move or copy some files. For directory views this is based - on the URIs, but that should be done by the controller, not - here in the view. - - Second, the start_x and start_y values are only good for - this window. To make dragging between multiple windows work, - we need to communicate the offset between the mouse and the - corner of the selection along with the other selection info - so we can position the icons correctly in the window they - are dropped in. The geometry that's currently included along - with the selection is not sufficient. - */ - if (context->action == GDK_ACTION_MOVE) { - double world_x, world_y; + /* Move files. */ + if (context->action != GDK_ACTION_MOVE) { + /* FIXME: We want to copy files here, I think. */ + g_warning ("non-move action not implemented yet"); + } else { GList *icons_to_select; - - gnome_canvas_window_to_world (GNOME_CANVAS (container), - x, y, &world_x, &world_y); - + icons_to_select = NULL; for (p = dnd_info->selection_list; p != NULL; p = p->next) { DndSelectionItem *item; GnomeIconContainerIcon *icon; - + item = p->data; icon = gnome_icon_container_get_icon_by_uri (container, item->uri); - + if (icon == NULL) { + /* FIXME: Do we ever get a MOVE between windows? + * If so, we need to move files here. + */ g_warning ("drag between containers not implemented yet"); continue; } - + if (item->got_icon_position) { - int icon_x, icon_y; - double scale = icon->item->canvas->pixels_per_unit; - int center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (icon->item)); - - icon_x = (int) world_x + item->icon_x - (center_offset / scale); - icon_y = (int) world_y + item->icon_y; + double world_x, world_y; + gnome_canvas_window_to_world (GNOME_CANVAS (container), + x + item->icon_x, + y + item->icon_y, + &world_x, &world_y); gnome_icon_container_move_icon - (container, icon, icon_x, icon_y, TRUE); + (container, icon, world_x, world_y, TRUE); } - + icons_to_select = g_list_prepend (icons_to_select, icon); } - + gnome_icon_container_select_list_unselect_others (container, icons_to_select); g_list_free (icons_to_select); @@ -621,8 +584,8 @@ gnome_icon_container_free_drag_data (GnomeIconContainer *container) static gboolean drag_drop_cb (GtkWidget *widget, GdkDragContext *context, - gint x, - gint y, + int x, + int y, guint32 time, gpointer data) { @@ -680,7 +643,7 @@ gnome_icon_container_dnd_init (GnomeIconContainer *container, dnd_info = g_new0 (GnomeIconContainerDndInfo, 1); dnd_info->target_list = gtk_target_list_new (drag_types, - num_drag_types); + NAUTILUS_N_ELEMENTS (drag_types)); dnd_info->stipple = gdk_bitmap_ref (stipple); @@ -691,7 +654,7 @@ gnome_icon_container_dnd_init (GnomeIconContainer *container, gtk_drag_dest_set (GTK_WIDGET (container), 0, - drop_types, num_drop_types, + drop_types, NAUTILUS_N_ELEMENTS (drop_types), GDK_ACTION_COPY | GDK_ACTION_MOVE); /* Messages for outgoing drag. */ @@ -740,30 +703,33 @@ gnome_icon_container_dnd_fini (GnomeIconContainer *container) void gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, GdkDragAction actions, - gint button, + int button, GdkEventMotion *event) { - GtkArg pixbuf_args[1]; GnomeIconContainerDndInfo *dnd_info; - GdkDragContext *context; - GnomeCanvasItem *pixbuf_item; GnomeCanvas *canvas; - GdkPixbuf *temp_pixbuf, *scaled_pixbuf; + GdkDragContext *context; + GtkArg pixbuf_arg; + GnomeCanvasItem *item; + GdkPixbuf *pixbuf; GdkPixmap *pixmap_for_dragged_file; GdkBitmap *mask_for_dragged_file; - gint x_offset, y_offset, center_offset; + int x_offset, y_offset; + ArtIRect rect; - g_return_if_fail (container != NULL); g_return_if_fail (GNOME_IS_ICON_CONTAINER (container)); g_return_if_fail (event != NULL); dnd_info = container->details->dnd_info; g_return_if_fail (dnd_info != NULL); - /* Notice that the event is already in world coordinates, because of - the way the canvas handles events! */ - dnd_info->start_x = event->x; - dnd_info->start_y = event->y; + /* Notice that the event is in world coordinates, because of + the way the canvas handles events. + */ + canvas = GNOME_CANVAS (container); + gnome_canvas_world_to_window (canvas, + event->x, event->y, + &dnd_info->start_x, &dnd_info->start_y); /* start the drag */ context = gtk_drag_begin (GTK_WIDGET (container), @@ -773,46 +739,21 @@ gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, (GdkEvent *) event); /* create a pixmap and mask to drag with */ - pixbuf_item = GNOME_CANVAS_ITEM (container->details->drag_icon->item); - pixbuf_args[0].name = "NautilusIconsViewIconItem::pixbuf"; - gtk_object_getv (GTK_OBJECT (pixbuf_item), 1, pixbuf_args); - temp_pixbuf = (GdkPixbuf *) GTK_VALUE_OBJECT (pixbuf_args[0]); - + item = GNOME_CANVAS_ITEM (container->details->drag_icon->item); + pixbuf_arg.name = "NautilusIconsViewIconItem::pixbuf"; + gtk_object_getv (GTK_OBJECT (item), 1, &pixbuf_arg); + pixbuf = GTK_VALUE_BOXED (pixbuf_arg); + gdk_pixbuf_render_pixmap_and_mask (pixbuf, + &pixmap_for_dragged_file, + &mask_for_dragged_file, + 128); + /* compute the image's offset */ - canvas = GNOME_CANVAS (container); - - x_offset = floor (event->x - pixbuf_item->x1 + .5); - y_offset = floor (event->y - pixbuf_item->y1 + .5); + nautilus_icons_view_icon_item_get_icon_window_rectangle + (container->details->drag_icon->item, &rect); + x_offset = dnd_info->start_x - rect.x0; + y_offset = dnd_info->start_y - rect.y0; - center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (container->details->drag_icon->item)); - x_offset -= center_offset; - - /* if the scale factor isn't 1.0, we have to scale the pixmap */ - /* FIXME: eventually need to get the size, if any, from the metadata here */ - - scaled_pixbuf = NULL; - if (container->details->zoom_level != NAUTILUS_ZOOM_LEVEL_STANDARD) { - gint old_width, old_height; - gint new_width, new_height; - - x_offset = floor (event->x * canvas->pixels_per_unit - center_offset - pixbuf_item->x1 + .5); - y_offset = floor (event->y * canvas->pixels_per_unit - pixbuf_item->y1 + .5); - - old_width = gdk_pixbuf_get_width (temp_pixbuf); - old_height = gdk_pixbuf_get_height (temp_pixbuf); - - new_width = floor ((old_width * canvas->pixels_per_unit) + .5); - new_height = floor ((old_height * canvas->pixels_per_unit) + .5); - - scaled_pixbuf = gdk_pixbuf_scale_simple (temp_pixbuf, new_width, new_height, ART_FILTER_BILINEAR); - temp_pixbuf = scaled_pixbuf; - } - - gdk_pixbuf_render_pixmap_and_mask (temp_pixbuf, &pixmap_for_dragged_file, &mask_for_dragged_file, 128); - if (scaled_pixbuf) - gdk_pixbuf_unref(scaled_pixbuf); - /* set the pixmap and mask for dragging */ gtk_drag_set_icon_pixmap (context, gtk_widget_get_colormap (GTK_WIDGET (container)), pixmap_for_dragged_file, mask_for_dragged_file, @@ -824,7 +765,6 @@ gnome_icon_container_dnd_end_drag (GnomeIconContainer *container) { GnomeIconContainerDndInfo *dnd_info; - g_return_if_fail (container != NULL); g_return_if_fail (GNOME_IS_ICON_CONTAINER (container)); dnd_info = container->details->dnd_info; diff --git a/libnautilus-private/gnome-icon-container-private.h b/libnautilus-private/gnome-icon-container-private.h index 1ecd0625d..abb781303 100644 --- a/libnautilus-private/gnome-icon-container-private.h +++ b/libnautilus-private/gnome-icon-container-private.h @@ -28,20 +28,20 @@ #include "gnome-icon-container.h" #include "gnome-icon-container-dnd.h" #include "nautilus-icon-factory.h" -#include +#include "nautilus-icons-view-icon-item.h" /* An Icon. */ typedef struct { /* Canvas item for the icon. */ - GnomeCanvasItem *item; + NautilusIconsViewIconItem *item; /* X/Y coordinates and size. We could use the GnomeCanvasItem * functions, but this is a lot faster */ - gdouble x, y; + double x, y; - /* Whether this item is selected (i.e. highlighted) for operation. */ + /* Whether this item is selected for operation. */ gboolean is_selected : 1; /* Whether this item is selected for keyboard navigation. */ @@ -89,7 +89,7 @@ typedef struct { typedef struct { gboolean active; - gdouble start_x, start_y; + double start_x, start_y; GnomeCanvasItem *selection_rectangle; guint timer_id; diff --git a/libnautilus-private/gnome-icon-container.c b/libnautilus-private/gnome-icon-container.c index 04e1c054d..7f144c396 100644 --- a/libnautilus-private/gnome-icon-container.c +++ b/libnautilus-private/gnome-icon-container.c @@ -37,8 +37,6 @@ #include "nautilus-gtk-macros.h" #include "gnome-icon-container-private.h" -#include "gnome-icon-container-dnd.h" -#include "nautilus-icons-view-icon-item.h" /* Interval for updating the rubberband selection, in milliseconds. */ #define RUBBERBAND_TIMEOUT_INTERVAL 10 @@ -117,10 +115,10 @@ icon_new (GnomeIconContainer *container, new->data = data; - new->item = gnome_canvas_item_new - (GNOME_CANVAS_GROUP (canvas->root), - nautilus_icons_view_icon_item_get_type (), - NULL); + new->item = NAUTILUS_ICONS_VIEW_ICON_ITEM + (gnome_canvas_item_new (GNOME_CANVAS_GROUP (canvas->root), + nautilus_icons_view_icon_item_get_type (), + NULL)); request_update_one (container, new); @@ -129,20 +127,17 @@ icon_new (GnomeIconContainer *container, static void icon_position (GnomeIconContainerIcon *icon, - GnomeIconContainer *container, - gdouble x, gdouble y) + double x, double y) { - GnomeIconContainerDetails *details; + if (icon->x == x && icon->y == y) + return; - details = container->details; + gnome_canvas_item_move (GNOME_CANVAS_ITEM (icon->item), + x - icon->x, + y - icon->y); icon->x = x; icon->y = y; - - gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "x", (gdouble) icon->x, - "y", (gdouble) icon->y, - NULL); } static void @@ -162,7 +157,7 @@ icon_toggle_selected (GnomeIconContainerIcon *icon) { icon->is_selected = !icon->is_selected; gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "selected", (gboolean) icon->is_selected, + "highlighted_for_selection", (gboolean) icon->is_selected, NULL); } @@ -187,28 +182,23 @@ icon_select (GnomeIconContainerIcon *icon, static gboolean icon_is_in_region (GnomeIconContainer *container, GnomeIconContainerIcon *icon, - int x1, int y1, - int x2, int y2) + int x0, int y0, + int x1, int y1) { - int icon_x2, icon_y2; - int size; - - size = nautilus_icon_size_for_zoom_level - (gnome_icon_container_get_zoom_level (container)); - - icon_x2 = icon->x + size; - icon_y2 = icon->y + size; + ArtDRect rect; - if (x1 >= x2 || y1 >= y2) + if (x0 >= x1 || y0 >= y1) return FALSE; - return x1 < icon_x2 && x2 >= icon->x && y1 < icon_y2 && y2 >= icon->y; + nautilus_icons_view_icon_item_get_icon_world_rectangle + (icon->item, &rect); + return x0 < rect.x1 && x1 >= rect.x0 && y0 < rect.y1 && y1 >= rect.y0; } static void icon_get_bounding_box (GnomeIconContainerIcon *icon, - guint *x1_return, guint *y1_return, - guint *x2_return, guint *y2_return) + int *x1_return, int *y1_return, + int *x2_return, int *y2_return) { double x1, y1, x2, y2; @@ -829,15 +819,15 @@ set_kbd_current (GnomeIconContainer *container, details = container->details; if (details->kbd_current != NULL) - gnome_canvas_item_set (details->kbd_current->item, - "alt_selected", 0, + gnome_canvas_item_set (GNOME_CANVAS_ITEM (details->kbd_current->item), + "highlighted_for_keyboard_selection", 0, NULL); details->kbd_current = icon; if (icon != NULL) { - gnome_canvas_item_set (icon->item, - "alt_selected", 1, + gnome_canvas_item_set (GNOME_CANVAS_ITEM (details->kbd_current->item), + "highlighted_for_keyboard_selection", 1, NULL); icon_raise (icon); } @@ -859,7 +849,7 @@ set_scroll_region (GnomeIconContainer *container) GnomeIconContainerIconGrid *grid; GtkAllocation *allocation; GtkAdjustment *vadj, *hadj; - gdouble x1, y1, x2, y2; + double x1, y1, x2, y2; guint scroll_width, scroll_height; details = container->details; @@ -883,8 +873,8 @@ set_scroll_region (GnomeIconContainer *container) gnome_canvas_set_scroll_region (GNOME_CANVAS (container), 0.0, 0.0, - (gdouble) scroll_width, - (gdouble) scroll_height); + (double) scroll_width, + (double) scroll_height); if (details->width <= allocation->width) gtk_adjustment_set_value (hadj, 0.0); @@ -1005,7 +995,7 @@ gnome_icon_container_move_icon (GnomeIconContainer *container, if (new_x_offset > 0 && new_y_offset > 0) icon_grid_add (details->grid, icon, new_grid_x + 1, new_grid_y + 1); - icon_position (icon, container, x, y); + icon_position (icon, x, y); if (raise) icon_raise (icon); @@ -1023,10 +1013,10 @@ gnome_icon_container_move_icon (GnomeIconContainer *container, static gboolean rubberband_select_in_cell (GnomeIconContainer *container, GList *cell, - gdouble curr_x1, gdouble curr_y1, - gdouble curr_x2, gdouble curr_y2, - gdouble prev_x1, gdouble prev_y1, - gdouble prev_x2, gdouble prev_y2) + double curr_x1, double curr_y1, + double curr_x2, double curr_y2, + double prev_x1, double prev_y1, + double prev_x2, double prev_y2) { GList *p; gboolean selection_changed; @@ -1061,10 +1051,10 @@ rubberband_select_in_cell (GnomeIconContainer *container, static void rubberband_select (GnomeIconContainer *container, - gdouble curr_x1, gdouble curr_y1, - gdouble curr_x2, gdouble curr_y2, - gdouble prev_x1, gdouble prev_y1, - gdouble prev_x2, gdouble prev_y2) + double curr_x1, double curr_y1, + double curr_x2, double curr_y2, + double prev_x1, double prev_y1, + double prev_x2, double prev_y2) { GList **p; GnomeIconContainerIconGrid *grid; @@ -1117,8 +1107,8 @@ rubberband_timeout_cb (gpointer data) GtkWidget *widget; GnomeIconContainerRubberbandInfo *band_info; int x, y; - gdouble x1, y1, x2, y2; - gdouble world_x, world_y; + double x1, y1, x2, y2; + double world_x, world_y; int x_scroll, y_scroll; GDK_THREADS_ENTER (); @@ -1127,6 +1117,9 @@ rubberband_timeout_cb (gpointer data) container = GNOME_ICON_CONTAINER (data); band_info = &container->details->rubberband_info; + g_assert (band_info->timer_id != 0); + g_assert (GNOME_IS_CANVAS_RECT (band_info->selection_rectangle)); + gdk_window_get_pointer (widget->window, &x, &y, NULL); if (x < 0) { @@ -1177,10 +1170,10 @@ rubberband_timeout_cb (gpointer data) } gnome_canvas_item_set (band_info->selection_rectangle, - "x1", (gdouble) x1, - "y1", (gdouble) y1, - "x2", (gdouble) x2, - "y2", (gdouble) y2, + "x1", x1, + "y1", y1, + "x2", x2, + "y2", y2, NULL); rubberband_select (container, @@ -1241,8 +1234,8 @@ start_rubberbanding (GnomeIconContainer *container, band_info->active = TRUE; band_info->timer_id = gtk_timeout_add (RUBBERBAND_TIMEOUT_INTERVAL, - rubberband_timeout_cb, - container); + rubberband_timeout_cb, + container); gnome_canvas_item_grab (band_info->selection_rectangle, (GDK_POINTER_MOTION_MASK @@ -2014,7 +2007,7 @@ gnome_icon_container_initialize (GnomeIconContainer *container) details->grid = icon_grid_new (); details->canvas_item_to_icon = g_hash_table_new (g_direct_hash, - g_direct_equal); + g_direct_equal); details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD; @@ -2277,19 +2270,28 @@ static void request_update_one (GnomeIconContainer *container, GnomeIconContainerIcon *icon) { GnomeIconContainerDetails *details; - GdkPixbuf *image; + NautilusScalableIcon *scalable_icon; + GdkPixbuf *pixbuf; char *label; + GdkFont *font; details = container->details; - image = nautilus_icons_controller_get_icon_image (details->controller, icon->data); + scalable_icon = nautilus_icons_controller_get_icon_image (details->controller, icon->data); + pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (scalable_icon, nautilus_icon_size_for_zoom_level (details->zoom_level)); + nautilus_scalable_icon_unref (scalable_icon); + label = nautilus_icons_controller_get_icon_text (details->controller, icon->data); + + font = details->label_font[details->zoom_level]; gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "pixbuf", image, - "label", label, + "pixbuf", pixbuf, + "text", label, + "font", font, NULL); + gdk_pixbuf_unref (pixbuf); g_free (label); } @@ -2308,7 +2310,7 @@ gnome_icon_container_add (GnomeIconContainer *container, details = container->details; new_icon = icon_new (container, data); - icon_position (new_icon, container, x, y); + icon_position (new_icon, x, y); world_to_grid (container, x, y, &grid_x, &grid_y); icon_grid_add (details->grid, new_icon, grid_x, grid_y); @@ -2350,7 +2352,7 @@ gnome_icon_container_add_auto (GnomeIconContainer *container, icon_grid_add_auto (container->details->grid, new_icon, &grid_x, &grid_y); grid_to_world (container, grid_x, grid_y, &x, &y); - icon_position (new_icon, container, x, y); + icon_position (new_icon, x, y); setup_icon_in_container (container, new_icon); @@ -2368,9 +2370,9 @@ gnome_icon_container_get_zoom_level(GnomeIconContainer *container) void gnome_icon_container_set_zoom_level(GnomeIconContainer *container, int new_level) { + GnomeIconContainerDetails *details; int pinned_level; double pixels_per_unit; - GnomeIconContainerDetails *details; details = container->details; @@ -2379,15 +2381,15 @@ gnome_icon_container_set_zoom_level(GnomeIconContainer *container, int new_level pinned_level = NAUTILUS_ZOOM_LEVEL_SMALLEST; else if (pinned_level > NAUTILUS_ZOOM_LEVEL_LARGEST) pinned_level = NAUTILUS_ZOOM_LEVEL_LARGEST; - + if (pinned_level == details->zoom_level) return; - + details->zoom_level = pinned_level; pixels_per_unit = (double) nautilus_icon_size_for_zoom_level (pinned_level) / NAUTILUS_ICON_SIZE_STANDARD; - gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(container), pixels_per_unit); + gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (container), pixels_per_unit); gnome_icon_container_request_update_all (container); } @@ -2403,20 +2405,13 @@ void gnome_icon_container_request_update_all (GnomeIconContainer *container) { GList *p; - GnomeIconContainerDetails *details; - details = container->details; - - for (p = details->icons; p != NULL; p = p->next) - { - GnomeIconContainerIcon *icon; - icon = p->data; - - request_update_one (container, icon); - } + for (p = container->details->icons; p != NULL; p = p->next) + request_update_one (container, p->data); } + /** * gnome_icon_container_relayout: * @container: An icon container. @@ -2492,7 +2487,7 @@ gnome_icon_container_relayout (GnomeIconContainer *container) dp[cols] = g_list_alloc (); dp[cols]->data = icon; - icon_position (icon, container, dx, dy); + icon_position (icon, dx, dy); icon->layout_done = TRUE; @@ -2631,7 +2626,7 @@ gnome_icon_container_line_up (GnomeIconContainer *container) || (icon->y >= 0 && icon->y < y)) continue; - icon_position (icon, container, dx, y); + icon_position (icon, dx, y); icon->layout_done = TRUE; q[k] = g_list_alloc (); diff --git a/libnautilus-private/nautilus-icons-controller.c b/libnautilus-private/nautilus-icons-controller.c index ac68e783c..850ffdce8 100644 --- a/libnautilus-private/nautilus-icons-controller.c +++ b/libnautilus-private/nautilus-icons-controller.c @@ -50,7 +50,7 @@ nautilus_icons_controller_initialize (NautilusIconsController *controller) { } -GdkPixbuf * +NautilusScalableIcon * nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, NautilusControllerIcon *icon) { diff --git a/libnautilus-private/nautilus-icons-controller.h b/libnautilus-private/nautilus-icons-controller.h index fa123c455..a9256dd13 100644 --- a/libnautilus-private/nautilus-icons-controller.h +++ b/libnautilus-private/nautilus-icons-controller.h @@ -28,6 +28,7 @@ #include #include +#include "nautilus-icon-factory.h" /* NautilusIconsController is an abstract class that describes the interface that a NautilusIconsView (currently named GnomeIconContainer) @@ -54,15 +55,15 @@ typedef struct NautilusControllerIconDummy NautilusControllerIcon; ((NautilusControllerIcon *)(icon)) /* Basic GtkObject requirements. */ -GtkType nautilus_icons_controller_get_type (void); +GtkType nautilus_icons_controller_get_type (void); /* Icon operations. */ -GdkPixbuf *nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, - NautilusControllerIcon *icon); -char * nautilus_icons_controller_get_icon_text (NautilusIconsController *controller, - NautilusControllerIcon *icon); -char * nautilus_icons_controller_get_icon_uri (NautilusIconsController *controller, - NautilusControllerIcon *icon); +NautilusScalableIcon *nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, + NautilusControllerIcon *icon); +char * nautilus_icons_controller_get_icon_text (NautilusIconsController *controller, + NautilusControllerIcon *icon); +char * nautilus_icons_controller_get_icon_uri (NautilusIconsController *controller, + NautilusControllerIcon *icon); struct _NautilusIconsController { @@ -73,12 +74,12 @@ struct _NautilusIconsControllerClass { GtkObjectClass parent_class; - GdkPixbuf * (*get_icon_image) (NautilusIconsController *controller, - NautilusControllerIcon *icon); - char * (* get_icon_text) (NautilusIconsController *controller, - NautilusControllerIcon *icon); - char * (* get_icon_uri) (NautilusIconsController *controller, - NautilusControllerIcon *icon); + NautilusScalableIcon * (*get_icon_image) (NautilusIconsController *controller, + NautilusControllerIcon *icon); + char * (* get_icon_text) (NautilusIconsController *controller, + NautilusControllerIcon *icon); + char * (* get_icon_uri) (NautilusIconsController *controller, + NautilusControllerIcon *icon); }; #endif /* NAUTILUS_ICONS_CONTROLLER_H */ diff --git a/libnautilus-private/nautilus-icons-view-icon-item.c b/libnautilus-private/nautilus-icons-view-icon-item.c index 027bb7901..3c83c5be0 100644 --- a/libnautilus-private/nautilus-icons-view-icon-item.c +++ b/libnautilus-private/nautilus-icons-view-icon-item.c @@ -30,50 +30,27 @@ #include #include #include +#include #include "gnome-icon-container-private.h" #include "nautilus-gtk-macros.h" #include "nautilus-string.h" +#include "gdk-extensions.h" /* Private part of the NautilusIconsViewIconItem structure */ struct _NautilusIconsViewIconItemDetails { - /* Our main gdk-pixbuf */ + /* The image, text, font. */ GdkPixbuf *pixbuf; - - /* text for our label */ - char* label; + char* text; + GdkFont *font; - /* Width value */ - double width; - - /* Height value */ - double height; - - /* X translation */ - double x; - - /* Y translation */ - double y; - - /* width in pixels of the label */ - double text_width; - - /* height in pixels of the label */ - double text_height; + /* Size of the text at current font. */ + int text_width; + int text_height; - /* boolean to indicate selection state */ - guint is_selected : 1; - - /* boolean to indicate keyboard selection state */ - guint is_alt_selected: 1; - - /* boolean to indicate highlight state (for swallow) */ - guint is_highlighted : 1; - - /* Whether the pixbuf has changed */ - guint need_pixbuf_update : 1; - - /* Whether the transformation or size have changed */ - guint need_xform_update : 1; + /* Highlight state. */ + guint is_highlighted_for_selection : 1; + guint is_highlighted_for_keyboard_selection: 1; + guint is_highlighted_for_drop : 1; }; @@ -82,60 +59,73 @@ struct _NautilusIconsViewIconItemDetails { enum { ARG_0, ARG_PIXBUF, - ARG_LABEL, - ARG_WIDTH, - ARG_HEIGHT, - ARG_X, - ARG_Y, - ARG_SELECTED, - ARG_ALT_SELECTED, - ARG_HIGHLIGHTD + ARG_TEXT, + ARG_FONT, + ARG_HIGHLIGHTED_FOR_SELECTION, + ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION, + ARG_HIGHLIGHTED_FOR_DROP }; /* constants */ -#define MAX_LABEL_WIDTH 80 +#define MAX_TEXT_WIDTH 80 /* Bitmap for stippled selection rectangles. */ static GdkBitmap *stipple; static char stipple_bits[] = { 0x02, 0x01 }; /* GtkObject */ -static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class); -static void nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *item); -static void nautilus_icons_view_icon_item_destroy (GtkObject *object); -static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); -static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class); +static void nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *item); +static void nautilus_icons_view_icon_item_destroy (GtkObject *object); +static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); /* GnomeCanvasItem */ -static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags); -static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height); -static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf); -static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item); -static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2); +static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, + double *affine, + ArtSVP *clip_path, + int flags); +static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, + GdkDrawable *drawable, + int x, + int y, + int width, + int height); +static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, + GnomeCanvasBuf *buf); +static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, + double x, + double y, + int cx, + int cy, + GnomeCanvasItem **actual_item); +static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, + double *x1, + double *y1, + double *x2, + double *y2); /* private */ -static GdkFont* get_font_for_item (GnomeCanvasItem *item); -static void draw_or_measure_text_box (GnomeCanvasItem* item, - GdkDrawable *drawable, - GdkFont *title_font, - const char* label, - int icon_left, - int icon_bottom, - gboolean do_draw); -static void nautilus_icons_view_draw_text_box (GnomeCanvasItem* item, - GdkDrawable *drawable, - GdkFont *title_font, - const char *label, - int icon_left, - int icon_bottom); -static void nautilus_icons_view_measure_text_box (GnomeCanvasItem* item, - GdkFont *title_font, - const char *label); +static void draw_or_measure_text_box (GnomeCanvasItem *item, + GdkDrawable *drawable, + int icon_left, + int icon_bottom); +static void nautilus_icons_view_draw_text_box (GnomeCanvasItem *item, + GdkDrawable *drawable, + int icon_left, + int icon_bottom); +static void nautilus_icons_view_measure_text_box (GnomeCanvasItem *item); +static void nautilus_icons_view_icon_item_get_icon_canvas_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect); NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconsViewIconItem, nautilus_icons_view_icon_item, GNOME_TYPE_CANVAS_ITEM) -/* Class initialization function for the icon canvas item */ +/* Class initialization function for the icon canvas item. */ static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class) { @@ -146,24 +136,17 @@ nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass * item_class = GNOME_CANVAS_ITEM_CLASS (class); gtk_object_add_arg_type ("NautilusIconsViewIconItem::pixbuf", - GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PIXBUF); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::label", - GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::width", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH); - - gtk_object_add_arg_type ("NautilusIconsViewIconItem::height", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::x", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::y", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::selected", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SELECTED); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::alt_selected", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ALT_SELECTED); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlightd", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTD); + GTK_TYPE_BOXED, GTK_ARG_READWRITE, ARG_PIXBUF); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::text", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TEXT); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::font", + GTK_TYPE_BOXED, GTK_ARG_READWRITE, ARG_FONT); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_selection", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_SELECTION); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_keyboard_selection", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_drop", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_DROP); object_class->destroy = nautilus_icons_view_icon_item_destroy; object_class->set_arg = nautilus_icons_view_icon_item_set_arg; @@ -178,186 +161,154 @@ nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass * stipple = gdk_bitmap_create_from_data (NULL, stipple_bits, 2, 2); } -/* Object initialization function for the icon item */ +/* Object initialization function for the icon item. */ static void -nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *icon_view_item) +nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *icon_item) { NautilusIconsViewIconItemDetails *details; details = g_new0 (NautilusIconsViewIconItemDetails, 1); - icon_view_item->details = details; + + icon_item->details = details; } -/* Destroy handler for the icon canvas item */ +/* Destroy handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_destroy (GtkObject *object) { GnomeCanvasItem *item; - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (object)); item = GNOME_CANVAS_ITEM (object); - icon_view_item = (NAUTILUS_ICONS_VIEW_ICON_ITEM (object)); - details = icon_view_item->details; + icon_item = (NAUTILUS_ICONS_VIEW_ICON_ITEM (object)); + details = icon_item->details; gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); if (details->pixbuf != NULL) gdk_pixbuf_unref (details->pixbuf); - g_free (details->label); - + g_free (details->text); + if (details->font != NULL) + gdk_font_unref (details->font); + g_free (details); NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); } -/* Set_arg handler for the icon item */ - +/* Set_arg handler for the icon item. */ static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) { - GnomeCanvasItem *item; - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; GdkPixbuf *pixbuf; - char* new_label; - double val; + GdkFont *font; - item = GNOME_CANVAS_ITEM (object); - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (object); - details = icon_view_item->details; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (object)->details; switch (arg_id) { case ARG_PIXBUF: - pixbuf = GTK_VALUE_POINTER (*arg); - if (pixbuf != details->pixbuf) { - if (pixbuf) { - g_return_if_fail (pixbuf->art_pixbuf->format == ART_PIX_RGB); - g_return_if_fail (pixbuf->art_pixbuf->n_channels == 3 - || pixbuf->art_pixbuf->n_channels == 4); - g_return_if_fail (pixbuf->art_pixbuf->bits_per_sample == 8); - - gdk_pixbuf_ref (pixbuf); - } + pixbuf = GTK_VALUE_BOXED (*arg); + if (pixbuf == details->pixbuf) + return; + + if (pixbuf != NULL) { + g_return_if_fail (pixbuf->art_pixbuf->format == ART_PIX_RGB); + g_return_if_fail (pixbuf->art_pixbuf->n_channels == 3 + || pixbuf->art_pixbuf->n_channels == 4); + g_return_if_fail (pixbuf->art_pixbuf->bits_per_sample == 8); - if (details->pixbuf) - gdk_pixbuf_unref (details->pixbuf); - - details->pixbuf = pixbuf; + gdk_pixbuf_ref (pixbuf); } - - details->need_pixbuf_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_LABEL: - new_label = GTK_VALUE_STRING (*arg); - if (details->label) - g_free(details->label); - details->label = g_strdup(new_label); - details->need_pixbuf_update = TRUE; - gnome_canvas_item_request_update (item); + if (details->pixbuf != NULL) + gdk_pixbuf_unref (details->pixbuf); + + details->pixbuf = pixbuf; break; - case ARG_WIDTH: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - details->width = val; - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; + case ARG_TEXT: + if (nautilus_strcmp (details->text, GTK_VALUE_STRING (*arg)) == 0) + return; - case ARG_HEIGHT: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - details->height = val; - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); + g_free (details->text); + details->text = g_strdup (GTK_VALUE_STRING (*arg)); break; - case ARG_X: - details->x = GTK_VALUE_DOUBLE (*arg); - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; + case ARG_FONT: + font = GTK_VALUE_BOXED (*arg); + if (nautilus_gdk_font_equal (font, details->font)) + return; - case ARG_Y: - details->y = GTK_VALUE_DOUBLE (*arg); - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); + if (font != NULL) + gdk_font_ref (font); + if (details->font != NULL) + gdk_font_unref (details->font); + details->font = font; break; - - case ARG_SELECTED: - details->is_selected = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + + case ARG_HIGHLIGHTED_FOR_SELECTION: + if (!details->is_highlighted_for_selection == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_selection = GTK_VALUE_BOOL (*arg); break; - case ARG_ALT_SELECTED: - details->is_alt_selected = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + case ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION: + if (!details->is_highlighted_for_keyboard_selection == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_keyboard_selection = GTK_VALUE_BOOL (*arg); break; - case ARG_HIGHLIGHTD: - details->is_highlighted = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + case ARG_HIGHLIGHTED_FOR_DROP: + if (!details->is_highlighted_for_drop == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_drop = GTK_VALUE_BOOL (*arg); break; - default: - break; + g_warning ("nautilus_icons_view_item_item_set_arg on unknown argument"); + return; } + + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (object)); } /* Get_arg handler for the icon item */ static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) { - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (object); - details = icon_view_item->details; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (object)->details; switch (arg_id) { case ARG_PIXBUF: - GTK_VALUE_POINTER (*arg) = details->pixbuf; - break; - - case ARG_LABEL: - GTK_VALUE_STRING (*arg) = details->label; - break; - - case ARG_WIDTH: - GTK_VALUE_DOUBLE (*arg) = details->width; - break; - - case ARG_HEIGHT: - GTK_VALUE_DOUBLE (*arg) = details->height; + GTK_VALUE_BOXED (*arg) = details->pixbuf; break; - case ARG_X: - GTK_VALUE_DOUBLE (*arg) = details->x; + case ARG_TEXT: + GTK_VALUE_STRING (*arg) = g_strdup (details->text); break; - case ARG_Y: - GTK_VALUE_DOUBLE (*arg) = details->y; + case ARG_FONT: + GTK_VALUE_BOXED (*arg) = details->font; break; - case ARG_SELECTED: - GTK_VALUE_BOOL (*arg) = details->is_selected; + case ARG_HIGHLIGHTED_FOR_SELECTION: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_selection; break; - case ARG_ALT_SELECTED: - GTK_VALUE_BOOL (*arg) = details->is_alt_selected; + case ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_keyboard_selection; break; - case ARG_HIGHLIGHTD: - GTK_VALUE_BOOL (*arg) = details->is_highlighted; + case ARG_HIGHLIGHTED_FOR_DROP: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_drop; break; default: @@ -366,324 +317,147 @@ nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg } } - -/* Bounds and utilities */ - -/* Computes the amount by which the unit horizontal and vertical vectors will be - * scaled by an affine transformation. - */ -static void -compute_xform_scaling (double *affine, ArtPoint *i_c, ArtPoint *j_c) -{ - ArtPoint orig, orig_c; - ArtPoint i, j; - - /* Origin */ - - orig.x = 0.0; - orig.y = 0.0; - art_affine_point (&orig_c, &orig, affine); - - /* Horizontal and vertical vectors */ - - i.x = 1.0; - i.y = 0.0; - art_affine_point (i_c, &i, affine); - i_c->x -= orig_c.x; - i_c->y -= orig_c.y; - - j.x = 0.0; - j.y = 1.0; - art_affine_point (j_c, &j, affine); - j_c->x -= orig_c.x; - j_c->y -= orig_c.y; -} - -/* computes the addtional resolution dependent affine needed to - * fit the image within its viewport defined by x,y,width and height - * args - */ -static void -compute_viewport_affine (NautilusIconsViewIconItem *icon_view_item, double *viewport_affine, double *i2c) -{ - NautilusIconsViewIconItemDetails *details; - ArtPoint i_c, j_c; - double i_len, j_len; - double si_len, sj_len; - double ti_len, tj_len; - double scale[6], translate[6]; - double w, h; - double x, y; - - details = icon_view_item->details; - - /* Compute scaling vectors and required width/height */ - - compute_xform_scaling (i2c, &i_c, &j_c); - - i_len = sqrt (i_c.x * i_c.x + i_c.y * i_c.y); - j_len = sqrt (j_c.x * j_c.x + j_c.y * j_c.y); - - w = details->width; - if (!w) - w = details->pixbuf->art_pixbuf->width; - - h = details->height; - if (!h) - h = details->pixbuf->art_pixbuf->height; - - x = details->x; - y = details->y; - - si_len = w / details->pixbuf->art_pixbuf->width; - sj_len = h / details->pixbuf->art_pixbuf->height; - - ti_len = x; - tj_len = y; - - /* Compute the final affine */ - - art_affine_scale (scale, si_len, sj_len); - art_affine_translate (translate, ti_len, tj_len); - art_affine_multiply (viewport_affine, scale, translate); -} - -/* Computes the affine transformation with which the pixbuf needs to be - * transformed to render it on the canvas. This is not the same as the - * item_to_canvas transformation because we may need to scale the pixbuf - * by some other amount. - */ -static void -compute_render_affine (NautilusIconsViewIconItem *icon_view_item, double *render_affine, double *i2c) -{ - double viewport_affine[6]; - - compute_viewport_affine (icon_view_item, viewport_affine, i2c); - art_affine_multiply (render_affine, viewport_affine, i2c); -} - -/* utility to return the proper font for a given item, factoring in the current zoom level */ -static GdkFont* -get_font_for_item (GnomeCanvasItem *item) -{ - GnomeIconContainer* container = GNOME_ICON_CONTAINER (item->canvas); - return container->details->label_font[container->details->zoom_level]; -} - /* Recomputes the bounding box of a icon canvas item. */ static void -recompute_bounding_box (NautilusIconsViewIconItem *icon_view_item) +recompute_bounding_box (NautilusIconsViewIconItem *icon_item) { + /* The key to understanding this function: + * You must know that the documentation for gnome-canvas.h lies. + * x1, y1, x2, and y2 are in canvas coordinates, not world. + */ + GnomeCanvasItem *item; - NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - ArtDRect rect; + ArtDRect bounds; - item = GNOME_CANVAS_ITEM (icon_view_item); - details = icon_view_item->details; + item = GNOME_CANVAS_ITEM (icon_item); - if (!details->pixbuf) { - item->x1 = item->y1 = item->x2 = item->y2 = 0.0; - return; - } + gnome_canvas_item_get_bounds (item, + &bounds.x0, &bounds.y0, + &bounds.x1, &bounds.y1); - /* add 2 pixels slop to each side for highlight margin */ - rect.x0 = 0.0; - rect.x1 = details->pixbuf->art_pixbuf->width + 4; - if ((details->text_width + 4)> rect.x1) - rect.x1 = details->text_width + 4; - - rect.y0 = 0.0; - rect.y1 = details->pixbuf->art_pixbuf->height; - rect.y1 += floor(details->text_height); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - art_drect_affine_transform (&rect, &rect, render_affine); - - item->x1 = floor (rect.x0); - item->y1 = floor (rect.y0); - item->x2 = ceil (rect.x1); - item->y2 = ceil (rect.y1); -} + gnome_canvas_w2c_d (item->canvas, + bounds.x0, bounds.y0, + &item->x1, &item->y1); -/* Update sequence */ + gnome_canvas_w2c_d (item->canvas, + bounds.x1, bounds.y1, + &item->x2, &item->y2); +} -/* Update handler for the icon canvas item */ +/* Update handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - GdkFont *title_font; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - title_font = get_font_for_item(item); + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; - /* make sure the text box measurements are set up before recalculating the bounding box */ - nautilus_icons_view_measure_text_box(item, title_font, details->label); - recompute_bounding_box(icon_view_item); + /* Make sure the text box measurements are set up + * before recalculating the bounding box. + */ + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + nautilus_icons_view_measure_text_box (item); + recompute_bounding_box (icon_item); + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); NAUTILUS_CALL_PARENT_CLASS (GNOME_CANVAS_ITEM_CLASS, update, (item, affine, clip_path, flags)); - - if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE) - || details->need_pixbuf_update - || details->need_xform_update) - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - - /* If we need a pixbuf update, or if the item changed visibility to - * shown, recompute the bounding box. - */ - if (details->need_pixbuf_update - || details->need_xform_update - || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && (GTK_OBJECT_FLAGS (icon_view_item) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE)) { - recompute_bounding_box (icon_view_item); - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - details->need_pixbuf_update = FALSE; - details->need_xform_update = FALSE; - } } /* Rendering */ -/* This is detailsate to libart, but we need it. Sigh. */ -extern void art_rgb_affine_run (int *p_x0, int *p_x1, int y, int src_width, int src_height, - const double affine[6]); - -/* Fills the specified buffer with the transformed version of a pixbuf */ -static void -transform_pixbuf (guchar *dest, int x, int y, int width, int height, int rowstride, - GdkPixbuf *pixbuf, double *affine) -{ - ArtPixBuf *apb; - int xx, yy; - double inv[6]; - guchar *src, *d; - ArtPoint src_p, dest_p; - int run_x1, run_x2; - int src_x, src_y; - int i; - - apb = pixbuf->art_pixbuf; - - art_affine_invert (inv, affine); - - for (yy = 0; yy < height; yy++) { - dest_p.y = y + yy + 0.5; - - run_x1 = x; - run_x2 = x + width; - art_rgb_affine_run (&run_x1, &run_x2, yy + y, - apb->width, apb->height, - inv); - - d = dest + yy * rowstride + (run_x1 - x) * 4; - - for (xx = run_x1; xx < run_x2; xx++) { - dest_p.x = xx + 0.5; - art_affine_point (&src_p, &dest_p, inv); - src_x = floor (src_p.x); - src_y = floor (src_p.y); - - src = apb->pixels + src_y * apb->rowstride + src_x * apb->n_channels; - - for (i = 0; i < apb->n_channels; i++) - *d++ = *src++; - - if (!apb->has_alpha) - *d++ = 255; /* opaque */ - } - } -} - -/* Draw the label in a box, using gnomelib routines. */ +/* Draw the text in a box, using gnomelib routines. */ static void draw_or_measure_text_box (GnomeCanvasItem* item, GdkDrawable *drawable, - GdkFont *title_font, - const char *label, - int icon_left, - int icon_bottom, - gboolean do_draw) + int icon_left, + int icon_bottom) { - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; int width_so_far, height_so_far; GdkGC* gc; - int max_label_width; - int item_width, box_left; + int max_text_width; + int icon_width, text_left, box_left; GnomeIconTextInfo *icon_text_info; - gchar **pieces; - const char *label_piece; - guint piece_index; + char **pieces; + const char *text_piece; + int i; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - pieces = g_strsplit (label, "\n", 0); - piece_index = 0; - label_piece = pieces[piece_index]; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (item)->details; + + if (details->font == NULL || details->text == NULL || details->text[0] == '\0') { + details->text_height = 0; + details->text_width = 0; + return; + } + width_so_far = 0; height_so_far = 0; - while (label_piece != NULL) { + + if (drawable != NULL) { + icon_width = details->pixbuf == NULL ? 0 : details->pixbuf->art_pixbuf->width; + gc = gdk_gc_new (item->canvas->layout.bin_window); + } + + max_text_width = floor (MAX_TEXT_WIDTH * item->canvas->pixels_per_unit); + + pieces = g_strsplit (details->text, "\n", 0); + for (i = 0; (text_piece = pieces[i]) != NULL; i++) { /* Replace empty string with space for measurement and drawing. - * This make empty lines appear, instead of being collapsed out. + * This makes empty lines appear, instead of being collapsed out. */ - if (strlen (label_piece) == 0) - label_piece = " "; - - if (do_draw) { - item_width = floor (item->x2 - item->x1); - gc = gdk_gc_new (item->canvas->layout.bin_window); - } + if (text_piece[0] == '\0') + text_piece = " "; - max_label_width = floor (MAX_LABEL_WIDTH * item->canvas->pixels_per_unit); - icon_text_info = gnome_icon_layout_text - (title_font, label_piece, " -_,;.:?/&", max_label_width, TRUE); + (details->font, text_piece, " -_,;.:?/&", max_text_width, TRUE); - if (do_draw) { - box_left = icon_left + (item_width - icon_text_info->width) / 2; + if (drawable != NULL) { + text_left = icon_left + (icon_width - icon_text_info->width) / 2; gnome_icon_paint_text (icon_text_info, drawable, gc, - box_left, icon_bottom + height_so_far, GTK_JUSTIFY_CENTER); + text_left, icon_bottom + height_so_far, GTK_JUSTIFY_CENTER); } - gnome_icon_text_info_free (icon_text_info); - width_so_far = MAX (width_so_far, icon_text_info->width); height_so_far += icon_text_info->height; - - label_piece = pieces[++piece_index]; + + gnome_icon_text_info_free (icon_text_info); } g_strfreev (pieces); - height_so_far += 4; /* extra slop for nicer highlighting */ + height_so_far += 2; /* extra slop for nicer highlighting */ - if (do_draw) { + if (drawable != NULL) { - /* Current calculations should match what we measured before drawing */ + /* Current calculations should match what we measured before drawing. + * This assumes that we will always make a separate call to measure + * before the call to draw. We might later decide to use this function + * differently and change these asserts. + */ g_assert (height_so_far == details->text_height); g_assert (width_so_far == details->text_width); + box_left = icon_left + (icon_width - width_so_far) / 2; + /* invert to indicate selection if necessary */ - if (details->is_selected) { - gdk_gc_set_function (gc, GDK_INVERT); - gdk_draw_rectangle (drawable, gc, TRUE, box_left, icon_bottom - 2, width_so_far, height_so_far); - gdk_gc_set_function (gc, GDK_COPY); + if (details->is_highlighted_for_selection) { + gdk_gc_set_function (gc, GDK_INVERT); + gdk_draw_rectangle (drawable, gc, TRUE, + box_left, icon_bottom - 2, + width_so_far, 2 + height_so_far); + gdk_gc_set_function (gc, GDK_COPY); } - /* indicate alt-selection by framing the text with a gray-stippled rectangle */ - if (details->is_alt_selected) { - gdk_gc_set_stipple(gc, stipple); - gdk_gc_set_fill(gc, GDK_STIPPLED); - gdk_draw_rectangle (drawable, gc, FALSE, box_left, icon_bottom - 2, width_so_far, height_so_far); + /* indicate keyboard selection by framing the text with a gray-stippled rectangle */ + if (details->is_highlighted_for_keyboard_selection) { + gdk_gc_set_stipple (gc, stipple); + gdk_gc_set_fill (gc, GDK_STIPPLED); + gdk_draw_rectangle (drawable, gc, FALSE, + box_left, icon_bottom - 2, + width_so_far, 2 + height_so_far); } gdk_gc_unref (gc); @@ -691,252 +465,262 @@ draw_or_measure_text_box (GnomeCanvasItem* item, else { /* If measuring, remember the width & height. */ - details->text_width = (double) width_so_far; - details->text_height = (double) height_so_far; + details->text_width = width_so_far; + details->text_height = height_so_far; } } static void -nautilus_icons_view_measure_text_box (GnomeCanvasItem* item, - GdkFont *title_font, - const char *label) +nautilus_icons_view_measure_text_box (GnomeCanvasItem* item) { - draw_or_measure_text_box (item, - NULL, - title_font, - label, - 0, - 0, - FALSE); + draw_or_measure_text_box (item, NULL, 0, 0); } static void nautilus_icons_view_draw_text_box (GnomeCanvasItem* item, GdkDrawable *drawable, - GdkFont *title_font, const char *label, int icon_left, int icon_bottom) { - draw_or_measure_text_box (item, - drawable, - title_font, - label, - icon_left, - icon_bottom, - TRUE); + draw_or_measure_text_box (item, drawable, icon_left, icon_bottom); } -/* draw the icon item */ - +/* Draw the icon item. */ static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - guchar *buf; - GdkPixbuf *pixbuf; - ArtIRect p_rect, a_rect, d_rect; - int w, h, icon_height; - int center_offset = 0; - GdkFont *title_font = get_font_for_item(item); - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - /* handle drawing the pixbuf */ - - if (details->pixbuf) { - center_offset = nautilus_icons_view_icon_item_center_offset (icon_view_item); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - - /* Compute the area we need to repaint */ - - p_rect.x0 = item->x1; - p_rect.y0 = item->y1; - p_rect.x1 = item->x2; - p_rect.y1 = item->y2; - - a_rect.x0 = x - center_offset; - a_rect.y0 = y; - a_rect.x1 = x + width - center_offset; - a_rect.y1 = y + height; - - art_irect_intersect (&d_rect, &p_rect, &a_rect); - if (art_irect_empty (&d_rect)) - return; - - /* Create a temporary buffer and transform the pixbuf there */ - /* FIXME: only do this if really necessary */ - - w = d_rect.x1 - d_rect.x0; - h = d_rect.y1 - d_rect.y0; - - buf = g_new0 (guchar, w * h * 4); - transform_pixbuf (buf, - d_rect.x0, d_rect.y0, - w, h, - w * 4, - details->pixbuf, render_affine); - - pixbuf = gdk_pixbuf_new_from_data (buf, ART_PIX_RGB, TRUE, w, h, w * 4, NULL, NULL); - - gdk_pixbuf_render_to_drawable_alpha (pixbuf, drawable, - 0, 0, - d_rect.x0 - x + center_offset, d_rect.y0 - y, - w, h, - GDK_PIXBUF_ALPHA_BILEVEL, - 128, - GDK_RGB_DITHER_MAX, - d_rect.x0, d_rect.y0); - gdk_pixbuf_unref (pixbuf); - g_free (buf); + ArtIRect pixbuf_rect, drawable_rect, draw_rect; + + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + + /* Compute pixbuf rectangle in canvas coordinates. */ + nautilus_icons_view_icon_item_get_icon_canvas_rectangle + (icon_item, &pixbuf_rect); + + /* Draw the pixbuf. */ + if (details->pixbuf != NULL) { + /* Compute the area we need to draw. */ + drawable_rect.x0 = x; + drawable_rect.y0 = y; + drawable_rect.x1 = x + width; + drawable_rect.y1 = y + height; + art_irect_intersect (&draw_rect, &pixbuf_rect, &drawable_rect); + if (!art_irect_empty (&draw_rect)) + gdk_pixbuf_render_to_drawable_alpha + (details->pixbuf, drawable, + draw_rect.x0 - pixbuf_rect.x0, draw_rect.y0 - pixbuf_rect.y0, + draw_rect.x0 - x, draw_rect.y0 - y, + draw_rect.x1 - draw_rect.x0, draw_rect.y1 - draw_rect.y0, + GDK_PIXBUF_ALPHA_BILEVEL, 128, GDK_RGB_DITHER_MAX, + draw_rect.x0, draw_rect.y0); } - /* now compute the position of the label and draw it */ - if (nautilus_strlen (details->label) > 0) - { - icon_height = details->pixbuf->art_pixbuf->height * item->canvas->pixels_per_unit; - nautilus_icons_view_draw_text_box(item, drawable, title_font, details->label, item->x1 - x, - item->y1 - y + icon_height); - } -} - -/* return the center offset for this icon */ -int -nautilus_icons_view_icon_item_center_offset(NautilusIconsViewIconItem *icon_view_item) -{ - GnomeCanvasItem *item; - NautilusIconsViewIconItemDetails *details; - int box_width; - int center_offset; - - g_return_val_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (icon_view_item), 0); - - item = GNOME_CANVAS_ITEM (icon_view_item); - details = icon_view_item->details; - - box_width = floor (item->x2 - item->x1); - center_offset = (box_width - floor (details->pixbuf->art_pixbuf->width * item->canvas->pixels_per_unit)) / 2; - return center_offset; + /* Draw the text. */ + nautilus_icons_view_draw_text_box + (item, drawable, + pixbuf_rect.x0 - x, pixbuf_rect.y1 - y); } -/* Render handler for the icon canvas item */ +/* Render handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) { - NautilusIconsViewIconItem *icon_view_item; - NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - if (!details->pixbuf) - return; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); + g_assert_not_reached (); +#if 0 gnome_canvas_buf_ensure_buf (buf); art_rgb_pixbuf_affine (buf->buf, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, buf->buf_rowstride, details->pixbuf->art_pixbuf, - render_affine, + i2c, ART_FILTER_BILINEAR, NULL); buf->is_bg = 0; +#endif } -/* Point handler for the icon canvas item */ +/* Point handler for the icon canvas item. */ +/* FIXME: This currently only reports a hit if the pixbuf is hit. */ static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) + GnomeCanvasItem **actual_item) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6], inv[6]; - ArtPoint c, p; - int px, py; - int center_offset; double no_hit; - ArtPixBuf *apb; - guchar *src; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - center_offset = nautilus_icons_view_icon_item_center_offset (icon_view_item); + ArtIRect rect; + ArtPixBuf *art_pixbuf; + guint8 *pixel; + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + *actual_item = item; - no_hit = item->canvas->pixels_per_unit * 2 + 10; - - if (!details->pixbuf) + + /* Check to see if it's within the item's rectangle at all. */ + nautilus_icons_view_icon_item_get_icon_canvas_rectangle (icon_item, &rect); + if (cx <= rect.x0 || cx >= rect.x1 || cy <= rect.y0 || cy >= rect.y1) return no_hit; - - apb = details->pixbuf->art_pixbuf; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - art_affine_invert (inv, render_affine); - - c.x = cx - center_offset; - c.y = cy; - art_affine_point (&p, &c, inv); - px = p.x; - py = p.y; - - if (px < 0 || px >= apb->width || py < 0 || py >= apb->height) + + /* Can't get this far without a pixbuf. */ + g_assert (details->pixbuf != NULL); + if (details->pixbuf == NULL) return no_hit; - if (!apb->has_alpha) + /* If there's no alpha channel, it's opaque and we have a hit. */ + art_pixbuf = details->pixbuf->art_pixbuf; + if (!art_pixbuf->has_alpha) return 0.0; + g_assert (art_pixbuf->n_channels == 4); - src = apb->pixels + py * apb->rowstride + px * apb->n_channels; - - if (src[3] < 128) - return no_hit; - else + /* Check the alpha channel of the pixel to see if we have a hit. */ + pixel = art_pixbuf->pixels + + (cy - rect.y0) * art_pixbuf->rowstride + + (cx - rect.x0) * 4; + if (pixel[3] >= 128) return 0.0; -} + return no_hit; +} -/* Bounds handler for the icon canvas item */ +/* Bounds handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], viewport_affine[6]; - ArtDRect rect; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; + ArtIRect rect; + int pixbuf_width, pixbuf_height; + double pixels_per_unit; + + g_assert (x1 != NULL); + g_assert (y1 != NULL); + g_assert (x2 != NULL); + g_assert (y2 != NULL); + + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + + if (details->pixbuf == NULL) { + pixbuf_width = 0; + pixbuf_height = 0; + } else { + pixbuf_width = details->pixbuf->art_pixbuf->width; + pixbuf_height = details->pixbuf->art_pixbuf->height; + } - if (!details->pixbuf) { - *x1 = *y1 = *x2 = *y2 = 0.0; - return; + /* Compute rectangle enclosing both the icon and the text. */ + if (pixbuf_width > details->text_width) { + rect.x0 = 0; + rect.x1 = pixbuf_width; + } else { + rect.x0 = (pixbuf_width - details->text_width) / 2; + rect.x1 = rect.x0 + details->text_width; } + rect.y0 = 0; + rect.y1 = pixbuf_height + details->text_height; + + /* Add 2 pixels slop to each side. */ + rect.x0 -= 2; + rect.x1 += 2; + rect.y0 -= 2; + rect.y1 += 2; + + /* Return the result. */ + pixels_per_unit = item->canvas->pixels_per_unit; + *x1 = rect.x0 / pixels_per_unit; + *y1 = rect.y0 / pixels_per_unit; + *x2 = rect.x1 / pixels_per_unit; + *y2 = rect.y1 / pixels_per_unit; +} + +/* Get the rectangle of the icon only, in world coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_world_rectangle (NautilusIconsViewIconItem *item, + ArtDRect *rect) +{ + double i2w[6]; + ArtPoint art_point; + double pixels_per_unit; + GdkPixbuf *pixbuf; - /* add 2 pixels slop to each side for highlight margin */ - rect.x0 = 0.0; - rect.x1 = details->pixbuf->art_pixbuf->width + 4; - if ((details->text_width + 4) > rect.x1) - rect.x1 = details->text_width + 4; + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2w_affine (GNOME_CANVAS_ITEM (item), i2w); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2w); - rect.y0 = 0.0; - rect.y1 = details->pixbuf->art_pixbuf->height; - rect.y1 += floor(details->text_height); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_viewport_affine (icon_view_item, viewport_affine, i2c); - art_drect_affine_transform (&rect, &rect, viewport_affine); + rect->x0 = art_point.x; + rect->y0 = art_point.y; + + pixbuf = item->details->pixbuf; + pixels_per_unit = GNOME_CANVAS_ITEM (item)->canvas->pixels_per_unit; + + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width) / pixels_per_unit; + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height) / pixels_per_unit; +} + +/* Get the rectangle of the icon only, in canvas coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_canvas_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect) +{ + double i2c[6]; + ArtPoint art_point; + GdkPixbuf *pixbuf; + + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (item), i2c); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2c); + + rect->x0 = floor (art_point.x); + rect->y0 = floor (art_point.y); + + pixbuf = item->details->pixbuf; + + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height); +} + +/* Get the rectangle of the icon only, in window coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_window_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect) +{ + double i2w[6]; + ArtPoint art_point; + GdkPixbuf *pixbuf; + + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2w_affine (GNOME_CANVAS_ITEM (item), i2w); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2w); + gnome_canvas_world_to_window (GNOME_CANVAS_ITEM (item)->canvas, + art_point.x, art_point.y, + &art_point.x, &art_point.y); + + rect->x0 = floor (art_point.x); + rect->y0 = floor (art_point.y); + + pixbuf = item->details->pixbuf; - *x1 = rect.x0; - *y1 = rect.y0; - *x2 = rect.x1; - *y2 = rect.y1; + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height); } diff --git a/libnautilus-private/nautilus-icons-view-icon-item.h b/libnautilus-private/nautilus-icons-view-icon-item.h index 4e95dcefb..03ae11862 100644 --- a/libnautilus-private/nautilus-icons-view-icon-item.h +++ b/libnautilus-private/nautilus-icons-view-icon-item.h @@ -55,8 +55,11 @@ struct _NautilusIconsViewIconItemClass { GnomeCanvasItemClass parent_class; }; -GtkType nautilus_icons_view_icon_item_get_type (void); -int nautilus_icons_view_icon_item_center_offset (NautilusIconsViewIconItem *item); +GtkType nautilus_icons_view_icon_item_get_type (void); +void nautilus_icons_view_icon_item_get_icon_world_rectangle (NautilusIconsViewIconItem *item, + ArtDRect *world_rectangle); +void nautilus_icons_view_icon_item_get_icon_window_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *window_rectangle); END_GNOME_DECLS diff --git a/libnautilus/gdk-extensions.c b/libnautilus/gdk-extensions.c index 73731dc41..7d7f2c286 100644 --- a/libnautilus/gdk-extensions.c +++ b/libnautilus/gdk-extensions.c @@ -393,6 +393,24 @@ nautilus_gdk_color_parse_with_white_default (const char *color_spec, } } +/** + * nautilus_gdk_font_equal + * @font_a_null_allowed: A font or NULL. + * @font_b_null_allowed: A font or NULL. + * + * Calls gdk_font_equal, unless one of the fonts is NULL. + */ +gboolean +nautilus_gdk_font_equal (GdkFont *font_a_null_allowed, + GdkFont *font_b_null_allowed) +{ + if (font_a_null_allowed == NULL) + return font_b_null_allowed == NULL; + if (font_b_null_allowed == NULL) + return FALSE; + return gdk_font_equal (font_a_null_allowed, font_b_null_allowed); +} + #if ! defined (NAUTILUS_OMIT_SELF_CHECK) static char * diff --git a/libnautilus/gdk-extensions.h b/libnautilus/gdk-extensions.h index f5dd0c27b..366303c1d 100644 --- a/libnautilus/gdk-extensions.h +++ b/libnautilus/gdk-extensions.h @@ -81,4 +81,7 @@ void nautilus_interpolate_color (gdouble ratio, const GdkColor *end_color, GdkColor *interpolated_color); +gboolean nautilus_gdk_font_equal (GdkFont *font_a_null_allowed, + GdkFont *font_b_null_allowed); + #endif /* GDK_EXTENSIONS_H */ diff --git a/libnautilus/gnome-icon-container-dnd.c b/libnautilus/gnome-icon-container-dnd.c index e01c1c43d..dd74f85ea 100644 --- a/libnautilus/gnome-icon-container-dnd.c +++ b/libnautilus/gnome-icon-container-dnd.c @@ -26,17 +26,15 @@ #include #include "gnome-icon-container-dnd.h" -#include "gnome-icon-container-private.h" -#include "nautilus-icons-view-icon-item.h" -#include "nautilus-background.h" -#include "nautilus-gtk-extensions.h" - -#include #include #include #include +#include "nautilus-glib-extensions.h" #include - +#include "nautilus-gtk-extensions.h" +#include "nautilus-background.h" +#include "gnome-icon-container-private.h" +#include typedef struct { char *uri; @@ -50,7 +48,6 @@ static GtkTargetEntry drag_types [] = { { GNOME_ICON_CONTAINER_DND_URI_LIST_TYPE, 0, GNOME_ICON_CONTAINER_DND_URI_LIST }, { GNOME_ICON_CONTAINER_DND_URL_TYPE, 0, GNOME_ICON_CONTAINER_DND_URL } }; -static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]); static GtkTargetEntry drop_types [] = { { GNOME_ICON_CONTAINER_DND_GNOME_ICON_LIST_TYPE, 0, GNOME_ICON_CONTAINER_DND_GNOME_ICON_LIST }, @@ -58,7 +55,6 @@ static GtkTargetEntry drop_types [] = { { GNOME_ICON_CONTAINER_DND_URL_TYPE, 0, GNOME_ICON_CONTAINER_DND_URL }, { GNOME_ICON_CONTAINER_DND_COLOR_TYPE, 0, GNOME_ICON_CONTAINER_DND_COLOR } }; -static const int num_drop_types = sizeof (drop_types) / sizeof (drop_types[0]); static GnomeCanvasItem * create_selection_shadow (GnomeIconContainer *container, @@ -70,6 +66,7 @@ create_selection_shadow (GnomeIconContainer *container, int max_x, max_y; int min_x, min_y; GList *p; + double pixels_per_unit; if (list == NULL) return NULL; @@ -83,6 +80,7 @@ create_selection_shadow (GnomeIconContainer *container, we try to be smart and only create the maximum number of rectangles that we will need, in the vertical/horizontal directions. */ + /* FIXME: Does this work properly if the window is scrolled? */ max_x = GTK_WIDGET (container)->allocation.width; min_x = -max_x; @@ -96,10 +94,10 @@ create_selection_shadow (GnomeIconContainer *container, gnome_canvas_group_get_type (), NULL)); + pixels_per_unit = canvas->pixels_per_unit; for (p = list; p != NULL; p = p->next) { DndSelectionItem *item; - int x1, y1; - int x2, y2; + int x1, y1, x2, y2; item = p->data; @@ -111,32 +109,29 @@ create_selection_shadow (GnomeIconContainer *container, x2 = x1 + item->icon_width; y2 = y1 + item->icon_height; - if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y) { - GnomeCanvasItem *rect; - - rect = gnome_canvas_item_new + if (x2 >= min_x && x1 <= max_x && y2 >= min_y && y1 <= max_y) + gnome_canvas_item_new (group, gnome_canvas_rect_get_type (), - "x1", (double) x1, "y1", (double) y1, - "x2", (double) x2, "y2", (double) y2, + "x1", (double) x1 / pixels_per_unit, + "y1", (double) y1 / pixels_per_unit, + "x2", (double) x2 / pixels_per_unit, + "y2", (double) y2 / pixels_per_unit, "outline_color", "black", "outline_stipple", stipple, "width_pixels", 1, NULL); - } } return GNOME_CANVAS_ITEM (group); } -/* This is a workaround for a gnome-canvas bug: with the current (1.0.18) - gnome-libs, setting the x/y values for an existing group fails at updating - the bounds of the group. So, instead of setting the x/y values to the - current position at initialization time, we set them to (0,0) and then use a - simple affine transform. */ +/* Set the affine instead of the x and y position. + * Simple, and setting x and y was broken at one point. + */ static void set_shadow_position (GnomeCanvasItem *shadow, - gdouble x, gdouble y) + double x, double y) { double affine[6]; @@ -151,6 +146,7 @@ set_shadow_position (GnomeCanvasItem *shadow, } + /* Functions to deal with DndSelectionItems. */ static DndSelectionItem * @@ -195,7 +191,6 @@ set_gnome_icon_list_selection (GnomeIconContainer *container, GtkSelectionData *selection_data) { GnomeIconContainerDetails *details; - GnomeCanvas* canvas = GNOME_CANVAS(container); GList *p; GString *data; @@ -204,31 +199,28 @@ set_gnome_icon_list_selection (GnomeIconContainer *container, data = g_string_new (NULL); for (p = details->icons; p != NULL; p = p->next) { GnomeIconContainerIcon *icon; - gint center_offset; + ArtIRect rect; char *uri; char *s; - GdkPixbuf *pixbuf; - int icon_x, icon_y; icon = p->data; if (!icon->is_selected) continue; - center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (icon->item)); - - /* Corner of the icon relative to the cursor. */ - icon_x = icon->x - details->dnd_info->start_x + floor(center_offset / canvas->pixels_per_unit); - icon_y = icon->y - details->dnd_info->start_y; + nautilus_icons_view_icon_item_get_icon_window_rectangle + (icon->item, &rect); + uri = nautilus_icons_controller_get_icon_uri + (details->controller, icon->data); + + s = g_strdup_printf ("%s\r%d:%d:%hu:%hu\r\n", + uri, + (int) (rect.x0 - details->dnd_info->start_x), + (int) (rect.y0 - details->dnd_info->start_y), + rect.x1 - rect.x0, + rect.y1 - rect.y0); - uri = nautilus_icons_controller_get_icon_uri (details->controller, icon->data); - pixbuf = nautilus_icons_controller_get_icon_image(details->controller, icon->data); - - s = g_strdup_printf ("%s\r%d:%d:%d:%d\r\n", - uri, icon_x, icon_y, pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height); g_free (uri); - gdk_pixbuf_unref(pixbuf); - + g_string_append (data, s); g_free (s); } @@ -312,7 +304,7 @@ get_gnome_icon_list_selection (GnomeIconContainer *container, { GnomeIconContainerDndInfo *dnd_info; const guchar *p, *oldp; - gint size; + int size; dnd_info = container->details->dnd_info; @@ -401,8 +393,8 @@ gnome_icon_container_position_shadow (GnomeIconContainer *container, gnome_canvas_window_to_world (GNOME_CANVAS (container), x, y, &world_x, &world_y); - gnome_canvas_item_show (shadow); set_shadow_position (shadow, world_x, world_y); + gnome_canvas_item_show (shadow); } static void @@ -412,44 +404,31 @@ gnome_icon_container_dropped_icon_feedback (GtkWidget *widget, { GnomeIconContainer *container; GnomeIconContainerDndInfo *dnd_info; - GnomeCanvasItem *shadow; - double world_x, world_y; container = GNOME_ICON_CONTAINER (widget); dnd_info = container->details->dnd_info; - /* delete old selection list if any */ - + /* Delete old selection list if any. */ if (dnd_info->selection_list != NULL) { destroy_selection_list (dnd_info->selection_list); dnd_info->selection_list = NULL; } - /* build the selection list from the drag data */ - - get_gnome_icon_list_selection (container, data); - - shadow = create_selection_shadow (container, dnd_info->selection_list); - - gnome_canvas_item_set (shadow, "x", (gdouble) 0, "y", (gdouble) 0, - NULL); - - gnome_canvas_window_to_world (GNOME_CANVAS (widget), - x, y, &world_x, &world_y); - set_shadow_position (shadow, world_x, world_y); - - gnome_canvas_item_show (shadow); - + /* Delete old shadow if any. */ if (dnd_info->shadow != NULL) gtk_object_destroy (GTK_OBJECT (dnd_info->shadow)); - dnd_info->shadow = shadow; + + /* Build the selection list and the shadow. */ + get_gnome_icon_list_selection (container, data); + dnd_info->shadow = create_selection_shadow (container, dnd_info->selection_list); + gnome_icon_container_position_shadow (container, x, y); } static void drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, - gint x, - gint y, + int x, + int y, GtkSelectionData *data, guint info, guint32 time, @@ -535,60 +514,44 @@ gnome_icon_container_receive_dropped_icons (GnomeIconContainer *container, if (dnd_info->selection_list == NULL) return; - /* Move files in same window. - - FIXME: This won't work between windows for two reasons. - - First, we have to figure out whether we need to actually - move or copy some files. For directory views this is based - on the URIs, but that should be done by the controller, not - here in the view. - - Second, the start_x and start_y values are only good for - this window. To make dragging between multiple windows work, - we need to communicate the offset between the mouse and the - corner of the selection along with the other selection info - so we can position the icons correctly in the window they - are dropped in. The geometry that's currently included along - with the selection is not sufficient. - */ - if (context->action == GDK_ACTION_MOVE) { - double world_x, world_y; + /* Move files. */ + if (context->action != GDK_ACTION_MOVE) { + /* FIXME: We want to copy files here, I think. */ + g_warning ("non-move action not implemented yet"); + } else { GList *icons_to_select; - - gnome_canvas_window_to_world (GNOME_CANVAS (container), - x, y, &world_x, &world_y); - + icons_to_select = NULL; for (p = dnd_info->selection_list; p != NULL; p = p->next) { DndSelectionItem *item; GnomeIconContainerIcon *icon; - + item = p->data; icon = gnome_icon_container_get_icon_by_uri (container, item->uri); - + if (icon == NULL) { + /* FIXME: Do we ever get a MOVE between windows? + * If so, we need to move files here. + */ g_warning ("drag between containers not implemented yet"); continue; } - + if (item->got_icon_position) { - int icon_x, icon_y; - double scale = icon->item->canvas->pixels_per_unit; - int center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (icon->item)); - - icon_x = (int) world_x + item->icon_x - (center_offset / scale); - icon_y = (int) world_y + item->icon_y; + double world_x, world_y; + gnome_canvas_window_to_world (GNOME_CANVAS (container), + x + item->icon_x, + y + item->icon_y, + &world_x, &world_y); gnome_icon_container_move_icon - (container, icon, icon_x, icon_y, TRUE); + (container, icon, world_x, world_y, TRUE); } - + icons_to_select = g_list_prepend (icons_to_select, icon); } - + gnome_icon_container_select_list_unselect_others (container, icons_to_select); g_list_free (icons_to_select); @@ -621,8 +584,8 @@ gnome_icon_container_free_drag_data (GnomeIconContainer *container) static gboolean drag_drop_cb (GtkWidget *widget, GdkDragContext *context, - gint x, - gint y, + int x, + int y, guint32 time, gpointer data) { @@ -680,7 +643,7 @@ gnome_icon_container_dnd_init (GnomeIconContainer *container, dnd_info = g_new0 (GnomeIconContainerDndInfo, 1); dnd_info->target_list = gtk_target_list_new (drag_types, - num_drag_types); + NAUTILUS_N_ELEMENTS (drag_types)); dnd_info->stipple = gdk_bitmap_ref (stipple); @@ -691,7 +654,7 @@ gnome_icon_container_dnd_init (GnomeIconContainer *container, gtk_drag_dest_set (GTK_WIDGET (container), 0, - drop_types, num_drop_types, + drop_types, NAUTILUS_N_ELEMENTS (drop_types), GDK_ACTION_COPY | GDK_ACTION_MOVE); /* Messages for outgoing drag. */ @@ -740,30 +703,33 @@ gnome_icon_container_dnd_fini (GnomeIconContainer *container) void gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, GdkDragAction actions, - gint button, + int button, GdkEventMotion *event) { - GtkArg pixbuf_args[1]; GnomeIconContainerDndInfo *dnd_info; - GdkDragContext *context; - GnomeCanvasItem *pixbuf_item; GnomeCanvas *canvas; - GdkPixbuf *temp_pixbuf, *scaled_pixbuf; + GdkDragContext *context; + GtkArg pixbuf_arg; + GnomeCanvasItem *item; + GdkPixbuf *pixbuf; GdkPixmap *pixmap_for_dragged_file; GdkBitmap *mask_for_dragged_file; - gint x_offset, y_offset, center_offset; + int x_offset, y_offset; + ArtIRect rect; - g_return_if_fail (container != NULL); g_return_if_fail (GNOME_IS_ICON_CONTAINER (container)); g_return_if_fail (event != NULL); dnd_info = container->details->dnd_info; g_return_if_fail (dnd_info != NULL); - /* Notice that the event is already in world coordinates, because of - the way the canvas handles events! */ - dnd_info->start_x = event->x; - dnd_info->start_y = event->y; + /* Notice that the event is in world coordinates, because of + the way the canvas handles events. + */ + canvas = GNOME_CANVAS (container); + gnome_canvas_world_to_window (canvas, + event->x, event->y, + &dnd_info->start_x, &dnd_info->start_y); /* start the drag */ context = gtk_drag_begin (GTK_WIDGET (container), @@ -773,46 +739,21 @@ gnome_icon_container_dnd_begin_drag (GnomeIconContainer *container, (GdkEvent *) event); /* create a pixmap and mask to drag with */ - pixbuf_item = GNOME_CANVAS_ITEM (container->details->drag_icon->item); - pixbuf_args[0].name = "NautilusIconsViewIconItem::pixbuf"; - gtk_object_getv (GTK_OBJECT (pixbuf_item), 1, pixbuf_args); - temp_pixbuf = (GdkPixbuf *) GTK_VALUE_OBJECT (pixbuf_args[0]); - + item = GNOME_CANVAS_ITEM (container->details->drag_icon->item); + pixbuf_arg.name = "NautilusIconsViewIconItem::pixbuf"; + gtk_object_getv (GTK_OBJECT (item), 1, &pixbuf_arg); + pixbuf = GTK_VALUE_BOXED (pixbuf_arg); + gdk_pixbuf_render_pixmap_and_mask (pixbuf, + &pixmap_for_dragged_file, + &mask_for_dragged_file, + 128); + /* compute the image's offset */ - canvas = GNOME_CANVAS (container); - - x_offset = floor (event->x - pixbuf_item->x1 + .5); - y_offset = floor (event->y - pixbuf_item->y1 + .5); + nautilus_icons_view_icon_item_get_icon_window_rectangle + (container->details->drag_icon->item, &rect); + x_offset = dnd_info->start_x - rect.x0; + y_offset = dnd_info->start_y - rect.y0; - center_offset = nautilus_icons_view_icon_item_center_offset - (NAUTILUS_ICONS_VIEW_ICON_ITEM (container->details->drag_icon->item)); - x_offset -= center_offset; - - /* if the scale factor isn't 1.0, we have to scale the pixmap */ - /* FIXME: eventually need to get the size, if any, from the metadata here */ - - scaled_pixbuf = NULL; - if (container->details->zoom_level != NAUTILUS_ZOOM_LEVEL_STANDARD) { - gint old_width, old_height; - gint new_width, new_height; - - x_offset = floor (event->x * canvas->pixels_per_unit - center_offset - pixbuf_item->x1 + .5); - y_offset = floor (event->y * canvas->pixels_per_unit - pixbuf_item->y1 + .5); - - old_width = gdk_pixbuf_get_width (temp_pixbuf); - old_height = gdk_pixbuf_get_height (temp_pixbuf); - - new_width = floor ((old_width * canvas->pixels_per_unit) + .5); - new_height = floor ((old_height * canvas->pixels_per_unit) + .5); - - scaled_pixbuf = gdk_pixbuf_scale_simple (temp_pixbuf, new_width, new_height, ART_FILTER_BILINEAR); - temp_pixbuf = scaled_pixbuf; - } - - gdk_pixbuf_render_pixmap_and_mask (temp_pixbuf, &pixmap_for_dragged_file, &mask_for_dragged_file, 128); - if (scaled_pixbuf) - gdk_pixbuf_unref(scaled_pixbuf); - /* set the pixmap and mask for dragging */ gtk_drag_set_icon_pixmap (context, gtk_widget_get_colormap (GTK_WIDGET (container)), pixmap_for_dragged_file, mask_for_dragged_file, @@ -824,7 +765,6 @@ gnome_icon_container_dnd_end_drag (GnomeIconContainer *container) { GnomeIconContainerDndInfo *dnd_info; - g_return_if_fail (container != NULL); g_return_if_fail (GNOME_IS_ICON_CONTAINER (container)); dnd_info = container->details->dnd_info; diff --git a/libnautilus/gnome-icon-container-private.h b/libnautilus/gnome-icon-container-private.h index 1ecd0625d..abb781303 100644 --- a/libnautilus/gnome-icon-container-private.h +++ b/libnautilus/gnome-icon-container-private.h @@ -28,20 +28,20 @@ #include "gnome-icon-container.h" #include "gnome-icon-container-dnd.h" #include "nautilus-icon-factory.h" -#include +#include "nautilus-icons-view-icon-item.h" /* An Icon. */ typedef struct { /* Canvas item for the icon. */ - GnomeCanvasItem *item; + NautilusIconsViewIconItem *item; /* X/Y coordinates and size. We could use the GnomeCanvasItem * functions, but this is a lot faster */ - gdouble x, y; + double x, y; - /* Whether this item is selected (i.e. highlighted) for operation. */ + /* Whether this item is selected for operation. */ gboolean is_selected : 1; /* Whether this item is selected for keyboard navigation. */ @@ -89,7 +89,7 @@ typedef struct { typedef struct { gboolean active; - gdouble start_x, start_y; + double start_x, start_y; GnomeCanvasItem *selection_rectangle; guint timer_id; diff --git a/libnautilus/gnome-icon-container.c b/libnautilus/gnome-icon-container.c index 04e1c054d..7f144c396 100644 --- a/libnautilus/gnome-icon-container.c +++ b/libnautilus/gnome-icon-container.c @@ -37,8 +37,6 @@ #include "nautilus-gtk-macros.h" #include "gnome-icon-container-private.h" -#include "gnome-icon-container-dnd.h" -#include "nautilus-icons-view-icon-item.h" /* Interval for updating the rubberband selection, in milliseconds. */ #define RUBBERBAND_TIMEOUT_INTERVAL 10 @@ -117,10 +115,10 @@ icon_new (GnomeIconContainer *container, new->data = data; - new->item = gnome_canvas_item_new - (GNOME_CANVAS_GROUP (canvas->root), - nautilus_icons_view_icon_item_get_type (), - NULL); + new->item = NAUTILUS_ICONS_VIEW_ICON_ITEM + (gnome_canvas_item_new (GNOME_CANVAS_GROUP (canvas->root), + nautilus_icons_view_icon_item_get_type (), + NULL)); request_update_one (container, new); @@ -129,20 +127,17 @@ icon_new (GnomeIconContainer *container, static void icon_position (GnomeIconContainerIcon *icon, - GnomeIconContainer *container, - gdouble x, gdouble y) + double x, double y) { - GnomeIconContainerDetails *details; + if (icon->x == x && icon->y == y) + return; - details = container->details; + gnome_canvas_item_move (GNOME_CANVAS_ITEM (icon->item), + x - icon->x, + y - icon->y); icon->x = x; icon->y = y; - - gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "x", (gdouble) icon->x, - "y", (gdouble) icon->y, - NULL); } static void @@ -162,7 +157,7 @@ icon_toggle_selected (GnomeIconContainerIcon *icon) { icon->is_selected = !icon->is_selected; gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "selected", (gboolean) icon->is_selected, + "highlighted_for_selection", (gboolean) icon->is_selected, NULL); } @@ -187,28 +182,23 @@ icon_select (GnomeIconContainerIcon *icon, static gboolean icon_is_in_region (GnomeIconContainer *container, GnomeIconContainerIcon *icon, - int x1, int y1, - int x2, int y2) + int x0, int y0, + int x1, int y1) { - int icon_x2, icon_y2; - int size; - - size = nautilus_icon_size_for_zoom_level - (gnome_icon_container_get_zoom_level (container)); - - icon_x2 = icon->x + size; - icon_y2 = icon->y + size; + ArtDRect rect; - if (x1 >= x2 || y1 >= y2) + if (x0 >= x1 || y0 >= y1) return FALSE; - return x1 < icon_x2 && x2 >= icon->x && y1 < icon_y2 && y2 >= icon->y; + nautilus_icons_view_icon_item_get_icon_world_rectangle + (icon->item, &rect); + return x0 < rect.x1 && x1 >= rect.x0 && y0 < rect.y1 && y1 >= rect.y0; } static void icon_get_bounding_box (GnomeIconContainerIcon *icon, - guint *x1_return, guint *y1_return, - guint *x2_return, guint *y2_return) + int *x1_return, int *y1_return, + int *x2_return, int *y2_return) { double x1, y1, x2, y2; @@ -829,15 +819,15 @@ set_kbd_current (GnomeIconContainer *container, details = container->details; if (details->kbd_current != NULL) - gnome_canvas_item_set (details->kbd_current->item, - "alt_selected", 0, + gnome_canvas_item_set (GNOME_CANVAS_ITEM (details->kbd_current->item), + "highlighted_for_keyboard_selection", 0, NULL); details->kbd_current = icon; if (icon != NULL) { - gnome_canvas_item_set (icon->item, - "alt_selected", 1, + gnome_canvas_item_set (GNOME_CANVAS_ITEM (details->kbd_current->item), + "highlighted_for_keyboard_selection", 1, NULL); icon_raise (icon); } @@ -859,7 +849,7 @@ set_scroll_region (GnomeIconContainer *container) GnomeIconContainerIconGrid *grid; GtkAllocation *allocation; GtkAdjustment *vadj, *hadj; - gdouble x1, y1, x2, y2; + double x1, y1, x2, y2; guint scroll_width, scroll_height; details = container->details; @@ -883,8 +873,8 @@ set_scroll_region (GnomeIconContainer *container) gnome_canvas_set_scroll_region (GNOME_CANVAS (container), 0.0, 0.0, - (gdouble) scroll_width, - (gdouble) scroll_height); + (double) scroll_width, + (double) scroll_height); if (details->width <= allocation->width) gtk_adjustment_set_value (hadj, 0.0); @@ -1005,7 +995,7 @@ gnome_icon_container_move_icon (GnomeIconContainer *container, if (new_x_offset > 0 && new_y_offset > 0) icon_grid_add (details->grid, icon, new_grid_x + 1, new_grid_y + 1); - icon_position (icon, container, x, y); + icon_position (icon, x, y); if (raise) icon_raise (icon); @@ -1023,10 +1013,10 @@ gnome_icon_container_move_icon (GnomeIconContainer *container, static gboolean rubberband_select_in_cell (GnomeIconContainer *container, GList *cell, - gdouble curr_x1, gdouble curr_y1, - gdouble curr_x2, gdouble curr_y2, - gdouble prev_x1, gdouble prev_y1, - gdouble prev_x2, gdouble prev_y2) + double curr_x1, double curr_y1, + double curr_x2, double curr_y2, + double prev_x1, double prev_y1, + double prev_x2, double prev_y2) { GList *p; gboolean selection_changed; @@ -1061,10 +1051,10 @@ rubberband_select_in_cell (GnomeIconContainer *container, static void rubberband_select (GnomeIconContainer *container, - gdouble curr_x1, gdouble curr_y1, - gdouble curr_x2, gdouble curr_y2, - gdouble prev_x1, gdouble prev_y1, - gdouble prev_x2, gdouble prev_y2) + double curr_x1, double curr_y1, + double curr_x2, double curr_y2, + double prev_x1, double prev_y1, + double prev_x2, double prev_y2) { GList **p; GnomeIconContainerIconGrid *grid; @@ -1117,8 +1107,8 @@ rubberband_timeout_cb (gpointer data) GtkWidget *widget; GnomeIconContainerRubberbandInfo *band_info; int x, y; - gdouble x1, y1, x2, y2; - gdouble world_x, world_y; + double x1, y1, x2, y2; + double world_x, world_y; int x_scroll, y_scroll; GDK_THREADS_ENTER (); @@ -1127,6 +1117,9 @@ rubberband_timeout_cb (gpointer data) container = GNOME_ICON_CONTAINER (data); band_info = &container->details->rubberband_info; + g_assert (band_info->timer_id != 0); + g_assert (GNOME_IS_CANVAS_RECT (band_info->selection_rectangle)); + gdk_window_get_pointer (widget->window, &x, &y, NULL); if (x < 0) { @@ -1177,10 +1170,10 @@ rubberband_timeout_cb (gpointer data) } gnome_canvas_item_set (band_info->selection_rectangle, - "x1", (gdouble) x1, - "y1", (gdouble) y1, - "x2", (gdouble) x2, - "y2", (gdouble) y2, + "x1", x1, + "y1", y1, + "x2", x2, + "y2", y2, NULL); rubberband_select (container, @@ -1241,8 +1234,8 @@ start_rubberbanding (GnomeIconContainer *container, band_info->active = TRUE; band_info->timer_id = gtk_timeout_add (RUBBERBAND_TIMEOUT_INTERVAL, - rubberband_timeout_cb, - container); + rubberband_timeout_cb, + container); gnome_canvas_item_grab (band_info->selection_rectangle, (GDK_POINTER_MOTION_MASK @@ -2014,7 +2007,7 @@ gnome_icon_container_initialize (GnomeIconContainer *container) details->grid = icon_grid_new (); details->canvas_item_to_icon = g_hash_table_new (g_direct_hash, - g_direct_equal); + g_direct_equal); details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD; @@ -2277,19 +2270,28 @@ static void request_update_one (GnomeIconContainer *container, GnomeIconContainerIcon *icon) { GnomeIconContainerDetails *details; - GdkPixbuf *image; + NautilusScalableIcon *scalable_icon; + GdkPixbuf *pixbuf; char *label; + GdkFont *font; details = container->details; - image = nautilus_icons_controller_get_icon_image (details->controller, icon->data); + scalable_icon = nautilus_icons_controller_get_icon_image (details->controller, icon->data); + pixbuf = nautilus_icon_factory_get_pixbuf_for_icon (scalable_icon, nautilus_icon_size_for_zoom_level (details->zoom_level)); + nautilus_scalable_icon_unref (scalable_icon); + label = nautilus_icons_controller_get_icon_text (details->controller, icon->data); + + font = details->label_font[details->zoom_level]; gnome_canvas_item_set (GNOME_CANVAS_ITEM (icon->item), - "pixbuf", image, - "label", label, + "pixbuf", pixbuf, + "text", label, + "font", font, NULL); + gdk_pixbuf_unref (pixbuf); g_free (label); } @@ -2308,7 +2310,7 @@ gnome_icon_container_add (GnomeIconContainer *container, details = container->details; new_icon = icon_new (container, data); - icon_position (new_icon, container, x, y); + icon_position (new_icon, x, y); world_to_grid (container, x, y, &grid_x, &grid_y); icon_grid_add (details->grid, new_icon, grid_x, grid_y); @@ -2350,7 +2352,7 @@ gnome_icon_container_add_auto (GnomeIconContainer *container, icon_grid_add_auto (container->details->grid, new_icon, &grid_x, &grid_y); grid_to_world (container, grid_x, grid_y, &x, &y); - icon_position (new_icon, container, x, y); + icon_position (new_icon, x, y); setup_icon_in_container (container, new_icon); @@ -2368,9 +2370,9 @@ gnome_icon_container_get_zoom_level(GnomeIconContainer *container) void gnome_icon_container_set_zoom_level(GnomeIconContainer *container, int new_level) { + GnomeIconContainerDetails *details; int pinned_level; double pixels_per_unit; - GnomeIconContainerDetails *details; details = container->details; @@ -2379,15 +2381,15 @@ gnome_icon_container_set_zoom_level(GnomeIconContainer *container, int new_level pinned_level = NAUTILUS_ZOOM_LEVEL_SMALLEST; else if (pinned_level > NAUTILUS_ZOOM_LEVEL_LARGEST) pinned_level = NAUTILUS_ZOOM_LEVEL_LARGEST; - + if (pinned_level == details->zoom_level) return; - + details->zoom_level = pinned_level; pixels_per_unit = (double) nautilus_icon_size_for_zoom_level (pinned_level) / NAUTILUS_ICON_SIZE_STANDARD; - gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(container), pixels_per_unit); + gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (container), pixels_per_unit); gnome_icon_container_request_update_all (container); } @@ -2403,20 +2405,13 @@ void gnome_icon_container_request_update_all (GnomeIconContainer *container) { GList *p; - GnomeIconContainerDetails *details; - details = container->details; - - for (p = details->icons; p != NULL; p = p->next) - { - GnomeIconContainerIcon *icon; - icon = p->data; - - request_update_one (container, icon); - } + for (p = container->details->icons; p != NULL; p = p->next) + request_update_one (container, p->data); } + /** * gnome_icon_container_relayout: * @container: An icon container. @@ -2492,7 +2487,7 @@ gnome_icon_container_relayout (GnomeIconContainer *container) dp[cols] = g_list_alloc (); dp[cols]->data = icon; - icon_position (icon, container, dx, dy); + icon_position (icon, dx, dy); icon->layout_done = TRUE; @@ -2631,7 +2626,7 @@ gnome_icon_container_line_up (GnomeIconContainer *container) || (icon->y >= 0 && icon->y < y)) continue; - icon_position (icon, container, dx, y); + icon_position (icon, dx, y); icon->layout_done = TRUE; q[k] = g_list_alloc (); diff --git a/libnautilus/nautilus-icons-controller.c b/libnautilus/nautilus-icons-controller.c index ac68e783c..850ffdce8 100644 --- a/libnautilus/nautilus-icons-controller.c +++ b/libnautilus/nautilus-icons-controller.c @@ -50,7 +50,7 @@ nautilus_icons_controller_initialize (NautilusIconsController *controller) { } -GdkPixbuf * +NautilusScalableIcon * nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, NautilusControllerIcon *icon) { diff --git a/libnautilus/nautilus-icons-controller.h b/libnautilus/nautilus-icons-controller.h index fa123c455..a9256dd13 100644 --- a/libnautilus/nautilus-icons-controller.h +++ b/libnautilus/nautilus-icons-controller.h @@ -28,6 +28,7 @@ #include #include +#include "nautilus-icon-factory.h" /* NautilusIconsController is an abstract class that describes the interface that a NautilusIconsView (currently named GnomeIconContainer) @@ -54,15 +55,15 @@ typedef struct NautilusControllerIconDummy NautilusControllerIcon; ((NautilusControllerIcon *)(icon)) /* Basic GtkObject requirements. */ -GtkType nautilus_icons_controller_get_type (void); +GtkType nautilus_icons_controller_get_type (void); /* Icon operations. */ -GdkPixbuf *nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, - NautilusControllerIcon *icon); -char * nautilus_icons_controller_get_icon_text (NautilusIconsController *controller, - NautilusControllerIcon *icon); -char * nautilus_icons_controller_get_icon_uri (NautilusIconsController *controller, - NautilusControllerIcon *icon); +NautilusScalableIcon *nautilus_icons_controller_get_icon_image (NautilusIconsController *controller, + NautilusControllerIcon *icon); +char * nautilus_icons_controller_get_icon_text (NautilusIconsController *controller, + NautilusControllerIcon *icon); +char * nautilus_icons_controller_get_icon_uri (NautilusIconsController *controller, + NautilusControllerIcon *icon); struct _NautilusIconsController { @@ -73,12 +74,12 @@ struct _NautilusIconsControllerClass { GtkObjectClass parent_class; - GdkPixbuf * (*get_icon_image) (NautilusIconsController *controller, - NautilusControllerIcon *icon); - char * (* get_icon_text) (NautilusIconsController *controller, - NautilusControllerIcon *icon); - char * (* get_icon_uri) (NautilusIconsController *controller, - NautilusControllerIcon *icon); + NautilusScalableIcon * (*get_icon_image) (NautilusIconsController *controller, + NautilusControllerIcon *icon); + char * (* get_icon_text) (NautilusIconsController *controller, + NautilusControllerIcon *icon); + char * (* get_icon_uri) (NautilusIconsController *controller, + NautilusControllerIcon *icon); }; #endif /* NAUTILUS_ICONS_CONTROLLER_H */ diff --git a/libnautilus/nautilus-icons-view-icon-item.c b/libnautilus/nautilus-icons-view-icon-item.c index 027bb7901..3c83c5be0 100644 --- a/libnautilus/nautilus-icons-view-icon-item.c +++ b/libnautilus/nautilus-icons-view-icon-item.c @@ -30,50 +30,27 @@ #include #include #include +#include #include "gnome-icon-container-private.h" #include "nautilus-gtk-macros.h" #include "nautilus-string.h" +#include "gdk-extensions.h" /* Private part of the NautilusIconsViewIconItem structure */ struct _NautilusIconsViewIconItemDetails { - /* Our main gdk-pixbuf */ + /* The image, text, font. */ GdkPixbuf *pixbuf; - - /* text for our label */ - char* label; + char* text; + GdkFont *font; - /* Width value */ - double width; - - /* Height value */ - double height; - - /* X translation */ - double x; - - /* Y translation */ - double y; - - /* width in pixels of the label */ - double text_width; - - /* height in pixels of the label */ - double text_height; + /* Size of the text at current font. */ + int text_width; + int text_height; - /* boolean to indicate selection state */ - guint is_selected : 1; - - /* boolean to indicate keyboard selection state */ - guint is_alt_selected: 1; - - /* boolean to indicate highlight state (for swallow) */ - guint is_highlighted : 1; - - /* Whether the pixbuf has changed */ - guint need_pixbuf_update : 1; - - /* Whether the transformation or size have changed */ - guint need_xform_update : 1; + /* Highlight state. */ + guint is_highlighted_for_selection : 1; + guint is_highlighted_for_keyboard_selection: 1; + guint is_highlighted_for_drop : 1; }; @@ -82,60 +59,73 @@ struct _NautilusIconsViewIconItemDetails { enum { ARG_0, ARG_PIXBUF, - ARG_LABEL, - ARG_WIDTH, - ARG_HEIGHT, - ARG_X, - ARG_Y, - ARG_SELECTED, - ARG_ALT_SELECTED, - ARG_HIGHLIGHTD + ARG_TEXT, + ARG_FONT, + ARG_HIGHLIGHTED_FOR_SELECTION, + ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION, + ARG_HIGHLIGHTED_FOR_DROP }; /* constants */ -#define MAX_LABEL_WIDTH 80 +#define MAX_TEXT_WIDTH 80 /* Bitmap for stippled selection rectangles. */ static GdkBitmap *stipple; static char stipple_bits[] = { 0x02, 0x01 }; /* GtkObject */ -static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class); -static void nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *item); -static void nautilus_icons_view_icon_item_destroy (GtkObject *object); -static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); -static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class); +static void nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *item); +static void nautilus_icons_view_icon_item_destroy (GtkObject *object); +static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); /* GnomeCanvasItem */ -static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags); -static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height); -static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf); -static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item); -static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2); +static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, + double *affine, + ArtSVP *clip_path, + int flags); +static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, + GdkDrawable *drawable, + int x, + int y, + int width, + int height); +static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, + GnomeCanvasBuf *buf); +static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, + double x, + double y, + int cx, + int cy, + GnomeCanvasItem **actual_item); +static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, + double *x1, + double *y1, + double *x2, + double *y2); /* private */ -static GdkFont* get_font_for_item (GnomeCanvasItem *item); -static void draw_or_measure_text_box (GnomeCanvasItem* item, - GdkDrawable *drawable, - GdkFont *title_font, - const char* label, - int icon_left, - int icon_bottom, - gboolean do_draw); -static void nautilus_icons_view_draw_text_box (GnomeCanvasItem* item, - GdkDrawable *drawable, - GdkFont *title_font, - const char *label, - int icon_left, - int icon_bottom); -static void nautilus_icons_view_measure_text_box (GnomeCanvasItem* item, - GdkFont *title_font, - const char *label); +static void draw_or_measure_text_box (GnomeCanvasItem *item, + GdkDrawable *drawable, + int icon_left, + int icon_bottom); +static void nautilus_icons_view_draw_text_box (GnomeCanvasItem *item, + GdkDrawable *drawable, + int icon_left, + int icon_bottom); +static void nautilus_icons_view_measure_text_box (GnomeCanvasItem *item); +static void nautilus_icons_view_icon_item_get_icon_canvas_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect); NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusIconsViewIconItem, nautilus_icons_view_icon_item, GNOME_TYPE_CANVAS_ITEM) -/* Class initialization function for the icon canvas item */ +/* Class initialization function for the icon canvas item. */ static void nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass *class) { @@ -146,24 +136,17 @@ nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass * item_class = GNOME_CANVAS_ITEM_CLASS (class); gtk_object_add_arg_type ("NautilusIconsViewIconItem::pixbuf", - GTK_TYPE_POINTER, GTK_ARG_READWRITE, ARG_PIXBUF); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::label", - GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::width", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH); - - gtk_object_add_arg_type ("NautilusIconsViewIconItem::height", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::x", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::y", - GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::selected", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SELECTED); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::alt_selected", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ALT_SELECTED); - gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlightd", - GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTD); + GTK_TYPE_BOXED, GTK_ARG_READWRITE, ARG_PIXBUF); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::text", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TEXT); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::font", + GTK_TYPE_BOXED, GTK_ARG_READWRITE, ARG_FONT); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_selection", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_SELECTION); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_keyboard_selection", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION); + gtk_object_add_arg_type ("NautilusIconsViewIconItem::highlighted_for_drop", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HIGHLIGHTED_FOR_DROP); object_class->destroy = nautilus_icons_view_icon_item_destroy; object_class->set_arg = nautilus_icons_view_icon_item_set_arg; @@ -178,186 +161,154 @@ nautilus_icons_view_icon_item_initialize_class (NautilusIconsViewIconItemClass * stipple = gdk_bitmap_create_from_data (NULL, stipple_bits, 2, 2); } -/* Object initialization function for the icon item */ +/* Object initialization function for the icon item. */ static void -nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *icon_view_item) +nautilus_icons_view_icon_item_initialize (NautilusIconsViewIconItem *icon_item) { NautilusIconsViewIconItemDetails *details; details = g_new0 (NautilusIconsViewIconItemDetails, 1); - icon_view_item->details = details; + + icon_item->details = details; } -/* Destroy handler for the icon canvas item */ +/* Destroy handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_destroy (GtkObject *object) { GnomeCanvasItem *item; - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (object)); item = GNOME_CANVAS_ITEM (object); - icon_view_item = (NAUTILUS_ICONS_VIEW_ICON_ITEM (object)); - details = icon_view_item->details; + icon_item = (NAUTILUS_ICONS_VIEW_ICON_ITEM (object)); + details = icon_item->details; gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); if (details->pixbuf != NULL) gdk_pixbuf_unref (details->pixbuf); - g_free (details->label); - + g_free (details->text); + if (details->font != NULL) + gdk_font_unref (details->font); + g_free (details); NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object)); } -/* Set_arg handler for the icon item */ - +/* Set_arg handler for the icon item. */ static void nautilus_icons_view_icon_item_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) { - GnomeCanvasItem *item; - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; GdkPixbuf *pixbuf; - char* new_label; - double val; + GdkFont *font; - item = GNOME_CANVAS_ITEM (object); - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (object); - details = icon_view_item->details; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (object)->details; switch (arg_id) { case ARG_PIXBUF: - pixbuf = GTK_VALUE_POINTER (*arg); - if (pixbuf != details->pixbuf) { - if (pixbuf) { - g_return_if_fail (pixbuf->art_pixbuf->format == ART_PIX_RGB); - g_return_if_fail (pixbuf->art_pixbuf->n_channels == 3 - || pixbuf->art_pixbuf->n_channels == 4); - g_return_if_fail (pixbuf->art_pixbuf->bits_per_sample == 8); - - gdk_pixbuf_ref (pixbuf); - } + pixbuf = GTK_VALUE_BOXED (*arg); + if (pixbuf == details->pixbuf) + return; + + if (pixbuf != NULL) { + g_return_if_fail (pixbuf->art_pixbuf->format == ART_PIX_RGB); + g_return_if_fail (pixbuf->art_pixbuf->n_channels == 3 + || pixbuf->art_pixbuf->n_channels == 4); + g_return_if_fail (pixbuf->art_pixbuf->bits_per_sample == 8); - if (details->pixbuf) - gdk_pixbuf_unref (details->pixbuf); - - details->pixbuf = pixbuf; + gdk_pixbuf_ref (pixbuf); } - - details->need_pixbuf_update = TRUE; - gnome_canvas_item_request_update (item); - break; - - case ARG_LABEL: - new_label = GTK_VALUE_STRING (*arg); - if (details->label) - g_free(details->label); - details->label = g_strdup(new_label); - details->need_pixbuf_update = TRUE; - gnome_canvas_item_request_update (item); + if (details->pixbuf != NULL) + gdk_pixbuf_unref (details->pixbuf); + + details->pixbuf = pixbuf; break; - case ARG_WIDTH: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - details->width = val; - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; + case ARG_TEXT: + if (nautilus_strcmp (details->text, GTK_VALUE_STRING (*arg)) == 0) + return; - case ARG_HEIGHT: - val = GTK_VALUE_DOUBLE (*arg); - g_return_if_fail (val >= 0.0); - details->height = val; - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); + g_free (details->text); + details->text = g_strdup (GTK_VALUE_STRING (*arg)); break; - case ARG_X: - details->x = GTK_VALUE_DOUBLE (*arg); - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); - break; + case ARG_FONT: + font = GTK_VALUE_BOXED (*arg); + if (nautilus_gdk_font_equal (font, details->font)) + return; - case ARG_Y: - details->y = GTK_VALUE_DOUBLE (*arg); - details->need_xform_update = TRUE; - gnome_canvas_item_request_update (item); + if (font != NULL) + gdk_font_ref (font); + if (details->font != NULL) + gdk_font_unref (details->font); + details->font = font; break; - - case ARG_SELECTED: - details->is_selected = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + + case ARG_HIGHLIGHTED_FOR_SELECTION: + if (!details->is_highlighted_for_selection == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_selection = GTK_VALUE_BOOL (*arg); break; - case ARG_ALT_SELECTED: - details->is_alt_selected = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + case ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION: + if (!details->is_highlighted_for_keyboard_selection == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_keyboard_selection = GTK_VALUE_BOOL (*arg); break; - case ARG_HIGHLIGHTD: - details->is_highlighted = GTK_VALUE_BOOL (*arg); - gnome_canvas_item_request_update (item); + case ARG_HIGHLIGHTED_FOR_DROP: + if (!details->is_highlighted_for_drop == !GTK_VALUE_BOOL (*arg)) + return; + details->is_highlighted_for_drop = GTK_VALUE_BOOL (*arg); break; - default: - break; + g_warning ("nautilus_icons_view_item_item_set_arg on unknown argument"); + return; } + + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (object)); } /* Get_arg handler for the icon item */ static void nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) { - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (object); - details = icon_view_item->details; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (object)->details; switch (arg_id) { case ARG_PIXBUF: - GTK_VALUE_POINTER (*arg) = details->pixbuf; - break; - - case ARG_LABEL: - GTK_VALUE_STRING (*arg) = details->label; - break; - - case ARG_WIDTH: - GTK_VALUE_DOUBLE (*arg) = details->width; - break; - - case ARG_HEIGHT: - GTK_VALUE_DOUBLE (*arg) = details->height; + GTK_VALUE_BOXED (*arg) = details->pixbuf; break; - case ARG_X: - GTK_VALUE_DOUBLE (*arg) = details->x; + case ARG_TEXT: + GTK_VALUE_STRING (*arg) = g_strdup (details->text); break; - case ARG_Y: - GTK_VALUE_DOUBLE (*arg) = details->y; + case ARG_FONT: + GTK_VALUE_BOXED (*arg) = details->font; break; - case ARG_SELECTED: - GTK_VALUE_BOOL (*arg) = details->is_selected; + case ARG_HIGHLIGHTED_FOR_SELECTION: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_selection; break; - case ARG_ALT_SELECTED: - GTK_VALUE_BOOL (*arg) = details->is_alt_selected; + case ARG_HIGHLIGHTED_FOR_KEYBOARD_SELECTION: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_keyboard_selection; break; - case ARG_HIGHLIGHTD: - GTK_VALUE_BOOL (*arg) = details->is_highlighted; + case ARG_HIGHLIGHTED_FOR_DROP: + GTK_VALUE_BOOL (*arg) = details->is_highlighted_for_drop; break; default: @@ -366,324 +317,147 @@ nautilus_icons_view_icon_item_get_arg (GtkObject *object, GtkArg *arg, guint arg } } - -/* Bounds and utilities */ - -/* Computes the amount by which the unit horizontal and vertical vectors will be - * scaled by an affine transformation. - */ -static void -compute_xform_scaling (double *affine, ArtPoint *i_c, ArtPoint *j_c) -{ - ArtPoint orig, orig_c; - ArtPoint i, j; - - /* Origin */ - - orig.x = 0.0; - orig.y = 0.0; - art_affine_point (&orig_c, &orig, affine); - - /* Horizontal and vertical vectors */ - - i.x = 1.0; - i.y = 0.0; - art_affine_point (i_c, &i, affine); - i_c->x -= orig_c.x; - i_c->y -= orig_c.y; - - j.x = 0.0; - j.y = 1.0; - art_affine_point (j_c, &j, affine); - j_c->x -= orig_c.x; - j_c->y -= orig_c.y; -} - -/* computes the addtional resolution dependent affine needed to - * fit the image within its viewport defined by x,y,width and height - * args - */ -static void -compute_viewport_affine (NautilusIconsViewIconItem *icon_view_item, double *viewport_affine, double *i2c) -{ - NautilusIconsViewIconItemDetails *details; - ArtPoint i_c, j_c; - double i_len, j_len; - double si_len, sj_len; - double ti_len, tj_len; - double scale[6], translate[6]; - double w, h; - double x, y; - - details = icon_view_item->details; - - /* Compute scaling vectors and required width/height */ - - compute_xform_scaling (i2c, &i_c, &j_c); - - i_len = sqrt (i_c.x * i_c.x + i_c.y * i_c.y); - j_len = sqrt (j_c.x * j_c.x + j_c.y * j_c.y); - - w = details->width; - if (!w) - w = details->pixbuf->art_pixbuf->width; - - h = details->height; - if (!h) - h = details->pixbuf->art_pixbuf->height; - - x = details->x; - y = details->y; - - si_len = w / details->pixbuf->art_pixbuf->width; - sj_len = h / details->pixbuf->art_pixbuf->height; - - ti_len = x; - tj_len = y; - - /* Compute the final affine */ - - art_affine_scale (scale, si_len, sj_len); - art_affine_translate (translate, ti_len, tj_len); - art_affine_multiply (viewport_affine, scale, translate); -} - -/* Computes the affine transformation with which the pixbuf needs to be - * transformed to render it on the canvas. This is not the same as the - * item_to_canvas transformation because we may need to scale the pixbuf - * by some other amount. - */ -static void -compute_render_affine (NautilusIconsViewIconItem *icon_view_item, double *render_affine, double *i2c) -{ - double viewport_affine[6]; - - compute_viewport_affine (icon_view_item, viewport_affine, i2c); - art_affine_multiply (render_affine, viewport_affine, i2c); -} - -/* utility to return the proper font for a given item, factoring in the current zoom level */ -static GdkFont* -get_font_for_item (GnomeCanvasItem *item) -{ - GnomeIconContainer* container = GNOME_ICON_CONTAINER (item->canvas); - return container->details->label_font[container->details->zoom_level]; -} - /* Recomputes the bounding box of a icon canvas item. */ static void -recompute_bounding_box (NautilusIconsViewIconItem *icon_view_item) +recompute_bounding_box (NautilusIconsViewIconItem *icon_item) { + /* The key to understanding this function: + * You must know that the documentation for gnome-canvas.h lies. + * x1, y1, x2, and y2 are in canvas coordinates, not world. + */ + GnomeCanvasItem *item; - NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - ArtDRect rect; + ArtDRect bounds; - item = GNOME_CANVAS_ITEM (icon_view_item); - details = icon_view_item->details; + item = GNOME_CANVAS_ITEM (icon_item); - if (!details->pixbuf) { - item->x1 = item->y1 = item->x2 = item->y2 = 0.0; - return; - } + gnome_canvas_item_get_bounds (item, + &bounds.x0, &bounds.y0, + &bounds.x1, &bounds.y1); - /* add 2 pixels slop to each side for highlight margin */ - rect.x0 = 0.0; - rect.x1 = details->pixbuf->art_pixbuf->width + 4; - if ((details->text_width + 4)> rect.x1) - rect.x1 = details->text_width + 4; - - rect.y0 = 0.0; - rect.y1 = details->pixbuf->art_pixbuf->height; - rect.y1 += floor(details->text_height); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - art_drect_affine_transform (&rect, &rect, render_affine); - - item->x1 = floor (rect.x0); - item->y1 = floor (rect.y0); - item->x2 = ceil (rect.x1); - item->y2 = ceil (rect.y1); -} + gnome_canvas_w2c_d (item->canvas, + bounds.x0, bounds.y0, + &item->x1, &item->y1); -/* Update sequence */ + gnome_canvas_w2c_d (item->canvas, + bounds.x1, bounds.y1, + &item->x2, &item->y2); +} -/* Update handler for the icon canvas item */ +/* Update handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - GdkFont *title_font; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - title_font = get_font_for_item(item); + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; - /* make sure the text box measurements are set up before recalculating the bounding box */ - nautilus_icons_view_measure_text_box(item, title_font, details->label); - recompute_bounding_box(icon_view_item); + /* Make sure the text box measurements are set up + * before recalculating the bounding box. + */ + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); + nautilus_icons_view_measure_text_box (item); + recompute_bounding_box (icon_item); + gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); NAUTILUS_CALL_PARENT_CLASS (GNOME_CANVAS_ITEM_CLASS, update, (item, affine, clip_path, flags)); - - if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE) - || details->need_pixbuf_update - || details->need_xform_update) - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - - /* If we need a pixbuf update, or if the item changed visibility to - * shown, recompute the bounding box. - */ - if (details->need_pixbuf_update - || details->need_xform_update - || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY) - && (GTK_OBJECT_FLAGS (icon_view_item) & GNOME_CANVAS_ITEM_VISIBLE)) - || (flags & GNOME_CANVAS_UPDATE_AFFINE)) { - recompute_bounding_box (icon_view_item); - gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2); - details->need_pixbuf_update = FALSE; - details->need_xform_update = FALSE; - } } /* Rendering */ -/* This is detailsate to libart, but we need it. Sigh. */ -extern void art_rgb_affine_run (int *p_x0, int *p_x1, int y, int src_width, int src_height, - const double affine[6]); - -/* Fills the specified buffer with the transformed version of a pixbuf */ -static void -transform_pixbuf (guchar *dest, int x, int y, int width, int height, int rowstride, - GdkPixbuf *pixbuf, double *affine) -{ - ArtPixBuf *apb; - int xx, yy; - double inv[6]; - guchar *src, *d; - ArtPoint src_p, dest_p; - int run_x1, run_x2; - int src_x, src_y; - int i; - - apb = pixbuf->art_pixbuf; - - art_affine_invert (inv, affine); - - for (yy = 0; yy < height; yy++) { - dest_p.y = y + yy + 0.5; - - run_x1 = x; - run_x2 = x + width; - art_rgb_affine_run (&run_x1, &run_x2, yy + y, - apb->width, apb->height, - inv); - - d = dest + yy * rowstride + (run_x1 - x) * 4; - - for (xx = run_x1; xx < run_x2; xx++) { - dest_p.x = xx + 0.5; - art_affine_point (&src_p, &dest_p, inv); - src_x = floor (src_p.x); - src_y = floor (src_p.y); - - src = apb->pixels + src_y * apb->rowstride + src_x * apb->n_channels; - - for (i = 0; i < apb->n_channels; i++) - *d++ = *src++; - - if (!apb->has_alpha) - *d++ = 255; /* opaque */ - } - } -} - -/* Draw the label in a box, using gnomelib routines. */ +/* Draw the text in a box, using gnomelib routines. */ static void draw_or_measure_text_box (GnomeCanvasItem* item, GdkDrawable *drawable, - GdkFont *title_font, - const char *label, - int icon_left, - int icon_bottom, - gboolean do_draw) + int icon_left, + int icon_bottom) { - NautilusIconsViewIconItem *icon_view_item; NautilusIconsViewIconItemDetails *details; int width_so_far, height_so_far; GdkGC* gc; - int max_label_width; - int item_width, box_left; + int max_text_width; + int icon_width, text_left, box_left; GnomeIconTextInfo *icon_text_info; - gchar **pieces; - const char *label_piece; - guint piece_index; + char **pieces; + const char *text_piece; + int i; - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - pieces = g_strsplit (label, "\n", 0); - piece_index = 0; - label_piece = pieces[piece_index]; + details = NAUTILUS_ICONS_VIEW_ICON_ITEM (item)->details; + + if (details->font == NULL || details->text == NULL || details->text[0] == '\0') { + details->text_height = 0; + details->text_width = 0; + return; + } + width_so_far = 0; height_so_far = 0; - while (label_piece != NULL) { + + if (drawable != NULL) { + icon_width = details->pixbuf == NULL ? 0 : details->pixbuf->art_pixbuf->width; + gc = gdk_gc_new (item->canvas->layout.bin_window); + } + + max_text_width = floor (MAX_TEXT_WIDTH * item->canvas->pixels_per_unit); + + pieces = g_strsplit (details->text, "\n", 0); + for (i = 0; (text_piece = pieces[i]) != NULL; i++) { /* Replace empty string with space for measurement and drawing. - * This make empty lines appear, instead of being collapsed out. + * This makes empty lines appear, instead of being collapsed out. */ - if (strlen (label_piece) == 0) - label_piece = " "; - - if (do_draw) { - item_width = floor (item->x2 - item->x1); - gc = gdk_gc_new (item->canvas->layout.bin_window); - } + if (text_piece[0] == '\0') + text_piece = " "; - max_label_width = floor (MAX_LABEL_WIDTH * item->canvas->pixels_per_unit); - icon_text_info = gnome_icon_layout_text - (title_font, label_piece, " -_,;.:?/&", max_label_width, TRUE); + (details->font, text_piece, " -_,;.:?/&", max_text_width, TRUE); - if (do_draw) { - box_left = icon_left + (item_width - icon_text_info->width) / 2; + if (drawable != NULL) { + text_left = icon_left + (icon_width - icon_text_info->width) / 2; gnome_icon_paint_text (icon_text_info, drawable, gc, - box_left, icon_bottom + height_so_far, GTK_JUSTIFY_CENTER); + text_left, icon_bottom + height_so_far, GTK_JUSTIFY_CENTER); } - gnome_icon_text_info_free (icon_text_info); - width_so_far = MAX (width_so_far, icon_text_info->width); height_so_far += icon_text_info->height; - - label_piece = pieces[++piece_index]; + + gnome_icon_text_info_free (icon_text_info); } g_strfreev (pieces); - height_so_far += 4; /* extra slop for nicer highlighting */ + height_so_far += 2; /* extra slop for nicer highlighting */ - if (do_draw) { + if (drawable != NULL) { - /* Current calculations should match what we measured before drawing */ + /* Current calculations should match what we measured before drawing. + * This assumes that we will always make a separate call to measure + * before the call to draw. We might later decide to use this function + * differently and change these asserts. + */ g_assert (height_so_far == details->text_height); g_assert (width_so_far == details->text_width); + box_left = icon_left + (icon_width - width_so_far) / 2; + /* invert to indicate selection if necessary */ - if (details->is_selected) { - gdk_gc_set_function (gc, GDK_INVERT); - gdk_draw_rectangle (drawable, gc, TRUE, box_left, icon_bottom - 2, width_so_far, height_so_far); - gdk_gc_set_function (gc, GDK_COPY); + if (details->is_highlighted_for_selection) { + gdk_gc_set_function (gc, GDK_INVERT); + gdk_draw_rectangle (drawable, gc, TRUE, + box_left, icon_bottom - 2, + width_so_far, 2 + height_so_far); + gdk_gc_set_function (gc, GDK_COPY); } - /* indicate alt-selection by framing the text with a gray-stippled rectangle */ - if (details->is_alt_selected) { - gdk_gc_set_stipple(gc, stipple); - gdk_gc_set_fill(gc, GDK_STIPPLED); - gdk_draw_rectangle (drawable, gc, FALSE, box_left, icon_bottom - 2, width_so_far, height_so_far); + /* indicate keyboard selection by framing the text with a gray-stippled rectangle */ + if (details->is_highlighted_for_keyboard_selection) { + gdk_gc_set_stipple (gc, stipple); + gdk_gc_set_fill (gc, GDK_STIPPLED); + gdk_draw_rectangle (drawable, gc, FALSE, + box_left, icon_bottom - 2, + width_so_far, 2 + height_so_far); } gdk_gc_unref (gc); @@ -691,252 +465,262 @@ draw_or_measure_text_box (GnomeCanvasItem* item, else { /* If measuring, remember the width & height. */ - details->text_width = (double) width_so_far; - details->text_height = (double) height_so_far; + details->text_width = width_so_far; + details->text_height = height_so_far; } } static void -nautilus_icons_view_measure_text_box (GnomeCanvasItem* item, - GdkFont *title_font, - const char *label) +nautilus_icons_view_measure_text_box (GnomeCanvasItem* item) { - draw_or_measure_text_box (item, - NULL, - title_font, - label, - 0, - 0, - FALSE); + draw_or_measure_text_box (item, NULL, 0, 0); } static void nautilus_icons_view_draw_text_box (GnomeCanvasItem* item, GdkDrawable *drawable, - GdkFont *title_font, const char *label, int icon_left, int icon_bottom) { - draw_or_measure_text_box (item, - drawable, - title_font, - label, - icon_left, - icon_bottom, - TRUE); + draw_or_measure_text_box (item, drawable, icon_left, icon_bottom); } -/* draw the icon item */ - +/* Draw the icon item. */ static void nautilus_icons_view_icon_item_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - guchar *buf; - GdkPixbuf *pixbuf; - ArtIRect p_rect, a_rect, d_rect; - int w, h, icon_height; - int center_offset = 0; - GdkFont *title_font = get_font_for_item(item); - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - /* handle drawing the pixbuf */ - - if (details->pixbuf) { - center_offset = nautilus_icons_view_icon_item_center_offset (icon_view_item); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - - /* Compute the area we need to repaint */ - - p_rect.x0 = item->x1; - p_rect.y0 = item->y1; - p_rect.x1 = item->x2; - p_rect.y1 = item->y2; - - a_rect.x0 = x - center_offset; - a_rect.y0 = y; - a_rect.x1 = x + width - center_offset; - a_rect.y1 = y + height; - - art_irect_intersect (&d_rect, &p_rect, &a_rect); - if (art_irect_empty (&d_rect)) - return; - - /* Create a temporary buffer and transform the pixbuf there */ - /* FIXME: only do this if really necessary */ - - w = d_rect.x1 - d_rect.x0; - h = d_rect.y1 - d_rect.y0; - - buf = g_new0 (guchar, w * h * 4); - transform_pixbuf (buf, - d_rect.x0, d_rect.y0, - w, h, - w * 4, - details->pixbuf, render_affine); - - pixbuf = gdk_pixbuf_new_from_data (buf, ART_PIX_RGB, TRUE, w, h, w * 4, NULL, NULL); - - gdk_pixbuf_render_to_drawable_alpha (pixbuf, drawable, - 0, 0, - d_rect.x0 - x + center_offset, d_rect.y0 - y, - w, h, - GDK_PIXBUF_ALPHA_BILEVEL, - 128, - GDK_RGB_DITHER_MAX, - d_rect.x0, d_rect.y0); - gdk_pixbuf_unref (pixbuf); - g_free (buf); + ArtIRect pixbuf_rect, drawable_rect, draw_rect; + + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + + /* Compute pixbuf rectangle in canvas coordinates. */ + nautilus_icons_view_icon_item_get_icon_canvas_rectangle + (icon_item, &pixbuf_rect); + + /* Draw the pixbuf. */ + if (details->pixbuf != NULL) { + /* Compute the area we need to draw. */ + drawable_rect.x0 = x; + drawable_rect.y0 = y; + drawable_rect.x1 = x + width; + drawable_rect.y1 = y + height; + art_irect_intersect (&draw_rect, &pixbuf_rect, &drawable_rect); + if (!art_irect_empty (&draw_rect)) + gdk_pixbuf_render_to_drawable_alpha + (details->pixbuf, drawable, + draw_rect.x0 - pixbuf_rect.x0, draw_rect.y0 - pixbuf_rect.y0, + draw_rect.x0 - x, draw_rect.y0 - y, + draw_rect.x1 - draw_rect.x0, draw_rect.y1 - draw_rect.y0, + GDK_PIXBUF_ALPHA_BILEVEL, 128, GDK_RGB_DITHER_MAX, + draw_rect.x0, draw_rect.y0); } - /* now compute the position of the label and draw it */ - if (nautilus_strlen (details->label) > 0) - { - icon_height = details->pixbuf->art_pixbuf->height * item->canvas->pixels_per_unit; - nautilus_icons_view_draw_text_box(item, drawable, title_font, details->label, item->x1 - x, - item->y1 - y + icon_height); - } -} - -/* return the center offset for this icon */ -int -nautilus_icons_view_icon_item_center_offset(NautilusIconsViewIconItem *icon_view_item) -{ - GnomeCanvasItem *item; - NautilusIconsViewIconItemDetails *details; - int box_width; - int center_offset; - - g_return_val_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (icon_view_item), 0); - - item = GNOME_CANVAS_ITEM (icon_view_item); - details = icon_view_item->details; - - box_width = floor (item->x2 - item->x1); - center_offset = (box_width - floor (details->pixbuf->art_pixbuf->width * item->canvas->pixels_per_unit)) / 2; - return center_offset; + /* Draw the text. */ + nautilus_icons_view_draw_text_box + (item, drawable, + pixbuf_rect.x0 - x, pixbuf_rect.y1 - y); } -/* Render handler for the icon canvas item */ +/* Render handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) { - NautilusIconsViewIconItem *icon_view_item; - NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6]; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - - if (!details->pixbuf) - return; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); + g_assert_not_reached (); +#if 0 gnome_canvas_buf_ensure_buf (buf); art_rgb_pixbuf_affine (buf->buf, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, buf->buf_rowstride, details->pixbuf->art_pixbuf, - render_affine, + i2c, ART_FILTER_BILINEAR, NULL); buf->is_bg = 0; +#endif } -/* Point handler for the icon canvas item */ +/* Point handler for the icon canvas item. */ +/* FIXME: This currently only reports a hit if the pixbuf is hit. */ static double nautilus_icons_view_icon_item_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) + GnomeCanvasItem **actual_item) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], render_affine[6], inv[6]; - ArtPoint c, p; - int px, py; - int center_offset; double no_hit; - ArtPixBuf *apb; - guchar *src; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; - center_offset = nautilus_icons_view_icon_item_center_offset (icon_view_item); + ArtIRect rect; + ArtPixBuf *art_pixbuf; + guint8 *pixel; + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + *actual_item = item; - no_hit = item->canvas->pixels_per_unit * 2 + 10; - - if (!details->pixbuf) + + /* Check to see if it's within the item's rectangle at all. */ + nautilus_icons_view_icon_item_get_icon_canvas_rectangle (icon_item, &rect); + if (cx <= rect.x0 || cx >= rect.x1 || cy <= rect.y0 || cy >= rect.y1) return no_hit; - - apb = details->pixbuf->art_pixbuf; - - gnome_canvas_item_i2c_affine (item, i2c); - compute_render_affine (icon_view_item, render_affine, i2c); - art_affine_invert (inv, render_affine); - - c.x = cx - center_offset; - c.y = cy; - art_affine_point (&p, &c, inv); - px = p.x; - py = p.y; - - if (px < 0 || px >= apb->width || py < 0 || py >= apb->height) + + /* Can't get this far without a pixbuf. */ + g_assert (details->pixbuf != NULL); + if (details->pixbuf == NULL) return no_hit; - if (!apb->has_alpha) + /* If there's no alpha channel, it's opaque and we have a hit. */ + art_pixbuf = details->pixbuf->art_pixbuf; + if (!art_pixbuf->has_alpha) return 0.0; + g_assert (art_pixbuf->n_channels == 4); - src = apb->pixels + py * apb->rowstride + px * apb->n_channels; - - if (src[3] < 128) - return no_hit; - else + /* Check the alpha channel of the pixel to see if we have a hit. */ + pixel = art_pixbuf->pixels + + (cy - rect.y0) * art_pixbuf->rowstride + + (cx - rect.x0) * 4; + if (pixel[3] >= 128) return 0.0; -} + return no_hit; +} -/* Bounds handler for the icon canvas item */ +/* Bounds handler for the icon canvas item. */ static void nautilus_icons_view_icon_item_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) { - NautilusIconsViewIconItem *icon_view_item; + NautilusIconsViewIconItem *icon_item; NautilusIconsViewIconItemDetails *details; - double i2c[6], viewport_affine[6]; - ArtDRect rect; - - icon_view_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); - details = icon_view_item->details; + ArtIRect rect; + int pixbuf_width, pixbuf_height; + double pixels_per_unit; + + g_assert (x1 != NULL); + g_assert (y1 != NULL); + g_assert (x2 != NULL); + g_assert (y2 != NULL); + + icon_item = NAUTILUS_ICONS_VIEW_ICON_ITEM (item); + details = icon_item->details; + + if (details->pixbuf == NULL) { + pixbuf_width = 0; + pixbuf_height = 0; + } else { + pixbuf_width = details->pixbuf->art_pixbuf->width; + pixbuf_height = details->pixbuf->art_pixbuf->height; + } - if (!details->pixbuf) { - *x1 = *y1 = *x2 = *y2 = 0.0; - return; + /* Compute rectangle enclosing both the icon and the text. */ + if (pixbuf_width > details->text_width) { + rect.x0 = 0; + rect.x1 = pixbuf_width; + } else { + rect.x0 = (pixbuf_width - details->text_width) / 2; + rect.x1 = rect.x0 + details->text_width; } + rect.y0 = 0; + rect.y1 = pixbuf_height + details->text_height; + + /* Add 2 pixels slop to each side. */ + rect.x0 -= 2; + rect.x1 += 2; + rect.y0 -= 2; + rect.y1 += 2; + + /* Return the result. */ + pixels_per_unit = item->canvas->pixels_per_unit; + *x1 = rect.x0 / pixels_per_unit; + *y1 = rect.y0 / pixels_per_unit; + *x2 = rect.x1 / pixels_per_unit; + *y2 = rect.y1 / pixels_per_unit; +} + +/* Get the rectangle of the icon only, in world coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_world_rectangle (NautilusIconsViewIconItem *item, + ArtDRect *rect) +{ + double i2w[6]; + ArtPoint art_point; + double pixels_per_unit; + GdkPixbuf *pixbuf; - /* add 2 pixels slop to each side for highlight margin */ - rect.x0 = 0.0; - rect.x1 = details->pixbuf->art_pixbuf->width + 4; - if ((details->text_width + 4) > rect.x1) - rect.x1 = details->text_width + 4; + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2w_affine (GNOME_CANVAS_ITEM (item), i2w); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2w); - rect.y0 = 0.0; - rect.y1 = details->pixbuf->art_pixbuf->height; - rect.y1 += floor(details->text_height); - - gnome_canvas_item_i2c_affine (item, i2c); - compute_viewport_affine (icon_view_item, viewport_affine, i2c); - art_drect_affine_transform (&rect, &rect, viewport_affine); + rect->x0 = art_point.x; + rect->y0 = art_point.y; + + pixbuf = item->details->pixbuf; + pixels_per_unit = GNOME_CANVAS_ITEM (item)->canvas->pixels_per_unit; + + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width) / pixels_per_unit; + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height) / pixels_per_unit; +} + +/* Get the rectangle of the icon only, in canvas coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_canvas_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect) +{ + double i2c[6]; + ArtPoint art_point; + GdkPixbuf *pixbuf; + + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (item), i2c); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2c); + + rect->x0 = floor (art_point.x); + rect->y0 = floor (art_point.y); + + pixbuf = item->details->pixbuf; + + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height); +} + +/* Get the rectangle of the icon only, in window coordinates. */ +void +nautilus_icons_view_icon_item_get_icon_window_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *rect) +{ + double i2w[6]; + ArtPoint art_point; + GdkPixbuf *pixbuf; + + g_return_if_fail (NAUTILUS_IS_ICONS_VIEW_ICON_ITEM (item)); + g_return_if_fail (rect != NULL); + + gnome_canvas_item_i2w_affine (GNOME_CANVAS_ITEM (item), i2w); + + art_point.x = 0; + art_point.y = 0; + art_affine_point (&art_point, &art_point, i2w); + gnome_canvas_world_to_window (GNOME_CANVAS_ITEM (item)->canvas, + art_point.x, art_point.y, + &art_point.x, &art_point.y); + + rect->x0 = floor (art_point.x); + rect->y0 = floor (art_point.y); + + pixbuf = item->details->pixbuf; - *x1 = rect.x0; - *y1 = rect.y0; - *x2 = rect.x1; - *y2 = rect.y1; + rect->x1 = rect->x0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->width); + rect->y1 = rect->y0 + (pixbuf == NULL ? 0 : pixbuf->art_pixbuf->height); } diff --git a/libnautilus/nautilus-icons-view-icon-item.h b/libnautilus/nautilus-icons-view-icon-item.h index 4e95dcefb..03ae11862 100644 --- a/libnautilus/nautilus-icons-view-icon-item.h +++ b/libnautilus/nautilus-icons-view-icon-item.h @@ -55,8 +55,11 @@ struct _NautilusIconsViewIconItemClass { GnomeCanvasItemClass parent_class; }; -GtkType nautilus_icons_view_icon_item_get_type (void); -int nautilus_icons_view_icon_item_center_offset (NautilusIconsViewIconItem *item); +GtkType nautilus_icons_view_icon_item_get_type (void); +void nautilus_icons_view_icon_item_get_icon_world_rectangle (NautilusIconsViewIconItem *item, + ArtDRect *world_rectangle); +void nautilus_icons_view_icon_item_get_icon_window_rectangle (NautilusIconsViewIconItem *item, + ArtIRect *window_rectangle); END_GNOME_DECLS diff --git a/src/file-manager/fm-icons-controller.c b/src/file-manager/fm-icons-controller.c index 7cdb611d9..05bc7b2f0 100644 --- a/src/file-manager/fm-icons-controller.c +++ b/src/file-manager/fm-icons-controller.c @@ -27,16 +27,15 @@ #include "fm-icons-controller.h" #include -#include -static void fm_icons_controller_initialize_class (FMIconsControllerClass *klass); -static void fm_icons_controller_initialize (FMIconsController *controller); -static GdkPixbuf *fm_icons_controller_get_icon_image (NautilusIconsController *controller, - NautilusControllerIcon *icon); -static char * fm_icons_controller_get_icon_text (NautilusIconsController *controller, - NautilusControllerIcon *icon); -static char * fm_icons_controller_get_icon_uri (NautilusIconsController *controller, - NautilusControllerIcon *icon); +static void fm_icons_controller_initialize_class (FMIconsControllerClass *klass); +static void fm_icons_controller_initialize (FMIconsController *controller); +static NautilusScalableIcon *fm_icons_controller_get_icon_image (NautilusIconsController *controller, + NautilusControllerIcon *icon); +static char * fm_icons_controller_get_icon_text (NautilusIconsController *controller, + NautilusControllerIcon *icon); +static char * fm_icons_controller_get_icon_uri (NautilusIconsController *controller, + NautilusControllerIcon *icon); NAUTILUS_DEFINE_CLASS_BOILERPLATE (FMIconsController, fm_icons_controller, NAUTILUS_TYPE_ICONS_CONTROLLER) @@ -70,25 +69,12 @@ fm_icons_controller_new (FMDirectoryViewIcons *icons) return controller; } -static GdkPixbuf * +static NautilusScalableIcon * fm_icons_controller_get_icon_image (NautilusIconsController *controller, NautilusControllerIcon *icon) { - /* Get the appropriate image for the file. For the moment, - * we always use the standard size of icons. - */ - - NautilusScalableIcon *scalable_icon; - GdkPixbuf *pixbuf; - - scalable_icon = nautilus_icon_factory_get_icon_for_file - (NAUTILUS_FILE (icon)); - pixbuf = nautilus_icon_factory_get_pixbuf_for_icon - (scalable_icon, - NAUTILUS_ICON_SIZE_STANDARD); - nautilus_scalable_icon_unref (scalable_icon); - - return pixbuf; + /* Get the appropriate image for the file. */ + return nautilus_icon_factory_get_icon_for_file (NAUTILUS_FILE (icon)); } static char * @@ -100,21 +86,19 @@ fm_icons_controller_get_icon_text (NautilusIconsController *controller, char *result; int index; - attribute_names = fm_directory_view_icons_get_icon_text_attribute_names ( - FM_ICONS_CONTROLLER (controller)->icons); + attribute_names = fm_directory_view_icons_get_icon_text_attribute_names + (FM_ICONS_CONTROLLER (controller)->icons); text_array = g_strsplit (attribute_names, "|", 0); g_free (attribute_names); - index = 0; - while (text_array[index] != NULL) + for (index = 0; text_array[index] != NULL; index++) { - char * attribute_string; + char *attribute_string; - attribute_string = - nautilus_file_get_string_attribute (NAUTILUS_FILE (icon), - text_array[index]); - - /* unknown attributes get turned into blank lines (also note that + attribute_string = nautilus_file_get_string_attribute + (NAUTILUS_FILE (icon), text_array[index]); + + /* Unknown attributes get turned into blank lines (also note that * leaving a NULL in text_array would cause it to be incompletely * freed). */ @@ -124,8 +108,6 @@ fm_icons_controller_get_icon_text (NautilusIconsController *controller, /* Replace each attribute name in the array with its string value */ g_free (text_array[index]); text_array[index] = attribute_string; - - ++index; } result = g_strjoinv ("\n", text_array); diff --git a/src/nautilus-window-manage-views.c b/src/nautilus-window-manage-views.c index f8a10193d..7d8e74605 100644 --- a/src/nautilus-window-manage-views.c +++ b/src/nautilus-window-manage-views.c @@ -874,7 +874,8 @@ nautilus_window_change_location_2(NautilusNavigationInfo *navi, gpointer data) errout: nautilus_window_allow_stop(window, FALSE); - nautilus_navinfo_free(navi); + if (navi != NULL) + nautilus_navinfo_free(navi); window->is_back = FALSE; nautilus_window_progress_indicate(window, PROGRESS_ERROR, 0, errmsg); } diff --git a/src/ntl-window-msgs.c b/src/ntl-window-msgs.c index f8a10193d..7d8e74605 100644 --- a/src/ntl-window-msgs.c +++ b/src/ntl-window-msgs.c @@ -874,7 +874,8 @@ nautilus_window_change_location_2(NautilusNavigationInfo *navi, gpointer data) errout: nautilus_window_allow_stop(window, FALSE); - nautilus_navinfo_free(navi); + if (navi != NULL) + nautilus_navinfo_free(navi); window->is_back = FALSE; nautilus_window_progress_indicate(window, PROGRESS_ERROR, 0, errmsg); } -- GitLab