r2228: Made 'Automatic' an icon size, rather than a separate option.
[rox-filer.git] / ROX-Filer / src / view_collection.c
blob85e3da1aff0de5f871b3adc49786845ace2f50dd
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* view_collection.c - a subclass of Collection, used for displaying files */
24 #include "config.h"
26 #include <gtk/gtk.h>
27 #include <time.h>
28 #include <math.h>
30 #include "global.h"
32 #include "collection.h"
33 #include "view_iface.h"
34 #include "view_collection.h"
35 #include "type.h"
36 #include "pixmaps.h"
37 #include "dir.h"
38 #include "diritem.h"
39 #include "gui_support.h"
40 #include "support.h"
41 #include "dnd.h"
42 #include "bind.h"
43 #include "options.h"
45 #include "display.h" /* XXX */
46 #include "toolbar.h" /* XXX */
47 #include "filer.h" /* XXX */
48 #include "menu.h" /* XXX */
50 #define MIN_ITEM_WIDTH 64
52 #if 0
53 /* The handler of the signal handler for scroll events.
54 * This is used to cancel spring loading when autoscrolling is used.
56 static gulong scrolled_signal = -1;
57 static GtkObject *scrolled_adj = NULL; /* The object watched */
58 #endif
60 static gpointer parent_class = NULL;
62 struct _ViewCollectionClass {
63 GtkViewportClass parent;
66 struct _ViewCollection {
67 GtkViewport viewport;
69 Collection *collection;
70 FilerWindow *filer_window; /* Used for styles, etc */
72 int cursor_base; /* Cursor when minibuffer opened */
75 typedef struct _Template Template;
77 struct _Template {
78 GdkRectangle icon;
79 GdkRectangle leafname;
80 GdkRectangle details;
83 /* GC for drawing colour filenames */
84 static GdkGC *type_gc = NULL;
86 /* Static prototypes */
87 static void view_collection_finialize(GObject *object);
88 static void view_collection_class_init(gpointer gclass, gpointer data);
89 static void view_collection_init(GTypeInstance *object, gpointer gclass);
91 static void draw_item(GtkWidget *widget,
92 CollectionItem *item,
93 GdkRectangle *area,
94 gpointer user_data);
95 static void fill_template(GdkRectangle *area, CollectionItem *item,
96 ViewCollection *view_collection, Template *template);
97 static void huge_template(GdkRectangle *area, CollectionItem *colitem,
98 ViewCollection *view_collection, Template *template);
99 static void large_template(GdkRectangle *area, CollectionItem *colitem,
100 ViewCollection *view_collection, Template *template);
101 static void small_template(GdkRectangle *area, CollectionItem *colitem,
102 ViewCollection *view_collection, Template *template);
103 static void huge_full_template(GdkRectangle *area, CollectionItem *colitem,
104 ViewCollection *view_collection, Template *template);
105 static void large_full_template(GdkRectangle *area, CollectionItem *colitem,
106 ViewCollection *view_collection, Template *template);
107 static void small_full_template(GdkRectangle *area, CollectionItem *colitem,
108 ViewCollection *view_collection, Template *template);
109 static gboolean test_point(Collection *collection,
110 int point_x, int point_y,
111 CollectionItem *item,
112 int width, int height,
113 gpointer user_data);
114 static void draw_string(GtkWidget *widget,
115 PangoLayout *layout,
116 GdkRectangle *area, /* Area available on screen */
117 int width, /* Width of the full string */
118 GtkStateType selection_state,
119 gboolean selected,
120 gboolean box);
121 static void draw_huge_icon(GtkWidget *widget,
122 GdkRectangle *area,
123 DirItem *item,
124 MaskedPixmap *image,
125 gboolean selected);
126 static void view_collection_iface_init(gpointer giface, gpointer iface_data);
127 static gint coll_motion_notify(GtkWidget *widget,
128 GdkEventMotion *event,
129 ViewCollection *view_collection);
130 static gint coll_button_release(GtkWidget *widget,
131 GdkEventButton *event,
132 ViewCollection *view_collection);
133 static gint coll_button_press(GtkWidget *widget,
134 GdkEventButton *event,
135 ViewCollection *view_collection);
136 static void size_allocate(GtkWidget *w, GtkAllocation *a, gpointer data);
137 static void style_set(Collection *collection,
138 GtkStyle *style,
139 ViewCollection *view_collection);
140 static void display_free_colitem(Collection *collection,
141 CollectionItem *colitem);
142 static void lost_selection(Collection *collection,
143 guint time,
144 gpointer user_data);
145 static void selection_changed(Collection *collection,
146 gint time,
147 gpointer user_data);
148 static void calc_size(FilerWindow *filer_window, CollectionItem *colitem,
149 int *width, int *height);
150 static void make_iter(ViewCollection *view_collection, ViewIter *iter,
151 IterFlags flags);
152 static void make_item_iter(ViewCollection *vc, ViewIter *iter, int i);
154 static void view_collection_sort(ViewIface *view);
155 static void view_collection_style_changed(ViewIface *view, int flags);
156 static gboolean view_collection_autoselect(ViewIface *view, const gchar *leaf);
157 static void view_collection_add_items(ViewIface *view, GPtrArray *items);
158 static void view_collection_update_items(ViewIface *view, GPtrArray *items);
159 static void view_collection_delete_if(ViewIface *view,
160 gboolean (*test)(gpointer item, gpointer data),
161 gpointer data);
162 static void view_collection_clear(ViewIface *view);
163 static void view_collection_select_all(ViewIface *view);
164 static void view_collection_clear_selection(ViewIface *view);
165 static int view_collection_count_items(ViewIface *view);
166 static int view_collection_count_selected(ViewIface *view);
167 static void view_collection_show_cursor(ViewIface *view);
168 static void view_collection_get_iter(ViewIface *view,
169 ViewIter *iter, IterFlags flags);
170 static void view_collection_get_iter_at_point(ViewIface *view, ViewIter *iter,
171 int x, int y);
172 static void view_collection_cursor_to_iter(ViewIface *view, ViewIter *iter);
173 static void view_collection_set_selected(ViewIface *view,
174 ViewIter *iter,
175 gboolean selected);
176 static gboolean view_collection_get_selected(ViewIface *view, ViewIter *iter);
177 static void view_collection_select_only(ViewIface *view, ViewIter *iter);
178 static void view_collection_set_frozen(ViewIface *view, gboolean frozen);
179 static void view_collection_wink_item(ViewIface *view, ViewIter *iter);
180 static void view_collection_autosize(ViewIface *view);
181 static gboolean view_collection_cursor_visible(ViewIface *view);
182 static void view_collection_set_base(ViewIface *view, ViewIter *iter);
183 static void view_collection_start_lasso_box(ViewIface *view,
184 GdkEventButton *event);
185 static void view_collection_extend_tip(ViewIface *view, ViewIter *iter,
186 GString *tip);
188 static DirItem *iter_next(ViewIter *iter);
189 static DirItem *iter_prev(ViewIter *iter);
190 static DirItem *iter_peek(ViewIter *iter);
193 /****************************************************************
194 * EXTERNAL INTERFACE *
195 ****************************************************************/
197 GtkWidget *view_collection_new(FilerWindow *filer_window)
199 ViewCollection *view_collection;
201 view_collection = g_object_new(view_collection_get_type(), NULL);
202 view_collection->filer_window = filer_window;
204 gtk_range_set_adjustment(GTK_RANGE(filer_window->scrollbar),
205 view_collection->collection->vadj);
207 return GTK_WIDGET(view_collection);
210 GType view_collection_get_type(void)
212 static GType type = 0;
214 if (!type)
216 static const GTypeInfo info =
218 sizeof (ViewCollectionClass),
219 NULL, /* base_init */
220 NULL, /* base_finalise */
221 view_collection_class_init,
222 NULL, /* class_finalise */
223 NULL, /* class_data */
224 sizeof(ViewCollection),
225 0, /* n_preallocs */
226 view_collection_init
228 static const GInterfaceInfo iface_info =
230 view_collection_iface_init, NULL, NULL
233 type = g_type_register_static(gtk_viewport_get_type(),
234 "ViewCollection", &info, 0);
235 g_type_add_interface_static(type, VIEW_TYPE_IFACE, &iface_info);
238 return type;
241 /****************************************************************
242 * INTERNAL FUNCTIONS *
243 ****************************************************************/
245 static void view_collection_destroy(GtkObject *view_collection)
247 VIEW_COLLECTION(view_collection)->filer_window = NULL;
250 static void view_collection_finialize(GObject *object)
252 /* ViewCollection *view_collection = (ViewCollection *) object; */
254 G_OBJECT_CLASS(parent_class)->finalize(object);
257 static void view_collection_class_init(gpointer gclass, gpointer data)
259 GObjectClass *object = (GObjectClass *) gclass;
261 parent_class = g_type_class_peek_parent(gclass);
263 object->finalize = view_collection_finialize;
264 GTK_OBJECT_CLASS(object)->destroy = view_collection_destroy;
267 static void view_collection_init(GTypeInstance *object, gpointer gclass)
269 ViewCollection *view_collection = (ViewCollection *) object;
270 GtkViewport *viewport = (GtkViewport *) object;
271 GtkWidget *collection;
272 GtkAdjustment *adj;
274 collection = collection_new();
275 view_collection->collection = COLLECTION(collection);
277 adj = view_collection->collection->vadj;
278 gtk_viewport_set_vadjustment(viewport, adj);
279 gtk_viewport_set_hadjustment(viewport, NULL); /* Or Gtk will crash */
280 gtk_viewport_set_shadow_type(viewport, GTK_SHADOW_NONE);
281 gtk_container_add(GTK_CONTAINER(object), collection);
282 gtk_widget_show(collection);
283 gtk_widget_set_size_request(GTK_WIDGET(view_collection), 4, 4);
285 gtk_container_set_resize_mode(GTK_CONTAINER(viewport),
286 GTK_RESIZE_IMMEDIATE);
288 view_collection->collection->free_item = display_free_colitem;
289 view_collection->collection->draw_item = draw_item;
290 view_collection->collection->test_point = test_point;
291 view_collection->collection->cb_user_data = view_collection;
293 g_signal_connect(collection, "style_set",
294 G_CALLBACK(style_set),
295 view_collection);
297 g_signal_connect(collection, "lose_selection",
298 G_CALLBACK(lost_selection), view_collection);
299 g_signal_connect(collection, "selection_changed",
300 G_CALLBACK(selection_changed), view_collection);
302 g_signal_connect(collection, "button-release-event",
303 G_CALLBACK(coll_button_release), view_collection);
304 g_signal_connect(collection, "button-press-event",
305 G_CALLBACK(coll_button_press), view_collection);
306 g_signal_connect(collection, "motion-notify-event",
307 G_CALLBACK(coll_motion_notify), view_collection);
308 g_signal_connect(viewport, "size-allocate",
309 G_CALLBACK(size_allocate), view_collection);
311 gtk_widget_set_events(collection,
312 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
313 GDK_BUTTON3_MOTION_MASK | GDK_POINTER_MOTION_MASK |
314 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
318 static void draw_item(GtkWidget *widget,
319 CollectionItem *colitem,
320 GdkRectangle *area,
321 gpointer user_data)
323 DirItem *item = (DirItem *) colitem->data;
324 gboolean selected = colitem->selected;
325 Template template;
326 ViewData *view = (ViewData *) colitem->view_data;
327 ViewCollection *view_collection = (ViewCollection *) user_data;
328 FilerWindow *filer_window = view_collection->filer_window;
330 g_return_if_fail(view != NULL);
332 fill_template(area, colitem, view_collection, &template);
334 /* Set up GC for coloured file types */
335 if (!type_gc)
336 type_gc = gdk_gc_new(widget->window);
338 gdk_gc_set_foreground(type_gc, type_get_colour(item,
339 &widget->style->fg[GTK_STATE_NORMAL]));
341 if (template.icon.width <= SMALL_WIDTH &&
342 template.icon.height <= SMALL_HEIGHT)
344 draw_small_icon(widget->window, &template.icon,
345 item, view->image, selected);
347 else if (template.icon.width <= ICON_WIDTH &&
348 template.icon.height <= ICON_HEIGHT)
350 draw_large_icon(widget, &template.icon,
351 item, view->image, selected);
353 else
355 draw_huge_icon(widget, &template.icon,
356 item, view->image, selected);
359 draw_string(widget, view->layout,
360 &template.leafname,
361 view->name_width,
362 filer_window->selection_state,
363 selected, TRUE);
364 if (view->details)
365 draw_string(widget, view->details,
366 &template.details,
367 template.details.width,
368 filer_window->selection_state,
369 selected, TRUE);
372 /* A template contains the locations of the three rectangles (for the icon,
373 * name and extra details).
374 * Fill in the empty 'template' with the rectanges for this item.
376 static void fill_template(GdkRectangle *area, CollectionItem *colitem,
377 ViewCollection *view_collection, Template *template)
379 DisplayStyle style = view_collection->filer_window->display_style;
380 ViewData *view = (ViewData *) colitem->view_data;
382 if (view->details)
384 template->details.width = view->details_width;
385 template->details.height = view->details_height;
387 if (style == SMALL_ICONS)
388 small_full_template(area, colitem,
389 view_collection, template);
390 else if (style == LARGE_ICONS)
391 large_full_template(area, colitem,
392 view_collection, template);
393 else
394 huge_full_template(area, colitem,
395 view_collection, template);
397 else
399 if (style == HUGE_ICONS)
400 huge_template(area, colitem,
401 view_collection, template);
402 else if (style == LARGE_ICONS)
403 large_template(area, colitem,
404 view_collection, template);
405 else
406 small_template(area, colitem,
407 view_collection, template);
411 static void huge_template(GdkRectangle *area, CollectionItem *colitem,
412 ViewCollection *view_collection, Template *template)
414 int col_width = view_collection->collection->item_width;
415 int text_x, text_y;
416 ViewData *view = (ViewData *) colitem->view_data;
417 MaskedPixmap *image = view->image;
419 if (image)
421 if (!image->huge_pixbuf)
422 pixmap_make_huge(image);
423 template->icon.width = image->huge_width;
424 template->icon.height = image->huge_height;
426 else
428 template->icon.width = HUGE_WIDTH * 3 / 2;
429 template->icon.height = HUGE_HEIGHT;
432 template->leafname.width = view->name_width;
433 template->leafname.height = view->name_height;
435 text_x = area->x + ((col_width - template->leafname.width) >> 1);
436 text_y = area->y + area->height - template->leafname.height;
438 template->leafname.x = text_x;
439 template->leafname.y = text_y;
441 template->icon.x = area->x + ((col_width - template->icon.width) >> 1);
442 template->icon.y = template->leafname.y - template->icon.height - 2;
445 static void large_template(GdkRectangle *area, CollectionItem *colitem,
446 ViewCollection *view_collection, Template *template)
448 int col_width = view_collection->collection->item_width;
449 int iwidth, iheight;
450 int image_x;
451 int image_y;
452 ViewData *view = (ViewData *) colitem->view_data;
453 MaskedPixmap *image = view->image;
455 int text_x, text_y;
457 if (image)
459 iwidth = MIN(image->width, ICON_WIDTH);
460 iheight = MIN(image->height + 6, ICON_HEIGHT);
462 else
464 iwidth = ICON_WIDTH;
465 iheight = ICON_HEIGHT;
467 image_x = area->x + ((col_width - iwidth) >> 1);
469 template->leafname.width = view->name_width;
470 template->leafname.height = view->name_height;
472 text_x = area->x + ((col_width - template->leafname.width) >> 1);
473 text_y = area->y + ICON_HEIGHT + 2;
475 template->leafname.x = text_x;
476 template->leafname.y = text_y;
478 image_y = text_y - iheight;
479 image_y = MAX(area->y, image_y);
481 template->icon.x = image_x;
482 template->icon.y = image_y;
483 template->icon.width = iwidth;
484 template->icon.height = MIN(ICON_HEIGHT, iheight);
487 static void small_template(GdkRectangle *area, CollectionItem *colitem,
488 ViewCollection *view_collection, Template *template)
490 int text_x = area->x + SMALL_WIDTH + 4;
491 int low_text_y;
492 int max_text_width = area->width - SMALL_WIDTH - 4;
493 ViewData *view = (ViewData *) colitem->view_data;
495 low_text_y = area->y + area->height / 2 - view->name_height / 2;
497 template->leafname.x = text_x;
498 template->leafname.y = low_text_y;
499 template->leafname.width = MIN(max_text_width, view->name_width);
500 template->leafname.height = view->name_height;
502 template->icon.x = area->x;
503 template->icon.y = area->y + 1;
504 template->icon.width = SMALL_WIDTH;
505 template->icon.height = SMALL_HEIGHT;
508 static void huge_full_template(GdkRectangle *area, CollectionItem *colitem,
509 ViewCollection *view_collection, Template *template)
511 int max_text_width = area->width - HUGE_WIDTH - 4;
512 ViewData *view = (ViewData *) colitem->view_data;
513 MaskedPixmap *image = view->image;
515 if (image)
517 if (!image->huge_pixbuf)
518 pixmap_make_huge(image);
519 template->icon.width = image->huge_width;
520 template->icon.height = image->huge_height;
522 else
524 template->icon.width = HUGE_WIDTH * 3 / 2;
525 template->icon.height = HUGE_HEIGHT;
528 template->icon.x = area->x + (HUGE_WIDTH - template->icon.width) / 2;
529 template->icon.y = area->y + (area->height - template->icon.height) / 2;
531 template->leafname.x = area->x + HUGE_WIDTH + 4;
532 template->leafname.y = area->y + area->height / 2
533 - (view->name_height + 2 + view->details_height) / 2;
534 template->leafname.width = MIN(max_text_width, view->name_width);
535 template->leafname.height = view->name_height;
537 if (!image)
538 return; /* Not scanned yet */
540 template->details.x = template->leafname.x;
541 template->details.y = template->leafname.y + view->name_height + 2;
544 static void large_full_template(GdkRectangle *area, CollectionItem *colitem,
545 ViewCollection *view_collection, Template *template)
547 int max_text_width = area->width - ICON_WIDTH - 4;
548 ViewData *view = (ViewData *) colitem->view_data;
549 MaskedPixmap *image = view->image;
551 if (image)
553 template->icon.width = image->width;
554 template->icon.height = image->height;
556 else
558 template->icon.width = ICON_WIDTH;
559 template->icon.height = ICON_HEIGHT;
562 template->icon.x = area->x + (ICON_WIDTH - template->icon.width) / 2;
563 template->icon.y = area->y + (area->height - template->icon.height) / 2;
566 template->leafname.x = area->x + ICON_WIDTH + 4;
567 template->leafname.y = area->y + area->height / 2
568 - (view->name_height + 2 + view->details_height) / 2;
569 template->leafname.width = MIN(max_text_width, view->name_width);
570 template->leafname.height = view->name_height;
572 if (!image)
573 return; /* Not scanned yet */
575 template->details.x = template->leafname.x;
576 template->details.y = template->leafname.y + view->name_height + 2;
579 static void small_full_template(GdkRectangle *area, CollectionItem *colitem,
580 ViewCollection *view_collection, Template *template)
582 int col_width = view_collection->collection->item_width;
583 ViewData *view = (ViewData *) colitem->view_data;
585 small_template(area, colitem, view_collection, template);
587 if (!view->image)
588 return; /* Not scanned yet */
590 template->details.x = area->x + col_width - template->details.width;
591 template->details.y = area->y + area->height / 2 - \
592 view->details_height / 2;
595 #define INSIDE(px, py, area) \
596 (px >= area.x && py >= area.y && \
597 px <= area.x + area.width && py <= area.y + area.height)
599 static gboolean test_point(Collection *collection,
600 int point_x, int point_y,
601 CollectionItem *colitem,
602 int width, int height,
603 gpointer user_data)
605 Template template;
606 GdkRectangle area;
607 ViewData *view = (ViewData *) colitem->view_data;
608 ViewCollection *view_collection = (ViewCollection *) user_data;
610 area.x = 0;
611 area.y = 0;
612 area.width = width;
613 area.height = height;
615 fill_template(&area, colitem, view_collection, &template);
617 return INSIDE(point_x, point_y, template.leafname) ||
618 INSIDE(point_x, point_y, template.icon) ||
619 (view->details && INSIDE(point_x, point_y, template.details));
622 /* 'box' renders a background box if the string is also selected */
623 static void draw_string(GtkWidget *widget,
624 PangoLayout *layout,
625 GdkRectangle *area, /* Area available on screen */
626 int width, /* Width of the full string */
627 GtkStateType selection_state,
628 gboolean selected,
629 gboolean box)
631 GdkGC *gc = selected
632 ? widget->style->fg_gc[selection_state]
633 : type_gc;
635 if (selected && box)
636 gtk_paint_flat_box(widget->style, widget->window,
637 selection_state, GTK_SHADOW_NONE,
638 NULL, widget, "text",
639 area->x, area->y,
640 MIN(width, area->width),
641 area->height);
643 if (width > area->width)
645 gdk_gc_set_clip_origin(gc, 0, 0);
646 gdk_gc_set_clip_rectangle(gc, area);
649 gdk_draw_layout(widget->window, gc, area->x, area->y, layout);
651 if (width > area->width)
653 static GdkGC *red_gc = NULL;
655 if (!red_gc)
657 gboolean success;
658 GdkColor red = {0, 0xffff, 0, 0};
660 red_gc = gdk_gc_new(widget->window);
661 gdk_colormap_alloc_colors(
662 gtk_widget_get_colormap(widget),
663 &red, 1, FALSE, TRUE, &success);
664 gdk_gc_set_foreground(red_gc, &red);
666 gdk_draw_rectangle(widget->window, red_gc, TRUE,
667 area->x + area->width - 1, area->y,
668 1, area->height);
669 gdk_gc_set_clip_rectangle(gc, NULL);
673 /* Draw this icon (including any symlink or mount symbol) inside the
674 * given rectangle.
676 static void draw_huge_icon(GtkWidget *widget,
677 GdkRectangle *area,
678 DirItem *item,
679 MaskedPixmap *image,
680 gboolean selected)
682 int width, height;
683 int image_x;
684 int image_y;
686 if (!image)
687 return;
689 width = image->huge_width;
690 height = image->huge_height;
691 image_x = area->x + ((area->width - width) >> 1);
692 image_y = MAX(0, area->height - height - 6);
694 gdk_pixbuf_render_to_drawable_alpha(
695 selected ? image->huge_pixbuf_lit
696 : image->huge_pixbuf,
697 widget->window,
698 0, 0, /* src */
699 image_x, area->y + image_y, /* dest */
700 width, height,
701 GDK_PIXBUF_ALPHA_FULL, 128, /* (unused) */
702 GDK_RGB_DITHER_NORMAL, 0, 0);
704 if (item->flags & ITEM_FLAG_SYMLINK)
706 gdk_pixbuf_render_to_drawable_alpha(im_symlink->pixbuf,
707 widget->window,
708 0, 0, /* src */
709 image_x, area->y + 2, /* dest */
710 -1, -1,
711 GDK_PIXBUF_ALPHA_FULL, 128, /* (unused) */
712 GDK_RGB_DITHER_NORMAL, 0, 0);
714 else if (item->flags & ITEM_FLAG_MOUNT_POINT)
716 MaskedPixmap *mp = item->flags & ITEM_FLAG_MOUNTED
717 ? im_mounted
718 : im_unmounted;
720 gdk_pixbuf_render_to_drawable_alpha(mp->pixbuf,
721 widget->window,
722 0, 0, /* src */
723 image_x, area->y + 2, /* dest */
724 -1, -1,
725 GDK_PIXBUF_ALPHA_FULL, 128, /* (unused) */
726 GDK_RGB_DITHER_NORMAL, 0, 0);
730 /* Create the handers for the View interface */
731 static void view_collection_iface_init(gpointer giface, gpointer iface_data)
733 ViewIfaceClass *iface = giface;
735 g_assert(G_TYPE_FROM_INTERFACE(iface) == VIEW_TYPE_IFACE);
737 /* override stuff */
738 iface->sort = view_collection_sort;
739 iface->style_changed = view_collection_style_changed;
740 iface->autoselect = view_collection_autoselect;
741 iface->add_items = view_collection_add_items;
742 iface->update_items = view_collection_update_items;
743 iface->delete_if = view_collection_delete_if;
744 iface->clear = view_collection_clear;
745 iface->select_all = view_collection_select_all;
746 iface->clear_selection = view_collection_clear_selection;
747 iface->count_items = view_collection_count_items;
748 iface->count_selected = view_collection_count_selected;
749 iface->show_cursor = view_collection_show_cursor;
750 iface->get_iter = view_collection_get_iter;
751 iface->get_iter_at_point = view_collection_get_iter_at_point;
752 iface->cursor_to_iter = view_collection_cursor_to_iter;
753 iface->set_selected = view_collection_set_selected;
754 iface->get_selected = view_collection_get_selected;
755 iface->set_frozen = view_collection_set_frozen;
756 iface->select_only = view_collection_select_only;
757 iface->wink_item = view_collection_wink_item;
758 iface->autosize = view_collection_autosize;
759 iface->cursor_visible = view_collection_cursor_visible;
760 iface->set_base = view_collection_set_base;
761 iface->start_lasso_box = view_collection_start_lasso_box;
762 iface->extend_tip = view_collection_extend_tip;
765 static void view_collection_extend_tip(ViewIface *view, ViewIter *iter,
766 GString *tip)
768 ViewCollection*view_collection = (ViewCollection *) view;
769 Collection *collection = view_collection->collection;
770 FilerWindow *filer_window = view_collection->filer_window;
771 Template template;
772 int i = iter->i;
773 CollectionItem *colitem = &collection->items[i];
774 int col = i % collection->columns;
775 int row = i / collection->columns;
776 ViewData *view_data = (ViewData *) colitem->view_data;
777 GdkRectangle area;
779 g_return_if_fail(iter->view_collection == view_collection);
780 g_return_if_fail(i >= 0 && i < collection->number_of_items);
782 /* TODO: What if the window is narrower than 1 column? */
783 if (filer_window->display_style == LARGE_ICONS ||
784 filer_window->display_style == HUGE_ICONS)
785 return; /* These wrap rather than truncate */
787 area.x = col * collection->item_width;
788 area.y = row * collection->item_height;
789 area.height = collection->item_height;
791 if (col == collection->columns - 1)
792 area.width = GTK_WIDGET(collection)->allocation.width - area.x;
793 else
794 area.width = collection->item_width;
796 fill_template(&area, colitem, view_collection, &template);
798 if (template.leafname.width < view_data->name_width)
800 DirItem *item = (DirItem *) collection->items[i].data;
802 g_string_append(tip, item->leafname);
803 g_string_append_c(tip, '\n');
807 static gint coll_motion_notify(GtkWidget *widget,
808 GdkEventMotion *event,
809 ViewCollection *view_collection)
811 return filer_motion_notify(view_collection->filer_window, event);
814 /* Viewport is to be resized, so calculate increments */
815 static void size_allocate(GtkWidget *w, GtkAllocation *a, gpointer data)
817 Collection *col = ((ViewCollection *) data)->collection;
819 col->vadj->step_increment = col->item_height;
820 col->vadj->page_increment = col->vadj->page_size;
823 static gint coll_button_release(GtkWidget *widget,
824 GdkEventButton *event,
825 ViewCollection *view_collection)
827 if (dnd_motion_release(event))
829 if (motion_buttons_pressed == 0 &&
830 view_collection->collection->lasso_box)
832 collection_end_lasso(view_collection->collection,
833 event->button == 1 ? GDK_SET : GDK_INVERT);
835 return FALSE;
838 filer_perform_action(view_collection->filer_window, event);
840 return FALSE;
843 static gint coll_button_press(GtkWidget *widget,
844 GdkEventButton *event,
845 ViewCollection *view_collection)
847 collection_set_cursor_item(view_collection->collection, -1);
849 if (dnd_motion_press(widget, event))
850 filer_perform_action(view_collection->filer_window, event);
852 return FALSE;
855 /* Nothing is selected anymore - give up primary */
856 static void lost_selection(Collection *collection,
857 guint time,
858 gpointer user_data)
860 ViewCollection *view_collection = VIEW_COLLECTION(user_data);
862 filer_lost_selection(view_collection->filer_window, time);
865 static void selection_changed(Collection *collection,
866 gint time,
867 gpointer user_data)
869 ViewCollection *view_collection = VIEW_COLLECTION(user_data);
871 filer_selection_changed(view_collection->filer_window, time);
874 static void display_free_colitem(Collection *collection,
875 CollectionItem *colitem)
877 ViewData *view = (ViewData *) colitem->view_data;
879 if (!view)
880 return;
882 if (view->layout)
884 g_object_unref(G_OBJECT(view->layout));
885 view->layout = NULL;
887 if (view->details)
888 g_object_unref(G_OBJECT(view->details));
890 if (view->image)
891 g_object_unref(view->image);
893 g_free(view);
896 static void add_item(ViewCollection *view_collection, DirItem *item)
898 Collection *collection = view_collection->collection;
899 FilerWindow *filer_window = view_collection->filer_window;
900 int old_w = collection->item_width;
901 int old_h = collection->item_height;
902 int w, h, i;
904 i = collection_insert(collection, item,
905 display_create_viewdata(filer_window, item));
907 calc_size(filer_window, &collection->items[i], &w, &h);
909 if (w > old_w || h > old_h)
910 collection_set_item_size(collection,
911 MAX(old_w, w),
912 MAX(old_h, h));
915 static void style_set(Collection *collection,
916 GtkStyle *style,
917 ViewCollection *view_collection)
919 view_collection_style_changed(VIEW(view_collection),
920 VIEW_UPDATE_VIEWDATA | VIEW_UPDATE_NAME);
923 /* Return the size needed for this item */
924 static void calc_size(FilerWindow *filer_window, CollectionItem *colitem,
925 int *width, int *height)
927 int pix_width, pix_height;
928 int w;
929 DisplayStyle style = filer_window->display_style;
930 ViewData *view = (ViewData *) colitem->view_data;
932 if (filer_window->details_type == DETAILS_NONE)
934 if (style == HUGE_ICONS)
936 if (view->image)
938 if (!view->image->huge_pixbuf)
939 pixmap_make_huge(view->image);
940 pix_width = view->image->huge_width;
941 pix_height = view->image->huge_height;
943 else
945 pix_width = HUGE_WIDTH * 3 / 2;
946 pix_height = HUGE_HEIGHT * 3 / 2;
948 *width = MAX(pix_width, view->name_width) + 4;
949 *height = view->name_height + pix_height + 4;
951 else if (style == SMALL_ICONS)
953 w = MIN(view->name_width, o_small_width.int_value);
954 *width = SMALL_WIDTH + 12 + w;
955 *height = MAX(view->name_height, SMALL_HEIGHT) + 4;
957 else
959 if (view->image)
960 pix_width = view->image->width;
961 else
962 pix_width = ICON_WIDTH;
963 *width = MAX(pix_width, view->name_width) + 4;
964 *height = view->name_height + ICON_HEIGHT + 2;
967 else
969 w = view->details_width;
970 if (style == HUGE_ICONS)
972 *width = HUGE_WIDTH + 12 + MAX(w, view->name_width);
973 *height = HUGE_HEIGHT - 4;
975 else if (style == SMALL_ICONS)
977 int text_height;
979 *width = SMALL_WIDTH + view->name_width + 12 + w;
980 text_height = MAX(view->name_height,
981 view->details_height);
982 *height = MAX(text_height, SMALL_HEIGHT) + 4;
984 else
986 *width = ICON_WIDTH + 12 + MAX(w, view->name_width);
987 *height = ICON_HEIGHT;
992 static void update_item(ViewCollection *view_collection, int i)
994 Collection *collection = view_collection->collection;
995 int old_w = collection->item_width;
996 int old_h = collection->item_height;
997 int w, h;
998 CollectionItem *colitem;
999 FilerWindow *filer_window = view_collection->filer_window;
1001 g_return_if_fail(i >= 0 && i < collection->number_of_items);
1003 colitem = &collection->items[i];
1005 display_update_view(filer_window,
1006 (DirItem *) colitem->data,
1007 (ViewData *) colitem->view_data,
1008 FALSE);
1010 calc_size(filer_window, colitem, &w, &h);
1011 if (w > old_w || h > old_h)
1012 collection_set_item_size(collection,
1013 MAX(old_w, w),
1014 MAX(old_h, h));
1016 collection_draw_item(collection, i, TRUE);
1019 /* Implementations of the View interface. See view_iface.c for comments. */
1021 static void view_collection_style_changed(ViewIface *view, int flags)
1023 ViewCollection *view_collection = VIEW_COLLECTION(view);
1024 FilerWindow *filer_window = view_collection->filer_window;
1025 int i;
1026 Collection *col = view_collection->collection;
1027 int width = MIN_ITEM_WIDTH;
1028 int height = SMALL_HEIGHT;
1029 int n = col->number_of_items;
1031 if (n == 0 && filer_window->display_style != SMALL_ICONS)
1032 height = ICON_HEIGHT;
1034 /* Recalculate all the ViewData structs for this window
1035 * (needed if the text or image has changed in any way) and
1036 * get the size of each item.
1038 for (i = 0; i < n; i++)
1040 CollectionItem *ci = &col->items[i];
1041 int w, h;
1043 if (flags & (VIEW_UPDATE_VIEWDATA | VIEW_UPDATE_NAME))
1044 display_update_view(filer_window,
1045 (DirItem *) ci->data,
1046 (ViewData *) ci->view_data,
1047 (flags & VIEW_UPDATE_NAME) != 0);
1049 calc_size(filer_window, ci, &w, &h);
1050 if (w > width)
1051 width = w;
1052 if (h > height)
1053 height = h;
1056 collection_set_item_size(col, width, height);
1058 gtk_widget_queue_draw(GTK_WIDGET(view_collection));
1061 static void view_collection_sort(ViewIface *view)
1063 ViewCollection *view_collection = VIEW_COLLECTION(view);
1065 collection_qsort(view_collection->collection,
1066 view_collection->filer_window->sort_fn);
1069 static gboolean view_collection_autoselect(ViewIface *view, const gchar *leaf)
1071 ViewCollection *view_collection = VIEW_COLLECTION(view);
1072 Collection *col = view_collection->collection;
1073 int i;
1075 for (i = 0; i < col->number_of_items; i++)
1077 DirItem *item = (DirItem *) col->items[i].data;
1079 if (strcmp(item->leafname, leaf) == 0)
1081 if (col->cursor_item != -1)
1082 collection_set_cursor_item(col, i);
1083 else
1084 collection_wink_item(col, i);
1085 return TRUE;
1089 return FALSE;
1092 static void view_collection_add_items(ViewIface *view, GPtrArray *items)
1094 ViewCollection *view_collection = VIEW_COLLECTION(view);
1095 Collection *collection = view_collection->collection;
1096 FilerWindow *filer_window = view_collection->filer_window;
1097 int old_num, i;
1099 old_num = collection->number_of_items;
1100 for (i = 0; i < items->len; i++)
1102 DirItem *item = (DirItem *) items->pdata[i];
1103 char *leafname = item->leafname;
1105 if (leafname[0] == '.' && !filer_window->show_hidden)
1106 continue;
1108 add_item(view_collection, item);
1111 if (old_num != collection->number_of_items)
1112 view_collection_sort(view);
1115 static void view_collection_update_items(ViewIface *view, GPtrArray *items)
1117 ViewCollection *view_collection = VIEW_COLLECTION(view);
1118 Collection *collection = view_collection->collection;
1119 FilerWindow *filer_window = view_collection->filer_window;
1120 int i;
1122 g_return_if_fail(items->len > 0);
1124 /* The item data has already been modified, so this gives the
1125 * final sort order...
1127 collection_qsort(collection, filer_window->sort_fn);
1129 for (i = 0; i < items->len; i++)
1131 DirItem *item = (DirItem *) items->pdata[i];
1132 const gchar *leafname = item->leafname;
1133 int j;
1135 if (leafname[0] == '.' && filer_window->show_hidden == FALSE)
1136 continue;
1138 j = collection_find_item(collection, item,
1139 filer_window->sort_fn);
1141 if (j < 0)
1142 g_warning("Failed to find '%s'\n", leafname);
1143 else
1144 update_item(view_collection, j);
1148 static void view_collection_delete_if(ViewIface *view,
1149 gboolean (*test)(gpointer item, gpointer data),
1150 gpointer data)
1152 ViewCollection *view_collection = VIEW_COLLECTION(view);
1153 Collection *collection = view_collection->collection;
1155 collection_delete_if(collection, test, data);
1158 static void view_collection_clear(ViewIface *view)
1160 ViewCollection *view_collection = VIEW_COLLECTION(view);
1161 Collection *collection = view_collection->collection;
1163 collection_clear(collection);
1166 static void view_collection_select_all(ViewIface *view)
1168 ViewCollection *view_collection = VIEW_COLLECTION(view);
1169 Collection *collection = view_collection->collection;
1171 collection_select_all(collection);
1174 static void view_collection_clear_selection(ViewIface *view)
1176 ViewCollection *view_collection = VIEW_COLLECTION(view);
1177 Collection *collection = view_collection->collection;
1179 collection_clear_selection(collection);
1182 static int view_collection_count_items(ViewIface *view)
1184 ViewCollection *view_collection = VIEW_COLLECTION(view);
1185 Collection *collection = view_collection->collection;
1187 return collection->number_of_items;
1190 static int view_collection_count_selected(ViewIface *view)
1192 ViewCollection *view_collection = VIEW_COLLECTION(view);
1193 Collection *collection = view_collection->collection;
1195 return collection->number_selected;
1198 static void view_collection_show_cursor(ViewIface *view)
1200 ViewCollection *view_collection = VIEW_COLLECTION(view);
1201 Collection *collection = view_collection->collection;
1203 collection_move_cursor(collection, 0, 0);
1206 /* The first time the next() method is used, this is called */
1207 static DirItem *iter_init(ViewIter *iter)
1209 ViewCollection *view_collection = iter->view_collection;
1210 Collection *collection = view_collection->collection;
1211 int i = -1;
1212 int n = collection->number_of_items;
1213 int flags = iter->flags;
1215 iter->peek = iter_peek;
1217 if (iter->n_remaining == 0)
1218 return NULL;
1220 if (flags & VIEW_ITER_FROM_CURSOR)
1222 i = collection->cursor_item;
1223 if (i == -1)
1224 return NULL; /* No cursor */
1226 else if (flags & VIEW_ITER_FROM_BASE)
1227 i = view_collection->cursor_base;
1229 if (i < 0 || i >= n)
1231 /* Either a normal iteration, or an iteration from an
1232 * invalid starting point.
1234 if (flags & VIEW_ITER_BACKWARDS)
1235 i = n - 1;
1236 else
1237 i = 0;
1240 if (i < 0 || i >= n)
1241 return NULL; /* No items at all! */
1243 iter->next = flags & VIEW_ITER_BACKWARDS ? iter_prev : iter_next;
1244 iter->n_remaining--;
1245 iter->i = i;
1247 if (flags & VIEW_ITER_SELECTED && !collection->items[i].selected)
1248 return iter->next(iter);
1249 return iter->peek(iter);
1251 /* Advance iter to point to the next item and return the new item
1252 * (this saves you calling peek after next each time).
1254 static DirItem *iter_next(ViewIter *iter)
1256 Collection *collection = iter->view_collection->collection;
1257 int n = collection->number_of_items;
1258 int i = iter->i;
1260 g_return_val_if_fail(iter->n_remaining >= 0, NULL);
1262 /* i is the last item returned (always valid) */
1264 g_return_val_if_fail(i >= 0 && i < n, NULL);
1266 while (iter->n_remaining)
1268 i++;
1269 iter->n_remaining--;
1271 if (i == n)
1272 i = 0;
1274 g_return_val_if_fail(i >= 0 && i < n, NULL);
1276 if (iter->flags & VIEW_ITER_SELECTED &&
1277 !collection->items[i].selected)
1278 continue;
1280 iter->i = i;
1281 return collection->items[i].data;
1284 iter->i = -1;
1285 return NULL;
1288 /* Like iter_next, but in the other direction */
1289 static DirItem *iter_prev(ViewIter *iter)
1291 Collection *collection = iter->view_collection->collection;
1292 int n = collection->number_of_items;
1293 int i = iter->i;
1295 g_return_val_if_fail(iter->n_remaining >= 0, NULL);
1297 /* i is the last item returned (always valid) */
1299 g_return_val_if_fail(i >= 0 && i < n, NULL);
1301 while (iter->n_remaining)
1303 i--;
1304 iter->n_remaining--;
1306 if (i == -1)
1307 i = collection->number_of_items - 1;
1309 g_return_val_if_fail(i >= 0 && i < n, NULL);
1311 if (iter->flags & VIEW_ITER_SELECTED &&
1312 !collection->items[i].selected)
1313 continue;
1315 iter->i = i;
1316 return collection->items[i].data;
1319 iter->i = -1;
1320 return NULL;
1323 static DirItem *iter_peek(ViewIter *iter)
1325 Collection *collection = iter->view_collection->collection;
1326 int i = iter->i;
1328 if (i == -1)
1329 return NULL;
1331 g_return_val_if_fail(i >= 0 && i < collection->number_of_items, NULL);
1333 return collection->items[i].data;
1336 static void make_iter(ViewCollection *view_collection, ViewIter *iter,
1337 IterFlags flags)
1339 Collection *collection = view_collection->collection;
1341 iter->view_collection = view_collection;
1342 iter->next = iter_init;
1343 iter->peek = NULL;
1344 iter->i = -1;
1346 iter->flags = flags;
1348 if (flags & VIEW_ITER_ONE_ONLY)
1350 iter->n_remaining = 1;
1351 iter->next(iter);
1353 else
1354 iter->n_remaining = collection->number_of_items;
1357 /* Set the iterator to return 'i' on the next peek() */
1358 static void make_item_iter(ViewCollection *view_collection,
1359 ViewIter *iter, int i)
1361 Collection *collection = view_collection->collection;
1363 g_return_if_fail(i >= -1 && i < collection->number_of_items);
1365 make_iter(view_collection, iter, 0);
1367 iter->i = i;
1368 iter->next = iter_next;
1369 iter->peek = iter_peek;
1370 iter->n_remaining = 0;
1373 static void view_collection_get_iter(ViewIface *view,
1374 ViewIter *iter, IterFlags flags)
1376 ViewCollection *view_collection = VIEW_COLLECTION(view);
1378 make_iter(view_collection, iter, flags);
1381 static void view_collection_get_iter_at_point(ViewIface *view, ViewIter *iter,
1382 int x, int y)
1384 ViewCollection *view_collection = VIEW_COLLECTION(view);
1385 Collection *collection = view_collection->collection;
1386 int i;
1388 i = collection_get_item(collection, x, y);
1389 make_item_iter(view_collection, iter, i);
1392 static void view_collection_cursor_to_iter(ViewIface *view, ViewIter *iter)
1394 ViewCollection *view_collection = VIEW_COLLECTION(view);
1395 Collection *collection = view_collection->collection;
1397 g_return_if_fail(iter == NULL ||
1398 iter->view_collection == view_collection);
1400 collection_set_cursor_item(collection, iter ? iter->i : -1);
1403 static void view_collection_set_selected(ViewIface *view,
1404 ViewIter *iter,
1405 gboolean selected)
1407 ViewCollection *view_collection = VIEW_COLLECTION(view);
1408 Collection *collection = view_collection->collection;
1410 g_return_if_fail(iter != NULL &&
1411 iter->view_collection == view_collection);
1412 g_return_if_fail(iter->i >= 0 && iter->i < collection->number_of_items);
1414 if (selected)
1415 collection_select_item(collection, iter->i);
1416 else
1417 collection_unselect_item(collection, iter->i);
1420 static gboolean view_collection_get_selected(ViewIface *view, ViewIter *iter)
1422 ViewCollection *view_collection = VIEW_COLLECTION(view);
1423 Collection *collection = view_collection->collection;
1425 g_return_val_if_fail(iter != NULL &&
1426 iter->view_collection == view_collection, FALSE);
1427 g_return_val_if_fail(iter->i >= 0 &&
1428 iter->i < collection->number_of_items, FALSE);
1430 return collection->items[iter->i].selected;
1433 static void view_collection_select_only(ViewIface *view, ViewIter *iter)
1435 ViewCollection *view_collection = VIEW_COLLECTION(view);
1436 Collection *collection = view_collection->collection;
1438 g_return_if_fail(iter != NULL &&
1439 iter->view_collection == view_collection);
1440 g_return_if_fail(iter->i >= 0 && iter->i < collection->number_of_items);
1442 collection_clear_except(collection, iter->i);
1445 static void view_collection_set_frozen(ViewIface *view, gboolean frozen)
1447 ViewCollection *view_collection = VIEW_COLLECTION(view);
1448 Collection *collection = view_collection->collection;
1450 if (frozen)
1451 collection->block_selection_changed++;
1452 else
1453 collection_unblock_selection_changed(collection,
1454 gtk_get_current_event_time(), TRUE);
1457 static void view_collection_wink_item(ViewIface *view, ViewIter *iter)
1459 ViewCollection *view_collection = VIEW_COLLECTION(view);
1460 Collection *collection = view_collection->collection;
1462 if (!iter)
1464 collection_wink_item(collection, -1);
1465 return;
1468 g_return_if_fail(iter != NULL &&
1469 iter->view_collection == view_collection);
1470 g_return_if_fail(iter->i >= 0 && iter->i < collection->number_of_items);
1472 collection_wink_item(collection, iter->i);
1475 static void view_collection_autosize(ViewIface *view)
1477 ViewCollection *view_collection = VIEW_COLLECTION(view);
1478 FilerWindow *filer_window = view_collection->filer_window;
1479 Collection *collection = view_collection->collection;
1480 int n;
1481 int w = collection->item_width;
1482 int h = collection->item_height;
1483 int x;
1484 int rows, cols;
1485 int max_x, max_rows;
1486 const float r = 2.5;
1487 int t = 0;
1488 int space = 0;
1490 /* Get the extra height required for the toolbar and minibuffer,
1491 * if visible.
1493 if (o_toolbar.int_value != TOOLBAR_NONE)
1494 t = filer_window->toolbar->allocation.height;
1495 if (filer_window->message)
1496 t += filer_window->message->allocation.height;
1497 if (GTK_WIDGET_VISIBLE(filer_window->minibuffer_area))
1499 GtkRequisition req;
1501 gtk_widget_size_request(filer_window->minibuffer_area, &req);
1502 space = req.height + 2;
1503 t += space;
1506 n = collection->number_of_items;
1507 if (n == 0)
1508 h = ICON_HEIGHT * 1.5;
1509 n = MAX(n, 2);
1511 max_x = (o_filer_size_limit.int_value * screen_width) / 100;
1512 max_rows = (o_filer_size_limit.int_value * screen_height) / (h * 100);
1514 /* Aim for a size where
1515 * x = r(y + t + h), (1)
1516 * unless that's too wide.
1518 * t = toolbar (and minibuffer) height
1519 * r = desired (width / height) ratio
1521 * Want to display all items:
1522 * (x/w)(y/h) = n
1523 * => xy = nwh
1524 * => x(x/r - t - h) = nwh (from 1)
1525 * => xx - x.rt - hr(1 - nw) = 0
1526 * => 2x = rt +/- sqrt(rt.rt + 4hr(nw - 1))
1527 * Now,
1528 * 4hr(nw - 1) > 0
1529 * so
1530 * sqrt(rt.rt + ...) > rt
1532 * So, the +/- must be +:
1534 * => x = (rt + sqrt(rt.rt + 4hr(nw - 1))) / 2
1536 * ( + w - 1 to round up)
1538 x = (r * t + sqrt(r*r*t*t + 4*h*r * (n*w - 1))) / 2 + w - 1;
1540 /* Limit x */
1541 if (x > max_x)
1542 x = max_x;
1544 cols = x / w;
1545 cols = MAX(cols, 1);
1547 /* Choose rows to display all items given our chosen x.
1548 * Don't make the window *too* big!
1550 rows = (n + cols - 1) / cols;
1551 if (rows > max_rows)
1552 rows = max_rows;
1554 /* Leave some room for extra icons, but only in Small Icons mode
1555 * otherwise it takes up too much space.
1556 * Also, don't add space if the minibuffer is open.
1558 if (space == 0)
1559 space = filer_window->display_style == SMALL_ICONS ? h : 2;
1561 filer_window_set_size(filer_window,
1562 w * MAX(cols, 1),
1563 h * MAX(rows, 1) + space);
1566 static gboolean view_collection_cursor_visible(ViewIface *view)
1568 ViewCollection *view_collection = VIEW_COLLECTION(view);
1569 Collection *collection = view_collection->collection;
1571 return collection->cursor_item != -1;
1574 static void view_collection_set_base(ViewIface *view, ViewIter *iter)
1576 ViewCollection *view_collection = VIEW_COLLECTION(view);
1578 view_collection->cursor_base = iter->i;
1581 static void view_collection_start_lasso_box(ViewIface *view,
1582 GdkEventButton *event)
1584 ViewCollection *view_collection = (ViewCollection *) view;
1585 Collection *collection = view_collection->collection;
1587 collection_lasso_box(collection, event->x, event->y);