diff --git a/libnautilus-extensions/gdk-extensions.c b/libnautilus-extensions/gdk-extensions.c index 73731dc4168b913dcceaeccbc8ec4b94d1563f0d..7d7f2c286615615175d11d6387ff0b0eed4ffc00 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 f5dd0c27b87a73a8ad56cd13c5897d78fb3dc9a5..366303c1d2c64c5a400224260fc51ccd06b94968 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 e01c1c43d150488817598fa6f0015a13a3993e7c..dd74f85ea1861b9d9a4c2f2b7bb751915dfa6524 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 1ecd0625db299cc05e9e76257dd61a010f32777a..abb781303f2919587ae1a28ff2a9f8dbb849da9a 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 04e1c054da06c9befdd37a30325bea740b327650..7f144c396f7721ad7cfff73c436f680d7f927d8a 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 ac68e783c9e7a083374ab9c91f0d6df5f575f832..850ffdce8dcfb092f5d28b9c25cefa39e80cbda1 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 fa123c455048c384a55c23ecde9a6c3bf26b4841..a9256dd13d8e0c8ec3c540333ea79fba002419ec 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 027bb7901144ecb1120590e8b562da01649e9cc3..3c83c5be0376aaa98d6aa6b11e1cfd43d3da7c98 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 4e95dcefb662325107c44a35efc574fb574f081c..03ae11862bbc61ec3af395304fc9d8194b07eb7d 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 73731dc4168b913dcceaeccbc8ec4b94d1563f0d..7d7f2c286615615175d11d6387ff0b0eed4ffc00 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 f5dd0c27b87a73a8ad56cd13c5897d78fb3dc9a5..366303c1d2c64c5a400224260fc51ccd06b94968 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 e01c1c43d150488817598fa6f0015a13a3993e7c..dd74f85ea1861b9d9a4c2f2b7bb751915dfa6524 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 1ecd0625db299cc05e9e76257dd61a010f32777a..abb781303f2919587ae1a28ff2a9f8dbb849da9a 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 04e1c054da06c9befdd37a30325bea740b327650..7f144c396f7721ad7cfff73c436f680d7f927d8a 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 ac68e783c9e7a083374ab9c91f0d6df5f575f832..850ffdce8dcfb092f5d28b9c25cefa39e80cbda1 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 fa123c455048c384a55c23ecde9a6c3bf26b4841..a9256dd13d8e0c8ec3c540333ea79fba002419ec 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 027bb7901144ecb1120590e8b562da01649e9cc3..3c83c5be0376aaa98d6aa6b11e1cfd43d3da7c98 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 4e95dcefb662325107c44a35efc574fb574f081c..03ae11862bbc61ec3af395304fc9d8194b07eb7d 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 73731dc4168b913dcceaeccbc8ec4b94d1563f0d..7d7f2c286615615175d11d6387ff0b0eed4ffc00 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 f5dd0c27b87a73a8ad56cd13c5897d78fb3dc9a5..366303c1d2c64c5a400224260fc51ccd06b94968 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 e01c1c43d150488817598fa6f0015a13a3993e7c..dd74f85ea1861b9d9a4c2f2b7bb751915dfa6524 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 1ecd0625db299cc05e9e76257dd61a010f32777a..abb781303f2919587ae1a28ff2a9f8dbb849da9a 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 04e1c054da06c9befdd37a30325bea740b327650..7f144c396f7721ad7cfff73c436f680d7f927d8a 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 ac68e783c9e7a083374ab9c91f0d6df5f575f832..850ffdce8dcfb092f5d28b9c25cefa39e80cbda1 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 fa123c455048c384a55c23ecde9a6c3bf26b4841..a9256dd13d8e0c8ec3c540333ea79fba002419ec 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 027bb7901144ecb1120590e8b562da01649e9cc3..3c83c5be0376aaa98d6aa6b11e1cfd43d3da7c98 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 4e95dcefb662325107c44a35efc574fb574f081c..03ae11862bbc61ec3af395304fc9d8194b07eb7d 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 7cdb611d908def0017490b5a85f88c0e852a6a8e..05bc7b2f06bbabd089ab9af6c3896e875f03acfb 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 f8a10193d345c6d2dfd061a4d0d0bc0a1d967245..7d8e74605634274d818af1ab2d42e5f8a870ae62 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 f8a10193d345c6d2dfd061a4d0d0bc0a1d967245..7d8e74605634274d818af1ab2d42e5f8a870ae62 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); }