4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2000, Thomas Leonard, <tal197@ecs.soton.ac.uk>.
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 /* display.c - code for arranging and displaying file items */
31 #include <sys/param.h>
38 #include <gdk/gdkkeysyms.h>
39 #include "collection.h"
43 #include "gui_support.h"
53 #include "minibuffer.h"
55 #define ROW_HEIGHT_SMALL 20
56 #define ROW_HEIGHT_FULL_INFO 44
57 #define SMALL_ICON_HEIGHT 20
59 # define SMALL_ICON_WIDTH 24
61 # define SMALL_ICON_WIDTH 48
63 #define MAX_ICON_HEIGHT 42
64 #define MAX_ICON_WIDTH 48
65 #define MIN_ITEM_WIDTH 64
67 #define MIN_TRUNCATE 0
68 #define MAX_TRUNCATE 250
70 DetailsType last_details_type
= DETAILS_SUMMARY
;
71 DisplayStyle last_display_style
= LARGE_ICONS
;
72 gboolean last_show_hidden
= FALSE
;
73 int (*last_sort_fn
)(const void *a
, const void *b
) = sort_by_type
;
76 static guchar
*style_to_name(void);
77 static guchar
*sort_fn_to_name(void);
78 static void update_options_label(void);
80 static GtkWidget
*create_options();
81 static void update_options();
82 static void set_options();
83 static void save_options();
84 static char *display_sort_nocase(char *data
);
85 static char *display_display_style(char *data
);
86 static char *display_sort_by(char *data
);
87 static char *display_truncate(char *data
);
89 static OptionsSection options
=
91 N_("Display options"),
98 static GtkWidget
*display_label
;
100 static gboolean o_sort_nocase
= TRUE
;
101 static gint o_small_truncate
= 250;
102 static gint o_large_truncate
= 89;
103 static GtkAdjustment
*adj_small_truncate
;
104 static GtkAdjustment
*adj_large_truncate
;
105 static GtkWidget
*toggle_sort_nocase
;
107 /* Static prototypes */
108 static void draw_large_icon(GtkWidget
*widget
,
112 static void draw_string(GtkWidget
*widget
,
121 static void draw_item_large(GtkWidget
*widget
,
122 CollectionItem
*item
,
124 FilerWindow
*filer_window
);
125 static void draw_item_small(GtkWidget
*widget
,
126 CollectionItem
*item
,
128 FilerWindow
*filer_window
);
129 static void draw_item_large_full(GtkWidget
*widget
,
130 CollectionItem
*colitem
,
132 FilerWindow
*filer_window
);
133 static void draw_item_small_full(GtkWidget
*widget
,
134 CollectionItem
*colitem
,
136 FilerWindow
*filer_window
);
137 static gboolean
test_point_large(Collection
*collection
,
138 int point_x
, int point_y
,
139 CollectionItem
*item
,
140 int width
, int height
,
141 FilerWindow
*filer_window
);
142 static gboolean
test_point_small(Collection
*collection
,
143 int point_x
, int point_y
,
144 CollectionItem
*item
,
145 int width
, int height
,
146 FilerWindow
*filer_window
);
147 static gboolean
test_point_large_full(Collection
*collection
,
148 int point_x
, int point_y
,
149 CollectionItem
*item
,
150 int width
, int height
,
151 FilerWindow
*filer_window
);
152 static gboolean
test_point_small_full(Collection
*collection
,
153 int point_x
, int point_y
,
154 CollectionItem
*item
,
155 int width
, int height
,
156 FilerWindow
*filer_window
);
160 options_sections
= g_slist_prepend(options_sections
, &options
);
161 option_register("display_sort_nocase", display_sort_nocase
);
162 option_register("display_display_style", display_display_style
);
163 option_register("display_sort_by", display_sort_by
);
164 option_register("display_truncate", display_truncate
);
167 #define BAR_SIZE(size) ((size) > 0 ? (log((size) + 1) * 16) : 0)
168 #define MAX_BAR_SIZE 460
170 static int details_width(FilerWindow
*filer_window
, DirItem
*item
)
174 if (filer_window
->details_type
== DETAILS_SIZE_BARS
&&
175 item
->base_type
!= TYPE_DIRECTORY
)
176 return 6 * fixed_width
+ MAX_BAR_SIZE
+ 16;
178 return bar
+ fixed_width
* strlen(details(filer_window
, item
));
181 int calc_width(FilerWindow
*filer_window
, DirItem
*item
)
183 int pix_width
= item
->image
->width
;
186 switch (filer_window
->display_style
)
188 case LARGE_FULL_INFO
:
189 w
= details_width(filer_window
, item
);
190 return MAX_ICON_WIDTH
+ 12 +
191 MAX(w
, item
->name_width
);
192 case SMALL_FULL_INFO
:
193 w
= details_width(filer_window
, item
);
194 return SMALL_ICON_WIDTH
+ item
->name_width
+ 12 + w
;
196 w
= MIN(item
->name_width
, o_small_truncate
);
197 return SMALL_ICON_WIDTH
+ 12 + w
;
199 w
= MIN(item
->name_width
, o_large_truncate
);
200 return MAX(pix_width
, w
) + 4;
204 /* Is a point inside an item? */
205 static gboolean
test_point_large(Collection
*collection
,
206 int point_x
, int point_y
,
207 CollectionItem
*colitem
,
208 int width
, int height
,
209 FilerWindow
*filer_window
)
211 DirItem
*item
= (DirItem
*) colitem
->data
;
212 int text_height
= item_font
->ascent
+ item_font
->descent
;
213 MaskedPixmap
*image
= item
->image
;
214 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
215 int image_width
= (image
->width
>> 1) + 2;
216 int text_width
= (item
->name_width
>> 1) + 2;
219 if (point_y
< image_y
)
220 return FALSE
; /* Too high up (don't worry about too low) */
222 if (point_y
<= image_y
+ image
->height
+ 2)
223 x_limit
= image_width
;
224 else if (point_y
> height
- text_height
- 2)
225 x_limit
= text_width
;
227 x_limit
= MIN(image_width
, text_width
);
229 return ABS(point_x
- (width
>> 1)) < x_limit
;
232 static gboolean
test_point_large_full(Collection
*collection
,
233 int point_x
, int point_y
,
234 CollectionItem
*colitem
,
235 int width
, int height
,
236 FilerWindow
*filer_window
)
238 DirItem
*item
= (DirItem
*) colitem
->data
;
239 MaskedPixmap
*image
= item
->image
;
240 int image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
242 - fixed_font
->descent
- 2 - fixed_font
->ascent
;
244 if (point_x
< image
->width
+ 2)
245 return point_x
> 2 && point_y
> image_y
;
247 point_x
-= MAX_ICON_WIDTH
+ 8;
249 if (point_y
>= low_top
)
250 return point_x
< details_width(filer_window
, item
);
251 if (point_y
>= low_top
- item_font
->ascent
- item_font
->descent
)
252 return point_x
< item
->name_width
;
256 static gboolean
test_point_small_full(Collection
*collection
,
257 int point_x
, int point_y
,
258 CollectionItem
*colitem
,
259 int width
, int height
,
260 FilerWindow
*filer_window
)
262 DirItem
*item
= (DirItem
*) colitem
->data
;
263 MaskedPixmap
*image
= item
->image
;
264 int image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
266 - fixed_font
->descent
- 2 - item_font
->ascent
;
267 int iwidth
= MIN(SMALL_ICON_WIDTH
, image
->width
);
269 if (point_x
< iwidth
+ 2)
270 return point_x
> 2 && point_y
> image_y
;
272 if (point_y
< low_top
)
275 if (filer_window
->details_type
== DETAILS_SIZE_BARS
)
277 int bar_x
= width
- MAX_BAR_SIZE
- 4;
280 if (item
->base_type
== TYPE_DIRECTORY
)
283 bar_size
= BAR_SIZE(item
->size
);
285 return point_x
< bar_x
+ bar_size
;
291 static gboolean
test_point_small(Collection
*collection
,
292 int point_x
, int point_y
,
293 CollectionItem
*colitem
,
294 int width
, int height
,
295 FilerWindow
*filer_window
)
297 DirItem
*item
= (DirItem
*) colitem
->data
;
298 MaskedPixmap
*image
= item
->image
;
299 int image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->height
);
301 - fixed_font
->descent
- 2 - item_font
->ascent
;
302 int iwidth
= MIN(SMALL_ICON_WIDTH
, image
->width
);
304 if (point_x
< iwidth
+ 2)
305 return point_x
> 2 && point_y
> image_y
;
307 point_x
-= SMALL_ICON_WIDTH
+ 4;
309 if (point_y
>= low_top
)
310 return point_x
< item
->name_width
;
314 static void draw_small_icon(GtkWidget
*widget
,
319 GdkGC
*gc
= selected
? widget
->style
->white_gc
320 : widget
->style
->black_gc
;
321 MaskedPixmap
*image
= item
->image
;
322 int width
, height
, image_x
, image_y
;
327 if (!image
->sm_pixmap
)
328 pixmap_make_small(image
);
330 width
= MIN(image
->sm_width
, SMALL_ICON_WIDTH
);
331 height
= MIN(image
->sm_height
, SMALL_ICON_HEIGHT
);
332 image_x
= area
->x
+ ((area
->width
- width
) >> 1);
334 gdk_gc_set_clip_mask(gc
, item
->image
->sm_mask
);
336 image_y
= MAX(0, SMALL_ICON_HEIGHT
- image
->sm_height
);
337 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
338 gdk_draw_pixmap(widget
->window
, gc
,
339 item
->image
->sm_pixmap
,
340 0, 0, /* Source x,y */
341 image_x
, area
->y
+ image_y
, /* Dest x,y */
346 gdk_gc_set_function(gc
, GDK_INVERT
);
347 gdk_draw_rectangle(widget
->window
,
349 TRUE
, image_x
, area
->y
+ image_y
,
351 gdk_gc_set_function(gc
, GDK_COPY
);
354 if (item
->flags
& ITEM_FLAG_SYMLINK
)
356 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
357 gdk_gc_set_clip_mask(gc
, im_symlink
->mask
);
358 gdk_draw_pixmap(widget
->window
, gc
, im_symlink
->pixmap
,
359 0, 0, /* Source x,y */
360 image_x
, area
->y
+ 8, /* Dest x,y */
363 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
365 MaskedPixmap
*mp
= item
->flags
& ITEM_FLAG_MOUNTED
370 pixmap_make_small(mp
);
371 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
372 gdk_gc_set_clip_mask(gc
, mp
->sm_mask
);
373 gdk_draw_pixmap(widget
->window
, gc
,
375 0, 0, /* Source x,y */
376 image_x
, area
->y
+ 8, /* Dest x,y */
380 gdk_gc_set_clip_mask(gc
, NULL
);
381 gdk_gc_set_clip_origin(gc
, 0, 0);
384 static void draw_large_icon(GtkWidget
*widget
,
389 MaskedPixmap
*image
= item
->image
;
390 int width
= MIN(image
->width
, MAX_ICON_WIDTH
);
391 int height
= MIN(image
->height
, MAX_ICON_WIDTH
);
392 int image_x
= area
->x
+ ((area
->width
- width
) >> 1);
394 GdkGC
*gc
= selected
? widget
->style
->white_gc
395 : widget
->style
->black_gc
;
397 gdk_gc_set_clip_mask(gc
, item
->image
->mask
);
399 image_y
= MAX(0, MAX_ICON_HEIGHT
- image
->height
);
400 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ image_y
);
401 gdk_draw_pixmap(widget
->window
, gc
,
403 0, 0, /* Source x,y */
404 image_x
, area
->y
+ image_y
, /* Dest x,y */
409 gdk_gc_set_function(gc
, GDK_INVERT
);
410 gdk_draw_rectangle(widget
->window
,
412 TRUE
, image_x
, area
->y
+ image_y
,
414 gdk_gc_set_function(gc
, GDK_COPY
);
417 if (item
->flags
& ITEM_FLAG_SYMLINK
)
419 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
420 gdk_gc_set_clip_mask(gc
, im_symlink
->mask
);
421 gdk_draw_pixmap(widget
->window
, gc
, im_symlink
->pixmap
,
422 0, 0, /* Source x,y */
423 image_x
, area
->y
+ 8, /* Dest x,y */
426 else if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
428 MaskedPixmap
*mp
= item
->flags
& ITEM_FLAG_MOUNTED
432 gdk_gc_set_clip_origin(gc
, image_x
, area
->y
+ 8);
433 gdk_gc_set_clip_mask(gc
, mp
->mask
);
434 gdk_draw_pixmap(widget
->window
, gc
, mp
->pixmap
,
435 0, 0, /* Source x,y */
436 image_x
, area
->y
+ 8, /* Dest x,y */
440 gdk_gc_set_clip_mask(gc
, NULL
);
441 gdk_gc_set_clip_origin(gc
, 0, 0);
444 /* 'box' renders a background box if the string is also selected */
445 static void draw_string(GtkWidget
*widget
,
455 int text_height
= font
->ascent
+ font
->descent
;
458 ? widget
->style
->fg_gc
[GTK_STATE_SELECTED
]
459 : widget
->style
->fg_gc
[GTK_STATE_NORMAL
];
462 gtk_paint_flat_box(widget
->style
, widget
->window
,
463 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
464 NULL
, widget
, "text",
466 MIN(width
, area_width
),
469 if (width
> area_width
)
472 clip
.y
= y
- font
->ascent
;
473 clip
.width
= area_width
;
474 clip
.height
= text_height
;
475 gdk_gc_set_clip_origin(gc
, 0, 0);
476 gdk_gc_set_clip_rectangle(gc
, &clip
);
479 gdk_draw_text(widget
->window
,
483 string
, strlen(string
));
485 if (width
> area_width
)
489 red_gc
= gdk_gc_new(widget
->window
);
490 gdk_gc_set_foreground(red_gc
, &red
);
492 gdk_draw_rectangle(widget
->window
, red_gc
, TRUE
,
493 x
+ area_width
- 1, clip
.y
, 1, text_height
);
494 gdk_gc_set_clip_rectangle(gc
, NULL
);
498 /* Render the details somewhere */
499 static void draw_details(FilerWindow
*filer_window
, DirItem
*item
, int x
, int y
,
500 int width
, gboolean selected
, gboolean box
)
502 GtkWidget
*widget
= GTK_WIDGET(filer_window
->collection
);
505 w
= details_width(filer_window
, item
);
509 details(filer_window
, item
),
515 if (item
->lstat_errno
)
518 if (filer_window
->details_type
== DETAILS_SIZE_BARS
)
521 int bar_x
= x
+ width
- MAX_BAR_SIZE
- 4;
523 if (item
->base_type
== TYPE_DIRECTORY
)
526 bar
= BAR_SIZE(item
->size
);
528 gdk_draw_rectangle(widget
->window
,
529 widget
->style
->black_gc
,
531 bar_x
, y
- fixed_font
->ascent
,
533 fixed_font
->ascent
+ fixed_font
->descent
);
534 gdk_draw_rectangle(widget
->window
,
535 widget
->style
->white_gc
,
538 y
- fixed_font
->ascent
+ 2,
540 fixed_font
->ascent
+ fixed_font
->descent
- 4);
545 if (filer_window
->details_type
== DETAILS_SUMMARY
)
547 /* Underline the effective permissions */
548 gdk_draw_rectangle(widget
->window
,
549 widget
->style
->fg_gc
[selected
553 x
- 1 + fixed_width
*
554 (5 + 4 * applicable(item
->uid
, item
->gid
)),
555 y
+ fixed_font
->descent
- 1,
556 fixed_width
* 3 + 1, 1);
560 /* Return a string (valid until next call) giving details
563 char *details(FilerWindow
*filer_window
, DirItem
*item
)
565 mode_t m
= item
->mode
;
566 static guchar
*buf
= NULL
;
571 if (item
->lstat_errno
)
572 buf
= g_strdup_printf(_("lstat(2) failed: %s"),
573 g_strerror(item
->lstat_errno
));
574 else if (filer_window
->details_type
== DETAILS_SUMMARY
)
576 buf
= g_strdup_printf("%s %s %-8.8s %-8.8s %s %s",
577 item
->flags
& ITEM_FLAG_APPDIR
? "App " :
578 S_ISDIR(m
) ? "Dir " :
579 S_ISCHR(m
) ? "Char" :
580 S_ISBLK(m
) ? "Blck" :
581 S_ISLNK(m
) ? "Link" :
582 S_ISSOCK(m
) ? "Sock" :
583 S_ISFIFO(m
) ? "Pipe" : "File",
584 pretty_permissions(m
),
585 user_name(item
->uid
),
586 group_name(item
->gid
),
587 format_size_aligned(item
->size
),
588 pretty_time(&item
->mtime
));
592 if (item
->base_type
!= TYPE_DIRECTORY
)
594 if (filer_window
->display_style
== SMALL_FULL_INFO
)
595 buf
= g_strdup(format_size_aligned(item
->size
));
597 buf
= g_strdup(format_size(item
->size
));
606 static void draw_item_large_full(GtkWidget
*widget
,
607 CollectionItem
*colitem
,
609 FilerWindow
*filer_window
)
611 DirItem
*item
= (DirItem
*) colitem
->data
;
612 MaskedPixmap
*image
= item
->image
;
613 int text_x
= area
->x
+ MAX_ICON_WIDTH
+ 8;
614 int low_text_y
= area
->y
+ area
->height
- fixed_font
->descent
- 2;
615 gboolean selected
= colitem
->selected
;
616 GdkRectangle pic_area
;
617 int text_area_width
= area
->width
- (text_x
- area
->x
);
619 pic_area
.x
= area
->x
;
620 pic_area
.y
= area
->y
;
621 pic_area
.width
= image
->width
+ 8;
622 pic_area
.height
= area
->height
;
624 draw_large_icon(widget
, &pic_area
, item
, selected
);
630 low_text_y
- item_font
->descent
- fixed_font
->ascent
,
635 draw_details(filer_window
, item
, text_x
, low_text_y
,
636 text_area_width
, selected
, TRUE
);
639 static void draw_item_small_full(GtkWidget
*widget
,
640 CollectionItem
*colitem
,
642 FilerWindow
*filer_window
)
644 DirItem
*item
= (DirItem
*) colitem
->data
;
645 int text_x
= area
->x
+ SMALL_ICON_WIDTH
+ 4;
646 int bottom
= area
->y
+ area
->height
;
647 int low_text_y
= bottom
- item_font
->descent
- 2;
648 gboolean selected
= colitem
->selected
;
649 GdkRectangle pic_area
;
650 int text_height
= item_font
->ascent
+ item_font
->descent
;
651 int fixed_height
= fixed_font
->ascent
+ fixed_font
->descent
;
652 int box_height
= MAX(text_height
, fixed_height
) + 2;
655 pic_area
.x
= area
->x
;
656 pic_area
.y
= area
->y
;
657 pic_area
.width
= SMALL_ICON_WIDTH
;
658 pic_area
.height
= SMALL_ICON_HEIGHT
;
660 draw_small_icon(widget
, &pic_area
, item
, selected
);
663 gtk_paint_flat_box(widget
->style
, widget
->window
,
664 GTK_STATE_SELECTED
, GTK_SHADOW_NONE
,
665 NULL
, widget
, "text",
666 text_x
, bottom
- 1 - box_height
,
667 area
->width
- (text_x
- area
->x
) - 1,
675 area
->width
- (text_x
- area
->x
),
678 w
= details_width(filer_window
, item
);
679 text_x
= area
->width
- w
- 4 + area
->x
;
680 draw_details(filer_window
,
681 item
, text_x
, bottom
- fixed_font
->descent
- 2,
682 w
+ 2, selected
, FALSE
);
685 static void draw_item_small(GtkWidget
*widget
,
686 CollectionItem
*colitem
,
688 FilerWindow
*filer_window
)
690 DirItem
*item
= (DirItem
*) colitem
->data
;
691 int text_x
= area
->x
+ SMALL_ICON_WIDTH
+ 4;
692 int low_text_y
= area
->y
+ area
->height
- item_font
->descent
- 2;
693 gboolean selected
= colitem
->selected
;
694 GdkRectangle pic_area
;
696 pic_area
.x
= area
->x
;
697 pic_area
.y
= area
->y
;
698 pic_area
.width
= SMALL_ICON_WIDTH
;
699 pic_area
.height
= SMALL_ICON_HEIGHT
;
701 draw_small_icon(widget
, &pic_area
, item
, selected
);
709 area
->width
- (text_x
- area
->x
),
713 static void draw_item_large(GtkWidget
*widget
,
714 CollectionItem
*colitem
,
716 FilerWindow
*filer_window
)
718 DirItem
*item
= (DirItem
*) colitem
->data
;
719 int text_width
= item
->name_width
;
720 int text_x
= area
->x
+ ((area
->width
- text_width
) >> 1);
721 int text_y
= area
->y
+ area
->height
- item_font
->descent
- 2;
722 gboolean selected
= colitem
->selected
;
724 draw_large_icon(widget
, area
, item
, selected
);
726 if (text_x
< area
->x
)
738 int sort_by_name(const void *item1
, const void *item2
)
741 return g_strcasecmp((*((DirItem
**)item1
))->leafname
,
742 (*((DirItem
**)item2
))->leafname
);
743 return strcmp((*((DirItem
**)item1
))->leafname
,
744 (*((DirItem
**)item2
))->leafname
);
747 int sort_by_type(const void *item1
, const void *item2
)
749 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
750 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
753 int diff
= i1
->base_type
- i2
->base_type
;
756 diff
= (i1
->flags
& ITEM_FLAG_APPDIR
)
757 - (i2
->flags
& ITEM_FLAG_APPDIR
);
759 return diff
> 0 ? 1 : -1;
766 diff
= strcmp(m1
->media_type
, m2
->media_type
);
768 diff
= strcmp(m1
->subtype
, m2
->subtype
);
776 return diff
> 0 ? 1 : -1;
778 return sort_by_name(item1
, item2
);
781 int sort_by_date(const void *item1
, const void *item2
)
783 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
784 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
786 return i1
->mtime
> i2
->mtime
? -1 :
787 i1
->mtime
< i2
->mtime
? 1 :
788 sort_by_name(item1
, item2
);
791 int sort_by_size(const void *item1
, const void *item2
)
793 const DirItem
*i1
= (DirItem
*) ((CollectionItem
*) item1
)->data
;
794 const DirItem
*i2
= (DirItem
*) ((CollectionItem
*) item2
)->data
;
796 return i1
->size
> i2
->size
? -1 :
797 i1
->size
< i2
->size
? 1 :
798 sort_by_name(item1
, item2
);
801 /* Make the items as narrow as possible */
802 void shrink_width(FilerWindow
*filer_window
)
805 Collection
*col
= filer_window
->collection
;
806 int width
= MIN_ITEM_WIDTH
;
808 DisplayStyle style
= filer_window
->display_style
;
809 int text_height
, fixed_height
;
812 text_height
= item_font
->ascent
+ item_font
->descent
;
814 for (i
= 0; i
< col
->number_of_items
; i
++)
816 this_width
= calc_width(filer_window
,
817 (DirItem
*) col
->items
[i
].data
);
818 if (this_width
> width
)
824 case LARGE_FULL_INFO
:
825 height
= MAX_ICON_HEIGHT
+ 4;
827 case SMALL_FULL_INFO
:
828 fixed_height
= fixed_font
->ascent
+ fixed_font
->descent
;
829 text_height
= MAX(text_height
, fixed_height
);
832 height
= MAX(text_height
, SMALL_ICON_HEIGHT
) + 4;
836 height
= text_height
+ MAX_ICON_HEIGHT
+ 8;
840 collection_set_item_size(filer_window
->collection
, width
, height
);
843 void display_set_sort_fn(FilerWindow
*filer_window
,
844 int (*fn
)(const void *a
, const void *b
))
846 if (filer_window
->sort_fn
== fn
)
849 filer_window
->sort_fn
= fn
;
852 collection_qsort(filer_window
->collection
,
853 filer_window
->sort_fn
);
855 update_options_label();
858 void display_details_set(FilerWindow
*filer_window
, DetailsType details
)
860 if (filer_window
->details_type
== details
)
862 filer_window
->details_type
= details
;
863 shrink_width(filer_window
);
864 update_options_label();
867 void display_style_set(FilerWindow
*filer_window
, DisplayStyle style
)
869 if (filer_window
->display_style
== style
)
872 if (filer_window
->panel_type
)
875 last_display_style
= style
;
877 filer_window
->display_style
= style
;
881 case SMALL_FULL_INFO
:
882 collection_set_functions(filer_window
->collection
,
883 (CollectionDrawFunc
) draw_item_small_full
,
884 (CollectionTestFunc
) test_point_small_full
,
888 collection_set_functions(filer_window
->collection
,
889 (CollectionDrawFunc
) draw_item_small
,
890 (CollectionTestFunc
) test_point_small
,
893 case LARGE_FULL_INFO
:
894 collection_set_functions(filer_window
->collection
,
895 (CollectionDrawFunc
) draw_item_large_full
,
896 (CollectionTestFunc
) test_point_large_full
,
900 collection_set_functions(filer_window
->collection
,
901 (CollectionDrawFunc
) draw_item_large
,
902 (CollectionTestFunc
) test_point_large
,
907 shrink_width(filer_window
);
909 update_options_label();
912 /* Build up some option widgets to go in the options dialog, but don't
915 static GtkWidget
*create_options()
917 GtkWidget
*vbox
, *hbox
, *slide
;
919 vbox
= gtk_vbox_new(FALSE
, 0);
920 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 4);
922 display_label
= gtk_label_new("<>");
923 gtk_label_set_line_wrap(GTK_LABEL(display_label
), TRUE
);
924 gtk_box_pack_start(GTK_BOX(vbox
), display_label
, FALSE
, TRUE
, 0);
927 gtk_check_button_new_with_label(_("Ignore case when sorting"));
928 gtk_box_pack_start(GTK_BOX(vbox
), toggle_sort_nocase
, FALSE
, TRUE
, 0);
930 hbox
= gtk_hbox_new(FALSE
, 4);
931 gtk_box_pack_start(GTK_BOX(hbox
),
932 gtk_label_new(_("Max Large Icons width")),
934 adj_large_truncate
= GTK_ADJUSTMENT(gtk_adjustment_new(0,
935 MIN_TRUNCATE
, MAX_TRUNCATE
, 1, 10, 0));
936 slide
= gtk_hscale_new(adj_large_truncate
);
937 gtk_widget_set_usize(slide
, MAX_TRUNCATE
, 24);
938 gtk_scale_set_draw_value(GTK_SCALE(slide
), FALSE
);
939 gtk_box_pack_start(GTK_BOX(hbox
), slide
, FALSE
, TRUE
, 0);
940 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
942 hbox
= gtk_hbox_new(FALSE
, 4);
943 gtk_box_pack_start(GTK_BOX(hbox
),
944 gtk_label_new(_("Max Small Icons width")),
946 adj_small_truncate
= GTK_ADJUSTMENT(gtk_adjustment_new(0,
947 MIN_TRUNCATE
, MAX_TRUNCATE
, 1, 10, 0));
948 slide
= gtk_hscale_new(adj_small_truncate
);
949 gtk_widget_set_usize(slide
, MAX_TRUNCATE
, 24);
950 gtk_scale_set_draw_value(GTK_SCALE(slide
), FALSE
);
951 gtk_box_pack_start(GTK_BOX(hbox
), slide
, FALSE
, TRUE
, 0);
952 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, TRUE
, 0);
957 static void update_options_label(void)
961 str
= g_strdup_printf(_("The last used display style (%s) and sort "
962 "function (Sort By %s) will be saved if you click on "
963 "Save."), style_to_name(), sort_fn_to_name());
964 gtk_label_set_text(GTK_LABEL(display_label
), str
);
968 /* Reflect current state by changing the widgets in the options box */
969 static void update_options()
971 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_sort_nocase
),
974 gtk_adjustment_set_value(adj_small_truncate
, o_small_truncate
);
975 gtk_adjustment_set_value(adj_large_truncate
, o_large_truncate
);
977 update_options_label();
980 /* Set current values by reading the states of the widgets in the options box */
981 static void set_options()
983 gboolean old_case
= o_sort_nocase
;
984 GList
*next
= all_filer_windows
;
986 o_sort_nocase
= gtk_toggle_button_get_active(
987 GTK_TOGGLE_BUTTON(toggle_sort_nocase
));
989 o_small_truncate
= adj_small_truncate
->value
;
990 o_large_truncate
= adj_large_truncate
->value
;
994 FilerWindow
*filer_window
= (FilerWindow
*) next
->data
;
996 if (o_sort_nocase
!= old_case
)
998 collection_qsort(filer_window
->collection
,
999 filer_window
->sort_fn
);
1001 shrink_width(filer_window
);
1007 static guchar
*style_to_name(void)
1009 return last_display_style
== LARGE_ICONS
? _("Large Icons") :
1010 last_display_style
== SMALL_ICONS
? _("Small Icons") :
1014 static guchar
*sort_fn_to_name(void)
1016 return last_sort_fn
== sort_by_name
? _("Name") :
1017 last_sort_fn
== sort_by_type
? _("Type") :
1018 last_sort_fn
== sort_by_date
? _("Date") :
1022 static void save_options()
1026 option_write("display_sort_nocase", o_sort_nocase
? "1" : "0");
1027 option_write("display_display_style",
1028 last_display_style
== LARGE_ICONS
? "Large Icons" :
1029 last_display_style
== SMALL_ICONS
? "Small Icons" :
1030 last_display_style
== SMALL_FULL_INFO
? "Small, Full Info" :
1031 "Large, Full Info");
1032 option_write("display_sort_by",
1033 last_sort_fn
== sort_by_name
? "Name" :
1034 last_sort_fn
== sort_by_type
? "Type" :
1035 last_sort_fn
== sort_by_date
? "Date" :
1038 tmp
= g_strdup_printf("%d, %d", o_large_truncate
, o_small_truncate
);
1039 option_write("display_truncate", tmp
);
1043 static char *display_sort_nocase(char *data
)
1045 o_sort_nocase
= atoi(data
) != 0;
1049 static char *display_display_style(char *data
)
1051 if (g_strcasecmp(data
, "Large Icons") == 0)
1052 last_display_style
= LARGE_ICONS
;
1053 else if (g_strcasecmp(data
, "Small Icons") == 0)
1054 last_display_style
= SMALL_ICONS
;
1055 else if (g_strcasecmp(data
, "Large, Full Info") == 0)
1056 last_display_style
= LARGE_FULL_INFO
;
1057 else if (g_strcasecmp(data
, "Small, Full Info") == 0)
1058 last_display_style
= SMALL_FULL_INFO
;
1060 return _("Unknown display style");
1065 static char *display_sort_by(char *data
)
1067 if (g_strcasecmp(data
, "Name") == 0)
1068 last_sort_fn
= sort_by_name
;
1069 else if (g_strcasecmp(data
, "Type") == 0)
1070 last_sort_fn
= sort_by_type
;
1071 else if (g_strcasecmp(data
, "Date") == 0)
1072 last_sort_fn
= sort_by_date
;
1073 else if (g_strcasecmp(data
, "Size") == 0)
1074 last_sort_fn
= sort_by_size
;
1076 return _("Unknown sort type");
1081 static char *display_truncate(char *data
)
1085 comma
= strchr(data
, ',');
1087 return "Missing , in display_truncate";
1089 o_large_truncate
= CLAMP(atoi(data
), MIN_TRUNCATE
, MAX_TRUNCATE
);
1090 o_small_truncate
= CLAMP(atoi(comma
+ 1), MIN_TRUNCATE
, MAX_TRUNCATE
);
1095 /* Set the 'Show Hidden' flag for this window */
1096 void display_set_hidden(FilerWindow
*filer_window
, gboolean hidden
)
1098 if (filer_window
->show_hidden
== hidden
)
1101 filer_window
->show_hidden
= hidden
;
1102 last_show_hidden
= hidden
;
1104 filer_detach_rescan(filer_window
);
1107 /* Highlight (wink or cursor) this item in the filer window. If the item
1108 * isn't already there but we're scanning then highlight it if it
1111 void display_set_autoselect(FilerWindow
*filer_window
, guchar
*leaf
)
1113 Collection
*col
= filer_window
->collection
;
1116 g_free(filer_window
->auto_select
);
1117 filer_window
->auto_select
= NULL
;
1119 for (i
= 0; i
< col
->number_of_items
; i
++)
1121 DirItem
*item
= (DirItem
*) col
->items
[i
].data
;
1123 if (strcmp(item
->leafname
, leaf
) == 0)
1125 if (col
->cursor_item
!= -1)
1126 collection_set_cursor_item(col
, i
);
1128 collection_wink_item(col
, i
);
1133 filer_window
->auto_select
= g_strdup(leaf
);