4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2003, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* view_collection.c - a subclass of Collection, used for displaying files */
33 #include "collection.h"
34 #include "view_iface.h"
35 #include "view_collection.h"
40 #include "gui_support.h"
46 #include "toolbar.h" /* for resizing */
50 #define MIN_ITEM_WIDTH 64
52 static gpointer parent_class
= NULL
;
54 struct _ViewCollectionClass
{
55 GtkViewportClass parent
;
58 struct _ViewCollection
{
61 Collection
*collection
;
62 FilerWindow
*filer_window
; /* Used for styles, etc */
64 int cursor_base
; /* Cursor when minibuffer opened */
67 typedef struct _Template Template
;
71 GdkRectangle leafname
;
75 /* GC for drawing colour filenames */
76 static GdkGC
*type_gc
= NULL
;
78 /* Static prototypes */
79 static void view_collection_finialize(GObject
*object
);
80 static void view_collection_class_init(gpointer gclass
, gpointer data
);
81 static void view_collection_init(GTypeInstance
*object
, gpointer gclass
);
83 static void draw_item(GtkWidget
*widget
,
87 static void fill_template(GdkRectangle
*area
, CollectionItem
*item
,
88 ViewCollection
*view_collection
, Template
*template);
89 static void huge_template(GdkRectangle
*area
, CollectionItem
*colitem
,
90 ViewCollection
*view_collection
, Template
*template);
91 static void large_template(GdkRectangle
*area
, CollectionItem
*colitem
,
92 ViewCollection
*view_collection
, Template
*template);
93 static void small_template(GdkRectangle
*area
, CollectionItem
*colitem
,
94 ViewCollection
*view_collection
, Template
*template);
95 static void huge_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
96 ViewCollection
*view_collection
, Template
*template);
97 static void large_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
98 ViewCollection
*view_collection
, Template
*template);
99 static void small_full_template(GdkRectangle
*area
, CollectionItem
*colitem
,
100 ViewCollection
*view_collection
, Template
*template);
101 static gboolean
test_point(Collection
*collection
,
102 int point_x
, int point_y
,
103 CollectionItem
*item
,
104 int width
, int height
,
106 static void draw_string(GtkWidget
*widget
,
108 GdkRectangle
*area
, /* Area available on screen */
109 int width
, /* Width of the full string */
110 GtkStateType selection_state
,
112 static void view_collection_iface_init(gpointer giface
, gpointer iface_data
);
113 static gint
coll_motion_notify(GtkWidget
*widget
,
114 GdkEventMotion
*event
,
115 ViewCollection
*view_collection
);
116 static gint
coll_button_release(GtkWidget
*widget
,
117 GdkEventButton
*event
,
118 ViewCollection
*view_collection
);
119 static gint
coll_button_press(GtkWidget
*widget
,
120 GdkEventButton
*event
,
121 ViewCollection
*view_collection
);
122 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
);
123 static void style_set(Collection
*collection
,
125 ViewCollection
*view_collection
);
126 static void display_free_colitem(Collection
*collection
,
127 CollectionItem
*colitem
);
128 static void lost_selection(Collection
*collection
,
131 static void selection_changed(Collection
*collection
,
134 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
135 int *width
, int *height
);
136 static void make_iter(ViewCollection
*view_collection
, ViewIter
*iter
,
138 static void make_item_iter(ViewCollection
*vc
, ViewIter
*iter
, int i
);
140 static void view_collection_sort(ViewIface
*view
);
141 static void view_collection_style_changed(ViewIface
*view
, int flags
);
142 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
);
143 static void view_collection_update_items(ViewIface
*view
, GPtrArray
*items
);
144 static void view_collection_delete_if(ViewIface
*view
,
145 gboolean (*test
)(gpointer item
, gpointer data
),
147 static void view_collection_clear(ViewIface
*view
);
148 static void view_collection_select_all(ViewIface
*view
);
149 static void view_collection_clear_selection(ViewIface
*view
);
150 static int view_collection_count_items(ViewIface
*view
);
151 static int view_collection_count_selected(ViewIface
*view
);
152 static void view_collection_show_cursor(ViewIface
*view
);
153 static void view_collection_get_iter(ViewIface
*view
,
154 ViewIter
*iter
, IterFlags flags
);
155 static void view_collection_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
156 GdkWindow
*src
, int x
, int y
);
157 static void view_collection_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
);
158 static void view_collection_set_selected(ViewIface
*view
,
161 static gboolean
view_collection_get_selected(ViewIface
*view
, ViewIter
*iter
);
162 static void view_collection_select_only(ViewIface
*view
, ViewIter
*iter
);
163 static void view_collection_set_frozen(ViewIface
*view
, gboolean frozen
);
164 static void view_collection_wink_item(ViewIface
*view
, ViewIter
*iter
);
165 static void view_collection_autosize(ViewIface
*view
);
166 static gboolean
view_collection_cursor_visible(ViewIface
*view
);
167 static void view_collection_set_base(ViewIface
*view
, ViewIter
*iter
);
168 static void view_collection_start_lasso_box(ViewIface
*view
,
169 GdkEventButton
*event
);
170 static void view_collection_extend_tip(ViewIface
*view
, ViewIter
*iter
,
172 static gboolean
view_collection_auto_scroll_callback(ViewIface
*view
);
174 static DirItem
*iter_next(ViewIter
*iter
);
175 static DirItem
*iter_prev(ViewIter
*iter
);
176 static DirItem
*iter_peek(ViewIter
*iter
);
179 /****************************************************************
180 * EXTERNAL INTERFACE *
181 ****************************************************************/
183 GtkWidget
*view_collection_new(FilerWindow
*filer_window
)
185 ViewCollection
*view_collection
;
187 view_collection
= g_object_new(view_collection_get_type(), NULL
);
188 view_collection
->filer_window
= filer_window
;
190 /* 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 int col
= i
% collection
->columns
;
725 int row
= i
/ collection
->columns
;
726 ViewData
*view_data
= (ViewData
*) colitem
->view_data
;
729 g_return_if_fail(iter
->view
== (ViewIface
*) view_collection
);
730 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
732 /* TODO: What if the window is narrower than 1 column? */
733 if (filer_window
->display_style
== LARGE_ICONS
||
734 filer_window
->display_style
== HUGE_ICONS
)
735 return; /* These wrap rather than truncate */
737 area
.x
= col
* collection
->item_width
;
738 area
.y
= row
* collection
->item_height
;
739 area
.height
= collection
->item_height
;
741 if (col
== collection
->columns
- 1)
742 area
.width
= GTK_WIDGET(collection
)->allocation
.width
- area
.x
;
744 area
.width
= collection
->item_width
;
746 fill_template(&area
, colitem
, view_collection
, &template);
748 if (template.leafname
.width
< view_data
->name_width
)
750 DirItem
*item
= (DirItem
*) collection
->items
[i
].data
;
752 g_string_append(tip
, item
->leafname
);
753 g_string_append_c(tip
, '\n');
757 static gint
coll_motion_notify(GtkWidget
*widget
,
758 GdkEventMotion
*event
,
759 ViewCollection
*view_collection
)
761 return filer_motion_notify(view_collection
->filer_window
, event
);
764 /* Viewport is to be resized, so calculate increments */
765 static void size_allocate(GtkWidget
*w
, GtkAllocation
*a
, gpointer data
)
767 Collection
*col
= ((ViewCollection
*) data
)->collection
;
769 col
->vadj
->step_increment
= col
->item_height
;
770 col
->vadj
->page_increment
= col
->vadj
->page_size
;
773 static gint
coll_button_release(GtkWidget
*widget
,
774 GdkEventButton
*event
,
775 ViewCollection
*view_collection
)
777 if (dnd_motion_release(event
))
779 if (motion_buttons_pressed
== 0 &&
780 view_collection
->collection
->lasso_box
)
782 filer_set_autoscroll(view_collection
->filer_window
,
784 collection_end_lasso(view_collection
->collection
,
785 event
->button
== 1 ? GDK_SET
: GDK_INVERT
);
790 filer_perform_action(view_collection
->filer_window
, event
);
795 static gint
coll_button_press(GtkWidget
*widget
,
796 GdkEventButton
*event
,
797 ViewCollection
*view_collection
)
799 collection_set_cursor_item(view_collection
->collection
, -1, TRUE
);
801 if (dnd_motion_press(widget
, event
))
802 filer_perform_action(view_collection
->filer_window
, event
);
807 /* Nothing is selected anymore - give up primary */
808 static void lost_selection(Collection
*collection
,
812 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
814 filer_lost_selection(view_collection
->filer_window
, time
);
817 static void selection_changed(Collection
*collection
,
821 ViewCollection
*view_collection
= VIEW_COLLECTION(user_data
);
823 filer_selection_changed(view_collection
->filer_window
, time
);
826 static void display_free_colitem(Collection
*collection
,
827 CollectionItem
*colitem
)
829 ViewData
*view
= (ViewData
*) colitem
->view_data
;
836 g_object_unref(G_OBJECT(view
->layout
));
840 g_object_unref(G_OBJECT(view
->details
));
843 g_object_unref(view
->image
);
848 static void add_item(ViewCollection
*view_collection
, DirItem
*item
)
850 Collection
*collection
= view_collection
->collection
;
851 FilerWindow
*filer_window
= view_collection
->filer_window
;
852 int old_w
= collection
->item_width
;
853 int old_h
= collection
->item_height
;
856 i
= collection_insert(collection
, item
,
857 display_create_viewdata(filer_window
, item
));
859 calc_size(filer_window
, &collection
->items
[i
], &w
, &h
);
861 if (w
> old_w
|| h
> old_h
)
862 collection_set_item_size(collection
,
867 static void style_set(Collection
*collection
,
869 ViewCollection
*view_collection
)
871 view_collection_style_changed(VIEW(view_collection
),
872 VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
);
875 /* Return the size needed for this item */
876 static void calc_size(FilerWindow
*filer_window
, CollectionItem
*colitem
,
877 int *width
, int *height
)
879 int pix_width
, pix_height
;
881 DisplayStyle style
= filer_window
->display_style
;
882 ViewData
*view
= (ViewData
*) colitem
->view_data
;
884 if (filer_window
->details_type
== DETAILS_NONE
)
886 if (style
== HUGE_ICONS
)
890 if (!view
->image
->huge_pixbuf
)
891 pixmap_make_huge(view
->image
);
892 pix_width
= view
->image
->huge_width
;
893 pix_height
= view
->image
->huge_height
;
897 pix_width
= HUGE_WIDTH
* 3 / 2;
898 pix_height
= HUGE_HEIGHT
* 3 / 2;
900 *width
= MAX(pix_width
, view
->name_width
) + 4;
901 *height
= MAX(view
->name_height
+ pix_height
+ 4,
902 HUGE_HEIGHT
* 3 / 4);
904 else if (style
== SMALL_ICONS
)
906 w
= MIN(view
->name_width
, o_small_width
.int_value
);
907 *width
= SMALL_WIDTH
+ 12 + w
;
908 *height
= MAX(view
->name_height
, SMALL_HEIGHT
) + 4;
913 pix_width
= view
->image
->width
;
915 pix_width
= ICON_WIDTH
;
916 *width
= MAX(pix_width
, view
->name_width
) + 4;
917 *height
= view
->name_height
+ ICON_HEIGHT
+ 2;
922 w
= view
->details_width
;
923 if (style
== HUGE_ICONS
)
925 *width
= HUGE_WIDTH
+ 12 + MAX(w
, view
->name_width
);
926 *height
= HUGE_HEIGHT
- 4;
928 else if (style
== SMALL_ICONS
)
932 *width
= SMALL_WIDTH
+ view
->name_width
+ 12 + w
;
933 text_height
= MAX(view
->name_height
,
934 view
->details_height
);
935 *height
= MAX(text_height
, SMALL_HEIGHT
) + 4;
939 *width
= ICON_WIDTH
+ 12 + MAX(w
, view
->name_width
);
940 *height
= ICON_HEIGHT
;
945 static void update_item(ViewCollection
*view_collection
, int i
)
947 Collection
*collection
= view_collection
->collection
;
948 int old_w
= collection
->item_width
;
949 int old_h
= collection
->item_height
;
951 CollectionItem
*colitem
;
952 FilerWindow
*filer_window
= view_collection
->filer_window
;
954 g_return_if_fail(i
>= 0 && i
< collection
->number_of_items
);
956 colitem
= &collection
->items
[i
];
958 display_update_view(filer_window
,
959 (DirItem
*) colitem
->data
,
960 (ViewData
*) colitem
->view_data
,
963 calc_size(filer_window
, colitem
, &w
, &h
);
964 if (w
> old_w
|| h
> old_h
)
965 collection_set_item_size(collection
,
969 collection_draw_item(collection
, i
, TRUE
);
972 /* Implementations of the View interface. See view_iface.c for comments. */
974 static void view_collection_style_changed(ViewIface
*view
, int flags
)
976 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
977 FilerWindow
*filer_window
= view_collection
->filer_window
;
979 Collection
*col
= view_collection
->collection
;
980 int width
= MIN_ITEM_WIDTH
;
981 int height
= SMALL_HEIGHT
;
982 int n
= col
->number_of_items
;
984 if (n
== 0 && filer_window
->display_style
!= SMALL_ICONS
)
985 height
= ICON_HEIGHT
;
987 /* Recalculate all the ViewData structs for this window
988 * (needed if the text or image has changed in any way) and
989 * get the size of each item.
991 for (i
= 0; i
< n
; i
++)
993 CollectionItem
*ci
= &col
->items
[i
];
996 if (flags
& (VIEW_UPDATE_VIEWDATA
| VIEW_UPDATE_NAME
))
997 display_update_view(filer_window
,
998 (DirItem
*) ci
->data
,
999 (ViewData
*) ci
->view_data
,
1000 (flags
& VIEW_UPDATE_NAME
) != 0);
1002 calc_size(filer_window
, ci
, &w
, &h
);
1009 collection_set_item_size(col
, width
, height
);
1011 gtk_widget_queue_draw(GTK_WIDGET(view_collection
));
1014 typedef int (*SortFn
)(gconstpointer a
, gconstpointer b
);
1016 static SortFn
sort_fn(FilerWindow
*fw
)
1018 switch (fw
->sort_type
)
1020 case SORT_NAME
: return sort_by_name
;
1021 case SORT_TYPE
: return sort_by_type
;
1022 case SORT_DATE
: return sort_by_date
;
1023 case SORT_SIZE
: return sort_by_size
;
1024 case SORT_OWNER
: return sort_by_owner
;
1025 case SORT_GROUP
: return sort_by_group
;
1027 g_assert_not_reached();
1033 static void view_collection_sort(ViewIface
*view
)
1035 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1036 FilerWindow
*filer_window
= view_collection
->filer_window
;
1038 collection_qsort(view_collection
->collection
, sort_fn(filer_window
),
1039 filer_window
->sort_order
);
1042 static void view_collection_add_items(ViewIface
*view
, GPtrArray
*items
)
1044 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1045 Collection
*collection
= view_collection
->collection
;
1046 FilerWindow
*filer_window
= view_collection
->filer_window
;
1049 old_num
= collection
->number_of_items
;
1050 for (i
= 0; i
< items
->len
; i
++)
1052 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1053 char *leafname
= item
->leafname
;
1055 if (leafname
[0] == '.' && !filer_window
->show_hidden
)
1058 add_item(view_collection
, item
);
1061 if (old_num
!= collection
->number_of_items
)
1062 view_collection_sort(view
);
1065 static void view_collection_update_items(ViewIface
*view
, GPtrArray
*items
)
1067 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1068 Collection
*collection
= view_collection
->collection
;
1069 FilerWindow
*filer_window
= view_collection
->filer_window
;
1072 g_return_if_fail(items
->len
> 0);
1074 /* The item data has already been modified, so this gives the
1075 * final sort order...
1077 collection_qsort(collection
, sort_fn(filer_window
),
1078 filer_window
->sort_order
);
1080 for (i
= 0; i
< items
->len
; i
++)
1082 DirItem
*item
= (DirItem
*) items
->pdata
[i
];
1083 const gchar
*leafname
= item
->leafname
;
1086 if (leafname
[0] == '.' && filer_window
->show_hidden
== FALSE
)
1089 j
= collection_find_item(collection
, item
,
1090 sort_fn(filer_window
),
1091 filer_window
->sort_order
);
1094 g_warning("Failed to find '%s'\n", leafname
);
1096 update_item(view_collection
, j
);
1100 static void view_collection_delete_if(ViewIface
*view
,
1101 gboolean (*test
)(gpointer item
, gpointer data
),
1104 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1105 Collection
*collection
= view_collection
->collection
;
1107 collection_delete_if(collection
, test
, data
);
1110 static void view_collection_clear(ViewIface
*view
)
1112 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1113 Collection
*collection
= view_collection
->collection
;
1115 collection_clear(collection
);
1118 static void view_collection_select_all(ViewIface
*view
)
1120 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1121 Collection
*collection
= view_collection
->collection
;
1123 collection_select_all(collection
);
1126 static void view_collection_clear_selection(ViewIface
*view
)
1128 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1129 Collection
*collection
= view_collection
->collection
;
1131 collection_clear_selection(collection
);
1134 static int view_collection_count_items(ViewIface
*view
)
1136 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1137 Collection
*collection
= view_collection
->collection
;
1139 return collection
->number_of_items
;
1142 static int view_collection_count_selected(ViewIface
*view
)
1144 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1145 Collection
*collection
= view_collection
->collection
;
1147 return collection
->number_selected
;
1150 static void view_collection_show_cursor(ViewIface
*view
)
1152 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1153 Collection
*collection
= view_collection
->collection
;
1155 collection_move_cursor(collection
, 0, 0);
1158 /* The first time the next() method is used, this is called */
1159 static DirItem
*iter_init(ViewIter
*iter
)
1161 ViewCollection
*view_collection
= (ViewCollection
*) iter
->view
;
1162 Collection
*collection
= view_collection
->collection
;
1164 int n
= collection
->number_of_items
;
1165 int flags
= iter
->flags
;
1167 iter
->peek
= iter_peek
;
1169 if (iter
->n_remaining
== 0)
1172 if (flags
& VIEW_ITER_FROM_CURSOR
)
1174 i
= collection
->cursor_item
;
1176 return NULL
; /* No cursor */
1178 else if (flags
& VIEW_ITER_FROM_BASE
)
1179 i
= view_collection
->cursor_base
;
1181 if (i
< 0 || i
>= n
)
1183 /* Either a normal iteration, or an iteration from an
1184 * invalid starting point.
1186 if (flags
& VIEW_ITER_BACKWARDS
)
1192 if (i
< 0 || i
>= n
)
1193 return NULL
; /* No items at all! */
1195 iter
->next
= flags
& VIEW_ITER_BACKWARDS
? iter_prev
: iter_next
;
1196 iter
->n_remaining
--;
1199 if (flags
& VIEW_ITER_SELECTED
&& !collection
->items
[i
].selected
)
1200 return iter
->next(iter
);
1201 return iter
->peek(iter
);
1203 /* Advance iter to point to the next item and return the new item
1204 * (this saves you calling peek after next each time).
1206 static DirItem
*iter_next(ViewIter
*iter
)
1208 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1209 int n
= collection
->number_of_items
;
1212 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1214 /* i is the last item returned (always valid) */
1216 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1218 while (iter
->n_remaining
)
1221 iter
->n_remaining
--;
1226 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1228 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1229 !collection
->items
[i
].selected
)
1233 return collection
->items
[i
].data
;
1240 /* Like iter_next, but in the other direction */
1241 static DirItem
*iter_prev(ViewIter
*iter
)
1243 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1244 int n
= collection
->number_of_items
;
1247 g_return_val_if_fail(iter
->n_remaining
>= 0, NULL
);
1249 /* i is the last item returned (always valid) */
1251 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1253 while (iter
->n_remaining
)
1256 iter
->n_remaining
--;
1259 i
= collection
->number_of_items
- 1;
1261 g_return_val_if_fail(i
>= 0 && i
< n
, NULL
);
1263 if (iter
->flags
& VIEW_ITER_SELECTED
&&
1264 !collection
->items
[i
].selected
)
1268 return collection
->items
[i
].data
;
1275 static DirItem
*iter_peek(ViewIter
*iter
)
1277 Collection
*collection
= ((ViewCollection
*) iter
->view
)->collection
;
1283 g_return_val_if_fail(i
>= 0 && i
< collection
->number_of_items
, NULL
);
1285 return collection
->items
[i
].data
;
1288 static void make_iter(ViewCollection
*view_collection
, ViewIter
*iter
,
1291 Collection
*collection
= view_collection
->collection
;
1293 iter
->view
= (ViewIface
*) view_collection
;
1294 iter
->next
= iter_init
;
1298 iter
->flags
= flags
;
1300 if (flags
& VIEW_ITER_ONE_ONLY
)
1302 iter
->n_remaining
= 1;
1306 iter
->n_remaining
= collection
->number_of_items
;
1309 /* Set the iterator to return 'i' on the next peek() */
1310 static void make_item_iter(ViewCollection
*view_collection
,
1311 ViewIter
*iter
, int i
)
1313 Collection
*collection
= view_collection
->collection
;
1315 g_return_if_fail(i
>= -1 && i
< collection
->number_of_items
);
1317 make_iter(view_collection
, iter
, 0);
1320 iter
->next
= iter_next
;
1321 iter
->peek
= iter_peek
;
1322 iter
->n_remaining
= 0;
1325 static void view_collection_get_iter(ViewIface
*view
,
1326 ViewIter
*iter
, IterFlags flags
)
1328 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1330 make_iter(view_collection
, iter
, flags
);
1333 static void view_collection_get_iter_at_point(ViewIface
*view
, ViewIter
*iter
,
1334 GdkWindow
*src
, int x
, int y
)
1336 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1337 Collection
*collection
= view_collection
->collection
;
1340 if (src
== ((GtkWidget
*) view
)->window
)
1342 /* The event is on the Viewport, not the collection... */
1343 y
+= collection
->vadj
->value
;
1346 i
= collection_get_item(collection
, x
, y
);
1347 make_item_iter(view_collection
, iter
, i
);
1350 static void view_collection_cursor_to_iter(ViewIface
*view
, ViewIter
*iter
)
1352 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1353 Collection
*collection
= view_collection
->collection
;
1354 FilerWindow
*filer_window
= view_collection
->filer_window
;
1356 g_return_if_fail(iter
== NULL
||
1357 iter
->view
== (ViewIface
*) view_collection
);
1359 collection_set_cursor_item(collection
, iter
? iter
->i
: -1,
1360 filer_window
->auto_scroll
== -1);
1363 static void view_collection_set_selected(ViewIface
*view
,
1367 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1368 Collection
*collection
= view_collection
->collection
;
1370 g_return_if_fail(iter
!= NULL
&&
1371 iter
->view
== (ViewIface
*) view_collection
);
1372 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1375 collection_select_item(collection
, iter
->i
);
1377 collection_unselect_item(collection
, iter
->i
);
1380 static gboolean
view_collection_get_selected(ViewIface
*view
, ViewIter
*iter
)
1382 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1383 Collection
*collection
= view_collection
->collection
;
1385 g_return_val_if_fail(iter
!= NULL
&&
1386 iter
->view
== (ViewIface
*) view_collection
, FALSE
);
1387 g_return_val_if_fail(iter
->i
>= 0 &&
1388 iter
->i
< collection
->number_of_items
, FALSE
);
1390 return collection
->items
[iter
->i
].selected
;
1393 static void view_collection_select_only(ViewIface
*view
, ViewIter
*iter
)
1395 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1396 Collection
*collection
= view_collection
->collection
;
1398 g_return_if_fail(iter
!= NULL
&&
1399 iter
->view
== (ViewIface
*) view_collection
);
1400 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1402 collection_clear_except(collection
, iter
->i
);
1405 static void view_collection_set_frozen(ViewIface
*view
, gboolean frozen
)
1407 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1408 Collection
*collection
= view_collection
->collection
;
1411 collection
->block_selection_changed
++;
1413 collection_unblock_selection_changed(collection
,
1414 gtk_get_current_event_time(), TRUE
);
1417 static void view_collection_wink_item(ViewIface
*view
, ViewIter
*iter
)
1419 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1420 Collection
*collection
= view_collection
->collection
;
1424 collection_wink_item(collection
, -1);
1428 g_return_if_fail(iter
!= NULL
&&
1429 iter
->view
== (ViewIface
*) view_collection
);
1430 g_return_if_fail(iter
->i
>= 0 && iter
->i
< collection
->number_of_items
);
1432 collection_wink_item(collection
, iter
->i
);
1435 static void view_collection_autosize(ViewIface
*view
)
1437 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1438 FilerWindow
*filer_window
= view_collection
->filer_window
;
1439 Collection
*collection
= view_collection
->collection
;
1441 int w
= collection
->item_width
;
1442 int h
= collection
->item_height
;
1445 int max_x
, max_rows
;
1446 const float r
= 2.5;
1450 /* Get the extra height required for the toolbar and minibuffer,
1453 if (o_toolbar
.int_value
!= TOOLBAR_NONE
)
1454 t
= filer_window
->toolbar
->allocation
.height
;
1455 if (filer_window
->message
)
1456 t
+= filer_window
->message
->allocation
.height
;
1457 if (GTK_WIDGET_VISIBLE(filer_window
->minibuffer_area
))
1461 gtk_widget_size_request(filer_window
->minibuffer_area
, &req
);
1462 space
= req
.height
+ 2;
1466 n
= collection
->number_of_items
;
1468 h
= ICON_HEIGHT
* 1.5;
1471 max_x
= (o_filer_size_limit
.int_value
* screen_width
) / 100;
1472 max_rows
= (o_filer_size_limit
.int_value
* screen_height
) / (h
* 100);
1474 /* Aim for a size where
1475 * x = r(y + t + h), (1)
1476 * unless that's too wide.
1478 * t = toolbar (and minibuffer) height
1479 * r = desired (width / height) ratio
1481 * Want to display all items:
1484 * => x(x/r - t - h) = nwh (from 1)
1485 * => xx - x.rt - hr(1 - nw) = 0
1486 * => 2x = rt +/- sqrt(rt.rt + 4hr(nw - 1))
1490 * sqrt(rt.rt + ...) > rt
1492 * So, the +/- must be +:
1494 * => x = (rt + sqrt(rt.rt + 4hr(nw - 1))) / 2
1496 * ( + w - 1 to round up)
1498 x
= (r
* t
+ sqrt(r
*r
*t
*t
+ 4*h
*r
* (n
*w
- 1))) / 2 + w
- 1;
1505 cols
= MAX(cols
, 1);
1507 /* Choose rows to display all items given our chosen x.
1508 * Don't make the window *too* big!
1510 rows
= (n
+ cols
- 1) / cols
;
1511 if (rows
> max_rows
)
1514 /* Leave some room for extra icons, but only in Small Icons mode
1515 * otherwise it takes up too much space.
1516 * Also, don't add space if the minibuffer is open.
1519 space
= filer_window
->display_style
== SMALL_ICONS
? h
: 2;
1521 filer_window_set_size(filer_window
,
1523 h
* MAX(rows
, 1) + space
);
1526 static gboolean
view_collection_cursor_visible(ViewIface
*view
)
1528 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1529 Collection
*collection
= view_collection
->collection
;
1531 return collection
->cursor_item
!= -1;
1534 static void view_collection_set_base(ViewIface
*view
, ViewIter
*iter
)
1536 ViewCollection
*view_collection
= VIEW_COLLECTION(view
);
1538 view_collection
->cursor_base
= iter
->i
;
1541 static void view_collection_start_lasso_box(ViewIface
*view
,
1542 GdkEventButton
*event
)
1544 ViewCollection
*view_collection
= (ViewCollection
*) view
;
1545 Collection
*collection
= view_collection
->collection
;
1547 filer_set_autoscroll(view_collection
->filer_window
, TRUE
);
1548 collection_lasso_box(collection
, event
->x
, event
->y
);
1552 /* Change the adjustment by this amount. Bounded. */
1553 static void diff_vpos(Collection
*collection
, int diff
)
1555 int old
= collection
->vadj
->value
;
1556 int value
= old
+ diff
;
1558 value
= CLAMP(value
, 0,
1559 collection
->vadj
->upper
- collection
->vadj
->page_size
);
1560 gtk_adjustment_set_value(collection
->vadj
, value
);
1562 if (collection
->vadj
->value
!= old
)
1566 static gboolean
view_collection_auto_scroll_callback(ViewIface
*view
)
1568 ViewCollection
*view_collection
= (ViewCollection
*) view
;
1569 Collection
*collection
= view_collection
->collection
;
1570 GdkWindow
*window
= ((GtkWidget
*) collection
)->window
;
1572 GdkModifierType mask
;
1575 gdk_window_get_pointer(window
, &x
, &y
, &mask
);
1576 gdk_drawable_get_size(window
, &w
, NULL
);
1578 h
= collection
->vadj
->page_size
;
1579 y
-= collection
->vadj
->value
;
1581 if ((x
< 0 || x
> w
|| y
< 0 || y
> h
) && !collection
->lasso_box
)
1582 return FALSE
; /* Out of window - stop */
1584 if (y
< AUTOSCROLL_STEP
)
1585 diff
= y
- AUTOSCROLL_STEP
;
1586 else if (y
> h
- AUTOSCROLL_STEP
)
1587 diff
= AUTOSCROLL_STEP
+ y
- h
;
1590 diff_vpos(collection
, diff
);