r4888: Don't try to thumbnail zero-byte files. They're either empty, or special and
[rox-filer/translations.git] / ROX-Filer / src / view_collection.c
blob3101d57c6ecf4112d9224689eff07d1af0f0038f
1 /*
2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* view_collection.c - a subclass of Collection, used for displaying files */
22 #include "config.h"
24 #include <gtk/gtk.h>
25 #include <time.h>
26 #include <math.h>
27 #include <string.h>
29 #include "global.h"
31 #include "collection.h"
32 #include "view_iface.h"
33 #include "view_collection.h"
34 #include "type.h"
35 #include "pixmaps.h"
36 #include "dir.h"
37 #include "diritem.h"
38 #include "gui_support.h"
39 #include "support.h"
40 #include "dnd.h"
41 #include "bind.h"
42 #include "options.h"
44 #include "toolbar.h" /* for resizing */
45 #include "filer.h"
46 #include "display.h"
48 #define MIN_ITEM_WIDTH 64
50 static gpointer parent_class = NULL;
52 struct _ViewCollectionClass {
53 GtkViewportClass parent;
56 struct _ViewCollection {
57 GtkViewport viewport;
59 Collection *collection;
60 FilerWindow *filer_window; /* Used for styles, etc */
62 int cursor_base; /* Cursor when minibuffer opened */
65 typedef struct _Template Template;
67 struct _Template {
68 GdkRectangle icon;
69 GdkRectangle leafname;
70 GdkRectangle details;
73 /* GC for drawing colour filenames */
74 static GdkGC *type_gc = NULL;
76 /* Static prototypes */
77 static void view_collection_finialize(GObject *object);
78 static void view_collection_class_init(gpointer gclass, gpointer data);
79 static void view_collection_init(GTypeInstance *object, gpointer gclass);
81 static void draw_item(GtkWidget *widget,
82 CollectionItem *item,
83 GdkRectangle *area,
84 gpointer user_data);
85 static void fill_template(GdkRectangle *area, CollectionItem *item,
86 ViewCollection *view_collection, Template *template);
87 static void huge_template(GdkRectangle *area, CollectionItem *colitem,
88 ViewCollection *view_collection, Template *template);
89 static void large_template(GdkRectangle *area, CollectionItem *colitem,
90 ViewCollection *view_collection, Template *template);
91 static void small_template(GdkRectangle *area, CollectionItem *colitem,
92 ViewCollection *view_collection, Template *template);
93 static void huge_full_template(GdkRectangle *area, CollectionItem *colitem,
94 ViewCollection *view_collection, Template *template);
95 static void large_full_template(GdkRectangle *area, CollectionItem *colitem,
96 ViewCollection *view_collection, Template *template);
97 static void small_full_template(GdkRectangle *area, CollectionItem *colitem,
98 ViewCollection *view_collection, Template *template);
99 static gboolean test_point(Collection *collection,
100 int point_x, int point_y,
101 CollectionItem *item,
102 int width, int height,
103 gpointer user_data);
104 static void draw_string(GtkWidget *widget,
105 PangoLayout *layout,
106 GdkRectangle *area, /* Area available on screen */
107 int width, /* Width of the full string */
108 GtkStateType selection_state,
109 gboolean box);
110 static void view_collection_iface_init(gpointer giface, gpointer iface_data);
111 static gint coll_motion_notify(GtkWidget *widget,
112 GdkEventMotion *event,
113 ViewCollection *view_collection);
114 static gint coll_button_release(GtkWidget *widget,
115 GdkEventButton *event,
116 ViewCollection *view_collection);
117 static gint coll_button_press(GtkWidget *widget,
118 GdkEventButton *event,
119 ViewCollection *view_collection);
120 static void size_allocate(GtkWidget *w, GtkAllocation *a, gpointer data);
121 static void style_set(Collection *collection,
122 GtkStyle *style,
123 ViewCollection *view_collection);
124 static void display_free_colitem(Collection *collection,
125 CollectionItem *colitem);
126 static void lost_selection(Collection *collection,
127 guint time,
128 gpointer user_data);
129 static void selection_changed(Collection *collection,
130 gint time,
131 gpointer user_data);
132 static void calc_size(FilerWindow *filer_window, CollectionItem *colitem,
133 int *width, int *height);
134 static void make_iter(ViewCollection *view_collection, ViewIter *iter,
135 IterFlags flags);
136 static void make_item_iter(ViewCollection *vc, ViewIter *iter, int i);
138 static void view_collection_sort(ViewIface *view);
139 static void view_collection_style_changed(ViewIface *view, int flags);
140 static void view_collection_add_items(ViewIface *view, GPtrArray *items);
141 static void view_collection_update_items(ViewIface *view, GPtrArray *items);
142 static void view_collection_delete_if(ViewIface *view,
143 gboolean (*test)(gpointer item, gpointer data),
144 gpointer data);
145 static void view_collection_clear(ViewIface *view);
146 static void view_collection_select_all(ViewIface *view);
147 static void view_collection_clear_selection(ViewIface *view);
148 static int view_collection_count_items(ViewIface *view);
149 static int view_collection_count_selected(ViewIface *view);
150 static void view_collection_show_cursor(ViewIface *view);
151 static void view_collection_get_iter(ViewIface *view,
152 ViewIter *iter, IterFlags flags);
153 static void view_collection_get_iter_at_point(ViewIface *view, ViewIter *iter,
154 GdkWindow *src, int x, int y);
155 static void view_collection_cursor_to_iter(ViewIface *view, ViewIter *iter);
156 static void view_collection_set_selected(ViewIface *view,
157 ViewIter *iter,
158 gboolean selected);
159 static gboolean view_collection_get_selected(ViewIface *view, ViewIter *iter);
160 static void view_collection_select_only(ViewIface *view, ViewIter *iter);
161 static void view_collection_set_frozen(ViewIface *view, gboolean frozen);
162 static void view_collection_wink_item(ViewIface *view, ViewIter *iter);
163 static void view_collection_autosize(ViewIface *view);
164 static gboolean view_collection_cursor_visible(ViewIface *view);
165 static void view_collection_set_base(ViewIface *view, ViewIter *iter);
166 static void view_collection_start_lasso_box(ViewIface *view,
167 GdkEventButton *event);
168 static void view_collection_extend_tip(ViewIface *view, ViewIter *iter,
169 GString *tip);
170 static gboolean view_collection_auto_scroll_callback(ViewIface *view);
172 static DirItem *iter_next(ViewIter *iter);
173 static DirItem *iter_prev(ViewIter *iter);
174 static DirItem *iter_peek(ViewIter *iter);
177 /****************************************************************
178 * EXTERNAL INTERFACE *
179 ****************************************************************/
181 GtkWidget *view_collection_new(FilerWindow *filer_window)
183 ViewCollection *view_collection;
185 view_collection = g_object_new(view_collection_get_type(), NULL);
186 view_collection->filer_window = filer_window;
188 /* Starting with GTK+-2.2.2, the vadjustment is reset after init
189 * (even though it's already set during init) to a new adjustment.
190 * Change it back:
192 gtk_viewport_set_vadjustment(GTK_VIEWPORT(view_collection),
193 view_collection->collection->vadj);
195 gtk_range_set_adjustment(GTK_RANGE(filer_window->scrollbar),
196 view_collection->collection->vadj);
198 return GTK_WIDGET(view_collection);
201 GType view_collection_get_type(void)
203 static GType type = 0;
205 if (!type)
207 static const GTypeInfo info =
209 sizeof (ViewCollectionClass),
210 NULL, /* base_init */
211 NULL, /* base_finalise */
212 view_collection_class_init,
213 NULL, /* class_finalise */
214 NULL, /* class_data */
215 sizeof(ViewCollection),
216 0, /* n_preallocs */
217 view_collection_init
219 static const GInterfaceInfo iface_info =
221 view_collection_iface_init, NULL, NULL
224 type = g_type_register_static(gtk_viewport_get_type(),
225 "ViewCollection", &info, 0);
226 g_type_add_interface_static(type, VIEW_TYPE_IFACE, &iface_info);
229 return type;
232 /****************************************************************
233 * INTERNAL FUNCTIONS *
234 ****************************************************************/
236 static void view_collection_destroy(GtkObject *view_collection)
238 VIEW_COLLECTION(view_collection)->filer_window = NULL;
241 static void view_collection_finialize(GObject *object)
243 /* ViewCollection *view_collection = (ViewCollection *) object; */
245 G_OBJECT_CLASS(parent_class)->finalize(object);
248 static void view_collection_grab_focus(GtkWidget *focus_widget)
250 ViewCollection *view_collection = VIEW_COLLECTION(focus_widget);
251 gtk_widget_grab_focus(GTK_WIDGET(view_collection->collection));
254 static void view_collection_class_init(gpointer gclass, gpointer data)
256 GObjectClass *object = (GObjectClass *) gclass;
257 GtkWidgetClass *widget = (GtkWidgetClass *) gclass;
259 parent_class = g_type_class_peek_parent(gclass);
261 widget->grab_focus = view_collection_grab_focus;
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;
329 GtkStateType selection_state;
330 GdkColor *color;
332 g_return_if_fail(view != NULL);
334 if (selected)
335 selection_state = filer_window->selection_state;
336 else
337 selection_state = GTK_STATE_NORMAL;
339 color = &widget->style->bg[selection_state];
341 fill_template(area, colitem, view_collection, &template);
343 /* Set up GC for coloured file types */
344 if (!type_gc)
345 type_gc = gdk_gc_new(widget->window);
347 gdk_gc_set_foreground(type_gc, type_get_colour(item,
348 &widget->style->fg[GTK_STATE_NORMAL]));
350 if (template.icon.width <= SMALL_WIDTH &&
351 template.icon.height <= SMALL_HEIGHT)
353 draw_small_icon(widget->window, &template.icon,
354 item, view->image, selected, color);
356 else if (template.icon.width <= ICON_WIDTH &&
357 template.icon.height <= ICON_HEIGHT)
359 draw_large_icon(widget->window, &template.icon,
360 item, view->image, selected, color);
362 else
364 draw_huge_icon(widget->window, &template.icon,
365 item, view->image, selected, color);
368 draw_string(widget, view->layout,
369 &template.leafname,
370 view->name_width,
371 selection_state,
372 TRUE);
373 if (view->details)
374 draw_string(widget, view->details,
375 &template.details,
376 template.details.width,
377 selection_state,
378 TRUE);
381 /* A template contains the locations of the three rectangles (for the icon,
382 * name and extra details).
383 * Fill in the empty 'template' with the rectanges for this item.
385 static void fill_template(GdkRectangle *area, CollectionItem *colitem,
386 ViewCollection *view_collection, Template *template)
388 DisplayStyle style = view_collection->filer_window->display_style;
389 ViewData *view = (ViewData *) colitem->view_data;
391 if (view->details)
393 template->details.width = view->details_width;
394 template->details.height = view->details_height;
396 if (style == SMALL_ICONS)
397 small_full_template(area, colitem,
398 view_collection, template);
399 else if (style == LARGE_ICONS)
400 large_full_template(area, colitem,
401 view_collection, template);
402 else
403 huge_full_template(area, colitem,
404 view_collection, template);
406 else
408 if (style == HUGE_ICONS)
409 huge_template(area, colitem,
410 view_collection, template);
411 else if (style == LARGE_ICONS)
412 large_template(area, colitem,
413 view_collection, template);
414 else
415 small_template(area, colitem,
416 view_collection, template);
420 static void huge_template(GdkRectangle *area, CollectionItem *colitem,
421 ViewCollection *view_collection, Template *template)
423 int col_width = view_collection->collection->item_width;
424 int text_x, text_y;
425 ViewData *view = (ViewData *) colitem->view_data;
426 MaskedPixmap *image = view->image;
428 if (image)
430 if (!image->huge_pixbuf)
431 pixmap_make_huge(image);
432 template->icon.width = image->huge_width;
433 template->icon.height = image->huge_height;
435 else
437 template->icon.width = HUGE_WIDTH * 3 / 2;
438 template->icon.height = HUGE_HEIGHT;
441 template->leafname.width = view->name_width;
442 template->leafname.height = view->name_height;
444 text_x = area->x + ((col_width - template->leafname.width) >> 1);
445 text_y = area->y + area->height - template->leafname.height;
447 template->leafname.x = text_x;
448 template->leafname.y = text_y;
450 template->icon.x = area->x + ((col_width - template->icon.width) >> 1);
451 template->icon.y = template->leafname.y - template->icon.height - 2;
454 static void large_template(GdkRectangle *area, CollectionItem *colitem,
455 ViewCollection *view_collection, Template *template)
457 int col_width = view_collection->collection->item_width;
458 int iwidth, iheight;
459 int image_x;
460 int image_y;
461 ViewData *view = (ViewData *) colitem->view_data;
462 MaskedPixmap *image = view->image;
464 int text_x, text_y;
466 if (image)
468 iwidth = MIN(image->width, ICON_WIDTH);
469 iheight = MIN(image->height + 6, ICON_HEIGHT);
471 else
473 iwidth = ICON_WIDTH;
474 iheight = ICON_HEIGHT;
476 image_x = area->x + ((col_width - iwidth) >> 1);
478 template->leafname.width = view->name_width;
479 template->leafname.height = view->name_height;
481 text_x = area->x + ((col_width - template->leafname.width) >> 1);
482 text_y = area->y + ICON_HEIGHT + 2;
484 template->leafname.x = text_x;
485 template->leafname.y = text_y;
487 image_y = text_y - iheight;
488 image_y = MAX(area->y, image_y);
490 template->icon.x = image_x;
491 template->icon.y = image_y;
492 template->icon.width = iwidth;
493 template->icon.height = MIN(ICON_HEIGHT, iheight);
496 static void small_template(GdkRectangle *area, CollectionItem *colitem,
497 ViewCollection *view_collection, Template *template)
499 int text_x = area->x + SMALL_WIDTH + 4;
500 int low_text_y;
501 int max_text_width = area->width - SMALL_WIDTH - 4;
502 ViewData *view = (ViewData *) colitem->view_data;
504 low_text_y = area->y + area->height / 2 - view->name_height / 2;
506 template->leafname.x = text_x;
507 template->leafname.y = low_text_y;
508 template->leafname.width = MIN(max_text_width, view->name_width);
509 template->leafname.height = view->name_height;
511 template->icon.x = area->x;
512 template->icon.y = area->y + 1;
513 template->icon.width = SMALL_WIDTH;
514 template->icon.height = SMALL_HEIGHT;
517 static void huge_full_template(GdkRectangle *area, CollectionItem *colitem,
518 ViewCollection *view_collection, Template *template)
520 int max_text_width = area->width - HUGE_WIDTH - 4;
521 ViewData *view = (ViewData *) colitem->view_data;
522 MaskedPixmap *image = view->image;
524 if (image)
526 if (!image->huge_pixbuf)
527 pixmap_make_huge(image);
528 template->icon.width = image->huge_width;
529 template->icon.height = image->huge_height;
531 else
533 template->icon.width = HUGE_WIDTH * 3 / 2;
534 template->icon.height = HUGE_HEIGHT;
537 template->icon.x = area->x + (HUGE_WIDTH - template->icon.width) / 2;
538 template->icon.y = area->y + (area->height - template->icon.height) / 2;
540 template->leafname.x = area->x + HUGE_WIDTH + 4;
541 template->leafname.y = area->y + area->height / 2
542 - (view->name_height + 2 + view->details_height) / 2;
543 template->leafname.width = MIN(max_text_width, view->name_width);
544 template->leafname.height = view->name_height;
546 if (!image)
547 return; /* Not scanned yet */
549 template->details.x = template->leafname.x;
550 template->details.y = template->leafname.y + view->name_height + 2;
553 static void large_full_template(GdkRectangle *area, CollectionItem *colitem,
554 ViewCollection *view_collection, Template *template)
556 int max_text_width = area->width - ICON_WIDTH - 4;
557 ViewData *view = (ViewData *) colitem->view_data;
558 MaskedPixmap *image = view->image;
560 if (image)
562 template->icon.width = image->width;
563 template->icon.height = image->height;
565 else
567 template->icon.width = ICON_WIDTH;
568 template->icon.height = ICON_HEIGHT;
571 template->icon.x = area->x + (ICON_WIDTH - template->icon.width) / 2;
572 template->icon.y = area->y + (area->height - template->icon.height) / 2;
575 template->leafname.x = area->x + ICON_WIDTH + 4;
576 template->leafname.y = area->y + area->height / 2
577 - (view->name_height + 2 + view->details_height) / 2;
578 template->leafname.width = MIN(max_text_width, view->name_width);
579 template->leafname.height = view->name_height;
581 if (!image)
582 return; /* Not scanned yet */
584 template->details.x = template->leafname.x;
585 template->details.y = template->leafname.y + view->name_height + 2;
588 static void small_full_template(GdkRectangle *area, CollectionItem *colitem,
589 ViewCollection *view_collection, Template *template)
591 int col_width = view_collection->collection->item_width;
592 ViewData *view = (ViewData *) colitem->view_data;
594 small_template(area, colitem, view_collection, template);
596 if (!view->image)
597 return; /* Not scanned yet */
599 template->details.x = area->x + col_width - template->details.width;
600 template->details.y = area->y + area->height / 2 - \
601 view->details_height / 2;
604 #define INSIDE(px, py, area) \
605 (px >= area.x && py >= area.y && \
606 px <= area.x + area.width && py <= area.y + area.height)
608 static gboolean test_point(Collection *collection,
609 int point_x, int point_y,
610 CollectionItem *colitem,
611 int width, int height,
612 gpointer user_data)
614 Template template;
615 GdkRectangle area;
616 ViewData *view = (ViewData *) colitem->view_data;
617 ViewCollection *view_collection = (ViewCollection *) user_data;
619 area.x = 0;
620 area.y = 0;
621 area.width = width;
622 area.height = height;
624 fill_template(&area, colitem, view_collection, &template);
626 return INSIDE(point_x, point_y, template.leafname) ||
627 INSIDE(point_x, point_y, template.icon) ||
628 (view->details && INSIDE(point_x, point_y, template.details));
631 /* 'box' renders a background box if the string is also selected */
632 static void draw_string(GtkWidget *widget,
633 PangoLayout *layout,
634 GdkRectangle *area, /* Area available on screen */
635 int width, /* Width of the full string */
636 GtkStateType selection_state,
637 gboolean box)
639 GdkGC *gc = selection_state == GTK_STATE_NORMAL
640 ? type_gc
641 : widget->style->fg_gc[selection_state];
643 if (selection_state != GTK_STATE_NORMAL && box)
644 gtk_paint_flat_box(widget->style, widget->window,
645 selection_state, GTK_SHADOW_NONE,
646 NULL, widget, "text",
647 area->x, area->y,
648 MIN(width, area->width),
649 area->height);
651 if (width > area->width)
653 gdk_gc_set_clip_origin(gc, 0, 0);
654 gdk_gc_set_clip_rectangle(gc, area);
657 gdk_draw_layout(widget->window, gc, area->x, area->y, layout);
659 if (width > area->width)
661 static GdkGC *red_gc = NULL;
663 if (!red_gc)
665 gboolean success;
666 GdkColor red = {0, 0xffff, 0, 0};
668 red_gc = gdk_gc_new(widget->window);
669 gdk_colormap_alloc_colors(
670 gtk_widget_get_colormap(widget),
671 &red, 1, FALSE, TRUE, &success);
672 gdk_gc_set_foreground(red_gc, &red);
674 gdk_draw_rectangle(widget->window, red_gc, TRUE,
675 area->x + area->width - 1, area->y,
676 1, area->height);
677 gdk_gc_set_clip_rectangle(gc, NULL);
681 /* Create the handers for the View interface */
682 static void view_collection_iface_init(gpointer giface, gpointer iface_data)
684 ViewIfaceClass *iface = giface;
686 g_assert(G_TYPE_FROM_INTERFACE(iface) == VIEW_TYPE_IFACE);
688 /* override stuff */
689 iface->sort = view_collection_sort;
690 iface->style_changed = view_collection_style_changed;
691 iface->add_items = view_collection_add_items;
692 iface->update_items = view_collection_update_items;
693 iface->delete_if = view_collection_delete_if;
694 iface->clear = view_collection_clear;
695 iface->select_all = view_collection_select_all;
696 iface->clear_selection = view_collection_clear_selection;
697 iface->count_items = view_collection_count_items;
698 iface->count_selected = view_collection_count_selected;
699 iface->show_cursor = view_collection_show_cursor;
700 iface->get_iter = view_collection_get_iter;
701 iface->get_iter_at_point = view_collection_get_iter_at_point;
702 iface->cursor_to_iter = view_collection_cursor_to_iter;
703 iface->set_selected = view_collection_set_selected;
704 iface->get_selected = view_collection_get_selected;
705 iface->set_frozen = view_collection_set_frozen;
706 iface->select_only = view_collection_select_only;
707 iface->wink_item = view_collection_wink_item;
708 iface->autosize = view_collection_autosize;
709 iface->cursor_visible = view_collection_cursor_visible;
710 iface->set_base = view_collection_set_base;
711 iface->start_lasso_box = view_collection_start_lasso_box;
712 iface->extend_tip = view_collection_extend_tip;
713 iface->auto_scroll_callback = view_collection_auto_scroll_callback;
716 static void view_collection_extend_tip(ViewIface *view, ViewIter *iter,
717 GString *tip)
719 ViewCollection*view_collection = (ViewCollection *) view;
720 Collection *collection = view_collection->collection;
721 FilerWindow *filer_window = view_collection->filer_window;
722 Template template;
723 int i = iter->i;
724 CollectionItem *colitem = &collection->items[i];
725 ViewData *view_data = (ViewData *) colitem->view_data;
726 GdkRectangle area;
727 int row,col;
729 collection_item_to_rowcol(collection, i, &row, &col);
731 g_return_if_fail(iter->view == (ViewIface *) view_collection);
732 g_return_if_fail(i >= 0 && i < collection->number_of_items);
734 /* TODO: What if the window is narrower than 1 column? */
735 if (filer_window->display_style == LARGE_ICONS ||
736 filer_window->display_style == HUGE_ICONS)
737 return; /* These wrap rather than truncate */
739 area.x = col * collection->item_width;
740 area.y = row * collection->item_height;
741 area.height = collection->item_height;
743 if (col == collection->columns - 1)
744 area.width = GTK_WIDGET(collection)->allocation.width - area.x;
745 else
746 area.width = collection->item_width;
748 fill_template(&area, colitem, view_collection, &template);
750 if (template.leafname.width < view_data->name_width)
752 DirItem *item = (DirItem *) collection->items[i].data;
754 g_string_append(tip, item->leafname);
755 g_string_append_c(tip, '\n');
759 static gint coll_motion_notify(GtkWidget *widget,
760 GdkEventMotion *event,
761 ViewCollection *view_collection)
763 return filer_motion_notify(view_collection->filer_window, event);
766 /* Viewport is to be resized, so calculate increments */
767 static void size_allocate(GtkWidget *w, GtkAllocation *a, gpointer data)
769 Collection *col = ((ViewCollection *) data)->collection;
771 col->vadj->step_increment = col->item_height;
772 col->vadj->page_increment = col->vadj->page_size;
775 static gint coll_button_release(GtkWidget *widget,
776 GdkEventButton *event,
777 ViewCollection *view_collection)
779 if (dnd_motion_release(event))
781 if (motion_buttons_pressed == 0 &&
782 view_collection->collection->lasso_box)
784 filer_set_autoscroll(view_collection->filer_window,
785 FALSE);
786 collection_end_lasso(view_collection->collection,
787 event->button == 1 ? GDK_SET : GDK_INVERT);
789 return FALSE;
792 filer_perform_action(view_collection->filer_window, event);
794 return FALSE;
797 static gint coll_button_press(GtkWidget *widget,
798 GdkEventButton *event,
799 ViewCollection *view_collection)
801 collection_set_cursor_item(view_collection->collection, -1, TRUE);
803 if (dnd_motion_press(widget, event))
804 filer_perform_action(view_collection->filer_window, event);
806 return FALSE;
809 /* Nothing is selected anymore - give up primary */
810 static void lost_selection(Collection *collection,
811 guint time,
812 gpointer user_data)
814 ViewCollection *view_collection = VIEW_COLLECTION(user_data);
816 filer_lost_selection(view_collection->filer_window, time);
819 static void selection_changed(Collection *collection,
820 gint time,
821 gpointer user_data)
823 ViewCollection *view_collection = VIEW_COLLECTION(user_data);
825 filer_selection_changed(view_collection->filer_window, time);
828 static void display_free_colitem(Collection *collection,
829 CollectionItem *colitem)
831 ViewData *view = (ViewData *) colitem->view_data;
833 if (!view)
834 return;
836 if (view->layout)
838 g_object_unref(G_OBJECT(view->layout));
839 view->layout = NULL;
841 if (view->details)
842 g_object_unref(G_OBJECT(view->details));
844 if (view->image)
845 g_object_unref(view->image);
847 g_free(view);
850 static void add_item(ViewCollection *view_collection, DirItem *item)
852 Collection *collection = view_collection->collection;
853 FilerWindow *filer_window = view_collection->filer_window;
854 int old_w = collection->item_width;
855 int old_h = collection->item_height;
856 int w, h, i;
858 i = collection_insert(collection, item,
859 display_create_viewdata(filer_window, item));
861 calc_size(filer_window, &collection->items[i], &w, &h);
863 if (w > old_w || h > old_h)
864 collection_set_item_size(collection,
865 MAX(old_w, w),
866 MAX(old_h, h));
869 static void style_set(Collection *collection,
870 GtkStyle *style,
871 ViewCollection *view_collection)
873 view_collection_style_changed(VIEW(view_collection),
874 VIEW_UPDATE_VIEWDATA | VIEW_UPDATE_NAME);
877 /* Return the size needed for this item */
878 static void calc_size(FilerWindow *filer_window, CollectionItem *colitem,
879 int *width, int *height)
881 int pix_width, pix_height;
882 int w;
883 DisplayStyle style = filer_window->display_style;
884 ViewData *view = (ViewData *) colitem->view_data;
886 if (filer_window->details_type == DETAILS_NONE)
888 if (style == HUGE_ICONS)
890 if (view->image)
892 if (!view->image->huge_pixbuf)
893 pixmap_make_huge(view->image);
894 pix_width = view->image->huge_width;
895 pix_height = view->image->huge_height;
897 else
899 pix_width = HUGE_WIDTH * 3 / 2;
900 pix_height = HUGE_HEIGHT * 3 / 2;
902 *width = MAX(pix_width, view->name_width) + 4;
903 *height = MAX(view->name_height + pix_height + 4,
904 HUGE_HEIGHT * 3 / 4);
906 else if (style == SMALL_ICONS)
908 w = MIN(view->name_width, o_small_width.int_value);
909 *width = SMALL_WIDTH + 12 + w;
910 *height = MAX(view->name_height, SMALL_HEIGHT) + 4;
912 else
914 if (view->image)
915 pix_width = view->image->width;
916 else
917 pix_width = ICON_WIDTH;
918 *width = MAX(pix_width, view->name_width) + 4;
919 *height = view->name_height + ICON_HEIGHT + 2;
922 else
924 w = view->details_width;
925 if (style == HUGE_ICONS)
927 *width = HUGE_WIDTH + 12 + MAX(w, view->name_width);
928 *height = HUGE_HEIGHT - 4;
930 else if (style == SMALL_ICONS)
932 int text_height;
934 *width = SMALL_WIDTH + view->name_width + 12 + w;
935 text_height = MAX(view->name_height,
936 view->details_height);
937 *height = MAX(text_height, SMALL_HEIGHT) + 4;
939 else
941 *width = ICON_WIDTH + 12 + MAX(w, view->name_width);
942 *height = ICON_HEIGHT;
947 static void update_item(ViewCollection *view_collection, int i)
949 Collection *collection = view_collection->collection;
950 int old_w = collection->item_width;
951 int old_h = collection->item_height;
952 int w, h;
953 CollectionItem *colitem;
954 FilerWindow *filer_window = view_collection->filer_window;
956 g_return_if_fail(i >= 0 && i < collection->number_of_items);
958 colitem = &collection->items[i];
960 display_update_view(filer_window,
961 (DirItem *) colitem->data,
962 (ViewData *) colitem->view_data,
963 FALSE);
965 calc_size(filer_window, colitem, &w, &h);
966 if (w > old_w || h > old_h)
967 collection_set_item_size(collection,
968 MAX(old_w, w),
969 MAX(old_h, h));
971 collection_draw_item(collection, i, TRUE);
974 /* Implementations of the View interface. See view_iface.c for comments. */
976 static void view_collection_style_changed(ViewIface *view, int flags)
978 ViewCollection *view_collection = VIEW_COLLECTION(view);
979 FilerWindow *filer_window = view_collection->filer_window;
980 int i;
981 Collection *col = view_collection->collection;
982 int width = MIN_ITEM_WIDTH;
983 int height = SMALL_HEIGHT;
984 int n = col->number_of_items;
986 if (n == 0 && filer_window->display_style != SMALL_ICONS)
987 height = ICON_HEIGHT;
989 view_collection->collection->vertical_order = FALSE;
990 if (filer_window->display_style == SMALL_ICONS &&
991 o_vertical_order_small.int_value)
992 view_collection->collection->vertical_order = TRUE;
993 if (filer_window->display_style != SMALL_ICONS &&
994 o_vertical_order_large.int_value)
995 view_collection->collection->vertical_order = TRUE;
1000 /* Recalculate all the ViewData structs for this window
1001 * (needed if the text or image has changed in any way) and
1002 * get the size of each item.
1004 for (i = 0; i < n; i++)
1006 CollectionItem *ci = &col->items[i];
1007 int w, h;
1009 if (flags & (VIEW_UPDATE_VIEWDATA | VIEW_UPDATE_NAME))
1010 display_update_view(filer_window,
1011 (DirItem *) ci->data,
1012 (ViewData *) ci->view_data,
1013 (flags & VIEW_UPDATE_NAME) != 0);
1015 calc_size(filer_window, ci, &w, &h);
1016 if (w > width)
1017 width = w;
1018 if (h > height)
1019 height = h;
1022 collection_set_item_size(col, width, height);
1024 gtk_widget_queue_draw(GTK_WIDGET(view_collection));
1027 typedef int (*SortFn)(gconstpointer a, gconstpointer b);
1029 static SortFn sort_fn(FilerWindow *fw)
1031 switch (fw->sort_type)
1033 case SORT_NAME: return sort_by_name;
1034 case SORT_TYPE: return sort_by_type;
1035 case SORT_DATE: return sort_by_date;
1036 case SORT_SIZE: return sort_by_size;
1037 case SORT_OWNER: return sort_by_owner;
1038 case SORT_GROUP: return sort_by_group;
1039 default:
1040 g_assert_not_reached();
1043 return NULL;
1046 static void view_collection_sort(ViewIface *view)
1048 ViewCollection *view_collection = VIEW_COLLECTION(view);
1049 FilerWindow *filer_window = view_collection->filer_window;
1051 collection_qsort(view_collection->collection, sort_fn(filer_window),
1052 filer_window->sort_order);
1055 static void view_collection_add_items(ViewIface *view, GPtrArray *items)
1057 ViewCollection *view_collection = VIEW_COLLECTION(view);
1058 Collection *collection = view_collection->collection;
1059 FilerWindow *filer_window = view_collection->filer_window;
1060 int old_num, i;
1062 old_num = collection->number_of_items;
1063 for (i = 0; i < items->len; i++)
1065 DirItem *item = (DirItem *) items->pdata[i];
1067 if (!filer_match_filter(filer_window, item))
1068 continue;
1070 add_item(view_collection, item);
1073 if (old_num != collection->number_of_items)
1074 view_collection_sort(view);
1077 static void view_collection_update_items(ViewIface *view, GPtrArray *items)
1079 ViewCollection *view_collection = VIEW_COLLECTION(view);
1080 Collection *collection = view_collection->collection;
1081 FilerWindow *filer_window = view_collection->filer_window;
1082 int i;
1084 g_return_if_fail(items->len > 0);
1086 /* The item data has already been modified, so this gives the
1087 * final sort order...
1089 collection_qsort(collection, sort_fn(filer_window),
1090 filer_window->sort_order);
1092 for (i = 0; i < items->len; i++)
1094 DirItem *item = (DirItem *) items->pdata[i];
1095 const gchar *leafname = item->leafname;
1096 int j;
1098 if (!filer_match_filter(filer_window, item))
1099 continue;
1101 j = collection_find_item(collection, item,
1102 sort_fn(filer_window),
1103 filer_window->sort_order);
1105 if (j < 0)
1106 g_warning("Failed to find '%s'\n", leafname);
1107 else
1108 update_item(view_collection, j);
1112 static void view_collection_delete_if(ViewIface *view,
1113 gboolean (*test)(gpointer item, gpointer data),
1114 gpointer data)
1116 ViewCollection *view_collection = VIEW_COLLECTION(view);
1117 Collection *collection = view_collection->collection;
1119 collection_delete_if(collection, test, data);
1122 static void view_collection_clear(ViewIface *view)
1124 ViewCollection *view_collection = VIEW_COLLECTION(view);
1125 Collection *collection = view_collection->collection;
1127 collection_clear(collection);
1130 static void view_collection_select_all(ViewIface *view)
1132 ViewCollection *view_collection = VIEW_COLLECTION(view);
1133 Collection *collection = view_collection->collection;
1135 collection_select_all(collection);
1138 static void view_collection_clear_selection(ViewIface *view)
1140 ViewCollection *view_collection = VIEW_COLLECTION(view);
1141 Collection *collection = view_collection->collection;
1143 collection_clear_selection(collection);
1146 static int view_collection_count_items(ViewIface *view)
1148 ViewCollection *view_collection = VIEW_COLLECTION(view);
1149 Collection *collection = view_collection->collection;
1151 return collection->number_of_items;
1154 static int view_collection_count_selected(ViewIface *view)
1156 ViewCollection *view_collection = VIEW_COLLECTION(view);
1157 Collection *collection = view_collection->collection;
1159 return collection->number_selected;
1162 static void view_collection_show_cursor(ViewIface *view)
1164 ViewCollection *view_collection = VIEW_COLLECTION(view);
1165 Collection *collection = view_collection->collection;
1167 collection_move_cursor(collection, 0, 0);
1170 /* The first time the next() method is used, this is called */
1171 static DirItem *iter_init(ViewIter *iter)
1173 ViewCollection *view_collection = (ViewCollection *) iter->view;
1174 Collection *collection = view_collection->collection;
1175 int i = -1;
1176 int n = collection->number_of_items;
1177 int flags = iter->flags;
1179 iter->peek = iter_peek;
1181 if (iter->n_remaining == 0)
1182 return NULL;
1184 if (flags & VIEW_ITER_FROM_CURSOR)
1186 i = collection->cursor_item;
1187 if (i == -1)
1188 return NULL; /* No cursor */
1190 else if (flags & VIEW_ITER_FROM_BASE)
1191 i = view_collection->cursor_base;
1193 if (i < 0 || i >= n)
1195 /* Either a normal iteration, or an iteration from an
1196 * invalid starting point.
1198 if (flags & VIEW_ITER_BACKWARDS)
1199 i = n - 1;
1200 else
1201 i = 0;
1204 if (i < 0 || i >= n)
1205 return NULL; /* No items at all! */
1207 iter->next = flags & VIEW_ITER_BACKWARDS ? iter_prev : iter_next;
1208 iter->n_remaining--;
1209 iter->i = i;
1211 if (flags & VIEW_ITER_SELECTED && !collection->items[i].selected)
1212 return iter->next(iter);
1213 return iter->peek(iter);
1215 /* Advance iter to point to the next item and return the new item
1216 * (this saves you calling peek after next each time).
1218 static DirItem *iter_next(ViewIter *iter)
1220 Collection *collection = ((ViewCollection *) iter->view)->collection;
1221 int n = collection->number_of_items;
1222 int i = iter->i;
1224 g_return_val_if_fail(iter->n_remaining >= 0, NULL);
1226 /* i is the last item returned (always valid) */
1228 g_return_val_if_fail(i >= 0 && i < n, NULL);
1230 while (iter->n_remaining)
1232 i++;
1233 iter->n_remaining--;
1235 if (i == n)
1236 i = 0;
1238 g_return_val_if_fail(i >= 0 && i < n, NULL);
1240 if (iter->flags & VIEW_ITER_SELECTED &&
1241 !collection->items[i].selected)
1242 continue;
1244 iter->i = i;
1245 return collection->items[i].data;
1248 iter->i = -1;
1249 return NULL;
1252 /* Like iter_next, but in the other direction */
1253 static DirItem *iter_prev(ViewIter *iter)
1255 Collection *collection = ((ViewCollection *) iter->view)->collection;
1256 int n = collection->number_of_items;
1257 int i = iter->i;
1259 g_return_val_if_fail(iter->n_remaining >= 0, NULL);
1261 /* i is the last item returned (always valid) */
1263 g_return_val_if_fail(i >= 0 && i < n, NULL);
1265 while (iter->n_remaining)
1267 i--;
1268 iter->n_remaining--;
1270 if (i == -1)
1271 i = collection->number_of_items - 1;
1273 g_return_val_if_fail(i >= 0 && i < n, NULL);
1275 if (iter->flags & VIEW_ITER_SELECTED &&
1276 !collection->items[i].selected)
1277 continue;
1279 iter->i = i;
1280 return collection->items[i].data;
1283 iter->i = -1;
1284 return NULL;
1287 static DirItem *iter_peek(ViewIter *iter)
1289 Collection *collection = ((ViewCollection *) iter->view)->collection;
1290 int i = iter->i;
1292 if (i == -1)
1293 return NULL;
1295 g_return_val_if_fail(i >= 0 && i < collection->number_of_items, NULL);
1297 return collection->items[i].data;
1300 static void make_iter(ViewCollection *view_collection, ViewIter *iter,
1301 IterFlags flags)
1303 Collection *collection = view_collection->collection;
1305 iter->view = (ViewIface *) view_collection;
1306 iter->next = iter_init;
1307 iter->peek = NULL;
1308 iter->i = -1;
1310 iter->flags = flags;
1312 if (flags & VIEW_ITER_ONE_ONLY)
1314 iter->n_remaining = 1;
1315 iter->next(iter);
1317 else
1318 iter->n_remaining = collection->number_of_items;
1321 /* Set the iterator to return 'i' on the next peek() */
1322 static void make_item_iter(ViewCollection *view_collection,
1323 ViewIter *iter, int i)
1325 Collection *collection = view_collection->collection;
1327 g_return_if_fail(i >= -1 && i < collection->number_of_items);
1329 make_iter(view_collection, iter, 0);
1331 iter->i = i;
1332 iter->next = iter_next;
1333 iter->peek = iter_peek;
1334 iter->n_remaining = 0;
1337 static void view_collection_get_iter(ViewIface *view,
1338 ViewIter *iter, IterFlags flags)
1340 ViewCollection *view_collection = VIEW_COLLECTION(view);
1342 make_iter(view_collection, iter, flags);
1345 static void view_collection_get_iter_at_point(ViewIface *view, ViewIter *iter,
1346 GdkWindow *src, int x, int y)
1348 ViewCollection *view_collection = VIEW_COLLECTION(view);
1349 Collection *collection = view_collection->collection;
1350 int i;
1352 if (src == ((GtkWidget *) view)->window)
1354 /* The event is on the Viewport, not the collection... */
1355 y += collection->vadj->value;
1358 i = collection_get_item(collection, x, y);
1359 make_item_iter(view_collection, iter, i);
1362 static void view_collection_cursor_to_iter(ViewIface *view, ViewIter *iter)
1364 ViewCollection *view_collection = VIEW_COLLECTION(view);
1365 Collection *collection = view_collection->collection;
1366 FilerWindow *filer_window = view_collection->filer_window;
1368 g_return_if_fail(iter == NULL ||
1369 iter->view == (ViewIface *) view_collection);
1371 collection_set_cursor_item(collection, iter ? iter->i : -1,
1372 filer_window->auto_scroll == -1);
1375 static void view_collection_set_selected(ViewIface *view,
1376 ViewIter *iter,
1377 gboolean selected)
1379 ViewCollection *view_collection = VIEW_COLLECTION(view);
1380 Collection *collection = view_collection->collection;
1382 g_return_if_fail(iter != NULL &&
1383 iter->view == (ViewIface *) view_collection);
1384 g_return_if_fail(iter->i >= 0 && iter->i < collection->number_of_items);
1386 if (selected)
1387 collection_select_item(collection, iter->i);
1388 else
1389 collection_unselect_item(collection, iter->i);
1392 static gboolean view_collection_get_selected(ViewIface *view, ViewIter *iter)
1394 ViewCollection *view_collection = VIEW_COLLECTION(view);
1395 Collection *collection = view_collection->collection;
1397 g_return_val_if_fail(iter != NULL &&
1398 iter->view == (ViewIface *) view_collection, FALSE);
1399 g_return_val_if_fail(iter->i >= 0 &&
1400 iter->i < collection->number_of_items, FALSE);
1402 return collection->items[iter->i].selected;
1405 static void view_collection_select_only(ViewIface *view, ViewIter *iter)
1407 ViewCollection *view_collection = VIEW_COLLECTION(view);
1408 Collection *collection = view_collection->collection;
1410 g_return_if_fail(iter != NULL &&
1411 iter->view == (ViewIface *) view_collection);
1412 g_return_if_fail(iter->i >= 0 && iter->i < collection->number_of_items);
1414 collection_clear_except(collection, iter->i);
1417 static void view_collection_set_frozen(ViewIface *view, gboolean frozen)
1419 ViewCollection *view_collection = VIEW_COLLECTION(view);
1420 Collection *collection = view_collection->collection;
1422 if (frozen)
1423 collection->block_selection_changed++;
1424 else
1425 collection_unblock_selection_changed(collection,
1426 gtk_get_current_event_time(), TRUE);
1429 static void view_collection_wink_item(ViewIface *view, ViewIter *iter)
1431 ViewCollection *view_collection = VIEW_COLLECTION(view);
1432 Collection *collection = view_collection->collection;
1434 if (!iter)
1436 collection_wink_item(collection, -1);
1437 return;
1440 g_return_if_fail(iter != NULL &&
1441 iter->view == (ViewIface *) view_collection);
1442 g_return_if_fail(iter->i >= 0 && iter->i < collection->number_of_items);
1444 collection_wink_item(collection, iter->i);
1447 static void view_collection_autosize(ViewIface *view)
1449 ViewCollection *view_collection = VIEW_COLLECTION(view);
1450 FilerWindow *filer_window = view_collection->filer_window;
1451 Collection *collection = view_collection->collection;
1452 int n;
1453 int w = collection->item_width;
1454 int h = collection->item_height;
1455 int x;
1456 int rows, cols;
1457 int max_x, max_rows;
1458 const float r = 2.5;
1459 int t = 0;
1460 int space = 0;
1462 /* Get the extra height required for the toolbar and minibuffer,
1463 * if visible.
1465 if (o_toolbar.int_value != TOOLBAR_NONE)
1466 t = filer_window->toolbar->allocation.height;
1467 if (filer_window->message)
1468 t += filer_window->message->allocation.height;
1469 if (GTK_WIDGET_VISIBLE(filer_window->minibuffer_area))
1471 GtkRequisition req;
1473 gtk_widget_size_request(filer_window->minibuffer_area, &req);
1474 space = req.height + 2;
1475 t += space;
1478 n = collection->number_of_items;
1479 if (n == 0)
1480 h = ICON_HEIGHT * 1.5;
1481 n = MAX(n, 2);
1483 max_x = (o_filer_size_limit.int_value * monitor_width) / 100;
1484 max_rows = (o_filer_size_limit.int_value * monitor_height) / (h * 100);
1486 /* Aim for a size where
1487 * x = r(y + t + h), (1)
1488 * unless that's too wide.
1490 * t = toolbar (and minibuffer) height
1491 * r = desired (width / height) ratio
1493 * Want to display all items:
1494 * (x/w)(y/h) = n
1495 * => xy = nwh
1496 * => x(x/r - t - h) = nwh (from 1)
1497 * => xx - x.rt - hr(1 - nw) = 0
1498 * => 2x = rt +/- sqrt(rt.rt + 4hr(nw - 1))
1499 * Now,
1500 * 4hr(nw - 1) > 0
1501 * so
1502 * sqrt(rt.rt + ...) > rt
1504 * So, the +/- must be +:
1506 * => x = (rt + sqrt(rt.rt + 4hr(nw - 1))) / 2
1508 * ( + w - 1 to round up)
1510 x = (r * t + sqrt(r*r*t*t + 4*h*r * (n*w - 1))) / 2 + w - 1;
1512 /* Limit x */
1513 if (x > max_x)
1514 x = max_x;
1516 cols = x / w;
1517 cols = MAX(cols, 1);
1519 /* Choose rows to display all items given our chosen x.
1520 * Don't make the window *too* big!
1522 rows = (n + cols - 1) / cols;
1523 if (rows > max_rows)
1524 rows = max_rows;
1526 /* Leave some room for extra icons, but only in Small Icons mode
1527 * otherwise it takes up too much space.
1528 * Also, don't add space if the minibuffer is open.
1530 if (space == 0)
1531 space = filer_window->display_style == SMALL_ICONS ? h : 2;
1533 filer_window_set_size(filer_window,
1534 w * MAX(cols, 1),
1535 h * MAX(rows, 1) + space);
1538 static gboolean view_collection_cursor_visible(ViewIface *view)
1540 ViewCollection *view_collection = VIEW_COLLECTION(view);
1541 Collection *collection = view_collection->collection;
1543 return collection->cursor_item != -1;
1546 static void view_collection_set_base(ViewIface *view, ViewIter *iter)
1548 ViewCollection *view_collection = VIEW_COLLECTION(view);
1550 view_collection->cursor_base = iter->i;
1553 static void view_collection_start_lasso_box(ViewIface *view,
1554 GdkEventButton *event)
1556 ViewCollection *view_collection = (ViewCollection *) view;
1557 Collection *collection = view_collection->collection;
1559 filer_set_autoscroll(view_collection->filer_window, TRUE);
1560 collection_lasso_box(collection, event->x, event->y);
1564 /* Change the adjustment by this amount. Bounded. */
1565 static void diff_vpos(Collection *collection, int diff)
1567 int old = collection->vadj->value;
1568 int value = old + diff;
1570 value = CLAMP(value, 0,
1571 collection->vadj->upper - collection->vadj->page_size);
1572 gtk_adjustment_set_value(collection->vadj, value);
1574 if (collection->vadj->value != old)
1575 dnd_spring_abort();
1578 static gboolean view_collection_auto_scroll_callback(ViewIface *view)
1580 ViewCollection *view_collection = (ViewCollection *) view;
1581 Collection *collection = view_collection->collection;
1582 GdkWindow *window = ((GtkWidget *) collection)->window;
1583 gint x, y, w, h;
1584 GdkModifierType mask;
1585 int diff = 0;
1587 gdk_window_get_pointer(window, &x, &y, &mask);
1588 gdk_drawable_get_size(window, &w, NULL);
1590 h = collection->vadj->page_size;
1591 y -= collection->vadj->value;
1593 if ((x < 0 || x > w || y < 0 || y > h) && !collection->lasso_box)
1594 return FALSE; /* Out of window - stop */
1596 if (y < AUTOSCROLL_STEP)
1597 diff = y - AUTOSCROLL_STEP;
1598 else if (y > h - AUTOSCROLL_STEP)
1599 diff = AUTOSCROLL_STEP + y - h;
1601 if (diff)
1602 diff_vpos(collection, diff);
1604 return TRUE;