2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* view_collection.c - a subclass of Collection, used for displaying files */
31 #include "collection.h"
32 #include "view_iface.h"
33 #include "view_collection.h"
38 #include "gui_support.h"
44 #include "toolbar.h" /* for resizing */
48 #define MIN_ITEM_WIDTH 64
50 static gpointer parent_class
= NULL
;
52 struct _ViewCollectionClass
{
53 GtkViewportClass parent
;
56 struct _ViewCollection
{
59 Collection
*collection
;
60 FilerWindow
*filer_window
; /* Used for styles, etc */
62 int cursor_base
; /* Cursor when minibuffer opened */
65 typedef struct _Template Template
;
69 GdkRectangle leafname
;
73 /* GC for drawing colour filenames */
74 static GdkGC
*type_gc
= NULL
;
76 /* Static prototypes */
77 static void view_collection_finialize(GObject
*object
);
78 static void view_collection_class_init(gpointer gclass
, gpointer data
);
79 static void view_collection_init(GTypeInstance
*object
, gpointer gclass
);
81 static void draw_item(GtkWidget
*widget
,
85 static void fill_template(GdkRectangle
*area
, CollectionItem
*item
,
86 ViewCollection
*view_collection
, Template
*template);
87 static void huge_template(GdkRectangle
*area
, CollectionItem
*colitem
,
88 ViewCollection
*view_collection
, Template
*template);
89 static void large_template(GdkRectangle
*area
, CollectionItem
*colitem
,
90 ViewCollection
*view_collection
, Template
*template);
91 static void small_template(GdkRectangle
*area
, CollectionItem
*colitem
,
92 ViewCollection
*view_collection
, Template
*template);
93 static void huge_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
94 ViewCollection
*view_collection
, Template
*template);
95 static void large_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
96 ViewCollection
*view_collection
, Template
*template);
97 static void small_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
98 ViewCollection
*view_collection
, Template
*template);
99 static gboolean
test_point(Collection
*collection
,
100 int point_x
, int point_y
,
101 CollectionItem
*item
,
102 int width
, int height
,
104 static void draw_string(GtkWidget
*widget
,
106 GdkRectangle
*area
, /* Area available on screen */
107 int width
, /* Width of the full string */
108 GtkStateType selection_state
,
110 static void view_collection_iface_init(gpointer giface
, gpointer iface_data
);
111 static gint
coll_motion_notify(GtkWidget
*widget
,
112 GdkEventMotion
*event
,
113 ViewCollection
*view_collection
);
114 static gint
coll_button_release(GtkWidget
*widget
,
115 GdkEventButton
*event
,
116 ViewCollection
*view_collection
);
117 static gint
coll_button_press(GtkWidget
*widget
,
118 GdkEventButton
*event
,
119 ViewCollection
*view_collection
);
120 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
);
121 static void style_set(Collection
*collection
,
123 ViewCollection
*view_collection
);
124 static void display_free_colitem(Collection
*collection
,
125 CollectionItem
*colitem
);
126 static void lost_selection(Collection
*collection
,
129 static void selection_changed(Collection
*collection
,
132 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
133 int *width
, int *height
);
134 static void make_iter(ViewCollection
*view_collection
, ViewIter
*iter
,
136 static void make_item_iter(ViewCollection
*vc
, ViewIter
*iter
, int i
);
138 static void view_collection_sort(ViewIface
*view
);
139 static void view_collection_style_changed(ViewIface
*view
, int flags
);
140 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
);
141 static void view_collection_update_items(ViewIface
*view
, GPtrArray
*items
);
142 static void view_collection_delete_if(ViewIface
*view
,
143 gboolean (*test
)(gpointer item
, gpointer data
),
145 static void view_collection_clear(ViewIface
*view
);
146 static void view_collection_select_all(ViewIface
*view
);
147 static void view_collection_clear_selection(ViewIface
*view
);
148 static int view_collection_count_items(ViewIface
*view
);
149 static int view_collection_count_selected(ViewIface
*view
);
150 static void view_collection_show_cursor(ViewIface
*view
);
151 static void view_collection_get_iter(ViewIface
*view
,
152 ViewIter
*iter
, IterFlags flags
);
153 static void view_collection_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
154 GdkWindow
*src
, int x
, int y
);
155 static void view_collection_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
156 static void view_collection_set_selected(ViewIface
*view
,
159 static gboolean
view_collection_get_selected(ViewIface
*view
, ViewIter
*iter
);
160 static void view_collection_select_only(ViewIface
*view
, ViewIter
*iter
);
161 static void view_collection_set_frozen(ViewIface
*view
, gboolean frozen
);
162 static void view_collection_wink_item(ViewIface
*view
, ViewIter
*iter
);
163 static void view_collection_autosize(ViewIface
*view
);
164 static gboolean
view_collection_cursor_visible(ViewIface
*view
);
165 static void view_collection_set_base(ViewIface
*view
, ViewIter
*iter
);
166 static void view_collection_start_lasso_box(ViewIface
*view
,
167 GdkEventButton
*event
);
168 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
170 static gboolean
view_collection_auto_scroll_callback(ViewIface
*view
);
172 static DirItem
*iter_next(ViewIter
*iter
);
173 static DirItem
*iter_prev(ViewIter
*iter
);
174 static DirItem
*iter_peek(ViewIter
*iter
);
177 /****************************************************************
178 * EXTERNAL INTERFACE *
179 ****************************************************************/
181 GtkWidget
*view_collection_new(FilerWindow
*filer_window
)
183 ViewCollection
*view_collection
;
185 view_collection
= g_object_new(view_collection_get_type(), NULL
);
186 view_collection
->filer_window
= filer_window
;
188 /* Starting with GTK+-2.2.2, the vadjustment is reset after init
189 * (even though it's already set during init) to a new adjustment.
192 gtk_viewport_set_vadjustment(GTK_VIEWPORT(view_collection
),
193 view_collection
->collection
->vadj
);
195 gtk_range_set_adjustment(GTK_RANGE(filer_window
->scrollbar
),
196 view_collection
->collection
->vadj
);
198 return GTK_WIDGET(view_collection
);
201 GType
view_collection_get_type(void)
203 static GType type
= 0;
207 static const GTypeInfo info
=
209 sizeof (ViewCollectionClass
),
210 NULL
, /* base_init */
211 NULL
, /* base_finalise */
212 view_collection_class_init
,
213 NULL
, /* class_finalise */
214 NULL
, /* class_data */
215 sizeof(ViewCollection
),
219 static const GInterfaceInfo iface_info
=
221 view_collection_iface_init
, NULL
, NULL
224 type
= g_type_register_static(gtk_viewport_get_type(),
225 "ViewCollection", &info
, 0);
226 g_type_add_interface_static(type
, VIEW_TYPE_IFACE
, &iface_info
);
232 /****************************************************************
233 * INTERNAL FUNCTIONS *
234 ****************************************************************/
236 static void view_collection_destroy(GtkObject
*view_collection
)
238 VIEW_COLLECTION(view_collection
)->filer_window
= NULL
;
241 static void view_collection_finialize(GObject
*object
)
243 /* ViewCollection *view_collection = (ViewCollection *) object; */
245 G_OBJECT_CLASS(parent_class
)->finalize(object
);
248 static void view_collection_grab_focus(GtkWidget
*focus_widget
)
250 ViewCollection
*view_collection
= VIEW_COLLECTION(focus_widget
);
251 gtk_widget_grab_focus(GTK_WIDGET(view_collection
->collection
));
254 static void view_collection_class_init(gpointer gclass
, gpointer data
)
256 GObjectClass
*object
= (GObjectClass
*) gclass
;
257 GtkWidgetClass
*widget
= (GtkWidgetClass
*) gclass
;
259 parent_class
= g_type_class_peek_parent(gclass
);
261 widget
->grab_focus
= view_collection_grab_focus
;
263 object
->finalize
= view_collection_finialize
;
264 GTK_OBJECT_CLASS(object
)->destroy
= view_collection_destroy
;
267 static void view_collection_init(GTypeInstance
*object
, gpointer gclass
)
269 ViewCollection
*view_collection
= (ViewCollection
*) object
;
270 GtkViewport
*viewport
= (GtkViewport
*) object
;
271 GtkWidget
*collection
;
274 collection
= collection_new();
275 view_collection
->collection
= COLLECTION(collection
);
277 adj
= view_collection
->collection
->vadj
;
278 gtk_viewport_set_vadjustment(viewport
, adj
);
279 gtk_viewport_set_hadjustment(viewport
, NULL
); /* Or Gtk will crash */
280 gtk_viewport_set_shadow_type(viewport
, GTK_SHADOW_NONE
);
281 gtk_container_add(GTK_CONTAINER(object
), collection
);
282 gtk_widget_show(collection
);
283 gtk_widget_set_size_request(GTK_WIDGET(view_collection
), 4, 4);
285 gtk_container_set_resize_mode(GTK_CONTAINER(viewport
),
286 GTK_RESIZE_IMMEDIATE
);
288 view_collection
->collection
->free_item
= display_free_colitem
;
289 view_collection
->collection
->draw_item
= draw_item
;
290 view_collection
->collection
->test_point
= test_point
;
291 view_collection
->collection
->cb_user_data
= view_collection
;
293 g_signal_connect(collection
, "style_set",
294 G_CALLBACK(style_set
),
297 g_signal_connect(collection
, "lose_selection",
298 G_CALLBACK(lost_selection
), view_collection
);
299 g_signal_connect(collection
, "selection_changed",
300 G_CALLBACK(selection_changed
), view_collection
);
302 g_signal_connect(collection
, "button-release-event",
303 G_CALLBACK(coll_button_release
), view_collection
);
304 g_signal_connect(collection
, "button-press-event",
305 G_CALLBACK(coll_button_press
), view_collection
);
306 g_signal_connect(collection
, "motion-notify-event",
307 G_CALLBACK(coll_motion_notify
), view_collection
);
308 g_signal_connect(viewport
, "size-allocate",
309 G_CALLBACK(size_allocate
), view_collection
);
311 gtk_widget_set_events(collection
,
312 GDK_BUTTON1_MOTION_MASK
| GDK_BUTTON2_MOTION_MASK
|
313 GDK_BUTTON3_MOTION_MASK
| GDK_POINTER_MOTION_MASK
|
314 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
);
318 static void draw_item(GtkWidget
*widget
,
319 CollectionItem
*colitem
,
323 DirItem
*item
= (DirItem
*) colitem
->data
;
324 gboolean selected
= colitem
->selected
;
326 ViewData
*view
= (ViewData
*) colitem
->view_data
;
327 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
328 FilerWindow
*filer_window
= view_collection
->filer_window
;
329 GtkStateType selection_state
;
332 g_return_if_fail(view
!= NULL
);
335 selection_state
= filer_window
->selection_state
;
337 selection_state
= GTK_STATE_NORMAL
;
339 color
= &widget
->style
->bg
[selection_state
];
341 fill_template(area
, colitem
, view_collection
, &template);
343 /* Set up GC for coloured file types */
345 type_gc
= gdk_gc_new(widget
->window
);
347 gdk_gc_set_foreground(type_gc
, type_get_colour(item
,
348 &widget
->style
->fg
[GTK_STATE_NORMAL
]));
350 if (template.icon
.width
<= SMALL_WIDTH
&&
351 template.icon
.height
<= SMALL_HEIGHT
)
353 draw_small_icon(widget
->window
, &template.icon
,
354 item
, view
->image
, selected
, color
);
356 else if (template.icon
.width
<= ICON_WIDTH
&&
357 template.icon
.height
<= ICON_HEIGHT
)
359 draw_large_icon(widget
->window
, &template.icon
,
360 item
, view
->image
, selected
, color
);
364 draw_huge_icon(widget
->window
, &template.icon
,
365 item
, view
->image
, selected
, color
);
368 draw_string(widget
, view
->layout
,
374 draw_string(widget
, view
->details
,
376 template.details
.width
,
381 /* A template contains the locations of the three rectangles (for the icon,
382 * name and extra details).
383 * Fill in the empty 'template' with the rectanges for this item.
385 static void fill_template(GdkRectangle
*area
, CollectionItem
*colitem
,
386 ViewCollection
*view_collection
, Template
*template)
388 DisplayStyle style
= view_collection
->filer_window
->display_style
;
389 ViewData
*view
= (ViewData
*) colitem
->view_data
;
393 template->details
.width
= view
->details_width
;
394 template->details
.height
= view
->details_height
;
396 if (style
== SMALL_ICONS
)
397 small_full_template(area
, colitem
,
398 view_collection
, template);
399 else if (style
== LARGE_ICONS
)
400 large_full_template(area
, colitem
,
401 view_collection
, template);
403 huge_full_template(area
, colitem
,
404 view_collection
, template);
408 if (style
== HUGE_ICONS
)
409 huge_template(area
, colitem
,
410 view_collection
, template);
411 else if (style
== LARGE_ICONS
)
412 large_template(area
, colitem
,
413 view_collection
, template);
415 small_template(area
, colitem
,
416 view_collection
, template);
420 static void huge_template(GdkRectangle
*area
, CollectionItem
*colitem
,
421 ViewCollection
*view_collection
, Template
*template)
423 int col_width
= view_collection
->collection
->item_width
;
425 ViewData
*view
= (ViewData
*) colitem
->view_data
;
426 MaskedPixmap
*image
= view
->image
;
430 if (!image
->huge_pixbuf
)
431 pixmap_make_huge(image
);
432 template->icon
.width
= image
->huge_width
;
433 template->icon
.height
= image
->huge_height
;
437 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
438 template->icon
.height
= HUGE_HEIGHT
;
441 template->leafname
.width
= view
->name_width
;
442 template->leafname
.height
= view
->name_height
;
444 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
445 text_y
= area
->y
+ area
->height
- template->leafname
.height
;
447 template->leafname
.x
= text_x
;
448 template->leafname
.y
= text_y
;
450 template->icon
.x
= area
->x
+ ((col_width
- template->icon
.width
) >> 1);
451 template->icon
.y
= template->leafname
.y
- template->icon
.height
- 2;
454 static void large_template(GdkRectangle
*area
, CollectionItem
*colitem
,
455 ViewCollection
*view_collection
, Template
*template)
457 int col_width
= view_collection
->collection
->item_width
;
461 ViewData
*view
= (ViewData
*) colitem
->view_data
;
462 MaskedPixmap
*image
= view
->image
;
468 iwidth
= MIN(image
->width
, ICON_WIDTH
);
469 iheight
= MIN(image
->height
+ 6, ICON_HEIGHT
);
474 iheight
= ICON_HEIGHT
;
476 image_x
= area
->x
+ ((col_width
- iwidth
) >> 1);
478 template->leafname
.width
= view
->name_width
;
479 template->leafname
.height
= view
->name_height
;
481 text_x
= area
->x
+ ((col_width
- template->leafname
.width
) >> 1);
482 text_y
= area
->y
+ ICON_HEIGHT
+ 2;
484 template->leafname
.x
= text_x
;
485 template->leafname
.y
= text_y
;
487 image_y
= text_y
- iheight
;
488 image_y
= MAX(area
->y
, image_y
);
490 template->icon
.x
= image_x
;
491 template->icon
.y
= image_y
;
492 template->icon
.width
= iwidth
;
493 template->icon
.height
= MIN(ICON_HEIGHT
, iheight
);
496 static void small_template(GdkRectangle
*area
, CollectionItem
*colitem
,
497 ViewCollection
*view_collection
, Template
*template)
499 int text_x
= area
->x
+ SMALL_WIDTH
+ 4;
501 int max_text_width
= area
->width
- SMALL_WIDTH
- 4;
502 ViewData
*view
= (ViewData
*) colitem
->view_data
;
504 low_text_y
= area
->y
+ area
->height
/ 2 - view
->name_height
/ 2;
506 template->leafname
.x
= text_x
;
507 template->leafname
.y
= low_text_y
;
508 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
509 template->leafname
.height
= view
->name_height
;
511 template->icon
.x
= area
->x
;
512 template->icon
.y
= area
->y
+ 1;
513 template->icon
.width
= SMALL_WIDTH
;
514 template->icon
.height
= SMALL_HEIGHT
;
517 static void huge_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
518 ViewCollection
*view_collection
, Template
*template)
520 int max_text_width
= area
->width
- HUGE_WIDTH
- 4;
521 ViewData
*view
= (ViewData
*) colitem
->view_data
;
522 MaskedPixmap
*image
= view
->image
;
526 if (!image
->huge_pixbuf
)
527 pixmap_make_huge(image
);
528 template->icon
.width
= image
->huge_width
;
529 template->icon
.height
= image
->huge_height
;
533 template->icon
.width
= HUGE_WIDTH
* 3 / 2;
534 template->icon
.height
= HUGE_HEIGHT
;
537 template->icon
.x
= area
->x
+ (HUGE_WIDTH
- template->icon
.width
) / 2;
538 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
540 template->leafname
.x
= area
->x
+ HUGE_WIDTH
+ 4;
541 template->leafname
.y
= area
->y
+ area
->height
/ 2
542 - (view
->name_height
+ 2 + view
->details_height
) / 2;
543 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
544 template->leafname
.height
= view
->name_height
;
547 return; /* Not scanned yet */
549 template->details
.x
= template->leafname
.x
;
550 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
553 static void large_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
554 ViewCollection
*view_collection
, Template
*template)
556 int max_text_width
= area
->width
- ICON_WIDTH
- 4;
557 ViewData
*view
= (ViewData
*) colitem
->view_data
;
558 MaskedPixmap
*image
= view
->image
;
562 template->icon
.width
= image
->width
;
563 template->icon
.height
= image
->height
;
567 template->icon
.width
= ICON_WIDTH
;
568 template->icon
.height
= ICON_HEIGHT
;
571 template->icon
.x
= area
->x
+ (ICON_WIDTH
- template->icon
.width
) / 2;
572 template->icon
.y
= area
->y
+ (area
->height
- template->icon
.height
) / 2;
575 template->leafname
.x
= area
->x
+ ICON_WIDTH
+ 4;
576 template->leafname
.y
= area
->y
+ area
->height
/ 2
577 - (view
->name_height
+ 2 + view
->details_height
) / 2;
578 template->leafname
.width
= MIN(max_text_width
, view
->name_width
);
579 template->leafname
.height
= view
->name_height
;
582 return; /* Not scanned yet */
584 template->details
.x
= template->leafname
.x
;
585 template->details
.y
= template->leafname
.y
+ view
->name_height
+ 2;
588 static void small_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
589 ViewCollection
*view_collection
, Template
*template)
591 int col_width
= view_collection
->collection
->item_width
;
592 ViewData
*view
= (ViewData
*) colitem
->view_data
;
594 small_template(area
, colitem
, view_collection
, template);
597 return; /* Not scanned yet */
599 template->details
.x
= area
->x
+ col_width
- template->details
.width
;
600 template->details
.y
= area
->y
+ area
->height
/ 2 - \
601 view
->details_height
/ 2;
604 #define INSIDE(px, py, area) \
605 (px >= area.x && py >= area.y && \
606 px <= area.x + area.width && py <= area.y + area.height)
608 static gboolean
test_point(Collection
*collection
,
609 int point_x
, int point_y
,
610 CollectionItem
*colitem
,
611 int width
, int height
,
616 ViewData
*view
= (ViewData
*) colitem
->view_data
;
617 ViewCollection
*view_collection
= (ViewCollection
*) user_data
;
622 area
.height
= height
;
624 fill_template(&area
, colitem
, view_collection
, &template);
626 return INSIDE(point_x
, point_y
, template.leafname
) ||
627 INSIDE(point_x
, point_y
, template.icon
) ||
628 (view
->details
&& INSIDE(point_x
, point_y
, template.details
));
631 /* 'box' renders a background box if the string is also selected */
632 static void draw_string(GtkWidget
*widget
,
634 GdkRectangle
*area
, /* Area available on screen */
635 int width
, /* Width of the full string */
636 GtkStateType selection_state
,
639 GdkGC
*gc
= selection_state
== GTK_STATE_NORMAL
641 : widget
->style
->fg_gc
[selection_state
];
643 if (selection_state
!= GTK_STATE_NORMAL
&& box
)
644 gtk_paint_flat_box(widget
->style
, widget
->window
,
645 selection_state
, GTK_SHADOW_NONE
,
646 NULL
, widget
, "text",
648 MIN(width
, area
->width
),
651 if (width
> area
->width
)
653 gdk_gc_set_clip_origin(gc
, 0, 0);
654 gdk_gc_set_clip_rectangle(gc
, area
);
657 gdk_draw_layout(widget
->window
, gc
, area
->x
, area
->y
, layout
);
659 if (width
> area
->width
)
661 static GdkGC
*red_gc
= NULL
;
666 GdkColor red
= {0, 0xffff, 0, 0};
668 red_gc
= gdk_gc_new(widget
->window
);
669 gdk_colormap_alloc_colors(
670 gtk_widget_get_colormap(widget
),
671 &red
, 1, FALSE
, TRUE
, &success
);
672 gdk_gc_set_foreground(red_gc
, &red
);
674 gdk_draw_rectangle(widget
->window
, red_gc
, TRUE
,
675 area
->x
+ area
->width
- 1, area
->y
,
677 gdk_gc_set_clip_rectangle(gc
, NULL
);
681 /* Create the handers for the View interface */
682 static void view_collection_iface_init(gpointer giface
, gpointer iface_data
)
684 ViewIfaceClass
*iface
= giface
;
686 g_assert(G_TYPE_FROM_INTERFACE(iface
) == VIEW_TYPE_IFACE
);
689 iface
->sort
= view_collection_sort
;
690 iface
->style_changed
= view_collection_style_changed
;
691 iface
->add_items
= view_collection_add_items
;
692 iface
->update_items
= view_collection_update_items
;
693 iface
->delete_if
= view_collection_delete_if
;
694 iface
->clear
= view_collection_clear
;
695 iface
->select_all
= view_collection_select_all
;
696 iface
->clear_selection
= view_collection_clear_selection
;
697 iface
->count_items
= view_collection_count_items
;
698 iface
->count_selected
= view_collection_count_selected
;
699 iface
->show_cursor
= view_collection_show_cursor
;
700 iface
->get_iter
= view_collection_get_iter
;
701 iface
->get_iter_at_point
= view_collection_get_iter_at_point
;
702 iface
->cursor_to_iter
= view_collection_cursor_to_iter
;
703 iface
->set_selected
= view_collection_set_selected
;
704 iface
->get_selected
= view_collection_get_selected
;
705 iface
->set_frozen
= view_collection_set_frozen
;
706 iface
->select_only
= view_collection_select_only
;
707 iface
->wink_item
= view_collection_wink_item
;
708 iface
->autosize
= view_collection_autosize
;
709 iface
->cursor_visible
= view_collection_cursor_visible
;
710 iface
->set_base
= view_collection_set_base
;
711 iface
->start_lasso_box
= view_collection_start_lasso_box
;
712 iface
->extend_tip
= view_collection_extend_tip
;
713 iface
->auto_scroll_callback
= view_collection_auto_scroll_callback
;
716 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
719 ViewCollection
*view_collection
= (ViewCollection
*) view
;
720 Collection
*collection
= view_collection
->collection
;
721 FilerWindow
*filer_window
= view_collection
->filer_window
;
724 CollectionItem
*colitem
= &collection
->items
[i
];
725 ViewData
*view_data
= (ViewData
*) colitem
->view_data
;
729 collection_item_to_rowcol(collection
, i
, &row
, &col
);
731 g_return_if_fail(iter
->view
== (ViewIface
*) view_collection
);
732 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
734 /* TODO: What if the window is narrower than 1 column? */
735 if (filer_window
->display_style
== LARGE_ICONS
||
736 filer_window
->display_style
== HUGE_ICONS
)
737 return; /* These wrap rather than truncate */
739 area
.x
= col
* collection
->item_width
;
740 area
.y
= row
* collection
->item_height
;
741 area
.height
= collection
->item_height
;
743 if (col
== collection
->columns
- 1)
744 area
.width
= GTK_WIDGET(collection
)->allocation
.width
- area
.x
;
746 area
.width
= collection
->item_width
;
748 fill_template(&area
, colitem
, view_collection
, &template);
750 if (template.leafname
.width
< view_data
->name_width
)
752 DirItem
*item
= (DirItem
*) collection
->items
[i
].data
;
754 g_string_append(tip
, item
->leafname
);
755 g_string_append_c(tip
, '\n');
759 static gint
coll_motion_notify(GtkWidget
*widget
,
760 GdkEventMotion
*event
,
761 ViewCollection
*view_collection
)
763 return filer_motion_notify(view_collection
->filer_window
, event
);
766 /* Viewport is to be resized, so calculate increments */
767 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
)
769 Collection
*col
= ((ViewCollection
*) data
)->collection
;
771 col
->vadj
->step_increment
= col
->item_height
;
772 col
->vadj
->page_increment
= col
->vadj
->page_size
;
775 static gint
coll_button_release(GtkWidget
*widget
,
776 GdkEventButton
*event
,
777 ViewCollection
*view_collection
)
779 if (dnd_motion_release(event
))
781 if (motion_buttons_pressed
== 0 &&
782 view_collection
->collection
->lasso_box
)
784 filer_set_autoscroll(view_collection
->filer_window
,
786 collection_end_lasso(view_collection
->collection
,
787 event
->button
== 1 ? GDK_SET
: GDK_INVERT
);
792 filer_perform_action(view_collection
->filer_window
, event
);
797 static gint
coll_button_press(GtkWidget
*widget
,
798 GdkEventButton
*event
,
799 ViewCollection
*view_collection
)
801 collection_set_cursor_item(view_collection
->collection
, -1, TRUE
);
803 if (dnd_motion_press(widget
, event
))
804 filer_perform_action(view_collection
->filer_window
, event
);
809 /* Nothing is selected anymore - give up primary */
810 static void lost_selection(Collection
*collection
,
814 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
816 filer_lost_selection(view_collection
->filer_window
, time
);
819 static void selection_changed(Collection
*collection
,
823 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
825 filer_selection_changed(view_collection
->filer_window
, time
);
828 static void display_free_colitem(Collection
*collection
,
829 CollectionItem
*colitem
)
831 ViewData
*view
= (ViewData
*) colitem
->view_data
;
838 g_object_unref(G_OBJECT(view
->layout
));
842 g_object_unref(G_OBJECT(view
->details
));
845 g_object_unref(view
->image
);
850 static void add_item(ViewCollection
*view_collection
, DirItem
*item
)
852 Collection
*collection
= view_collection
->collection
;
853 FilerWindow
*filer_window
= view_collection
->filer_window
;
854 int old_w
= collection
->item_width
;
855 int old_h
= collection
->item_height
;
858 i
= collection_insert(collection
, item
,
859 display_create_viewdata(filer_window
, item
));
861 calc_size(filer_window
, &collection
->items
[i
], &w
, &h
);
863 if (w
> old_w
|| h
> old_h
)
864 collection_set_item_size(collection
,
869 static void style_set(Collection
*collection
,
871 ViewCollection
*view_collection
)
873 view_collection_style_changed(VIEW(view_collection
),
874 VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
);
877 /* Return the size needed for this item */
878 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
879 int *width
, int *height
)
881 int pix_width
, pix_height
;
883 DisplayStyle style
= filer_window
->display_style
;
884 ViewData
*view
= (ViewData
*) colitem
->view_data
;
886 if (filer_window
->details_type
== DETAILS_NONE
)
888 if (style
== HUGE_ICONS
)
892 if (!view
->image
->huge_pixbuf
)
893 pixmap_make_huge(view
->image
);
894 pix_width
= view
->image
->huge_width
;
895 pix_height
= view
->image
->huge_height
;
899 pix_width
= HUGE_WIDTH
* 3 / 2;
900 pix_height
= HUGE_HEIGHT
* 3 / 2;
902 *width
= MAX(pix_width
, view
->name_width
) + 4;
903 *height
= MAX(view
->name_height
+ pix_height
+ 4,
904 HUGE_HEIGHT
* 3 / 4);
906 else if (style
== SMALL_ICONS
)
908 w
= MIN(view
->name_width
, o_small_width
.int_value
);
909 *width
= SMALL_WIDTH
+ 12 + w
;
910 *height
= MAX(view
->name_height
, SMALL_HEIGHT
) + 4;
915 pix_width
= view
->image
->width
;
917 pix_width
= ICON_WIDTH
;
918 *width
= MAX(pix_width
, view
->name_width
) + 4;
919 *height
= view
->name_height
+ ICON_HEIGHT
+ 2;
924 w
= view
->details_width
;
925 if (style
== HUGE_ICONS
)
927 *width
= HUGE_WIDTH
+ 12 + MAX(w
, view
->name_width
);
928 *height
= HUGE_HEIGHT
- 4;
930 else if (style
== SMALL_ICONS
)
934 *width
= SMALL_WIDTH
+ view
->name_width
+ 12 + w
;
935 text_height
= MAX(view
->name_height
,
936 view
->details_height
);
937 *height
= MAX(text_height
, SMALL_HEIGHT
) + 4;
941 *width
= ICON_WIDTH
+ 12 + MAX(w
, view
->name_width
);
942 *height
= ICON_HEIGHT
;
947 static void update_item(ViewCollection
*view_collection
, int i
)
949 Collection
*collection
= view_collection
->collection
;
950 int old_w
= collection
->item_width
;
951 int old_h
= collection
->item_height
;
953 CollectionItem
*colitem
;
954 FilerWindow
*filer_window
= view_collection
->filer_window
;
956 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
958 colitem
= &collection
->items
[i
];
960 display_update_view(filer_window
,
961 (DirItem
*) colitem
->data
,
962 (ViewData
*) colitem
->view_data
,
965 calc_size(filer_window
, colitem
, &w
, &h
);
966 if (w
> old_w
|| h
> old_h
)
967 collection_set_item_size(collection
,
971 collection_draw_item(collection
, i
, TRUE
);
974 /* Implementations of the View interface. See view_iface.c for comments. */
976 static void view_collection_style_changed(ViewIface
*view
, int flags
)
978 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
979 FilerWindow
*filer_window
= view_collection
->filer_window
;
981 Collection
*col
= view_collection
->collection
;
982 int width
= MIN_ITEM_WIDTH
;
983 int height
= SMALL_HEIGHT
;
984 int n
= col
->number_of_items
;
986 if (n
== 0 && filer_window
->display_style
!= SMALL_ICONS
)
987 height
= ICON_HEIGHT
;
989 view_collection
->collection
->vertical_order
= FALSE
;
990 if (filer_window
->display_style
== SMALL_ICONS
&&
991 o_vertical_order_small
.int_value
)
992 view_collection
->collection
->vertical_order
= TRUE
;
993 if (filer_window
->display_style
!= SMALL_ICONS
&&
994 o_vertical_order_large
.int_value
)
995 view_collection
->collection
->vertical_order
= TRUE
;
1000 /* Recalculate all the ViewData structs for this window
1001 * (needed if the text or image has changed in any way) and
1002 * get the size of each item.
1004 for (i
= 0; i
< n
; i
++)
1006 CollectionItem
*ci
= &col
->items
[i
];
1009 if (flags
& (VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
))
1010 display_update_view(filer_window
,
1011 (DirItem
*) ci
->data
,
1012 (ViewData
*) ci
->view_data
,
1013 (flags
& VIEW_UPDATE_NAME
) != 0);
1015 calc_size(filer_window
, ci
, &w
, &h
);
1022 collection_set_item_size(col
, width
, height
);
1024 gtk_widget_queue_draw(GTK_WIDGET(view_collection
));
1027 typedef int (*SortFn
)(gconstpointer a
, gconstpointer b
);
1029 static SortFn
sort_fn(FilerWindow
*fw
)
1031 switch (fw
->sort_type
)
1033 case SORT_NAME
: return sort_by_name
;
1034 case SORT_TYPE
: return sort_by_type
;
1035 case SORT_DATE
: return sort_by_date
;
1036 case SORT_SIZE
: return sort_by_size
;
1037 case SORT_OWNER
: return sort_by_owner
;
1038 case SORT_GROUP
: return sort_by_group
;
1040 g_assert_not_reached();
1046 static void view_collection_sort(ViewIface
*view
)
1048 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1049 FilerWindow
*filer_window
= view_collection
->filer_window
;
1051 collection_qsort(view_collection
->collection
, sort_fn(filer_window
),
1052 filer_window
->sort_order
);
1055 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
)
1057 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1058 Collection
*collection
= view_collection
->collection
;
1059 FilerWindow
*filer_window
= view_collection
->filer_window
;
1062 old_num
= collection
->number_of_items
;
1063 for (i
= 0; i
< items
->len
; i
++)
1065 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1067 if (!filer_match_filter(filer_window
, item
))
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
, item
))
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
);