4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2005, 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 /* Starting with GTK+-2.2.2, the vadjustment is reset after init
191 * (even though it's already set during init) to a new adjustment.
194 gtk_viewport_set_vadjustment(GTK_VIEWPORT(view_collection
),
195 view_collection
->collection
->vadj
);
197 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
198 view_collection
->collection
->vadj
);
200 return GTK_WIDGET(view_collection
);
203 GType
view_collection_get_type(void)
205 static GType type
= 0;
209 static const GTypeInfo info
=
211 sizeof (ViewCollectionClass
),
212 NULL
, /* base_init */
213 NULL
, /* base_finalise */
214 view_collection_class_init
,
215 NULL
, /* class_finalise */
216 NULL
, /* class_data */
217 sizeof(ViewCollection
),
221 static const GInterfaceInfo iface_info
=
223 view_collection_iface_init
, NULL
, NULL
226 type
= g_type_register_static(gtk_viewport_get_type(),
227 "ViewCollection", &info
, 0);
228 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
, &iface_info
);
234 /****************************************************************
235 * INTERNAL FUNCTIONS *
236 ****************************************************************/
238 static void view_collection_destroy(GtkObject
*view_collection
)
240 VIEW_COLLECTION(view_collection
)->filer_window
= NULL
;
243 static void view_collection_finialize(GObject
*object
)
245 /* ViewCollection *view_collection = (ViewCollection *) object; */
247 G_OBJECT_CLASS(parent_class
)->finalize(object
);
250 static void view_collection_grab_focus(GtkWidget
*focus_widget
)
252 ViewCollection
*view_collection
= VIEW_COLLECTION(focus_widget
);
253 gtk_widget_grab_focus(GTK_WIDGET(view_collection
->collection
));
256 static void view_collection_class_init(gpointer gclass
, gpointer data
)
258 GObjectClass
*object
= (GObjectClass
*) gclass
;
259 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
261 parent_class
= g_type_class_peek_parent(gclass
);
263 widget
->grab_focus
= view_collection_grab_focus
;
265 object
->finalize
= view_collection_finialize
;
266 GTK_OBJECT_CLASS(object
)->destroy
= view_collection_destroy
;
269 static void view_collection_init(GTypeInstance
*object
, gpointer gclass
)
271 ViewCollection
*view_collection
= (ViewCollection
*) object
;
272 GtkViewport
*viewport
= (GtkViewport
*) object
;
273 GtkWidget
*collection
;
276 collection
= collection_new();
277 view_collection
->collection
= COLLECTION(collection
);
279 adj
= view_collection
->collection
->vadj
;
280 gtk_viewport_set_vadjustment(viewport
, adj
);
281 gtk_viewport_set_hadjustment(viewport
, NULL
); /* Or Gtk will crash */
282 gtk_viewport_set_shadow_type(viewport
, GTK_SHADOW_NONE
);
283 gtk_container_add(GTK_CONTAINER(object
), collection
);
284 gtk_widget_show(collection
);
285 gtk_widget_set_size_request(GTK_WIDGET(view_collection
), 4, 4);
287 gtk_container_set_resize_mode(GTK_CONTAINER(viewport
),
288 GTK_RESIZE_IMMEDIATE
);
290 view_collection
->collection
->free_item
= display_free_colitem
;
291 view_collection
->collection
->draw_item
= draw_item
;
292 view_collection
->collection
->test_point
= test_point
;
293 view_collection
->collection
->cb_user_data
= view_collection
;
295 g_signal_connect(collection
, "style_set",
296 G_CALLBACK(style_set
),
299 g_signal_connect(collection
, "lose_selection",
300 G_CALLBACK(lost_selection
), view_collection
);
301 g_signal_connect(collection
, "selection_changed",
302 G_CALLBACK(selection_changed
), view_collection
);
304 g_signal_connect(collection
, "button-release-event",
305 G_CALLBACK(coll_button_release
), view_collection
);
306 g_signal_connect(collection
, "button-press-event",
307 G_CALLBACK(coll_button_press
), view_collection
);
308 g_signal_connect(collection
, "motion-notify-event",
309 G_CALLBACK(coll_motion_notify
), view_collection
);
310 g_signal_connect(viewport
, "size-allocate",
311 G_CALLBACK(size_allocate
), view_collection
);
313 gtk_widget_set_events(collection
,
314 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
315 GDK_BUTTON3_MOTION_MASK
| GDK_POINTER_MOTION_MASK
|
316 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
);
320 static void draw_item(GtkWidget
*widget
,
321 CollectionItem
*colitem
,
325 DirItem
*item
= (DirItem
*) colitem
->data
;
326 gboolean selected
= colitem
->selected
;
328 ViewData
*view
= (ViewData
*) colitem
->view_data
;
329 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
330 FilerWindow
*filer_window
= view_collection
->filer_window
;
331 GtkStateType selection_state
;
333 g_return_if_fail(view
!= NULL
);
336 selection_state
= filer_window
->selection_state
;
338 selection_state
= GTK_STATE_NORMAL
;
340 fill_template(area
, colitem
, view_collection
, &template);
342 /* Set up GC for coloured file types */
344 type_gc
= gdk_gc_new(widget
->window
);
346 gdk_gc_set_foreground(type_gc
, type_get_colour(item
,
347 &widget
->style
->fg
[GTK_STATE_NORMAL
]));
349 if (template.icon
.width
<= SMALL_WIDTH
&&
350 template.icon
.height
<= SMALL_HEIGHT
)
352 draw_small_icon(widget
->window
, &template.icon
,
353 item
, view
->image
, selected
);
355 else if (template.icon
.width
<= ICON_WIDTH
&&
356 template.icon
.height
<= ICON_HEIGHT
)
358 draw_large_icon(widget
->window
, &template.icon
,
359 item
, view
->image
, selected
);
363 draw_huge_icon(widget
->window
, &template.icon
,
364 item
, view
->image
, selected
);
367 draw_string(widget
, view
->layout
,
373 draw_string(widget
, view
->details
,
375 template.details
.width
,
380 /* A template contains the locations of the three rectangles (for the icon,
381 * name and extra details).
382 * Fill in the empty 'template' with the rectanges for this item.
384 static void fill_template(GdkRectangle
*area
, CollectionItem
*colitem
,
385 ViewCollection
*view_collection
, Template
*template)
387 DisplayStyle style
= view_collection
->filer_window
->display_style
;
388 ViewData
*view
= (ViewData
*) colitem
->view_data
;
392 template->details
.width
= view
->details_width
;
393 template->details
.height
= view
->details_height
;
395 if (style
== SMALL_ICONS
)
396 small_full_template(area
, colitem
,
397 view_collection
, template);
398 else if (style
== LARGE_ICONS
)
399 large_full_template(area
, colitem
,
400 view_collection
, template);
402 huge_full_template(area
, colitem
,
403 view_collection
, template);
407 if (style
== HUGE_ICONS
)
408 huge_template(area
, colitem
,
409 view_collection
, template);
410 else if (style
== LARGE_ICONS
)
411 large_template(area
, colitem
,
412 view_collection
, template);
414 small_template(area
, colitem
,
415 view_collection
, template);
419 static void huge_template(GdkRectangle
*area
, CollectionItem
*colitem
,
420 ViewCollection
*view_collection
, Template
*template)
422 int col_width
= view_collection
->collection
->item_width
;
424 ViewData
*view
= (ViewData
*) colitem
->view_data
;
425 MaskedPixmap
*image
= view
->image
;
429 if (!image
->huge_pixbuf
)
430 pixmap_make_huge(image
);
431 template->icon
.width
= image
->huge_width
;
432 template->icon
.height
= image
->huge_height
;
436 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
437 template->icon
.height
= HUGE_HEIGHT
;
440 template->leafname
.width
= view
->name_width
;
441 template->leafname
.height
= view
->name_height
;
443 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
444 text_y
= area
->y
+ area
->height
- template->leafname
.height
;
446 template->leafname
.x
= text_x
;
447 template->leafname
.y
= text_y
;
449 template->icon
.x
= area
->x
+ ((col_width
- template->icon
.width
) >> 1);
450 template->icon
.y
= template->leafname
.y
- template->icon
.height
- 2;
453 static void large_template(GdkRectangle
*area
, CollectionItem
*colitem
,
454 ViewCollection
*view_collection
, Template
*template)
456 int col_width
= view_collection
->collection
->item_width
;
460 ViewData
*view
= (ViewData
*) colitem
->view_data
;
461 MaskedPixmap
*image
= view
->image
;
467 iwidth
= MIN(image
->width
, ICON_WIDTH
);
468 iheight
= MIN(image
->height
+ 6, ICON_HEIGHT
);
473 iheight
= ICON_HEIGHT
;
475 image_x
= area
->x
+ ((col_width
- iwidth
) >> 1);
477 template->leafname
.width
= view
->name_width
;
478 template->leafname
.height
= view
->name_height
;
480 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
481 text_y
= area
->y
+ ICON_HEIGHT
+ 2;
483 template->leafname
.x
= text_x
;
484 template->leafname
.y
= text_y
;
486 image_y
= text_y
- iheight
;
487 image_y
= MAX(area
->y
, image_y
);
489 template->icon
.x
= image_x
;
490 template->icon
.y
= image_y
;
491 template->icon
.width
= iwidth
;
492 template->icon
.height
= MIN(ICON_HEIGHT
, iheight
);
495 static void small_template(GdkRectangle
*area
, CollectionItem
*colitem
,
496 ViewCollection
*view_collection
, Template
*template)
498 int text_x
= area
->x
+ SMALL_WIDTH
+ 4;
500 int max_text_width
= area
->width
- SMALL_WIDTH
- 4;
501 ViewData
*view
= (ViewData
*) colitem
->view_data
;
503 low_text_y
= area
->y
+ area
->height
/ 2 - view
->name_height
/ 2;
505 template->leafname
.x
= text_x
;
506 template->leafname
.y
= low_text_y
;
507 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
508 template->leafname
.height
= view
->name_height
;
510 template->icon
.x
= area
->x
;
511 template->icon
.y
= area
->y
+ 1;
512 template->icon
.width
= SMALL_WIDTH
;
513 template->icon
.height
= SMALL_HEIGHT
;
516 static void huge_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
517 ViewCollection
*view_collection
, Template
*template)
519 int max_text_width
= area
->width
- HUGE_WIDTH
- 4;
520 ViewData
*view
= (ViewData
*) colitem
->view_data
;
521 MaskedPixmap
*image
= view
->image
;
525 if (!image
->huge_pixbuf
)
526 pixmap_make_huge(image
);
527 template->icon
.width
= image
->huge_width
;
528 template->icon
.height
= image
->huge_height
;
532 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
533 template->icon
.height
= HUGE_HEIGHT
;
536 template->icon
.x
= area
->x
+ (HUGE_WIDTH
- template->icon
.width
) / 2;
537 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
539 template->leafname
.x
= area
->x
+ HUGE_WIDTH
+ 4;
540 template->leafname
.y
= area
->y
+ area
->height
/ 2
541 - (view
->name_height
+ 2 + view
->details_height
) / 2;
542 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
543 template->leafname
.height
= view
->name_height
;
546 return; /* Not scanned yet */
548 template->details
.x
= template->leafname
.x
;
549 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
552 static void large_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
553 ViewCollection
*view_collection
, Template
*template)
555 int max_text_width
= area
->width
- ICON_WIDTH
- 4;
556 ViewData
*view
= (ViewData
*) colitem
->view_data
;
557 MaskedPixmap
*image
= view
->image
;
561 template->icon
.width
= image
->width
;
562 template->icon
.height
= image
->height
;
566 template->icon
.width
= ICON_WIDTH
;
567 template->icon
.height
= ICON_HEIGHT
;
570 template->icon
.x
= area
->x
+ (ICON_WIDTH
- template->icon
.width
) / 2;
571 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
574 template->leafname
.x
= area
->x
+ ICON_WIDTH
+ 4;
575 template->leafname
.y
= area
->y
+ area
->height
/ 2
576 - (view
->name_height
+ 2 + view
->details_height
) / 2;
577 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
578 template->leafname
.height
= view
->name_height
;
581 return; /* Not scanned yet */
583 template->details
.x
= template->leafname
.x
;
584 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
587 static void small_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
588 ViewCollection
*view_collection
, Template
*template)
590 int col_width
= view_collection
->collection
->item_width
;
591 ViewData
*view
= (ViewData
*) colitem
->view_data
;
593 small_template(area
, colitem
, view_collection
, template);
596 return; /* Not scanned yet */
598 template->details
.x
= area
->x
+ col_width
- template->details
.width
;
599 template->details
.y
= area
->y
+ area
->height
/ 2 - \
600 view
->details_height
/ 2;
603 #define INSIDE(px, py, area) \
604 (px >= area.x && py >= area.y && \
605 px <= area.x + area.width && py <= area.y + area.height)
607 static gboolean
test_point(Collection
*collection
,
608 int point_x
, int point_y
,
609 CollectionItem
*colitem
,
610 int width
, int height
,
615 ViewData
*view
= (ViewData
*) colitem
->view_data
;
616 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
621 area
.height
= height
;
623 fill_template(&area
, colitem
, view_collection
, &template);
625 return INSIDE(point_x
, point_y
, template.leafname
) ||
626 INSIDE(point_x
, point_y
, template.icon
) ||
627 (view
->details
&& INSIDE(point_x
, point_y
, template.details
));
630 /* 'box' renders a background box if the string is also selected */
631 static void draw_string(GtkWidget
*widget
,
633 GdkRectangle
*area
, /* Area available on screen */
634 int width
, /* Width of the full string */
635 GtkStateType selection_state
,
638 GdkGC
*gc
= selection_state
== GTK_STATE_NORMAL
640 : widget
->style
->fg_gc
[selection_state
];
642 if (selection_state
!= GTK_STATE_NORMAL
&& box
)
643 gtk_paint_flat_box(widget
->style
, widget
->window
,
644 selection_state
, GTK_SHADOW_NONE
,
645 NULL
, widget
, "text",
647 MIN(width
, area
->width
),
650 if (width
> area
->width
)
652 gdk_gc_set_clip_origin(gc
, 0, 0);
653 gdk_gc_set_clip_rectangle(gc
, area
);
656 gdk_draw_layout(widget
->window
, gc
, area
->x
, area
->y
, layout
);
658 if (width
> area
->width
)
660 static GdkGC
*red_gc
= NULL
;
665 GdkColor red
= {0, 0xffff, 0, 0};
667 red_gc
= gdk_gc_new(widget
->window
);
668 gdk_colormap_alloc_colors(
669 gtk_widget_get_colormap(widget
),
670 &red
, 1, FALSE
, TRUE
, &success
);
671 gdk_gc_set_foreground(red_gc
, &red
);
673 gdk_draw_rectangle(widget
->window
, red_gc
, TRUE
,
674 area
->x
+ area
->width
- 1, area
->y
,
676 gdk_gc_set_clip_rectangle(gc
, NULL
);
680 /* Create the handers for the View interface */
681 static void view_collection_iface_init(gpointer giface
, gpointer iface_data
)
683 ViewIfaceClass
*iface
= giface
;
685 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
688 iface
->sort
= view_collection_sort
;
689 iface
->style_changed
= view_collection_style_changed
;
690 iface
->add_items
= view_collection_add_items
;
691 iface
->update_items
= view_collection_update_items
;
692 iface
->delete_if
= view_collection_delete_if
;
693 iface
->clear
= view_collection_clear
;
694 iface
->select_all
= view_collection_select_all
;
695 iface
->clear_selection
= view_collection_clear_selection
;
696 iface
->count_items
= view_collection_count_items
;
697 iface
->count_selected
= view_collection_count_selected
;
698 iface
->show_cursor
= view_collection_show_cursor
;
699 iface
->get_iter
= view_collection_get_iter
;
700 iface
->get_iter_at_point
= view_collection_get_iter_at_point
;
701 iface
->cursor_to_iter
= view_collection_cursor_to_iter
;
702 iface
->set_selected
= view_collection_set_selected
;
703 iface
->get_selected
= view_collection_get_selected
;
704 iface
->set_frozen
= view_collection_set_frozen
;
705 iface
->select_only
= view_collection_select_only
;
706 iface
->wink_item
= view_collection_wink_item
;
707 iface
->autosize
= view_collection_autosize
;
708 iface
->cursor_visible
= view_collection_cursor_visible
;
709 iface
->set_base
= view_collection_set_base
;
710 iface
->start_lasso_box
= view_collection_start_lasso_box
;
711 iface
->extend_tip
= view_collection_extend_tip
;
712 iface
->auto_scroll_callback
= view_collection_auto_scroll_callback
;
715 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
718 ViewCollection
*view_collection
= (ViewCollection
*) view
;
719 Collection
*collection
= view_collection
->collection
;
720 FilerWindow
*filer_window
= view_collection
->filer_window
;
723 CollectionItem
*colitem
= &collection
->items
[i
];
724 ViewData
*view_data
= (ViewData
*) colitem
->view_data
;
728 collection_item_to_rowcol(collection
, i
, &row
, &col
);
730 g_return_if_fail(iter
->view
== (ViewIface
*) view_collection
);
731 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
733 /* TODO: What if the window is narrower than 1 column? */
734 if (filer_window
->display_style
== LARGE_ICONS
||
735 filer_window
->display_style
== HUGE_ICONS
)
736 return; /* These wrap rather than truncate */
738 area
.x
= col
* collection
->item_width
;
739 area
.y
= row
* collection
->item_height
;
740 area
.height
= collection
->item_height
;
742 if (col
== collection
->columns
- 1)
743 area
.width
= GTK_WIDGET(collection
)->allocation
.width
- area
.x
;
745 area
.width
= collection
->item_width
;
747 fill_template(&area
, colitem
, view_collection
, &template);
749 if (template.leafname
.width
< view_data
->name_width
)
751 DirItem
*item
= (DirItem
*) collection
->items
[i
].data
;
753 g_string_append(tip
, item
->leafname
);
754 g_string_append_c(tip
, '\n');
758 static gint
coll_motion_notify(GtkWidget
*widget
,
759 GdkEventMotion
*event
,
760 ViewCollection
*view_collection
)
762 return filer_motion_notify(view_collection
->filer_window
, event
);
765 /* Viewport is to be resized, so calculate increments */
766 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
)
768 Collection
*col
= ((ViewCollection
*) data
)->collection
;
770 col
->vadj
->step_increment
= col
->item_height
;
771 col
->vadj
->page_increment
= col
->vadj
->page_size
;
774 static gint
coll_button_release(GtkWidget
*widget
,
775 GdkEventButton
*event
,
776 ViewCollection
*view_collection
)
778 if (dnd_motion_release(event
))
780 if (motion_buttons_pressed
== 0 &&
781 view_collection
->collection
->lasso_box
)
783 filer_set_autoscroll(view_collection
->filer_window
,
785 collection_end_lasso(view_collection
->collection
,
786 event
->button
== 1 ? GDK_SET
: GDK_INVERT
);
791 filer_perform_action(view_collection
->filer_window
, event
);
796 static gint
coll_button_press(GtkWidget
*widget
,
797 GdkEventButton
*event
,
798 ViewCollection
*view_collection
)
800 collection_set_cursor_item(view_collection
->collection
, -1, TRUE
);
802 if (dnd_motion_press(widget
, event
))
803 filer_perform_action(view_collection
->filer_window
, event
);
808 /* Nothing is selected anymore - give up primary */
809 static void lost_selection(Collection
*collection
,
813 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
815 filer_lost_selection(view_collection
->filer_window
, time
);
818 static void selection_changed(Collection
*collection
,
822 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
824 filer_selection_changed(view_collection
->filer_window
, time
);
827 static void display_free_colitem(Collection
*collection
,
828 CollectionItem
*colitem
)
830 ViewData
*view
= (ViewData
*) colitem
->view_data
;
837 g_object_unref(G_OBJECT(view
->layout
));
841 g_object_unref(G_OBJECT(view
->details
));
844 g_object_unref(view
->image
);
849 static void add_item(ViewCollection
*view_collection
, DirItem
*item
)
851 Collection
*collection
= view_collection
->collection
;
852 FilerWindow
*filer_window
= view_collection
->filer_window
;
853 int old_w
= collection
->item_width
;
854 int old_h
= collection
->item_height
;
857 i
= collection_insert(collection
, item
,
858 display_create_viewdata(filer_window
, item
));
860 calc_size(filer_window
, &collection
->items
[i
], &w
, &h
);
862 if (w
> old_w
|| h
> old_h
)
863 collection_set_item_size(collection
,
868 static void style_set(Collection
*collection
,
870 ViewCollection
*view_collection
)
872 view_collection_style_changed(VIEW(view_collection
),
873 VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
);
876 /* Return the size needed for this item */
877 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
878 int *width
, int *height
)
880 int pix_width
, pix_height
;
882 DisplayStyle style
= filer_window
->display_style
;
883 ViewData
*view
= (ViewData
*) colitem
->view_data
;
885 if (filer_window
->details_type
== DETAILS_NONE
)
887 if (style
== HUGE_ICONS
)
891 if (!view
->image
->huge_pixbuf
)
892 pixmap_make_huge(view
->image
);
893 pix_width
= view
->image
->huge_width
;
894 pix_height
= view
->image
->huge_height
;
898 pix_width
= HUGE_WIDTH
* 3 / 2;
899 pix_height
= HUGE_HEIGHT
* 3 / 2;
901 *width
= MAX(pix_width
, view
->name_width
) + 4;
902 *height
= MAX(view
->name_height
+ pix_height
+ 4,
903 HUGE_HEIGHT
* 3 / 4);
905 else if (style
== SMALL_ICONS
)
907 w
= MIN(view
->name_width
, o_small_width
.int_value
);
908 *width
= SMALL_WIDTH
+ 12 + w
;
909 *height
= MAX(view
->name_height
, SMALL_HEIGHT
) + 4;
914 pix_width
= view
->image
->width
;
916 pix_width
= ICON_WIDTH
;
917 *width
= MAX(pix_width
, view
->name_width
) + 4;
918 *height
= view
->name_height
+ ICON_HEIGHT
+ 2;
923 w
= view
->details_width
;
924 if (style
== HUGE_ICONS
)
926 *width
= HUGE_WIDTH
+ 12 + MAX(w
, view
->name_width
);
927 *height
= HUGE_HEIGHT
- 4;
929 else if (style
== SMALL_ICONS
)
933 *width
= SMALL_WIDTH
+ view
->name_width
+ 12 + w
;
934 text_height
= MAX(view
->name_height
,
935 view
->details_height
);
936 *height
= MAX(text_height
, SMALL_HEIGHT
) + 4;
940 *width
= ICON_WIDTH
+ 12 + MAX(w
, view
->name_width
);
941 *height
= ICON_HEIGHT
;
946 static void update_item(ViewCollection
*view_collection
, int i
)
948 Collection
*collection
= view_collection
->collection
;
949 int old_w
= collection
->item_width
;
950 int old_h
= collection
->item_height
;
952 CollectionItem
*colitem
;
953 FilerWindow
*filer_window
= view_collection
->filer_window
;
955 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
957 colitem
= &collection
->items
[i
];
959 display_update_view(filer_window
,
960 (DirItem
*) colitem
->data
,
961 (ViewData
*) colitem
->view_data
,
964 calc_size(filer_window
, colitem
, &w
, &h
);
965 if (w
> old_w
|| h
> old_h
)
966 collection_set_item_size(collection
,
970 collection_draw_item(collection
, i
, TRUE
);
973 /* Implementations of the View interface. See view_iface.c for comments. */
975 static void view_collection_style_changed(ViewIface
*view
, int flags
)
977 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
978 FilerWindow
*filer_window
= view_collection
->filer_window
;
980 Collection
*col
= view_collection
->collection
;
981 int width
= MIN_ITEM_WIDTH
;
982 int height
= SMALL_HEIGHT
;
983 int n
= col
->number_of_items
;
985 if (n
== 0 && filer_window
->display_style
!= SMALL_ICONS
)
986 height
= ICON_HEIGHT
;
988 view_collection
->collection
->vertical_order
= FALSE
;
989 if (filer_window
->display_style
== SMALL_ICONS
&&
990 o_vertical_order_small
.int_value
)
991 view_collection
->collection
->vertical_order
= TRUE
;
992 if (filer_window
->display_style
!= SMALL_ICONS
&&
993 o_vertical_order_large
.int_value
)
994 view_collection
->collection
->vertical_order
= TRUE
;
999 /* Recalculate all the ViewData structs for this window
1000 * (needed if the text or image has changed in any way) and
1001 * get the size of each item.
1003 for (i
= 0; i
< n
; i
++)
1005 CollectionItem
*ci
= &col
->items
[i
];
1008 if (flags
& (VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
))
1009 display_update_view(filer_window
,
1010 (DirItem
*) ci
->data
,
1011 (ViewData
*) ci
->view_data
,
1012 (flags
& VIEW_UPDATE_NAME
) != 0);
1014 calc_size(filer_window
, ci
, &w
, &h
);
1021 collection_set_item_size(col
, width
, height
);
1023 gtk_widget_queue_draw(GTK_WIDGET(view_collection
));
1026 typedef int (*SortFn
)(gconstpointer a
, gconstpointer b
);
1028 static SortFn
sort_fn(FilerWindow
*fw
)
1030 switch (fw
->sort_type
)
1032 case SORT_NAME
: return sort_by_name
;
1033 case SORT_TYPE
: return sort_by_type
;
1034 case SORT_DATE
: return sort_by_date
;
1035 case SORT_SIZE
: return sort_by_size
;
1036 case SORT_OWNER
: return sort_by_owner
;
1037 case SORT_GROUP
: return sort_by_group
;
1039 g_assert_not_reached();
1045 static void view_collection_sort(ViewIface
*view
)
1047 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1048 FilerWindow
*filer_window
= view_collection
->filer_window
;
1050 collection_qsort(view_collection
->collection
, sort_fn(filer_window
),
1051 filer_window
->sort_order
);
1054 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
)
1056 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1057 Collection
*collection
= view_collection
->collection
;
1058 FilerWindow
*filer_window
= view_collection
->filer_window
;
1061 old_num
= collection
->number_of_items
;
1062 for (i
= 0; i
< items
->len
; i
++)
1064 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1065 char *leafname
= item
->leafname
;
1067 if (!filer_match_filter(filer_window
, leafname
))
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
;
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
;
1098 if (!filer_match_filter(filer_window
, leafname
))
1101 j
= collection_find_item(collection
, item
,
1102 sort_fn(filer_window
),
1103 filer_window
->sort_order
);
1106 g_warning("Failed to find '%s'\n", leafname
);
1108 update_item(view_collection
, j
);
1112 static void view_collection_delete_if(ViewIface
*view
,
1113 gboolean (*test
)(gpointer item
, 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
;
1176 int n
= collection
->number_of_items
;
1177 int flags
= iter
->flags
;
1179 iter
->peek
= iter_peek
;
1181 if (iter
->n_remaining
== 0)
1184 if (flags
& VIEW_ITER_FROM_CURSOR
)
1186 i
= collection
->cursor_item
;
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
)
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
--;
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
;
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
)
1233 iter
->n_remaining
--;
1238 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1240 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1241 !collection
->items
[i
].selected
)
1245 return collection
->items
[i
].data
;
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
;
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
)
1268 iter
->n_remaining
--;
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
)
1280 return collection
->items
[i
].data
;
1287 static DirItem
*iter_peek(ViewIter
*iter
)
1289 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
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
,
1303 Collection
*collection
= view_collection
->collection
;
1305 iter
->view
= (ViewIface
*) view_collection
;
1306 iter
->next
= iter_init
;
1310 iter
->flags
= flags
;
1312 if (flags
& VIEW_ITER_ONE_ONLY
)
1314 iter
->n_remaining
= 1;
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);
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
;
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
,
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
);
1387 collection_select_item(collection
, iter
->i
);
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
;
1423 collection
->block_selection_changed
++;
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
;
1436 collection_wink_item(collection
, -1);
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
;
1453 int w
= collection
->item_width
;
1454 int h
= collection
->item_height
;
1457 int max_x
, max_rows
;
1458 const float r
= 2.5;
1462 /* Get the extra height required for the toolbar and minibuffer,
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
))
1473 gtk_widget_size_request(filer_window
->minibuffer_area
, &req
);
1474 space
= req
.height
+ 2;
1478 n
= collection
->number_of_items
;
1480 h
= ICON_HEIGHT
* 1.5;
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:
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))
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;
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
)
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.
1531 space
= filer_window
->display_style
== SMALL_ICONS
? h
: 2;
1533 filer_window_set_size(filer_window
,
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
)
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
;
1584 GdkModifierType mask
;
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
;
1602 diff_vpos(collection
, diff
);