[PATCH] Add compact icon view (column-wise)



I dediced to do some balancing computer hacking between two written
tests. I'm attaching the results, namely a "compact icon view" - I'm not
sure whether that name is verbose enough.

It provides a column-wise icon layout with tiny icons and one-lined text
descriptions next to the icons. It allows to display a few dozen icons
at the same time, which may make it interesting for people with much
data (like myself).

To make review a little bit easier (it's a nightmare anyway), I made a
patchset with 3 single patches:

* nautilus-forced-icon-size.diff
Actually force a particular size for the icons displayed in the icon
container.

* nautilus-compact-icon-layout.diff
The heart of the vertical layout code. Copied from horizontal layout
code, but simplified.

* nautilus-compact-icon-non-core.diff [gzipped]
changes to preferences, changes to FMIconView. Addition of new view
IIDs, a new preferences dialog section (yet another "default zoom"
preference for the new view).


Caveats:

The "Tight layout" (shorter labels) setting is currently shared with the
old icon view, but I assume we won't need it anymore for the old view.
It also made icons non grid-aligned which looks horrible.

RTL is probably not supported properly ATM.


Feedback appreciated.

best regards,
 Christian Neumair


-- 
Christian Neumair <cneumair gnome org>
Index: src/file-manager/fm-icon-container.c
===================================================================
--- src/file-manager/fm-icon-container.c	(Revision 13749)
+++ src/file-manager/fm-icon-container.c	(Arbeitskopie)
@@ -82,14 +83,18 @@ fm_icon_container_get_icon_images (Nauti
 	
 	if (emblem_pixbufs != NULL) {
 		emblem_size = nautilus_icon_get_emblem_size_for_icon_size (size);
-		
-		emblems_to_ignore = fm_directory_view_get_emblem_names_to_exclude 
-			(FM_DIRECTORY_VIEW (icon_view));
-		*emblem_pixbufs = nautilus_file_get_emblem_pixbufs (file,
-								    emblem_size,
-								    FALSE,
-								    emblems_to_ignore);
-		g_strfreev (emblems_to_ignore);
+		/* don't return images larger than the actual icon size */
+		emblem_size = MIN (emblem_size, size);
+
+		if (emblem_size > 0) {
+			emblems_to_ignore = fm_directory_view_get_emblem_names_to_exclude 
+				(FM_DIRECTORY_VIEW (icon_view));
+			*emblem_pixbufs = nautilus_file_get_emblem_pixbufs (file,
+									    emblem_size,
+									    FALSE,
+									    emblems_to_ignore);
+			g_strfreev (emblems_to_ignore);
+		}
 	}
 
 	*has_window_open = nautilus_file_has_open_window (file);
@@ -321,6 +326,11 @@ fm_icon_container_get_icon_text (Nautilu
 		*editable_text = nautilus_file_get_display_name (file);
 	}
 
+	if (fm_icon_view_is_compact (icon_view)) {
+		*additional_text = NULL;
+		return;
+	}
+
 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
 		/* Don't show the normal extra information for desktop icons, it doesn't
 		 * make sense. */
Index: libnautilus-private/nautilus-icon-canvas-item.c
===================================================================
--- libnautilus-private/nautilus-icon-canvas-item.c	(Revision 13749)
+++ libnautilus-private/nautilus-icon-canvas-item.c	(Arbeitskopie)
@@ -62,6 +62,7 @@
 #define MAX_TEXT_WIDTH_STANDARD 135
 #define MAX_TEXT_WIDTH_TIGHTER 80
 #define MAX_TEXT_WIDTH_BESIDE 90
+#define MAX_TEXT_WIDTH_BESIDE_TOP_TO_BOTTOM 300
 
 /* Private part of the NautilusIconCanvasItem structure. */
 struct NautilusIconCanvasItemDetails {
@@ -1816,6 +1817,11 @@ nautilus_icon_canvas_item_draw (EelCanva
 	 (g_ascii_isdigit (*(p+1)) && \
 	  g_ascii_isdigit (*(p+2))))
 
+#define IS_COMPACT_VIEW(container) \
+        container->details->layout_mode == NAUTILUS_ICON_LAYOUT_T_B_L_R && \
+        container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE
+
+
 static PangoLayout *
 create_label_layout (NautilusIconCanvasItem *item,
 		     const char *text)
@@ -1872,6 +1878,9 @@ create_label_layout (NautilusIconCanvasI
 
 	pango_layout_set_spacing (layout, LABEL_LINE_SPACING);
 	pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
+	if (IS_COMPACT_VIEW (container)) {
+		pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
+	}
 
 	/* Create a font description */
 	if (container->details->font) {
@@ -2424,14 +2433,19 @@ double
 nautilus_icon_canvas_item_get_max_text_width (NautilusIconCanvasItem *item)
 {
 	EelCanvasItem *canvas_item;
-	
+
 	canvas_item = EEL_CANVAS_ITEM (item);
 	if (nautilus_icon_container_is_tighter_layout (NAUTILUS_ICON_CONTAINER (canvas_item->canvas))) {
 		return MAX_TEXT_WIDTH_TIGHTER * canvas_item->canvas->pixels_per_unit;
 	} else {
 				
                 if (NAUTILUS_ICON_CONTAINER (canvas_item->canvas)->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
-			return MAX_TEXT_WIDTH_BESIDE * canvas_item->canvas->pixels_per_unit;
+			if (NAUTILUS_ICON_CONTAINER (canvas_item->canvas)->details->layout_mode == NAUTILUS_ICON_LAYOUT_T_B_L_R ||
+			    NAUTILUS_ICON_CONTAINER (canvas_item->canvas)->details->layout_mode == NAUTILUS_ICON_LAYOUT_T_B_R_L) {
+				return MAX_TEXT_WIDTH_BESIDE_TOP_TO_BOTTOM * canvas_item->canvas->pixels_per_unit;
+			} else {
+				return MAX_TEXT_WIDTH_BESIDE * canvas_item->canvas->pixels_per_unit;
+			}
                 } else {
 			return MAX_TEXT_WIDTH_STANDARD * canvas_item->canvas->pixels_per_unit;
                 }
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
--- libnautilus-private/nautilus-icon-container.c	(Revision 13749)
+++ libnautilus-private/nautilus-icon-container.c	(Arbeitskopie)
@@ -1000,6 +1000,40 @@ lay_down_one_line (NautilusIconContainer
 }
 
 static void
+lay_down_one_column (NautilusIconContainer *container,
+		     GList *line_start,
+		     GList *line_end,
+		     double x,
+		     double y_start,
+		     double y_iter,
+		     GArray *positions)
+{
+	GList *p;
+	NautilusIcon *icon;
+	double y;
+	IconPositions *position;
+	int i;
+
+	/* FIXME: Should layout differently when in RTL base mode */
+
+	/* Lay out the icons along the baseline. */
+	y = y_start;
+	i = 0;
+	for (p = line_start; p != line_end; p = p->next) {
+		icon = p->data;
+
+		position = &g_array_index (positions, IconPositions, i++);
+
+		icon_set_position
+			(icon,
+			 x + position->x_offset,
+			 y + position->y_offset);
+
+		y += y_iter;
+	}
+}
+
+static void
 lay_down_icons_horizontal (NautilusIconContainer *container,
 			   GList *icons,
 			   double start_y)
@@ -1160,6 +1194,118 @@ lay_down_icons_horizontal (NautilusIconC
 	g_array_free (positions, TRUE);
 }
 
+/* column-wise layout. At the moment, this only works with label-beside-icon (used by "Compact Icon View"). */
+static void
+lay_down_icons_vertical (NautilusIconContainer *container,
+			 GList *icons,
+			 double start_y)
+{
+	GList *p, *line_start;
+	NautilusIcon *icon;
+	double canvas_width, x, canvas_height;
+	GArray *positions;
+	IconPositions *position;
+	EelDRect icon_bounds;
+	EelDRect text_bounds;
+	EelCanvasItem *item;
+
+	double line_height;
+
+	double max_height;
+	double max_height_with_borders;
+	double max_width;
+
+	double max_text_width, max_icon_width;
+	double max_text_height, max_icon_height;
+	int height;
+	int i;
+
+	g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
+	g_assert (container->details->label_position == NAUTILUS_ICON_LABEL_POSITION_BESIDE);
+
+	if (icons == NULL) {
+		return;
+	}
+
+	positions = g_array_new (FALSE, FALSE, sizeof (IconPositions));
+
+	/* Lay out icons a column at a time. */
+	canvas_width = CANVAS_WIDTH(container);
+	canvas_height = CANVAS_HEIGHT(container);
+
+	max_icon_width = max_text_width = 0.0;
+	max_icon_height = max_text_height = 0.0;
+
+	/* Would it be worth caching these bounds for the next loop? */
+	for (p = icons; p != NULL; p = p->next) {
+		icon = p->data;
+
+		icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
+		max_icon_width = MAX (max_icon_width, ceil (icon_bounds.x1 - icon_bounds.x0));
+		max_icon_height = MAX (max_icon_height, ceil (icon_bounds.y1 - icon_bounds.y0));
+
+		text_bounds = nautilus_icon_canvas_item_get_text_rectangle (icon->item);
+		max_text_width = MAX (max_text_width, ceil (text_bounds.x1 - text_bounds.x0));
+		max_text_height = MAX (max_text_height, ceil (text_bounds.y1 - text_bounds.y0));
+	}
+
+	max_width = max_icon_width + max_text_width;
+	max_height = MAX (max_icon_height, max_text_height);
+	max_height_with_borders = ICON_PAD_TOP + max_height + ICON_PAD_BOTTOM;
+
+	line_height = ICON_PAD_TOP;
+	line_start = icons;
+	x = 0;
+	i = 0;
+	
+	for (p = icons; p != NULL; p = p->next) {
+		icon = p->data;
+
+		/* Get the width of the icon. */
+		item = EEL_CANVAS_ITEM (icon->item);
+
+		/* If this icon doesn't fit, it's time to lay out the column that's queued up. */
+		if (line_start != p && line_height + max_height_with_borders + ICON_PAD_BOTTOM > canvas_height ) {
+			x += ICON_PAD_LEFT;
+
+			lay_down_one_column (container, line_start, p, x, CONTAINER_PAD_TOP, max_height_with_borders, positions);
+
+			/* Advance to next column. */
+			x += max_width + ICON_PAD_RIGHT;
+
+			line_height = ICON_PAD_TOP;
+			line_start = p;
+			i = 0;
+		}
+
+		g_array_set_size (positions, i + 1);
+		position = &g_array_index (positions, IconPositions, i++);
+		position->width = max_width;
+		position->height = max_height;
+		position->y_offset = ICON_PAD_TOP;
+		position->x_offset = ICON_PAD_LEFT;
+
+		icon_bounds = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
+		text_bounds = nautilus_icon_canvas_item_get_text_rectangle (icon->item);
+
+		position->x_offset += max_icon_width - ceil (icon_bounds.x1 - icon_bounds.x0);
+
+		height = MAX (ceil (icon_bounds.y1 - icon_bounds.y0), ceil(text_bounds.y1 - text_bounds.y0));
+		position->y_offset += (max_height - height) / 2;
+
+		/* Add this icon. */
+		line_height += max_height_with_borders;
+	}
+
+	/* Lay down that last column of icons. */
+	if (line_start != NULL) {
+		x += ICON_PAD_LEFT;
+		lay_down_one_column (container, line_start, NULL, x, CONTAINER_PAD_TOP, max_height_with_borders, positions);
+	}
+
+	g_array_free (positions, TRUE);
+}
+
 static void
 snap_position (NautilusIconContainer *container,
 	       NautilusIcon *icon,
@@ -1487,7 +1633,7 @@ nautilus_icon_container_set_rtl_position
 }
 
 static void
-lay_down_icons_vertical (NautilusIconContainer *container, GList *icons)
+lay_down_icons_vertical_desktop (NautilusIconContainer *container, GList *icons)
 {
 	GList *p, *placed_icons, *unplaced_icons;
 	int total, new_length, placed;
@@ -1668,7 +1814,11 @@ lay_down_icons (NautilusIconContainer *c
 		
 	case NAUTILUS_ICON_LAYOUT_T_B_L_R:
 	case NAUTILUS_ICON_LAYOUT_T_B_R_L:
-		lay_down_icons_vertical (container, icons);
+		if (nautilus_icon_container_get_is_desktop (container)) {
+			lay_down_icons_vertical_desktop (container, icons);
+		} else {
+			lay_down_icons_vertical (container, icons, start_y);
+		}
 		break;
 		
 	default:
@@ -3147,6 +3297,10 @@ size_allocate (GtkWidget *widget,
 		need_layout_redone = TRUE;
 	}
 
+	if (allocation->height != widget->allocation.height) {
+		need_layout_redone = TRUE;
+	}
+
 	GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
 
 	container->details->has_been_allocated = TRUE;
@@ -5758,9 +5912,14 @@ nautilus_icon_container_update_icon (Nau
 	/* compute the maximum size based on the scale factor */
 	min_image_size = MINIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit;
 	max_image_size = MAX (MAXIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit, NAUTILUS_ICON_MAXIMUM_SIZE);
-		
+
 	/* Get the appropriate images for the file. */
-	icon_get_size (container, icon, &icon_size);
+	if (container->details->forced_icon_size > 0) {
+		icon_size = container->details->forced_icon_size;
+	} else {
+		icon_get_size (container, icon, &icon_size);
+	}
+
 
 	icon_size = MAX (icon_size, min_image_size);
 	icon_size = MIN (icon_size, max_image_size);
@@ -6762,6 +6924,7 @@ nautilus_icon_container_set_layout_mode 
 	g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
 
 	container->details->layout_mode = mode;
+	invalidate_label_sizes (container);
 
 	redo_layout (container);
 
@@ -6981,7 +7144,11 @@ nautilus_icon_container_start_renaming_s
 		eel_editable_label_set_line_wrap (EEL_EDITABLE_LABEL (details->rename_widget), TRUE);
 		eel_editable_label_set_line_wrap_mode (EEL_EDITABLE_LABEL (details->rename_widget), PANGO_WRAP_WORD_CHAR);
 		eel_editable_label_set_draw_outline (EEL_EDITABLE_LABEL (details->rename_widget), TRUE);
-		eel_editable_label_set_justify (EEL_EDITABLE_LABEL (details->rename_widget), GTK_JUSTIFY_CENTER);
+
+		if (details->label_position != NAUTILUS_ICON_LABEL_POSITION_BESIDE) {
+			eel_editable_label_set_justify (EEL_EDITABLE_LABEL (details->rename_widget), GTK_JUSTIFY_CENTER);
+		}
+
 		gtk_misc_set_padding (GTK_MISC (details->rename_widget), 1, 1);
 		gtk_layout_put (GTK_LAYOUT (container),
 				details->rename_widget, 0, 0);

Attachment: nautilus-compact-icon-non-core.diff.gz
Description: GNU Zip compressed data

Index: libnautilus-private/nautilus-icon-private.h
===================================================================
--- libnautilus-private/nautilus-icon-private.h	(Revision 13749)
+++ libnautilus-private/nautilus-icon-private.h	(Arbeitskopie)
@@ -231,6 +231,9 @@ struct NautilusIconContainerDetails {
 	/* Label position */
 	NautilusIconLabelPosition label_position;
 
+	/* Forced icon size, iff greater than 0 */
+	int forced_icon_size;
+
 	/* Should the container keep icons aligned to a grid */
 	gboolean keep_aligned;
 
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
--- libnautilus-private/nautilus-icon-container.c	(Revision 13749)
+++ libnautilus-private/nautilus-icon-container.c	(Arbeitskopie)
@@ -5777,7 +5777,10 @@ nautilus_icon_container_update_icon (Nau
 							     &has_open_window);
 
 
-	pixbuf = nautilus_icon_info_get_pixbuf (icon_info);
+	if (container->details->forced_icon_size > 0)
+		pixbuf = nautilus_icon_info_get_pixbuf_at_size (icon_info, icon_size);
+	else
+		pixbuf = nautilus_icon_info_get_pixbuf (icon_info);
 	nautilus_icon_info_get_attach_points (icon_info, &attach_points, &n_attach_points);
 	has_embedded_text_rect = nautilus_icon_info_get_embedded_rect (icon_info,
 								       &embedded_text_rect);
@@ -7550,6 +7553,15 @@ nautilus_icon_container_set_allow_moves	
 	container->details->drag_allow_moves = allow_moves;
 }
 
+void
+nautilus_icon_container_set_forced_icon_size (NautilusIconContainer *container,
+					      int                    forced_icon_size)
+{
+	g_return_if_fail (NAUTILUS_IS_ICON_CONTAINER (container));
+
+	container->details->forced_icon_size = forced_icon_size;
+}
+
 /* NautilusIconContainerAccessible */
 
 static NautilusIconContainerAccessiblePrivate *
Index: libnautilus-private/nautilus-icon-container.h
===================================================================
--- libnautilus-private/nautilus-icon-container.h	(Revision 13749)
+++ libnautilus-private/nautilus-icon-container.h	(Arbeitskopie)
@@ -301,6 +301,8 @@ char*             nautilus_icon_containe
 gboolean          nautilus_icon_container_get_allow_moves               (NautilusIconContainer  *container);
 void              nautilus_icon_container_set_allow_moves               (NautilusIconContainer  *container,
 									 gboolean                allow_moves);
+void		  nautilus_icon_container_set_forced_icon_size		(NautilusIconContainer  *container,
+									 int                     forced_icon_size);
 
 gboolean	  nautilus_icon_container_is_layout_rtl			(NautilusIconContainer  *container);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]