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 gboolean
view_collection_autoselect(ViewIface
*view
, const gchar
*leaf
);
143 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
);
144 static void view_collection_update_items(ViewIface
*view
, GPtrArray
*items
);
145 static void view_collection_delete_if(ViewIface
*view
,
146 gboolean (*test
)(gpointer item
, gpointer data
),
148 static void view_collection_clear(ViewIface
*view
);
149 static void view_collection_select_all(ViewIface
*view
);
150 static void view_collection_clear_selection(ViewIface
*view
);
151 static int view_collection_count_items(ViewIface
*view
);
152 static int view_collection_count_selected(ViewIface
*view
);
153 static void view_collection_show_cursor(ViewIface
*view
);
154 static void view_collection_get_iter(ViewIface
*view
,
155 ViewIter
*iter
, IterFlags flags
);
156 static void view_collection_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
157 GdkWindow
*src
, int x
, int y
);
158 static void view_collection_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
159 static void view_collection_set_selected(ViewIface
*view
,
162 static gboolean
view_collection_get_selected(ViewIface
*view
, ViewIter
*iter
);
163 static void view_collection_select_only(ViewIface
*view
, ViewIter
*iter
);
164 static void view_collection_set_frozen(ViewIface
*view
, gboolean frozen
);
165 static void view_collection_wink_item(ViewIface
*view
, ViewIter
*iter
);
166 static void view_collection_autosize(ViewIface
*view
);
167 static gboolean
view_collection_cursor_visible(ViewIface
*view
);
168 static void view_collection_set_base(ViewIface
*view
, ViewIter
*iter
);
169 static void view_collection_start_lasso_box(ViewIface
*view
,
170 GdkEventButton
*event
);
171 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
173 static gboolean
view_collection_auto_scroll_callback(ViewIface
*view
);
175 static DirItem
*iter_next(ViewIter
*iter
);
176 static DirItem
*iter_prev(ViewIter
*iter
);
177 static DirItem
*iter_peek(ViewIter
*iter
);
180 /****************************************************************
181 * EXTERNAL INTERFACE *
182 ****************************************************************/
184 GtkWidget
*view_collection_new(FilerWindow
*filer_window
)
186 ViewCollection
*view_collection
;
188 view_collection
= g_object_new(view_collection_get_type(), NULL
);
189 view_collection
->filer_window
= filer_window
;
191 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
192 view_collection
->collection
->vadj
);
194 return GTK_WIDGET(view_collection
);
197 GType
view_collection_get_type(void)
199 static GType type
= 0;
203 static const GTypeInfo info
=
205 sizeof (ViewCollectionClass
),
206 NULL
, /* base_init */
207 NULL
, /* base_finalise */
208 view_collection_class_init
,
209 NULL
, /* class_finalise */
210 NULL
, /* class_data */
211 sizeof(ViewCollection
),
215 static const GInterfaceInfo iface_info
=
217 view_collection_iface_init
, NULL
, NULL
220 type
= g_type_register_static(gtk_viewport_get_type(),
221 "ViewCollection", &info
, 0);
222 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
, &iface_info
);
228 /****************************************************************
229 * INTERNAL FUNCTIONS *
230 ****************************************************************/
232 static void view_collection_destroy(GtkObject
*view_collection
)
234 VIEW_COLLECTION(view_collection
)->filer_window
= NULL
;
237 static void view_collection_finialize(GObject
*object
)
239 /* ViewCollection *view_collection = (ViewCollection *) object; */
241 G_OBJECT_CLASS(parent_class
)->finalize(object
);
244 static void view_collection_class_init(gpointer gclass
, gpointer data
)
246 GObjectClass
*object
= (GObjectClass
*) gclass
;
248 parent_class
= g_type_class_peek_parent(gclass
);
250 object
->finalize
= view_collection_finialize
;
251 GTK_OBJECT_CLASS(object
)->destroy
= view_collection_destroy
;
254 static void view_collection_init(GTypeInstance
*object
, gpointer gclass
)
256 ViewCollection
*view_collection
= (ViewCollection
*) object
;
257 GtkViewport
*viewport
= (GtkViewport
*) object
;
258 GtkWidget
*collection
;
261 collection
= collection_new();
262 view_collection
->collection
= COLLECTION(collection
);
264 adj
= view_collection
->collection
->vadj
;
265 gtk_viewport_set_vadjustment(viewport
, adj
);
266 gtk_viewport_set_hadjustment(viewport
, NULL
); /* Or Gtk will crash */
267 gtk_viewport_set_shadow_type(viewport
, GTK_SHADOW_NONE
);
268 gtk_container_add(GTK_CONTAINER(object
), collection
);
269 gtk_widget_show(collection
);
270 gtk_widget_set_size_request(GTK_WIDGET(view_collection
), 4, 4);
272 gtk_container_set_resize_mode(GTK_CONTAINER(viewport
),
273 GTK_RESIZE_IMMEDIATE
);
275 view_collection
->collection
->free_item
= display_free_colitem
;
276 view_collection
->collection
->draw_item
= draw_item
;
277 view_collection
->collection
->test_point
= test_point
;
278 view_collection
->collection
->cb_user_data
= view_collection
;
280 g_signal_connect(collection
, "style_set",
281 G_CALLBACK(style_set
),
284 g_signal_connect(collection
, "lose_selection",
285 G_CALLBACK(lost_selection
), view_collection
);
286 g_signal_connect(collection
, "selection_changed",
287 G_CALLBACK(selection_changed
), view_collection
);
289 g_signal_connect(collection
, "button-release-event",
290 G_CALLBACK(coll_button_release
), view_collection
);
291 g_signal_connect(collection
, "button-press-event",
292 G_CALLBACK(coll_button_press
), view_collection
);
293 g_signal_connect(collection
, "motion-notify-event",
294 G_CALLBACK(coll_motion_notify
), view_collection
);
295 g_signal_connect(viewport
, "size-allocate",
296 G_CALLBACK(size_allocate
), view_collection
);
298 gtk_widget_set_events(collection
,
299 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
300 GDK_BUTTON3_MOTION_MASK
| GDK_POINTER_MOTION_MASK
|
301 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
);
305 static void draw_item(GtkWidget
*widget
,
306 CollectionItem
*colitem
,
310 DirItem
*item
= (DirItem
*) colitem
->data
;
311 gboolean selected
= colitem
->selected
;
313 ViewData
*view
= (ViewData
*) colitem
->view_data
;
314 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
315 FilerWindow
*filer_window
= view_collection
->filer_window
;
316 GtkStateType selection_state
;
318 g_return_if_fail(view
!= NULL
);
321 selection_state
= filer_window
->selection_state
;
323 selection_state
= GTK_STATE_NORMAL
;
325 fill_template(area
, colitem
, view_collection
, &template);
327 /* Set up GC for coloured file types */
329 type_gc
= gdk_gc_new(widget
->window
);
331 gdk_gc_set_foreground(type_gc
, type_get_colour(item
,
332 &widget
->style
->fg
[GTK_STATE_NORMAL
]));
334 if (template.icon
.width
<= SMALL_WIDTH
&&
335 template.icon
.height
<= SMALL_HEIGHT
)
337 draw_small_icon(widget
->window
, &template.icon
,
338 item
, view
->image
, selected
);
340 else if (template.icon
.width
<= ICON_WIDTH
&&
341 template.icon
.height
<= ICON_HEIGHT
)
343 draw_large_icon(widget
->window
, &template.icon
,
344 item
, view
->image
, selected
);
348 draw_huge_icon(widget
->window
, &template.icon
,
349 item
, view
->image
, selected
);
352 draw_string(widget
, view
->layout
,
358 draw_string(widget
, view
->details
,
360 template.details
.width
,
365 /* A template contains the locations of the three rectangles (for the icon,
366 * name and extra details).
367 * Fill in the empty 'template' with the rectanges for this item.
369 static void fill_template(GdkRectangle
*area
, CollectionItem
*colitem
,
370 ViewCollection
*view_collection
, Template
*template)
372 DisplayStyle style
= view_collection
->filer_window
->display_style
;
373 ViewData
*view
= (ViewData
*) colitem
->view_data
;
377 template->details
.width
= view
->details_width
;
378 template->details
.height
= view
->details_height
;
380 if (style
== SMALL_ICONS
)
381 small_full_template(area
, colitem
,
382 view_collection
, template);
383 else if (style
== LARGE_ICONS
)
384 large_full_template(area
, colitem
,
385 view_collection
, template);
387 huge_full_template(area
, colitem
,
388 view_collection
, template);
392 if (style
== HUGE_ICONS
)
393 huge_template(area
, colitem
,
394 view_collection
, template);
395 else if (style
== LARGE_ICONS
)
396 large_template(area
, colitem
,
397 view_collection
, template);
399 small_template(area
, colitem
,
400 view_collection
, template);
404 static void huge_template(GdkRectangle
*area
, CollectionItem
*colitem
,
405 ViewCollection
*view_collection
, Template
*template)
407 int col_width
= view_collection
->collection
->item_width
;
409 ViewData
*view
= (ViewData
*) colitem
->view_data
;
410 MaskedPixmap
*image
= view
->image
;
414 if (!image
->huge_pixbuf
)
415 pixmap_make_huge(image
);
416 template->icon
.width
= image
->huge_width
;
417 template->icon
.height
= image
->huge_height
;
421 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
422 template->icon
.height
= HUGE_HEIGHT
;
425 template->leafname
.width
= view
->name_width
;
426 template->leafname
.height
= view
->name_height
;
428 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
429 text_y
= area
->y
+ area
->height
- template->leafname
.height
;
431 template->leafname
.x
= text_x
;
432 template->leafname
.y
= text_y
;
434 template->icon
.x
= area
->x
+ ((col_width
- template->icon
.width
) >> 1);
435 template->icon
.y
= template->leafname
.y
- template->icon
.height
- 2;
438 static void large_template(GdkRectangle
*area
, CollectionItem
*colitem
,
439 ViewCollection
*view_collection
, Template
*template)
441 int col_width
= view_collection
->collection
->item_width
;
445 ViewData
*view
= (ViewData
*) colitem
->view_data
;
446 MaskedPixmap
*image
= view
->image
;
452 iwidth
= MIN(image
->width
, ICON_WIDTH
);
453 iheight
= MIN(image
->height
+ 6, ICON_HEIGHT
);
458 iheight
= ICON_HEIGHT
;
460 image_x
= area
->x
+ ((col_width
- iwidth
) >> 1);
462 template->leafname
.width
= view
->name_width
;
463 template->leafname
.height
= view
->name_height
;
465 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
466 text_y
= area
->y
+ ICON_HEIGHT
+ 2;
468 template->leafname
.x
= text_x
;
469 template->leafname
.y
= text_y
;
471 image_y
= text_y
- iheight
;
472 image_y
= MAX(area
->y
, image_y
);
474 template->icon
.x
= image_x
;
475 template->icon
.y
= image_y
;
476 template->icon
.width
= iwidth
;
477 template->icon
.height
= MIN(ICON_HEIGHT
, iheight
);
480 static void small_template(GdkRectangle
*area
, CollectionItem
*colitem
,
481 ViewCollection
*view_collection
, Template
*template)
483 int text_x
= area
->x
+ SMALL_WIDTH
+ 4;
485 int max_text_width
= area
->width
- SMALL_WIDTH
- 4;
486 ViewData
*view
= (ViewData
*) colitem
->view_data
;
488 low_text_y
= area
->y
+ area
->height
/ 2 - view
->name_height
/ 2;
490 template->leafname
.x
= text_x
;
491 template->leafname
.y
= low_text_y
;
492 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
493 template->leafname
.height
= view
->name_height
;
495 template->icon
.x
= area
->x
;
496 template->icon
.y
= area
->y
+ 1;
497 template->icon
.width
= SMALL_WIDTH
;
498 template->icon
.height
= SMALL_HEIGHT
;
501 static void huge_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
502 ViewCollection
*view_collection
, Template
*template)
504 int max_text_width
= area
->width
- HUGE_WIDTH
- 4;
505 ViewData
*view
= (ViewData
*) colitem
->view_data
;
506 MaskedPixmap
*image
= view
->image
;
510 if (!image
->huge_pixbuf
)
511 pixmap_make_huge(image
);
512 template->icon
.width
= image
->huge_width
;
513 template->icon
.height
= image
->huge_height
;
517 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
518 template->icon
.height
= HUGE_HEIGHT
;
521 template->icon
.x
= area
->x
+ (HUGE_WIDTH
- template->icon
.width
) / 2;
522 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
524 template->leafname
.x
= area
->x
+ HUGE_WIDTH
+ 4;
525 template->leafname
.y
= area
->y
+ area
->height
/ 2
526 - (view
->name_height
+ 2 + view
->details_height
) / 2;
527 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
528 template->leafname
.height
= view
->name_height
;
531 return; /* Not scanned yet */
533 template->details
.x
= template->leafname
.x
;
534 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
537 static void large_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
538 ViewCollection
*view_collection
, Template
*template)
540 int max_text_width
= area
->width
- ICON_WIDTH
- 4;
541 ViewData
*view
= (ViewData
*) colitem
->view_data
;
542 MaskedPixmap
*image
= view
->image
;
546 template->icon
.width
= image
->width
;
547 template->icon
.height
= image
->height
;
551 template->icon
.width
= ICON_WIDTH
;
552 template->icon
.height
= ICON_HEIGHT
;
555 template->icon
.x
= area
->x
+ (ICON_WIDTH
- template->icon
.width
) / 2;
556 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
559 template->leafname
.x
= area
->x
+ ICON_WIDTH
+ 4;
560 template->leafname
.y
= area
->y
+ area
->height
/ 2
561 - (view
->name_height
+ 2 + view
->details_height
) / 2;
562 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
563 template->leafname
.height
= view
->name_height
;
566 return; /* Not scanned yet */
568 template->details
.x
= template->leafname
.x
;
569 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
572 static void small_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
573 ViewCollection
*view_collection
, Template
*template)
575 int col_width
= view_collection
->collection
->item_width
;
576 ViewData
*view
= (ViewData
*) colitem
->view_data
;
578 small_template(area
, colitem
, view_collection
, template);
581 return; /* Not scanned yet */
583 template->details
.x
= area
->x
+ col_width
- template->details
.width
;
584 template->details
.y
= area
->y
+ area
->height
/ 2 - \
585 view
->details_height
/ 2;
588 #define INSIDE(px, py, area) \
589 (px >= area.x && py >= area.y && \
590 px <= area.x + area.width && py <= area.y + area.height)
592 static gboolean
test_point(Collection
*collection
,
593 int point_x
, int point_y
,
594 CollectionItem
*colitem
,
595 int width
, int height
,
600 ViewData
*view
= (ViewData
*) colitem
->view_data
;
601 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
606 area
.height
= height
;
608 fill_template(&area
, colitem
, view_collection
, &template);
610 return INSIDE(point_x
, point_y
, template.leafname
) ||
611 INSIDE(point_x
, point_y
, template.icon
) ||
612 (view
->details
&& INSIDE(point_x
, point_y
, template.details
));
615 /* 'box' renders a background box if the string is also selected */
616 static void draw_string(GtkWidget
*widget
,
618 GdkRectangle
*area
, /* Area available on screen */
619 int width
, /* Width of the full string */
620 GtkStateType selection_state
,
623 GdkGC
*gc
= selection_state
== GTK_STATE_NORMAL
625 : widget
->style
->fg_gc
[selection_state
];
627 if (selection_state
!= GTK_STATE_NORMAL
&& box
)
628 gtk_paint_flat_box(widget
->style
, widget
->window
,
629 selection_state
, GTK_SHADOW_NONE
,
630 NULL
, widget
, "text",
632 MIN(width
, area
->width
),
635 if (width
> area
->width
)
637 gdk_gc_set_clip_origin(gc
, 0, 0);
638 gdk_gc_set_clip_rectangle(gc
, area
);
641 gdk_draw_layout(widget
->window
, gc
, area
->x
, area
->y
, layout
);
643 if (width
> area
->width
)
645 static GdkGC
*red_gc
= NULL
;
650 GdkColor red
= {0, 0xffff, 0, 0};
652 red_gc
= gdk_gc_new(widget
->window
);
653 gdk_colormap_alloc_colors(
654 gtk_widget_get_colormap(widget
),
655 &red
, 1, FALSE
, TRUE
, &success
);
656 gdk_gc_set_foreground(red_gc
, &red
);
658 gdk_draw_rectangle(widget
->window
, red_gc
, TRUE
,
659 area
->x
+ area
->width
- 1, area
->y
,
661 gdk_gc_set_clip_rectangle(gc
, NULL
);
665 /* Create the handers for the View interface */
666 static void view_collection_iface_init(gpointer giface
, gpointer iface_data
)
668 ViewIfaceClass
*iface
= giface
;
670 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
673 iface
->sort
= view_collection_sort
;
674 iface
->style_changed
= view_collection_style_changed
;
675 iface
->autoselect
= view_collection_autoselect
;
676 iface
->add_items
= view_collection_add_items
;
677 iface
->update_items
= view_collection_update_items
;
678 iface
->delete_if
= view_collection_delete_if
;
679 iface
->clear
= view_collection_clear
;
680 iface
->select_all
= view_collection_select_all
;
681 iface
->clear_selection
= view_collection_clear_selection
;
682 iface
->count_items
= view_collection_count_items
;
683 iface
->count_selected
= view_collection_count_selected
;
684 iface
->show_cursor
= view_collection_show_cursor
;
685 iface
->get_iter
= view_collection_get_iter
;
686 iface
->get_iter_at_point
= view_collection_get_iter_at_point
;
687 iface
->cursor_to_iter
= view_collection_cursor_to_iter
;
688 iface
->set_selected
= view_collection_set_selected
;
689 iface
->get_selected
= view_collection_get_selected
;
690 iface
->set_frozen
= view_collection_set_frozen
;
691 iface
->select_only
= view_collection_select_only
;
692 iface
->wink_item
= view_collection_wink_item
;
693 iface
->autosize
= view_collection_autosize
;
694 iface
->cursor_visible
= view_collection_cursor_visible
;
695 iface
->set_base
= view_collection_set_base
;
696 iface
->start_lasso_box
= view_collection_start_lasso_box
;
697 iface
->extend_tip
= view_collection_extend_tip
;
698 iface
->auto_scroll_callback
= view_collection_auto_scroll_callback
;
701 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
704 ViewCollection
*view_collection
= (ViewCollection
*) view
;
705 Collection
*collection
= view_collection
->collection
;
706 FilerWindow
*filer_window
= view_collection
->filer_window
;
709 CollectionItem
*colitem
= &collection
->items
[i
];
710 int col
= i
% collection
->columns
;
711 int row
= i
/ collection
->columns
;
712 ViewData
*view_data
= (ViewData
*) colitem
->view_data
;
715 g_return_if_fail(iter
->view
== (ViewIface
*) view_collection
);
716 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
718 /* TODO: What if the window is narrower than 1 column? */
719 if (filer_window
->display_style
== LARGE_ICONS
||
720 filer_window
->display_style
== HUGE_ICONS
)
721 return; /* These wrap rather than truncate */
723 area
.x
= col
* collection
->item_width
;
724 area
.y
= row
* collection
->item_height
;
725 area
.height
= collection
->item_height
;
727 if (col
== collection
->columns
- 1)
728 area
.width
= GTK_WIDGET(collection
)->allocation
.width
- area
.x
;
730 area
.width
= collection
->item_width
;
732 fill_template(&area
, colitem
, view_collection
, &template);
734 if (template.leafname
.width
< view_data
->name_width
)
736 DirItem
*item
= (DirItem
*) collection
->items
[i
].data
;
738 g_string_append(tip
, item
->leafname
);
739 g_string_append_c(tip
, '\n');
743 static gint
coll_motion_notify(GtkWidget
*widget
,
744 GdkEventMotion
*event
,
745 ViewCollection
*view_collection
)
747 return filer_motion_notify(view_collection
->filer_window
, event
);
750 /* Viewport is to be resized, so calculate increments */
751 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
)
753 Collection
*col
= ((ViewCollection
*) data
)->collection
;
755 col
->vadj
->step_increment
= col
->item_height
;
756 col
->vadj
->page_increment
= col
->vadj
->page_size
;
759 static gint
coll_button_release(GtkWidget
*widget
,
760 GdkEventButton
*event
,
761 ViewCollection
*view_collection
)
763 if (dnd_motion_release(event
))
765 if (motion_buttons_pressed
== 0 &&
766 view_collection
->collection
->lasso_box
)
768 filer_set_autoscroll(view_collection
->filer_window
,
770 collection_end_lasso(view_collection
->collection
,
771 event
->button
== 1 ? GDK_SET
: GDK_INVERT
);
776 filer_perform_action(view_collection
->filer_window
, event
);
781 static gint
coll_button_press(GtkWidget
*widget
,
782 GdkEventButton
*event
,
783 ViewCollection
*view_collection
)
785 collection_set_cursor_item(view_collection
->collection
, -1, TRUE
);
787 if (dnd_motion_press(widget
, event
))
788 filer_perform_action(view_collection
->filer_window
, event
);
793 /* Nothing is selected anymore - give up primary */
794 static void lost_selection(Collection
*collection
,
798 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
800 filer_lost_selection(view_collection
->filer_window
, time
);
803 static void selection_changed(Collection
*collection
,
807 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
809 filer_selection_changed(view_collection
->filer_window
, time
);
812 static void display_free_colitem(Collection
*collection
,
813 CollectionItem
*colitem
)
815 ViewData
*view
= (ViewData
*) colitem
->view_data
;
822 g_object_unref(G_OBJECT(view
->layout
));
826 g_object_unref(G_OBJECT(view
->details
));
829 g_object_unref(view
->image
);
834 static void add_item(ViewCollection
*view_collection
, DirItem
*item
)
836 Collection
*collection
= view_collection
->collection
;
837 FilerWindow
*filer_window
= view_collection
->filer_window
;
838 int old_w
= collection
->item_width
;
839 int old_h
= collection
->item_height
;
842 i
= collection_insert(collection
, item
,
843 display_create_viewdata(filer_window
, item
));
845 calc_size(filer_window
, &collection
->items
[i
], &w
, &h
);
847 if (w
> old_w
|| h
> old_h
)
848 collection_set_item_size(collection
,
853 static void style_set(Collection
*collection
,
855 ViewCollection
*view_collection
)
857 view_collection_style_changed(VIEW(view_collection
),
858 VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
);
861 /* Return the size needed for this item */
862 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
863 int *width
, int *height
)
865 int pix_width
, pix_height
;
867 DisplayStyle style
= filer_window
->display_style
;
868 ViewData
*view
= (ViewData
*) colitem
->view_data
;
870 if (filer_window
->details_type
== DETAILS_NONE
)
872 if (style
== HUGE_ICONS
)
876 if (!view
->image
->huge_pixbuf
)
877 pixmap_make_huge(view
->image
);
878 pix_width
= view
->image
->huge_width
;
879 pix_height
= view
->image
->huge_height
;
883 pix_width
= HUGE_WIDTH
* 3 / 2;
884 pix_height
= HUGE_HEIGHT
* 3 / 2;
886 *width
= MAX(pix_width
, view
->name_width
) + 4;
887 *height
= MAX(view
->name_height
+ pix_height
+ 4,
888 HUGE_HEIGHT
* 3 / 4);
890 else if (style
== SMALL_ICONS
)
892 w
= MIN(view
->name_width
, o_small_width
.int_value
);
893 *width
= SMALL_WIDTH
+ 12 + w
;
894 *height
= MAX(view
->name_height
, SMALL_HEIGHT
) + 4;
899 pix_width
= view
->image
->width
;
901 pix_width
= ICON_WIDTH
;
902 *width
= MAX(pix_width
, view
->name_width
) + 4;
903 *height
= view
->name_height
+ ICON_HEIGHT
+ 2;
908 w
= view
->details_width
;
909 if (style
== HUGE_ICONS
)
911 *width
= HUGE_WIDTH
+ 12 + MAX(w
, view
->name_width
);
912 *height
= HUGE_HEIGHT
- 4;
914 else if (style
== SMALL_ICONS
)
918 *width
= SMALL_WIDTH
+ view
->name_width
+ 12 + w
;
919 text_height
= MAX(view
->name_height
,
920 view
->details_height
);
921 *height
= MAX(text_height
, SMALL_HEIGHT
) + 4;
925 *width
= ICON_WIDTH
+ 12 + MAX(w
, view
->name_width
);
926 *height
= ICON_HEIGHT
;
931 static void update_item(ViewCollection
*view_collection
, int i
)
933 Collection
*collection
= view_collection
->collection
;
934 int old_w
= collection
->item_width
;
935 int old_h
= collection
->item_height
;
937 CollectionItem
*colitem
;
938 FilerWindow
*filer_window
= view_collection
->filer_window
;
940 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
942 colitem
= &collection
->items
[i
];
944 display_update_view(filer_window
,
945 (DirItem
*) colitem
->data
,
946 (ViewData
*) colitem
->view_data
,
949 calc_size(filer_window
, colitem
, &w
, &h
);
950 if (w
> old_w
|| h
> old_h
)
951 collection_set_item_size(collection
,
955 collection_draw_item(collection
, i
, TRUE
);
958 /* Implementations of the View interface. See view_iface.c for comments. */
960 static void view_collection_style_changed(ViewIface
*view
, int flags
)
962 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
963 FilerWindow
*filer_window
= view_collection
->filer_window
;
965 Collection
*col
= view_collection
->collection
;
966 int width
= MIN_ITEM_WIDTH
;
967 int height
= SMALL_HEIGHT
;
968 int n
= col
->number_of_items
;
970 if (n
== 0 && filer_window
->display_style
!= SMALL_ICONS
)
971 height
= ICON_HEIGHT
;
973 /* Recalculate all the ViewData structs for this window
974 * (needed if the text or image has changed in any way) and
975 * get the size of each item.
977 for (i
= 0; i
< n
; i
++)
979 CollectionItem
*ci
= &col
->items
[i
];
982 if (flags
& (VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
))
983 display_update_view(filer_window
,
984 (DirItem
*) ci
->data
,
985 (ViewData
*) ci
->view_data
,
986 (flags
& VIEW_UPDATE_NAME
) != 0);
988 calc_size(filer_window
, ci
, &w
, &h
);
995 collection_set_item_size(col
, width
, height
);
997 gtk_widget_queue_draw(GTK_WIDGET(view_collection
));
1000 typedef int (*SortFn
)(gconstpointer a
, gconstpointer b
);
1002 static SortFn
sort_fn(FilerWindow
*fw
)
1004 switch (fw
->sort_type
)
1006 case SORT_NAME
: return sort_by_name
;
1007 case SORT_TYPE
: return sort_by_type
;
1008 case SORT_DATE
: return sort_by_date
;
1009 case SORT_SIZE
: return sort_by_size
;
1010 case SORT_OWNER
: return sort_by_owner
;
1011 case SORT_GROUP
: return sort_by_group
;
1013 g_assert_not_reached();
1019 static void view_collection_sort(ViewIface
*view
)
1021 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1022 FilerWindow
*filer_window
= view_collection
->filer_window
;
1024 collection_qsort(view_collection
->collection
, sort_fn(filer_window
),
1025 filer_window
->sort_order
);
1028 static gboolean
view_collection_autoselect(ViewIface
*view
, const gchar
*leaf
)
1030 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1031 Collection
*col
= view_collection
->collection
;
1034 for (i
= 0; i
< col
->number_of_items
; i
++)
1036 DirItem
*item
= (DirItem
*) col
->items
[i
].data
;
1038 if (strcmp(item
->leafname
, leaf
) == 0)
1040 if (col
->cursor_item
!= -1)
1041 collection_set_cursor_item(col
, i
, TRUE
);
1043 collection_wink_item(col
, i
);
1051 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
)
1053 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1054 Collection
*collection
= view_collection
->collection
;
1055 FilerWindow
*filer_window
= view_collection
->filer_window
;
1058 old_num
= collection
->number_of_items
;
1059 for (i
= 0; i
< items
->len
; i
++)
1061 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1062 char *leafname
= item
->leafname
;
1064 if (leafname
[0] == '.' && !filer_window
->show_hidden
)
1067 add_item(view_collection
, item
);
1070 if (old_num
!= collection
->number_of_items
)
1071 view_collection_sort(view
);
1074 static void view_collection_update_items(ViewIface
*view
, GPtrArray
*items
)
1076 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1077 Collection
*collection
= view_collection
->collection
;
1078 FilerWindow
*filer_window
= view_collection
->filer_window
;
1081 g_return_if_fail(items
->len
> 0);
1083 /* The item data has already been modified, so this gives the
1084 * final sort order...
1086 collection_qsort(collection
, sort_fn(filer_window
),
1087 filer_window
->sort_order
);
1089 for (i
= 0; i
< items
->len
; i
++)
1091 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1092 const gchar
*leafname
= item
->leafname
;
1095 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1098 j
= collection_find_item(collection
, item
,
1099 sort_fn(filer_window
),
1100 filer_window
->sort_order
);
1103 g_warning("Failed to find '%s'\n", leafname
);
1105 update_item(view_collection
, j
);
1109 static void view_collection_delete_if(ViewIface
*view
,
1110 gboolean (*test
)(gpointer item
, gpointer data
),
1113 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1114 Collection
*collection
= view_collection
->collection
;
1116 collection_delete_if(collection
, test
, data
);
1119 static void view_collection_clear(ViewIface
*view
)
1121 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1122 Collection
*collection
= view_collection
->collection
;
1124 collection_clear(collection
);
1127 static void view_collection_select_all(ViewIface
*view
)
1129 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1130 Collection
*collection
= view_collection
->collection
;
1132 collection_select_all(collection
);
1135 static void view_collection_clear_selection(ViewIface
*view
)
1137 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1138 Collection
*collection
= view_collection
->collection
;
1140 collection_clear_selection(collection
);
1143 static int view_collection_count_items(ViewIface
*view
)
1145 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1146 Collection
*collection
= view_collection
->collection
;
1148 return collection
->number_of_items
;
1151 static int view_collection_count_selected(ViewIface
*view
)
1153 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1154 Collection
*collection
= view_collection
->collection
;
1156 return collection
->number_selected
;
1159 static void view_collection_show_cursor(ViewIface
*view
)
1161 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1162 Collection
*collection
= view_collection
->collection
;
1164 collection_move_cursor(collection
, 0, 0);
1167 /* The first time the next() method is used, this is called */
1168 static DirItem
*iter_init(ViewIter
*iter
)
1170 ViewCollection
*view_collection
= (ViewCollection
*) iter
->view
;
1171 Collection
*collection
= view_collection
->collection
;
1173 int n
= collection
->number_of_items
;
1174 int flags
= iter
->flags
;
1176 iter
->peek
= iter_peek
;
1178 if (iter
->n_remaining
== 0)
1181 if (flags
& VIEW_ITER_FROM_CURSOR
)
1183 i
= collection
->cursor_item
;
1185 return NULL
; /* No cursor */
1187 else if (flags
& VIEW_ITER_FROM_BASE
)
1188 i
= view_collection
->cursor_base
;
1190 if (i
< 0 || i
>= n
)
1192 /* Either a normal iteration, or an iteration from an
1193 * invalid starting point.
1195 if (flags
& VIEW_ITER_BACKWARDS
)
1201 if (i
< 0 || i
>= n
)
1202 return NULL
; /* No items at all! */
1204 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1205 iter
->n_remaining
--;
1208 if (flags
& VIEW_ITER_SELECTED
&& !collection
->items
[i
].selected
)
1209 return iter
->next(iter
);
1210 return iter
->peek(iter
);
1212 /* Advance iter to point to the next item and return the new item
1213 * (this saves you calling peek after next each time).
1215 static DirItem
*iter_next(ViewIter
*iter
)
1217 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1218 int n
= collection
->number_of_items
;
1221 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1223 /* i is the last item returned (always valid) */
1225 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1227 while (iter
->n_remaining
)
1230 iter
->n_remaining
--;
1235 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1237 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1238 !collection
->items
[i
].selected
)
1242 return collection
->items
[i
].data
;
1249 /* Like iter_next, but in the other direction */
1250 static DirItem
*iter_prev(ViewIter
*iter
)
1252 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1253 int n
= collection
->number_of_items
;
1256 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1258 /* i is the last item returned (always valid) */
1260 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1262 while (iter
->n_remaining
)
1265 iter
->n_remaining
--;
1268 i
= collection
->number_of_items
- 1;
1270 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1272 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1273 !collection
->items
[i
].selected
)
1277 return collection
->items
[i
].data
;
1284 static DirItem
*iter_peek(ViewIter
*iter
)
1286 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1292 g_return_val_if_fail(i
>= 0 && i
< collection
->number_of_items
, NULL
);
1294 return collection
->items
[i
].data
;
1297 static void make_iter(ViewCollection
*view_collection
, ViewIter
*iter
,
1300 Collection
*collection
= view_collection
->collection
;
1302 iter
->view
= (ViewIface
*) view_collection
;
1303 iter
->next
= iter_init
;
1307 iter
->flags
= flags
;
1309 if (flags
& VIEW_ITER_ONE_ONLY
)
1311 iter
->n_remaining
= 1;
1315 iter
->n_remaining
= collection
->number_of_items
;
1318 /* Set the iterator to return 'i' on the next peek() */
1319 static void make_item_iter(ViewCollection
*view_collection
,
1320 ViewIter
*iter
, int i
)
1322 Collection
*collection
= view_collection
->collection
;
1324 g_return_if_fail(i
>= -1 && i
< collection
->number_of_items
);
1326 make_iter(view_collection
, iter
, 0);
1329 iter
->next
= iter_next
;
1330 iter
->peek
= iter_peek
;
1331 iter
->n_remaining
= 0;
1334 static void view_collection_get_iter(ViewIface
*view
,
1335 ViewIter
*iter
, IterFlags flags
)
1337 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1339 make_iter(view_collection
, iter
, flags
);
1342 static void view_collection_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1343 GdkWindow
*src
, int x
, int y
)
1345 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1346 Collection
*collection
= view_collection
->collection
;
1349 if (src
== ((GtkWidget
*) view
)->window
)
1351 /* The event is on the Viewport, not the collection... */
1352 y
+= collection
->vadj
->value
;
1355 i
= collection_get_item(collection
, x
, y
);
1356 make_item_iter(view_collection
, iter
, i
);
1359 static void view_collection_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1361 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1362 Collection
*collection
= view_collection
->collection
;
1363 FilerWindow
*filer_window
= view_collection
->filer_window
;
1365 g_return_if_fail(iter
== NULL
||
1366 iter
->view
== (ViewIface
*) view_collection
);
1368 collection_set_cursor_item(collection
, iter
? iter
->i
: -1,
1369 filer_window
->auto_scroll
== -1);
1372 static void view_collection_set_selected(ViewIface
*view
,
1376 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1377 Collection
*collection
= view_collection
->collection
;
1379 g_return_if_fail(iter
!= NULL
&&
1380 iter
->view
== (ViewIface
*) view_collection
);
1381 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1384 collection_select_item(collection
, iter
->i
);
1386 collection_unselect_item(collection
, iter
->i
);
1389 static gboolean
view_collection_get_selected(ViewIface
*view
, ViewIter
*iter
)
1391 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1392 Collection
*collection
= view_collection
->collection
;
1394 g_return_val_if_fail(iter
!= NULL
&&
1395 iter
->view
== (ViewIface
*) view_collection
, FALSE
);
1396 g_return_val_if_fail(iter
->i
>= 0 &&
1397 iter
->i
< collection
->number_of_items
, FALSE
);
1399 return collection
->items
[iter
->i
].selected
;
1402 static void view_collection_select_only(ViewIface
*view
, ViewIter
*iter
)
1404 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1405 Collection
*collection
= view_collection
->collection
;
1407 g_return_if_fail(iter
!= NULL
&&
1408 iter
->view
== (ViewIface
*) view_collection
);
1409 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1411 collection_clear_except(collection
, iter
->i
);
1414 static void view_collection_set_frozen(ViewIface
*view
, gboolean frozen
)
1416 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1417 Collection
*collection
= view_collection
->collection
;
1420 collection
->block_selection_changed
++;
1422 collection_unblock_selection_changed(collection
,
1423 gtk_get_current_event_time(), TRUE
);
1426 static void view_collection_wink_item(ViewIface
*view
, ViewIter
*iter
)
1428 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1429 Collection
*collection
= view_collection
->collection
;
1433 collection_wink_item(collection
, -1);
1437 g_return_if_fail(iter
!= NULL
&&
1438 iter
->view
== (ViewIface
*) view_collection
);
1439 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1441 collection_wink_item(collection
, iter
->i
);
1444 static void view_collection_autosize(ViewIface
*view
)
1446 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1447 FilerWindow
*filer_window
= view_collection
->filer_window
;
1448 Collection
*collection
= view_collection
->collection
;
1450 int w
= collection
->item_width
;
1451 int h
= collection
->item_height
;
1454 int max_x
, max_rows
;
1455 const float r
= 2.5;
1459 /* Get the extra height required for the toolbar and minibuffer,
1462 if (o_toolbar
.int_value
!= TOOLBAR_NONE
)
1463 t
= filer_window
->toolbar
->allocation
.height
;
1464 if (filer_window
->message
)
1465 t
+= filer_window
->message
->allocation
.height
;
1466 if (GTK_WIDGET_VISIBLE(filer_window
->minibuffer_area
))
1470 gtk_widget_size_request(filer_window
->minibuffer_area
, &req
);
1471 space
= req
.height
+ 2;
1475 n
= collection
->number_of_items
;
1477 h
= ICON_HEIGHT
* 1.5;
1480 max_x
= (o_filer_size_limit
.int_value
* screen_width
) / 100;
1481 max_rows
= (o_filer_size_limit
.int_value
* screen_height
) / (h
* 100);
1483 /* Aim for a size where
1484 * x = r(y + t + h), (1)
1485 * unless that's too wide.
1487 * t = toolbar (and minibuffer) height
1488 * r = desired (width / height) ratio
1490 * Want to display all items:
1493 * => x(x/r - t - h) = nwh (from 1)
1494 * => xx - x.rt - hr(1 - nw) = 0
1495 * => 2x = rt +/- sqrt(rt.rt + 4hr(nw - 1))
1499 * sqrt(rt.rt + ...) > rt
1501 * So, the +/- must be +:
1503 * => x = (rt + sqrt(rt.rt + 4hr(nw - 1))) / 2
1505 * ( + w - 1 to round up)
1507 x
= (r
* t
+ sqrt(r
*r
*t
*t
+ 4*h
*r
* (n
*w
- 1))) / 2 + w
- 1;
1514 cols
= MAX(cols
, 1);
1516 /* Choose rows to display all items given our chosen x.
1517 * Don't make the window *too* big!
1519 rows
= (n
+ cols
- 1) / cols
;
1520 if (rows
> max_rows
)
1523 /* Leave some room for extra icons, but only in Small Icons mode
1524 * otherwise it takes up too much space.
1525 * Also, don't add space if the minibuffer is open.
1528 space
= filer_window
->display_style
== SMALL_ICONS
? h
: 2;
1530 filer_window_set_size(filer_window
,
1532 h
* MAX(rows
, 1) + space
);
1535 static gboolean
view_collection_cursor_visible(ViewIface
*view
)
1537 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1538 Collection
*collection
= view_collection
->collection
;
1540 return collection
->cursor_item
!= -1;
1543 static void view_collection_set_base(ViewIface
*view
, ViewIter
*iter
)
1545 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1547 view_collection
->cursor_base
= iter
->i
;
1550 static void view_collection_start_lasso_box(ViewIface
*view
,
1551 GdkEventButton
*event
)
1553 ViewCollection
*view_collection
= (ViewCollection
*) view
;
1554 Collection
*collection
= view_collection
->collection
;
1556 filer_set_autoscroll(view_collection
->filer_window
, TRUE
);
1557 collection_lasso_box(collection
, event
->x
, event
->y
);
1561 /* Change the adjustment by this amount. Bounded. */
1562 static void diff_vpos(Collection
*collection
, int diff
)
1564 int old
= collection
->vadj
->value
;
1565 int value
= old
+ diff
;
1567 value
= CLAMP(value
, 0,
1568 collection
->vadj
->upper
- collection
->vadj
->page_size
);
1569 gtk_adjustment_set_value(collection
->vadj
, value
);
1571 if (collection
->vadj
->value
!= old
)
1575 static gboolean
view_collection_auto_scroll_callback(ViewIface
*view
)
1577 ViewCollection
*view_collection
= (ViewCollection
*) view
;
1578 Collection
*collection
= view_collection
->collection
;
1579 GdkWindow
*window
= ((GtkWidget
*) collection
)->window
;
1581 GdkModifierType mask
;
1584 gdk_window_get_pointer(window
, &x
, &y
, &mask
);
1585 gdk_drawable_get_size(window
, &w
, NULL
);
1587 h
= collection
->vadj
->page_size
;
1588 y
-= collection
->vadj
->value
;
1590 if ((x
< 0 || x
> w
|| y
< 0 || y
> h
) && !collection
->lasso_box
)
1591 return FALSE
; /* Out of window - stop */
1593 if (y
< AUTOSCROLL_STEP
)
1594 diff
= y
- AUTOSCROLL_STEP
;
1595 else if (y
> h
- AUTOSCROLL_STEP
)
1596 diff
= AUTOSCROLL_STEP
+ y
- h
;
1599 diff_vpos(collection
, diff
);