4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2003, 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)
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
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 */
33 #include "collection.h"
34 #include "view_iface.h"
35 #include "view_collection.h"
40 #include "gui_support.h"
46 #include "toolbar.h" /* for resizing */
50 #define MIN_ITEM_WIDTH 64
52 static gpointer parent_class
= NULL
;
54 struct _ViewCollectionClass
{
55 GtkViewportClass parent
;
58 struct _ViewCollection
{
61 Collection
*collection
;
62 FilerWindow
*filer_window
; /* Used for styles, etc */
64 int cursor_base
; /* Cursor when minibuffer opened */
67 typedef struct _Template Template
;
71 GdkRectangle leafname
;
75 /* GC for drawing colour filenames */
76 static GdkGC
*type_gc
= NULL
;
78 /* Static prototypes */
79 static void view_collection_finialize(GObject
*object
);
80 static void view_collection_class_init(gpointer gclass
, gpointer data
);
81 static void view_collection_init(GTypeInstance
*object
, gpointer gclass
);
83 static void draw_item(GtkWidget
*widget
,
87 static void fill_template(GdkRectangle
*area
, CollectionItem
*item
,
88 ViewCollection
*view_collection
, Template
*template);
89 static void huge_template(GdkRectangle
*area
, CollectionItem
*colitem
,
90 ViewCollection
*view_collection
, Template
*template);
91 static void large_template(GdkRectangle
*area
, CollectionItem
*colitem
,
92 ViewCollection
*view_collection
, Template
*template);
93 static void small_template(GdkRectangle
*area
, CollectionItem
*colitem
,
94 ViewCollection
*view_collection
, Template
*template);
95 static void huge_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
96 ViewCollection
*view_collection
, Template
*template);
97 static void large_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
98 ViewCollection
*view_collection
, Template
*template);
99 static void small_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
100 ViewCollection
*view_collection
, Template
*template);
101 static gboolean
test_point(Collection
*collection
,
102 int point_x
, int point_y
,
103 CollectionItem
*item
,
104 int width
, int height
,
106 static void draw_string(GtkWidget
*widget
,
108 GdkRectangle
*area
, /* Area available on screen */
109 int width
, /* Width of the full string */
110 GtkStateType selection_state
,
112 static void view_collection_iface_init(gpointer giface
, gpointer iface_data
);
113 static gint
coll_motion_notify(GtkWidget
*widget
,
114 GdkEventMotion
*event
,
115 ViewCollection
*view_collection
);
116 static gint
coll_button_release(GtkWidget
*widget
,
117 GdkEventButton
*event
,
118 ViewCollection
*view_collection
);
119 static gint
coll_button_press(GtkWidget
*widget
,
120 GdkEventButton
*event
,
121 ViewCollection
*view_collection
);
122 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
);
123 static void style_set(Collection
*collection
,
125 ViewCollection
*view_collection
);
126 static void display_free_colitem(Collection
*collection
,
127 CollectionItem
*colitem
);
128 static void lost_selection(Collection
*collection
,
131 static void selection_changed(Collection
*collection
,
134 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
135 int *width
, int *height
);
136 static void make_iter(ViewCollection
*view_collection
, ViewIter
*iter
,
138 static void make_item_iter(ViewCollection
*vc
, ViewIter
*iter
, int i
);
140 static void view_collection_sort(ViewIface
*view
);
141 static void view_collection_style_changed(ViewIface
*view
, int flags
);
142 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
);
143 static void view_collection_update_items(ViewIface
*view
, GPtrArray
*items
);
144 static void view_collection_delete_if(ViewIface
*view
,
145 gboolean (*test
)(gpointer item
, gpointer data
),
147 static void view_collection_clear(ViewIface
*view
);
148 static void view_collection_select_all(ViewIface
*view
);
149 static void view_collection_clear_selection(ViewIface
*view
);
150 static int view_collection_count_items(ViewIface
*view
);
151 static int view_collection_count_selected(ViewIface
*view
);
152 static void view_collection_show_cursor(ViewIface
*view
);
153 static void view_collection_get_iter(ViewIface
*view
,
154 ViewIter
*iter
, IterFlags flags
);
155 static void view_collection_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
156 GdkWindow
*src
, int x
, int y
);
157 static void view_collection_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
158 static void view_collection_set_selected(ViewIface
*view
,
161 static gboolean
view_collection_get_selected(ViewIface
*view
, ViewIter
*iter
);
162 static void view_collection_select_only(ViewIface
*view
, ViewIter
*iter
);
163 static void view_collection_set_frozen(ViewIface
*view
, gboolean frozen
);
164 static void view_collection_wink_item(ViewIface
*view
, ViewIter
*iter
);
165 static void view_collection_autosize(ViewIface
*view
);
166 static gboolean
view_collection_cursor_visible(ViewIface
*view
);
167 static void view_collection_set_base(ViewIface
*view
, ViewIter
*iter
);
168 static void view_collection_start_lasso_box(ViewIface
*view
,
169 GdkEventButton
*event
);
170 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
172 static gboolean
view_collection_auto_scroll_callback(ViewIface
*view
);
174 static DirItem
*iter_next(ViewIter
*iter
);
175 static DirItem
*iter_prev(ViewIter
*iter
);
176 static DirItem
*iter_peek(ViewIter
*iter
);
179 /****************************************************************
180 * EXTERNAL INTERFACE *
181 ****************************************************************/
183 GtkWidget
*view_collection_new(FilerWindow
*filer_window
)
185 ViewCollection
*view_collection
;
187 view_collection
= g_object_new(view_collection_get_type(), NULL
);
188 view_collection
->filer_window
= filer_window
;
190 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
191 view_collection
->collection
->vadj
);
193 return GTK_WIDGET(view_collection
);
196 GType
view_collection_get_type(void)
198 static GType type
= 0;
202 static const GTypeInfo info
=
204 sizeof (ViewCollectionClass
),
205 NULL
, /* base_init */
206 NULL
, /* base_finalise */
207 view_collection_class_init
,
208 NULL
, /* class_finalise */
209 NULL
, /* class_data */
210 sizeof(ViewCollection
),
214 static const GInterfaceInfo iface_info
=
216 view_collection_iface_init
, NULL
, NULL
219 type
= g_type_register_static(gtk_viewport_get_type(),
220 "ViewCollection", &info
, 0);
221 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
, &iface_info
);
227 /****************************************************************
228 * INTERNAL FUNCTIONS *
229 ****************************************************************/
231 static void view_collection_destroy(GtkObject
*view_collection
)
233 VIEW_COLLECTION(view_collection
)->filer_window
= NULL
;
236 static void view_collection_finialize(GObject
*object
)
238 /* ViewCollection *view_collection = (ViewCollection *) object; */
240 G_OBJECT_CLASS(parent_class
)->finalize(object
);
243 static void view_collection_grab_focus(GtkWidget
*focus_widget
)
245 ViewCollection
*view_collection
= VIEW_COLLECTION(focus_widget
);
246 gtk_widget_grab_focus(GTK_WIDGET(view_collection
->collection
));
249 static void view_collection_class_init(gpointer gclass
, gpointer data
)
251 GObjectClass
*object
= (GObjectClass
*) gclass
;
252 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
254 parent_class
= g_type_class_peek_parent(gclass
);
256 widget
->grab_focus
= view_collection_grab_focus
;
258 object
->finalize
= view_collection_finialize
;
259 GTK_OBJECT_CLASS(object
)->destroy
= view_collection_destroy
;
262 static void view_collection_init(GTypeInstance
*object
, gpointer gclass
)
264 ViewCollection
*view_collection
= (ViewCollection
*) object
;
265 GtkViewport
*viewport
= (GtkViewport
*) object
;
266 GtkWidget
*collection
;
269 collection
= collection_new();
270 view_collection
->collection
= COLLECTION(collection
);
272 adj
= view_collection
->collection
->vadj
;
273 gtk_viewport_set_vadjustment(viewport
, adj
);
274 gtk_viewport_set_hadjustment(viewport
, NULL
); /* Or Gtk will crash */
275 gtk_viewport_set_shadow_type(viewport
, GTK_SHADOW_NONE
);
276 gtk_container_add(GTK_CONTAINER(object
), collection
);
277 gtk_widget_show(collection
);
278 gtk_widget_set_size_request(GTK_WIDGET(view_collection
), 4, 4);
280 gtk_container_set_resize_mode(GTK_CONTAINER(viewport
),
281 GTK_RESIZE_IMMEDIATE
);
283 view_collection
->collection
->free_item
= display_free_colitem
;
284 view_collection
->collection
->draw_item
= draw_item
;
285 view_collection
->collection
->test_point
= test_point
;
286 view_collection
->collection
->cb_user_data
= view_collection
;
288 g_signal_connect(collection
, "style_set",
289 G_CALLBACK(style_set
),
292 g_signal_connect(collection
, "lose_selection",
293 G_CALLBACK(lost_selection
), view_collection
);
294 g_signal_connect(collection
, "selection_changed",
295 G_CALLBACK(selection_changed
), view_collection
);
297 g_signal_connect(collection
, "button-release-event",
298 G_CALLBACK(coll_button_release
), view_collection
);
299 g_signal_connect(collection
, "button-press-event",
300 G_CALLBACK(coll_button_press
), view_collection
);
301 g_signal_connect(collection
, "motion-notify-event",
302 G_CALLBACK(coll_motion_notify
), view_collection
);
303 g_signal_connect(viewport
, "size-allocate",
304 G_CALLBACK(size_allocate
), view_collection
);
306 gtk_widget_set_events(collection
,
307 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
308 GDK_BUTTON3_MOTION_MASK
| GDK_POINTER_MOTION_MASK
|
309 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
);
313 static void draw_item(GtkWidget
*widget
,
314 CollectionItem
*colitem
,
318 DirItem
*item
= (DirItem
*) colitem
->data
;
319 gboolean selected
= colitem
->selected
;
321 ViewData
*view
= (ViewData
*) colitem
->view_data
;
322 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
323 FilerWindow
*filer_window
= view_collection
->filer_window
;
324 GtkStateType selection_state
;
326 g_return_if_fail(view
!= NULL
);
329 selection_state
= filer_window
->selection_state
;
331 selection_state
= GTK_STATE_NORMAL
;
333 fill_template(area
, colitem
, view_collection
, &template);
335 /* Set up GC for coloured file types */
337 type_gc
= gdk_gc_new(widget
->window
);
339 gdk_gc_set_foreground(type_gc
, type_get_colour(item
,
340 &widget
->style
->fg
[GTK_STATE_NORMAL
]));
342 if (template.icon
.width
<= SMALL_WIDTH
&&
343 template.icon
.height
<= SMALL_HEIGHT
)
345 draw_small_icon(widget
->window
, &template.icon
,
346 item
, view
->image
, selected
);
348 else if (template.icon
.width
<= ICON_WIDTH
&&
349 template.icon
.height
<= ICON_HEIGHT
)
351 draw_large_icon(widget
->window
, &template.icon
,
352 item
, view
->image
, selected
);
356 draw_huge_icon(widget
->window
, &template.icon
,
357 item
, view
->image
, selected
);
360 draw_string(widget
, view
->layout
,
366 draw_string(widget
, view
->details
,
368 template.details
.width
,
373 /* A template contains the locations of the three rectangles (for the icon,
374 * name and extra details).
375 * Fill in the empty 'template' with the rectanges for this item.
377 static void fill_template(GdkRectangle
*area
, CollectionItem
*colitem
,
378 ViewCollection
*view_collection
, Template
*template)
380 DisplayStyle style
= view_collection
->filer_window
->display_style
;
381 ViewData
*view
= (ViewData
*) colitem
->view_data
;
385 template->details
.width
= view
->details_width
;
386 template->details
.height
= view
->details_height
;
388 if (style
== SMALL_ICONS
)
389 small_full_template(area
, colitem
,
390 view_collection
, template);
391 else if (style
== LARGE_ICONS
)
392 large_full_template(area
, colitem
,
393 view_collection
, template);
395 huge_full_template(area
, colitem
,
396 view_collection
, template);
400 if (style
== HUGE_ICONS
)
401 huge_template(area
, colitem
,
402 view_collection
, template);
403 else if (style
== LARGE_ICONS
)
404 large_template(area
, colitem
,
405 view_collection
, template);
407 small_template(area
, colitem
,
408 view_collection
, template);
412 static void huge_template(GdkRectangle
*area
, CollectionItem
*colitem
,
413 ViewCollection
*view_collection
, Template
*template)
415 int col_width
= view_collection
->collection
->item_width
;
417 ViewData
*view
= (ViewData
*) colitem
->view_data
;
418 MaskedPixmap
*image
= view
->image
;
422 if (!image
->huge_pixbuf
)
423 pixmap_make_huge(image
);
424 template->icon
.width
= image
->huge_width
;
425 template->icon
.height
= image
->huge_height
;
429 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
430 template->icon
.height
= HUGE_HEIGHT
;
433 template->leafname
.width
= view
->name_width
;
434 template->leafname
.height
= view
->name_height
;
436 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
437 text_y
= area
->y
+ area
->height
- template->leafname
.height
;
439 template->leafname
.x
= text_x
;
440 template->leafname
.y
= text_y
;
442 template->icon
.x
= area
->x
+ ((col_width
- template->icon
.width
) >> 1);
443 template->icon
.y
= template->leafname
.y
- template->icon
.height
- 2;
446 static void large_template(GdkRectangle
*area
, CollectionItem
*colitem
,
447 ViewCollection
*view_collection
, Template
*template)
449 int col_width
= view_collection
->collection
->item_width
;
453 ViewData
*view
= (ViewData
*) colitem
->view_data
;
454 MaskedPixmap
*image
= view
->image
;
460 iwidth
= MIN(image
->width
, ICON_WIDTH
);
461 iheight
= MIN(image
->height
+ 6, ICON_HEIGHT
);
466 iheight
= ICON_HEIGHT
;
468 image_x
= area
->x
+ ((col_width
- iwidth
) >> 1);
470 template->leafname
.width
= view
->name_width
;
471 template->leafname
.height
= view
->name_height
;
473 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
474 text_y
= area
->y
+ ICON_HEIGHT
+ 2;
476 template->leafname
.x
= text_x
;
477 template->leafname
.y
= text_y
;
479 image_y
= text_y
- iheight
;
480 image_y
= MAX(area
->y
, image_y
);
482 template->icon
.x
= image_x
;
483 template->icon
.y
= image_y
;
484 template->icon
.width
= iwidth
;
485 template->icon
.height
= MIN(ICON_HEIGHT
, iheight
);
488 static void small_template(GdkRectangle
*area
, CollectionItem
*colitem
,
489 ViewCollection
*view_collection
, Template
*template)
491 int text_x
= area
->x
+ SMALL_WIDTH
+ 4;
493 int max_text_width
= area
->width
- SMALL_WIDTH
- 4;
494 ViewData
*view
= (ViewData
*) colitem
->view_data
;
496 low_text_y
= area
->y
+ area
->height
/ 2 - view
->name_height
/ 2;
498 template->leafname
.x
= text_x
;
499 template->leafname
.y
= low_text_y
;
500 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
501 template->leafname
.height
= view
->name_height
;
503 template->icon
.x
= area
->x
;
504 template->icon
.y
= area
->y
+ 1;
505 template->icon
.width
= SMALL_WIDTH
;
506 template->icon
.height
= SMALL_HEIGHT
;
509 static void huge_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
510 ViewCollection
*view_collection
, Template
*template)
512 int max_text_width
= area
->width
- HUGE_WIDTH
- 4;
513 ViewData
*view
= (ViewData
*) colitem
->view_data
;
514 MaskedPixmap
*image
= view
->image
;
518 if (!image
->huge_pixbuf
)
519 pixmap_make_huge(image
);
520 template->icon
.width
= image
->huge_width
;
521 template->icon
.height
= image
->huge_height
;
525 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
526 template->icon
.height
= HUGE_HEIGHT
;
529 template->icon
.x
= area
->x
+ (HUGE_WIDTH
- template->icon
.width
) / 2;
530 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
532 template->leafname
.x
= area
->x
+ HUGE_WIDTH
+ 4;
533 template->leafname
.y
= area
->y
+ area
->height
/ 2
534 - (view
->name_height
+ 2 + view
->details_height
) / 2;
535 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
536 template->leafname
.height
= view
->name_height
;
539 return; /* Not scanned yet */
541 template->details
.x
= template->leafname
.x
;
542 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
545 static void large_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
546 ViewCollection
*view_collection
, Template
*template)
548 int max_text_width
= area
->width
- ICON_WIDTH
- 4;
549 ViewData
*view
= (ViewData
*) colitem
->view_data
;
550 MaskedPixmap
*image
= view
->image
;
554 template->icon
.width
= image
->width
;
555 template->icon
.height
= image
->height
;
559 template->icon
.width
= ICON_WIDTH
;
560 template->icon
.height
= ICON_HEIGHT
;
563 template->icon
.x
= area
->x
+ (ICON_WIDTH
- template->icon
.width
) / 2;
564 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
567 template->leafname
.x
= area
->x
+ ICON_WIDTH
+ 4;
568 template->leafname
.y
= area
->y
+ area
->height
/ 2
569 - (view
->name_height
+ 2 + view
->details_height
) / 2;
570 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
571 template->leafname
.height
= view
->name_height
;
574 return; /* Not scanned yet */
576 template->details
.x
= template->leafname
.x
;
577 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
580 static void small_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
581 ViewCollection
*view_collection
, Template
*template)
583 int col_width
= view_collection
->collection
->item_width
;
584 ViewData
*view
= (ViewData
*) colitem
->view_data
;
586 small_template(area
, colitem
, view_collection
, template);
589 return; /* Not scanned yet */
591 template->details
.x
= area
->x
+ col_width
- template->details
.width
;
592 template->details
.y
= area
->y
+ area
->height
/ 2 - \
593 view
->details_height
/ 2;
596 #define INSIDE(px, py, area) \
597 (px >= area.x && py >= area.y && \
598 px <= area.x + area.width && py <= area.y + area.height)
600 static gboolean
test_point(Collection
*collection
,
601 int point_x
, int point_y
,
602 CollectionItem
*colitem
,
603 int width
, int height
,
608 ViewData
*view
= (ViewData
*) colitem
->view_data
;
609 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
614 area
.height
= height
;
616 fill_template(&area
, colitem
, view_collection
, &template);
618 return INSIDE(point_x
, point_y
, template.leafname
) ||
619 INSIDE(point_x
, point_y
, template.icon
) ||
620 (view
->details
&& INSIDE(point_x
, point_y
, template.details
));
623 /* 'box' renders a background box if the string is also selected */
624 static void draw_string(GtkWidget
*widget
,
626 GdkRectangle
*area
, /* Area available on screen */
627 int width
, /* Width of the full string */
628 GtkStateType selection_state
,
631 GdkGC
*gc
= selection_state
== GTK_STATE_NORMAL
633 : widget
->style
->fg_gc
[selection_state
];
635 if (selection_state
!= GTK_STATE_NORMAL
&& box
)
636 gtk_paint_flat_box(widget
->style
, widget
->window
,
637 selection_state
, GTK_SHADOW_NONE
,
638 NULL
, widget
, "text",
640 MIN(width
, area
->width
),
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
;
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
,
669 gdk_gc_set_clip_rectangle(gc
, NULL
);
673 /* Create the handers for the View interface */
674 static void view_collection_iface_init(gpointer giface
, gpointer iface_data
)
676 ViewIfaceClass
*iface
= giface
;
678 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
681 iface
->sort
= view_collection_sort
;
682 iface
->style_changed
= view_collection_style_changed
;
683 iface
->add_items
= view_collection_add_items
;
684 iface
->update_items
= view_collection_update_items
;
685 iface
->delete_if
= view_collection_delete_if
;
686 iface
->clear
= view_collection_clear
;
687 iface
->select_all
= view_collection_select_all
;
688 iface
->clear_selection
= view_collection_clear_selection
;
689 iface
->count_items
= view_collection_count_items
;
690 iface
->count_selected
= view_collection_count_selected
;
691 iface
->show_cursor
= view_collection_show_cursor
;
692 iface
->get_iter
= view_collection_get_iter
;
693 iface
->get_iter_at_point
= view_collection_get_iter_at_point
;
694 iface
->cursor_to_iter
= view_collection_cursor_to_iter
;
695 iface
->set_selected
= view_collection_set_selected
;
696 iface
->get_selected
= view_collection_get_selected
;
697 iface
->set_frozen
= view_collection_set_frozen
;
698 iface
->select_only
= view_collection_select_only
;
699 iface
->wink_item
= view_collection_wink_item
;
700 iface
->autosize
= view_collection_autosize
;
701 iface
->cursor_visible
= view_collection_cursor_visible
;
702 iface
->set_base
= view_collection_set_base
;
703 iface
->start_lasso_box
= view_collection_start_lasso_box
;
704 iface
->extend_tip
= view_collection_extend_tip
;
705 iface
->auto_scroll_callback
= view_collection_auto_scroll_callback
;
708 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
711 ViewCollection
*view_collection
= (ViewCollection
*) view
;
712 Collection
*collection
= view_collection
->collection
;
713 FilerWindow
*filer_window
= view_collection
->filer_window
;
716 CollectionItem
*colitem
= &collection
->items
[i
];
717 int col
= i
% collection
->columns
;
718 int row
= i
/ collection
->columns
;
719 ViewData
*view_data
= (ViewData
*) colitem
->view_data
;
722 g_return_if_fail(iter
->view
== (ViewIface
*) view_collection
);
723 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
725 /* TODO: What if the window is narrower than 1 column? */
726 if (filer_window
->display_style
== LARGE_ICONS
||
727 filer_window
->display_style
== HUGE_ICONS
)
728 return; /* These wrap rather than truncate */
730 area
.x
= col
* collection
->item_width
;
731 area
.y
= row
* collection
->item_height
;
732 area
.height
= collection
->item_height
;
734 if (col
== collection
->columns
- 1)
735 area
.width
= GTK_WIDGET(collection
)->allocation
.width
- area
.x
;
737 area
.width
= collection
->item_width
;
739 fill_template(&area
, colitem
, view_collection
, &template);
741 if (template.leafname
.width
< view_data
->name_width
)
743 DirItem
*item
= (DirItem
*) collection
->items
[i
].data
;
745 g_string_append(tip
, item
->leafname
);
746 g_string_append_c(tip
, '\n');
750 static gint
coll_motion_notify(GtkWidget
*widget
,
751 GdkEventMotion
*event
,
752 ViewCollection
*view_collection
)
754 return filer_motion_notify(view_collection
->filer_window
, event
);
757 /* Viewport is to be resized, so calculate increments */
758 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
)
760 Collection
*col
= ((ViewCollection
*) data
)->collection
;
762 col
->vadj
->step_increment
= col
->item_height
;
763 col
->vadj
->page_increment
= col
->vadj
->page_size
;
766 static gint
coll_button_release(GtkWidget
*widget
,
767 GdkEventButton
*event
,
768 ViewCollection
*view_collection
)
770 if (dnd_motion_release(event
))
772 if (motion_buttons_pressed
== 0 &&
773 view_collection
->collection
->lasso_box
)
775 filer_set_autoscroll(view_collection
->filer_window
,
777 collection_end_lasso(view_collection
->collection
,
778 event
->button
== 1 ? GDK_SET
: GDK_INVERT
);
783 filer_perform_action(view_collection
->filer_window
, event
);
788 static gint
coll_button_press(GtkWidget
*widget
,
789 GdkEventButton
*event
,
790 ViewCollection
*view_collection
)
792 collection_set_cursor_item(view_collection
->collection
, -1, TRUE
);
794 if (dnd_motion_press(widget
, event
))
795 filer_perform_action(view_collection
->filer_window
, event
);
800 /* Nothing is selected anymore - give up primary */
801 static void lost_selection(Collection
*collection
,
805 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
807 filer_lost_selection(view_collection
->filer_window
, time
);
810 static void selection_changed(Collection
*collection
,
814 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
816 filer_selection_changed(view_collection
->filer_window
, time
);
819 static void display_free_colitem(Collection
*collection
,
820 CollectionItem
*colitem
)
822 ViewData
*view
= (ViewData
*) colitem
->view_data
;
829 g_object_unref(G_OBJECT(view
->layout
));
833 g_object_unref(G_OBJECT(view
->details
));
836 g_object_unref(view
->image
);
841 static void add_item(ViewCollection
*view_collection
, DirItem
*item
)
843 Collection
*collection
= view_collection
->collection
;
844 FilerWindow
*filer_window
= view_collection
->filer_window
;
845 int old_w
= collection
->item_width
;
846 int old_h
= collection
->item_height
;
849 i
= collection_insert(collection
, item
,
850 display_create_viewdata(filer_window
, item
));
852 calc_size(filer_window
, &collection
->items
[i
], &w
, &h
);
854 if (w
> old_w
|| h
> old_h
)
855 collection_set_item_size(collection
,
860 static void style_set(Collection
*collection
,
862 ViewCollection
*view_collection
)
864 view_collection_style_changed(VIEW(view_collection
),
865 VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
);
868 /* Return the size needed for this item */
869 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
870 int *width
, int *height
)
872 int pix_width
, pix_height
;
874 DisplayStyle style
= filer_window
->display_style
;
875 ViewData
*view
= (ViewData
*) colitem
->view_data
;
877 if (filer_window
->details_type
== DETAILS_NONE
)
879 if (style
== HUGE_ICONS
)
883 if (!view
->image
->huge_pixbuf
)
884 pixmap_make_huge(view
->image
);
885 pix_width
= view
->image
->huge_width
;
886 pix_height
= view
->image
->huge_height
;
890 pix_width
= HUGE_WIDTH
* 3 / 2;
891 pix_height
= HUGE_HEIGHT
* 3 / 2;
893 *width
= MAX(pix_width
, view
->name_width
) + 4;
894 *height
= MAX(view
->name_height
+ pix_height
+ 4,
895 HUGE_HEIGHT
* 3 / 4);
897 else if (style
== SMALL_ICONS
)
899 w
= MIN(view
->name_width
, o_small_width
.int_value
);
900 *width
= SMALL_WIDTH
+ 12 + w
;
901 *height
= MAX(view
->name_height
, SMALL_HEIGHT
) + 4;
906 pix_width
= view
->image
->width
;
908 pix_width
= ICON_WIDTH
;
909 *width
= MAX(pix_width
, view
->name_width
) + 4;
910 *height
= view
->name_height
+ ICON_HEIGHT
+ 2;
915 w
= view
->details_width
;
916 if (style
== HUGE_ICONS
)
918 *width
= HUGE_WIDTH
+ 12 + MAX(w
, view
->name_width
);
919 *height
= HUGE_HEIGHT
- 4;
921 else if (style
== SMALL_ICONS
)
925 *width
= SMALL_WIDTH
+ view
->name_width
+ 12 + w
;
926 text_height
= MAX(view
->name_height
,
927 view
->details_height
);
928 *height
= MAX(text_height
, SMALL_HEIGHT
) + 4;
932 *width
= ICON_WIDTH
+ 12 + MAX(w
, view
->name_width
);
933 *height
= ICON_HEIGHT
;
938 static void update_item(ViewCollection
*view_collection
, int i
)
940 Collection
*collection
= view_collection
->collection
;
941 int old_w
= collection
->item_width
;
942 int old_h
= collection
->item_height
;
944 CollectionItem
*colitem
;
945 FilerWindow
*filer_window
= view_collection
->filer_window
;
947 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
949 colitem
= &collection
->items
[i
];
951 display_update_view(filer_window
,
952 (DirItem
*) colitem
->data
,
953 (ViewData
*) colitem
->view_data
,
956 calc_size(filer_window
, colitem
, &w
, &h
);
957 if (w
> old_w
|| h
> old_h
)
958 collection_set_item_size(collection
,
962 collection_draw_item(collection
, i
, TRUE
);
965 /* Implementations of the View interface. See view_iface.c for comments. */
967 static void view_collection_style_changed(ViewIface
*view
, int flags
)
969 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
970 FilerWindow
*filer_window
= view_collection
->filer_window
;
972 Collection
*col
= view_collection
->collection
;
973 int width
= MIN_ITEM_WIDTH
;
974 int height
= SMALL_HEIGHT
;
975 int n
= col
->number_of_items
;
977 if (n
== 0 && filer_window
->display_style
!= SMALL_ICONS
)
978 height
= ICON_HEIGHT
;
980 /* Recalculate all the ViewData structs for this window
981 * (needed if the text or image has changed in any way) and
982 * get the size of each item.
984 for (i
= 0; i
< n
; i
++)
986 CollectionItem
*ci
= &col
->items
[i
];
989 if (flags
& (VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
))
990 display_update_view(filer_window
,
991 (DirItem
*) ci
->data
,
992 (ViewData
*) ci
->view_data
,
993 (flags
& VIEW_UPDATE_NAME
) != 0);
995 calc_size(filer_window
, ci
, &w
, &h
);
1002 collection_set_item_size(col
, width
, height
);
1004 gtk_widget_queue_draw(GTK_WIDGET(view_collection
));
1007 typedef int (*SortFn
)(gconstpointer a
, gconstpointer b
);
1009 static SortFn
sort_fn(FilerWindow
*fw
)
1011 switch (fw
->sort_type
)
1013 case SORT_NAME
: return sort_by_name
;
1014 case SORT_TYPE
: return sort_by_type
;
1015 case SORT_DATE
: return sort_by_date
;
1016 case SORT_SIZE
: return sort_by_size
;
1017 case SORT_OWNER
: return sort_by_owner
;
1018 case SORT_GROUP
: return sort_by_group
;
1020 g_assert_not_reached();
1026 static void view_collection_sort(ViewIface
*view
)
1028 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1029 FilerWindow
*filer_window
= view_collection
->filer_window
;
1031 collection_qsort(view_collection
->collection
, sort_fn(filer_window
),
1032 filer_window
->sort_order
);
1035 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
)
1037 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1038 Collection
*collection
= view_collection
->collection
;
1039 FilerWindow
*filer_window
= view_collection
->filer_window
;
1042 old_num
= collection
->number_of_items
;
1043 for (i
= 0; i
< items
->len
; i
++)
1045 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1046 char *leafname
= item
->leafname
;
1048 if (leafname
[0] == '.' && !filer_window
->show_hidden
)
1051 add_item(view_collection
, item
);
1054 if (old_num
!= collection
->number_of_items
)
1055 view_collection_sort(view
);
1058 static void view_collection_update_items(ViewIface
*view
, GPtrArray
*items
)
1060 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1061 Collection
*collection
= view_collection
->collection
;
1062 FilerWindow
*filer_window
= view_collection
->filer_window
;
1065 g_return_if_fail(items
->len
> 0);
1067 /* The item data has already been modified, so this gives the
1068 * final sort order...
1070 collection_qsort(collection
, sort_fn(filer_window
),
1071 filer_window
->sort_order
);
1073 for (i
= 0; i
< items
->len
; i
++)
1075 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1076 const gchar
*leafname
= item
->leafname
;
1079 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1082 j
= collection_find_item(collection
, item
,
1083 sort_fn(filer_window
),
1084 filer_window
->sort_order
);
1087 g_warning("Failed to find '%s'\n", leafname
);
1089 update_item(view_collection
, j
);
1093 static void view_collection_delete_if(ViewIface
*view
,
1094 gboolean (*test
)(gpointer item
, gpointer data
),
1097 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1098 Collection
*collection
= view_collection
->collection
;
1100 collection_delete_if(collection
, test
, data
);
1103 static void view_collection_clear(ViewIface
*view
)
1105 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1106 Collection
*collection
= view_collection
->collection
;
1108 collection_clear(collection
);
1111 static void view_collection_select_all(ViewIface
*view
)
1113 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1114 Collection
*collection
= view_collection
->collection
;
1116 collection_select_all(collection
);
1119 static void view_collection_clear_selection(ViewIface
*view
)
1121 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1122 Collection
*collection
= view_collection
->collection
;
1124 collection_clear_selection(collection
);
1127 static int view_collection_count_items(ViewIface
*view
)
1129 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1130 Collection
*collection
= view_collection
->collection
;
1132 return collection
->number_of_items
;
1135 static int view_collection_count_selected(ViewIface
*view
)
1137 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1138 Collection
*collection
= view_collection
->collection
;
1140 return collection
->number_selected
;
1143 static void view_collection_show_cursor(ViewIface
*view
)
1145 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1146 Collection
*collection
= view_collection
->collection
;
1148 collection_move_cursor(collection
, 0, 0);
1151 /* The first time the next() method is used, this is called */
1152 static DirItem
*iter_init(ViewIter
*iter
)
1154 ViewCollection
*view_collection
= (ViewCollection
*) iter
->view
;
1155 Collection
*collection
= view_collection
->collection
;
1157 int n
= collection
->number_of_items
;
1158 int flags
= iter
->flags
;
1160 iter
->peek
= iter_peek
;
1162 if (iter
->n_remaining
== 0)
1165 if (flags
& VIEW_ITER_FROM_CURSOR
)
1167 i
= collection
->cursor_item
;
1169 return NULL
; /* No cursor */
1171 else if (flags
& VIEW_ITER_FROM_BASE
)
1172 i
= view_collection
->cursor_base
;
1174 if (i
< 0 || i
>= n
)
1176 /* Either a normal iteration, or an iteration from an
1177 * invalid starting point.
1179 if (flags
& VIEW_ITER_BACKWARDS
)
1185 if (i
< 0 || i
>= n
)
1186 return NULL
; /* No items at all! */
1188 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1189 iter
->n_remaining
--;
1192 if (flags
& VIEW_ITER_SELECTED
&& !collection
->items
[i
].selected
)
1193 return iter
->next(iter
);
1194 return iter
->peek(iter
);
1196 /* Advance iter to point to the next item and return the new item
1197 * (this saves you calling peek after next each time).
1199 static DirItem
*iter_next(ViewIter
*iter
)
1201 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1202 int n
= collection
->number_of_items
;
1205 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1207 /* i is the last item returned (always valid) */
1209 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1211 while (iter
->n_remaining
)
1214 iter
->n_remaining
--;
1219 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1221 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1222 !collection
->items
[i
].selected
)
1226 return collection
->items
[i
].data
;
1233 /* Like iter_next, but in the other direction */
1234 static DirItem
*iter_prev(ViewIter
*iter
)
1236 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1237 int n
= collection
->number_of_items
;
1240 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1242 /* i is the last item returned (always valid) */
1244 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1246 while (iter
->n_remaining
)
1249 iter
->n_remaining
--;
1252 i
= collection
->number_of_items
- 1;
1254 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1256 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1257 !collection
->items
[i
].selected
)
1261 return collection
->items
[i
].data
;
1268 static DirItem
*iter_peek(ViewIter
*iter
)
1270 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1276 g_return_val_if_fail(i
>= 0 && i
< collection
->number_of_items
, NULL
);
1278 return collection
->items
[i
].data
;
1281 static void make_iter(ViewCollection
*view_collection
, ViewIter
*iter
,
1284 Collection
*collection
= view_collection
->collection
;
1286 iter
->view
= (ViewIface
*) view_collection
;
1287 iter
->next
= iter_init
;
1291 iter
->flags
= flags
;
1293 if (flags
& VIEW_ITER_ONE_ONLY
)
1295 iter
->n_remaining
= 1;
1299 iter
->n_remaining
= collection
->number_of_items
;
1302 /* Set the iterator to return 'i' on the next peek() */
1303 static void make_item_iter(ViewCollection
*view_collection
,
1304 ViewIter
*iter
, int i
)
1306 Collection
*collection
= view_collection
->collection
;
1308 g_return_if_fail(i
>= -1 && i
< collection
->number_of_items
);
1310 make_iter(view_collection
, iter
, 0);
1313 iter
->next
= iter_next
;
1314 iter
->peek
= iter_peek
;
1315 iter
->n_remaining
= 0;
1318 static void view_collection_get_iter(ViewIface
*view
,
1319 ViewIter
*iter
, IterFlags flags
)
1321 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1323 make_iter(view_collection
, iter
, flags
);
1326 static void view_collection_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1327 GdkWindow
*src
, int x
, int y
)
1329 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1330 Collection
*collection
= view_collection
->collection
;
1333 if (src
== ((GtkWidget
*) view
)->window
)
1335 /* The event is on the Viewport, not the collection... */
1336 y
+= collection
->vadj
->value
;
1339 i
= collection_get_item(collection
, x
, y
);
1340 make_item_iter(view_collection
, iter
, i
);
1343 static void view_collection_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1345 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1346 Collection
*collection
= view_collection
->collection
;
1347 FilerWindow
*filer_window
= view_collection
->filer_window
;
1349 g_return_if_fail(iter
== NULL
||
1350 iter
->view
== (ViewIface
*) view_collection
);
1352 collection_set_cursor_item(collection
, iter
? iter
->i
: -1,
1353 filer_window
->auto_scroll
== -1);
1356 static void view_collection_set_selected(ViewIface
*view
,
1360 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1361 Collection
*collection
= view_collection
->collection
;
1363 g_return_if_fail(iter
!= NULL
&&
1364 iter
->view
== (ViewIface
*) view_collection
);
1365 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1368 collection_select_item(collection
, iter
->i
);
1370 collection_unselect_item(collection
, iter
->i
);
1373 static gboolean
view_collection_get_selected(ViewIface
*view
, ViewIter
*iter
)
1375 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1376 Collection
*collection
= view_collection
->collection
;
1378 g_return_val_if_fail(iter
!= NULL
&&
1379 iter
->view
== (ViewIface
*) view_collection
, FALSE
);
1380 g_return_val_if_fail(iter
->i
>= 0 &&
1381 iter
->i
< collection
->number_of_items
, FALSE
);
1383 return collection
->items
[iter
->i
].selected
;
1386 static void view_collection_select_only(ViewIface
*view
, ViewIter
*iter
)
1388 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1389 Collection
*collection
= view_collection
->collection
;
1391 g_return_if_fail(iter
!= NULL
&&
1392 iter
->view
== (ViewIface
*) view_collection
);
1393 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1395 collection_clear_except(collection
, iter
->i
);
1398 static void view_collection_set_frozen(ViewIface
*view
, gboolean frozen
)
1400 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1401 Collection
*collection
= view_collection
->collection
;
1404 collection
->block_selection_changed
++;
1406 collection_unblock_selection_changed(collection
,
1407 gtk_get_current_event_time(), TRUE
);
1410 static void view_collection_wink_item(ViewIface
*view
, ViewIter
*iter
)
1412 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1413 Collection
*collection
= view_collection
->collection
;
1417 collection_wink_item(collection
, -1);
1421 g_return_if_fail(iter
!= NULL
&&
1422 iter
->view
== (ViewIface
*) view_collection
);
1423 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1425 collection_wink_item(collection
, iter
->i
);
1428 static void view_collection_autosize(ViewIface
*view
)
1430 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1431 FilerWindow
*filer_window
= view_collection
->filer_window
;
1432 Collection
*collection
= view_collection
->collection
;
1434 int w
= collection
->item_width
;
1435 int h
= collection
->item_height
;
1438 int max_x
, max_rows
;
1439 const float r
= 2.5;
1443 /* Get the extra height required for the toolbar and minibuffer,
1446 if (o_toolbar
.int_value
!= TOOLBAR_NONE
)
1447 t
= filer_window
->toolbar
->allocation
.height
;
1448 if (filer_window
->message
)
1449 t
+= filer_window
->message
->allocation
.height
;
1450 if (GTK_WIDGET_VISIBLE(filer_window
->minibuffer_area
))
1454 gtk_widget_size_request(filer_window
->minibuffer_area
, &req
);
1455 space
= req
.height
+ 2;
1459 n
= collection
->number_of_items
;
1461 h
= ICON_HEIGHT
* 1.5;
1464 max_x
= (o_filer_size_limit
.int_value
* screen_width
) / 100;
1465 max_rows
= (o_filer_size_limit
.int_value
* screen_height
) / (h
* 100);
1467 /* Aim for a size where
1468 * x = r(y + t + h), (1)
1469 * unless that's too wide.
1471 * t = toolbar (and minibuffer) height
1472 * r = desired (width / height) ratio
1474 * Want to display all items:
1477 * => x(x/r - t - h) = nwh (from 1)
1478 * => xx - x.rt - hr(1 - nw) = 0
1479 * => 2x = rt +/- sqrt(rt.rt + 4hr(nw - 1))
1483 * sqrt(rt.rt + ...) > rt
1485 * So, the +/- must be +:
1487 * => x = (rt + sqrt(rt.rt + 4hr(nw - 1))) / 2
1489 * ( + w - 1 to round up)
1491 x
= (r
* t
+ sqrt(r
*r
*t
*t
+ 4*h
*r
* (n
*w
- 1))) / 2 + w
- 1;
1498 cols
= MAX(cols
, 1);
1500 /* Choose rows to display all items given our chosen x.
1501 * Don't make the window *too* big!
1503 rows
= (n
+ cols
- 1) / cols
;
1504 if (rows
> max_rows
)
1507 /* Leave some room for extra icons, but only in Small Icons mode
1508 * otherwise it takes up too much space.
1509 * Also, don't add space if the minibuffer is open.
1512 space
= filer_window
->display_style
== SMALL_ICONS
? h
: 2;
1514 filer_window_set_size(filer_window
,
1516 h
* MAX(rows
, 1) + space
);
1519 static gboolean
view_collection_cursor_visible(ViewIface
*view
)
1521 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1522 Collection
*collection
= view_collection
->collection
;
1524 return collection
->cursor_item
!= -1;
1527 static void view_collection_set_base(ViewIface
*view
, ViewIter
*iter
)
1529 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1531 view_collection
->cursor_base
= iter
->i
;
1534 static void view_collection_start_lasso_box(ViewIface
*view
,
1535 GdkEventButton
*event
)
1537 ViewCollection
*view_collection
= (ViewCollection
*) view
;
1538 Collection
*collection
= view_collection
->collection
;
1540 filer_set_autoscroll(view_collection
->filer_window
, TRUE
);
1541 collection_lasso_box(collection
, event
->x
, event
->y
);
1545 /* Change the adjustment by this amount. Bounded. */
1546 static void diff_vpos(Collection
*collection
, int diff
)
1548 int old
= collection
->vadj
->value
;
1549 int value
= old
+ diff
;
1551 value
= CLAMP(value
, 0,
1552 collection
->vadj
->upper
- collection
->vadj
->page_size
);
1553 gtk_adjustment_set_value(collection
->vadj
, value
);
1555 if (collection
->vadj
->value
!= old
)
1559 static gboolean
view_collection_auto_scroll_callback(ViewIface
*view
)
1561 ViewCollection
*view_collection
= (ViewCollection
*) view
;
1562 Collection
*collection
= view_collection
->collection
;
1563 GdkWindow
*window
= ((GtkWidget
*) collection
)->window
;
1565 GdkModifierType mask
;
1568 gdk_window_get_pointer(window
, &x
, &y
, &mask
);
1569 gdk_drawable_get_size(window
, &w
, NULL
);
1571 h
= collection
->vadj
->page_size
;
1572 y
-= collection
->vadj
->value
;
1574 if ((x
< 0 || x
> w
|| y
< 0 || y
> h
) && !collection
->lasso_box
)
1575 return FALSE
; /* Out of window - stop */
1577 if (y
< AUTOSCROLL_STEP
)
1578 diff
= y
- AUTOSCROLL_STEP
;
1579 else if (y
> h
- AUTOSCROLL_STEP
)
1580 diff
= AUTOSCROLL_STEP
+ y
- h
;
1583 diff_vpos(collection
, diff
);