##### Note: GQview CVS on sourceforge is not always up to date, please use #####
[geeqie.git] / src / layout_util.c
1 /*
2  * GQview
3  * (C) 2004 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12
13 #include "gqview.h"
14 #include "layout_util.h"
15
16 #include "bar_info.h"
17 #include "bar_exif.h"
18 #include "bar_sort.h"
19 #include "cache_maint.h"
20 #include "collect.h"
21 #include "collect-dlg.h"
22 #include "dupe.h"
23 #include "editors.h"
24 #include "info.h"
25 #include "layout_image.h"
26 #include "pan-view.h"
27 #include "pixbuf_util.h"
28 #include "preferences.h"
29 #include "print.h"
30 #include "search.h"
31 #include "utilops.h"
32 #include "ui_bookmark.h"
33 #include "ui_fileops.h"
34 #include "ui_menu.h"
35 #include "ui_misc.h"
36 #include "ui_tabcomp.h"
37
38 #include <gdk/gdkkeysyms.h> /* for keyboard values */
39
40 #include "icons/icon_thumb.xpm"
41 #include "icons/icon_float.xpm"
42
43
44 #define MENU_EDIT_ACTION_OFFSET 16
45
46
47 /*
48  *-----------------------------------------------------------------------------
49  * keyboard handler
50  *-----------------------------------------------------------------------------
51  */
52
53 static guint tree_key_overrides[] = {
54         GDK_Page_Up,    GDK_KP_Page_Up,
55         GDK_Page_Down,  GDK_KP_Page_Down,
56         GDK_Home,       GDK_KP_Home,
57         GDK_End,        GDK_KP_End
58 };
59
60 static gint layout_key_match(guint keyval)
61 {
62         gint i;
63
64         for (i = 0; i < sizeof(tree_key_overrides) / sizeof(guint); i++)
65                 {
66                 if (keyval == tree_key_overrides[i]) return TRUE;
67                 }
68
69         return FALSE;
70 }
71
72 static gint layout_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
73 {
74         LayoutWindow *lw = data;
75         gint stop_signal = FALSE;
76         gint x = 0;
77         gint y = 0;
78
79         if (lw->path_entry && GTK_WIDGET_HAS_FOCUS(lw->path_entry))
80                 {
81                 if (event->keyval == GDK_Escape && lw->path)
82                         {
83                         gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->path);
84                         }
85
86                 /* the gtkaccelgroup of the window is stealing presses before they get to the entry (and more),
87                  * so when the some widgets have focus, give them priority (HACK)
88                  */
89                 if (gtk_widget_event(lw->path_entry, (GdkEvent *)event))
90                         {
91                         return TRUE;
92                         }
93                 }
94         if (lw->vdt && GTK_WIDGET_HAS_FOCUS(lw->vdt->treeview) &&
95             !layout_key_match(event->keyval) &&
96             gtk_widget_event(lw->vdt->treeview, (GdkEvent *)event))
97                 {
98                 return TRUE;
99                 }
100         if (lw->bar_info &&
101             bar_info_event(lw->bar_info, (GdkEvent *)event))
102                 {
103                 return TRUE;
104                 }
105
106         if (lw->image &&
107             (GTK_WIDGET_HAS_FOCUS(lw->image->widget) || (lw->tools && widget == lw->window)) )
108                 {
109                 switch (event->keyval)
110                         {
111                         case GDK_Left: case GDK_KP_Left:
112                                 x -= 1;
113                                 stop_signal = TRUE;
114                                 break;
115                         case GDK_Right: case GDK_KP_Right:
116                                 x += 1;
117                                 stop_signal = TRUE;
118                                 break;
119                         case GDK_Up: case GDK_KP_Up:
120                                 y -= 1;
121                                 stop_signal = TRUE;
122                                 break;
123                         case GDK_Down: case GDK_KP_Down:
124                                 y += 1;
125                                 stop_signal = TRUE;
126                                 break;
127                         case GDK_BackSpace:
128                         case 'B': case 'b':
129                                 layout_image_prev(lw);
130                                 stop_signal = TRUE;
131                                 break;
132                         case GDK_space:
133                         case 'N': case 'n':
134                                 layout_image_next(lw);
135                                 stop_signal = TRUE;
136                                 break;
137                         case GDK_Menu:
138                                 layout_image_menu_popup(lw);
139                                 stop_signal = TRUE;
140                                 break;
141                         }
142                 }
143
144         if (!stop_signal && !(event->state & GDK_CONTROL_MASK) )
145             switch (event->keyval)
146                 {
147                 case '+': case GDK_KP_Add:
148                         layout_image_zoom_adjust(lw, get_zoom_increment());
149                         stop_signal = TRUE;
150                         break;
151                 case GDK_KP_Subtract:
152                         layout_image_zoom_adjust(lw, -get_zoom_increment());
153                         stop_signal = TRUE;
154                         break;
155                 case GDK_KP_Multiply:
156                         layout_image_zoom_set(lw, 0.0);
157                         stop_signal = TRUE;
158                         break;
159                 case GDK_KP_Divide:
160                 case '1':
161                         layout_image_zoom_set(lw, 1.0);
162                         stop_signal = TRUE;
163                         break;
164                 case '2':
165                         layout_image_zoom_set(lw, 2.0);
166                         stop_signal = TRUE;
167                         break;
168                 case '3':
169                         layout_image_zoom_set(lw, 3.0);
170                         stop_signal = TRUE;
171                         break;
172                 case '4':
173                         layout_image_zoom_set(lw, 4.0);
174                         stop_signal = TRUE;
175                         break;
176                 case '7':
177                         layout_image_zoom_set(lw, -4.0);
178                         stop_signal = TRUE;
179                         break;
180                 case '8':
181                         layout_image_zoom_set(lw, -3.0);
182                         stop_signal = TRUE;
183                         break;
184                 case '9':
185                         layout_image_zoom_set(lw, -2.0);
186                         stop_signal = TRUE;
187                         break;
188                 case 'W': case 'w':
189                         layout_image_zoom_set_fill_geometry(lw, FALSE);
190                         break;
191                 case 'H': case 'h':
192                         layout_image_zoom_set_fill_geometry(lw, TRUE);
193                         break;
194                 case GDK_Page_Up: case GDK_KP_Page_Up:
195                         layout_image_prev(lw);
196                         stop_signal = TRUE;
197                         break;
198                 case GDK_Page_Down: case GDK_KP_Page_Down:
199                         layout_image_next(lw);
200                         stop_signal = TRUE;
201                         break;
202                 case GDK_Home: case GDK_KP_Home:
203                         layout_image_first(lw);
204                         stop_signal = TRUE;
205                         break;
206                 case GDK_End: case GDK_KP_End:
207                         layout_image_last(lw);
208                         stop_signal = TRUE;
209                         break;
210                 case GDK_Delete: case GDK_KP_Delete:
211                         if (enable_delete_key)
212                                 {
213                                 file_util_delete(NULL, layout_selection_list(lw), widget);
214                                 stop_signal = TRUE;
215                                 }
216                         break;
217                 case GDK_Escape:
218                         /* FIXME:interrupting thumbs no longer allowed */
219 #if 0
220                         interrupt_thumbs();
221 #endif
222                         stop_signal = TRUE;
223                         break;
224                 case 'P': case 'p':
225                         layout_image_slideshow_pause_toggle(lw);
226                         break;
227                 case 'V': case 'v':
228                         if (!(event->state & GDK_MOD1_MASK)) layout_image_full_screen_toggle(lw);
229                         break;
230                 }
231
232         if (event->state & GDK_SHIFT_MASK)
233                 {
234                 x *= 3;
235                 y *= 3;
236                 }
237
238         if (x != 0 || y!= 0)
239                 {
240                 keyboard_scroll_calc(&x, &y, event);
241                 layout_image_scroll(lw, x, y);
242                 }
243
244         if (stop_signal) g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
245
246         return stop_signal;
247 }
248
249 void layout_keyboard_init(LayoutWindow *lw, GtkWidget *window)
250 {
251         g_signal_connect(G_OBJECT(window), "key_press_event",
252                          G_CALLBACK(layout_key_press_cb), lw);
253 }
254
255 /*
256  *-----------------------------------------------------------------------------
257  * menu callbacks
258  *-----------------------------------------------------------------------------
259  */
260
261 static void layout_menu_new_window_cb(GtkAction *action, gpointer data)
262 {
263         LayoutWindow *lw = data;
264         LayoutWindow *nw;
265
266         nw = layout_new(NULL, FALSE, FALSE);
267         layout_sort_set(nw, file_sort_method, file_sort_ascending);
268         layout_set_path(nw, layout_get_path(lw));
269 }
270
271 static void layout_menu_new_cb(GtkAction *action, gpointer data)
272 {
273         collection_window_new(NULL);
274 }
275
276 static void layout_menu_open_cb(GtkAction *action, gpointer data)
277 {
278         collection_dialog_load(NULL);
279 }
280
281 static void layout_menu_search_cb(GtkAction *action, gpointer data)
282 {
283         LayoutWindow *lw = data;
284
285         search_new(lw->path, layout_image_get_path(lw));
286 }
287
288 static void layout_menu_dupes_cb(GtkAction *action, gpointer data)
289 {
290         dupe_window_new(DUPE_MATCH_NAME);
291 }
292
293 static void layout_menu_pan_cb(GtkAction *action, gpointer data)
294 {
295         LayoutWindow *lw = data;
296
297         pan_window_new(layout_get_path(lw));
298 }
299
300 static void layout_menu_print_cb(GtkAction *action, gpointer data)
301 {
302         LayoutWindow *lw = data;
303
304         print_window_new(layout_image_get_path(lw), layout_selection_list(lw), layout_list(lw), lw->window);
305 }
306
307 static void layout_menu_dir_cb(GtkAction *action, gpointer data)
308 {
309         LayoutWindow *lw = data;
310
311         file_util_create_dir(lw->path, lw->window);
312 }
313
314 static void layout_menu_copy_cb(GtkAction *action, gpointer data)
315 {
316         LayoutWindow *lw = data;
317
318         file_util_copy(NULL, layout_selection_list(lw), NULL, lw->window);
319 }
320
321 static void layout_menu_move_cb(GtkAction *action, gpointer data)
322 {
323         LayoutWindow *lw = data;
324
325         file_util_move(NULL, layout_selection_list(lw), NULL, lw->window);
326 }
327
328 static void layout_menu_rename_cb(GtkAction *action, gpointer data)
329 {
330         LayoutWindow *lw = data;
331
332         file_util_rename(NULL, layout_selection_list(lw), lw->window);
333 }
334
335 static void layout_menu_delete_cb(GtkAction *action, gpointer data)
336 {
337         LayoutWindow *lw = data;
338
339         file_util_delete(NULL, layout_selection_list(lw), lw->window);
340 }
341
342 static void layout_menu_close_cb(GtkAction *action, gpointer data)
343 {
344         LayoutWindow *lw = data;
345
346         layout_close(lw);
347 }
348
349 static void layout_menu_exit_cb(GtkAction *action, gpointer data)
350 {
351         exit_gqview();
352 }
353
354 static void layout_menu_alter_90_cb(GtkAction *action, gpointer data)
355 {
356         LayoutWindow *lw = data;
357
358         layout_image_alter(lw, ALTER_ROTATE_90);
359 }
360
361 static void layout_menu_alter_90cc_cb(GtkAction *action, gpointer data)
362 {
363         LayoutWindow *lw = data;
364
365         layout_image_alter(lw, ALTER_ROTATE_90_CC);
366 }
367
368 static void layout_menu_alter_180_cb(GtkAction *action, gpointer data)
369 {
370         LayoutWindow *lw = data;
371
372         layout_image_alter(lw, ALTER_ROTATE_180);
373 }
374
375 static void layout_menu_alter_mirror_cb(GtkAction *action, gpointer data)
376 {
377         LayoutWindow *lw = data;
378
379         layout_image_alter(lw, ALTER_MIRROR);
380 }
381
382 static void layout_menu_alter_flip_cb(GtkAction *action, gpointer data)
383 {
384         LayoutWindow *lw = data;
385
386         layout_image_alter(lw, ALTER_FLIP);
387 }
388
389 static void layout_menu_info_cb(GtkAction *action, gpointer data)
390 {
391         LayoutWindow *lw = data;
392         GList *list;
393         const gchar *path = NULL;
394
395         list = layout_selection_list(lw);
396         if (!list) path = layout_image_get_path(lw);
397
398         info_window_new(path, list);
399 }
400
401 static void layout_menu_select_all_cb(GtkAction *action, gpointer data)
402 {
403         LayoutWindow *lw = data;
404
405         layout_select_all(lw);
406 }
407
408 static void layout_menu_unselect_all_cb(GtkAction *action, gpointer data)
409 {
410         LayoutWindow *lw = data;
411
412         layout_select_none(lw);
413 }
414
415 static void layout_menu_config_cb(GtkAction *action, gpointer data)
416 {
417         show_config_window();
418 }
419
420 static void layout_menu_remove_thumb_cb(GtkAction *action, gpointer data)
421 {
422         cache_manager_show();
423 }
424
425 static void layout_menu_wallpaper_cb(GtkAction *action, gpointer data)
426 {
427         LayoutWindow *lw = data;
428
429         layout_image_to_root(lw);
430 }
431
432 static void layout_menu_zoom_in_cb(GtkAction *action, gpointer data)
433 {
434         LayoutWindow *lw = data;
435
436         layout_image_zoom_adjust(lw, get_zoom_increment());
437 }
438
439 static void layout_menu_zoom_out_cb(GtkAction *action, gpointer data)
440 {
441         LayoutWindow *lw = data;
442
443         layout_image_zoom_adjust(lw, -get_zoom_increment());
444 }
445
446 static void layout_menu_zoom_1_1_cb(GtkAction *action, gpointer data)
447 {
448         LayoutWindow *lw = data;
449
450         layout_image_zoom_set(lw, 1.0);
451 }
452
453 static void layout_menu_zoom_fit_cb(GtkAction *action, gpointer data)
454 {
455         LayoutWindow *lw = data;
456
457         layout_image_zoom_set(lw, 0.0);
458 }
459
460 static void layout_menu_thumb_cb(GtkToggleAction *action, gpointer data)
461 {
462         LayoutWindow *lw = data;
463
464         layout_thumb_set(lw, gtk_toggle_action_get_active(action));
465 }
466
467 static void layout_menu_list_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
468 {
469         LayoutWindow *lw = data;
470
471         layout_views_set(lw, lw->tree_view, (gtk_radio_action_get_current_value(action) == 1));
472 }
473
474 #if 0
475 static void layout_menu_icon_cb(gpointer data, guint action, GtkWidget *widget)
476 {
477         LayoutWindow *lw = data;
478
479         if (!GTK_CHECK_MENU_ITEM(widget)->active) return;
480
481         layout_views_set(lw, lw->tree_view, TRUE);
482 }
483 #endif
484
485 static void layout_menu_tree_cb(GtkToggleAction *action, gpointer data)
486 {
487         LayoutWindow *lw = data;
488
489         layout_views_set(lw, gtk_toggle_action_get_active(action), lw->icon_view);
490 }
491
492 static void layout_menu_fullscreen_cb(GtkAction *action, gpointer data)
493 {
494         LayoutWindow *lw = data;
495
496         layout_image_full_screen_toggle(lw);
497 }
498
499 static void layout_menu_refresh_cb(GtkAction *action, gpointer data)
500 {
501         LayoutWindow *lw = data;
502
503         layout_refresh(lw);
504 }
505
506 static void layout_menu_float_cb(GtkToggleAction *action, gpointer data)
507 {
508         LayoutWindow *lw = data;
509
510         if (lw->tools_float != gtk_toggle_action_get_active(action))
511                 {
512                 layout_tools_float_toggle(lw);
513                 }
514 }
515
516 static void layout_menu_hide_cb(GtkAction *action, gpointer data)
517 {
518         LayoutWindow *lw = data;
519
520         layout_tools_hide_toggle(lw);
521 }
522
523 static void layout_menu_toolbar_cb(GtkToggleAction *action, gpointer data)
524 {
525         LayoutWindow *lw = data;
526
527         if (lw->toolbar_hidden != gtk_toggle_action_get_active(action))
528                 {
529                 layout_toolbar_toggle(lw);
530                 }
531 }
532
533 static void layout_menu_bar_info_cb(GtkToggleAction *action, gpointer data)
534 {
535         LayoutWindow *lw = data;
536
537         if (lw->bar_info_enabled != gtk_toggle_action_get_active(action))
538                 {
539                 layout_bar_info_toggle(lw);
540                 }
541 }
542
543 static void layout_menu_bar_exif_cb(GtkToggleAction *action, gpointer data)
544 {
545         LayoutWindow *lw = data;
546
547         if (lw->bar_exif_enabled != gtk_toggle_action_get_active(action))
548                 {
549                 layout_bar_exif_toggle(lw);
550                 }
551 }
552
553 static void layout_menu_bar_sort_cb(GtkToggleAction *action, gpointer data)
554 {
555         LayoutWindow *lw = data;
556
557         if (lw->bar_sort_enabled != gtk_toggle_action_get_active(action))
558                 {
559                 layout_bar_sort_toggle(lw);
560                 }
561 }
562
563 static void layout_menu_slideshow_cb(GtkAction *action, gpointer data)
564 {
565         LayoutWindow *lw = data;
566
567         layout_image_slideshow_toggle(lw);
568 }
569
570 static void layout_menu_help_cb(GtkAction *action, gpointer data)
571 {
572         help_window_show("html_contents");
573 }
574
575 static void layout_menu_help_keys_cb(GtkAction *action, gpointer data)
576 {
577         help_window_show("documentation");
578 }
579
580 static void layout_menu_notes_cb(GtkAction *action, gpointer data)
581 {
582         help_window_show("release_notes");
583 }
584
585 static void layout_menu_about_cb(GtkAction *action, gpointer data)
586 {
587         show_about_window();
588 }
589
590 /*
591  *-----------------------------------------------------------------------------
592  * edit menu
593  *-----------------------------------------------------------------------------
594  */ 
595
596 static void layout_menu_edit_cb(GtkAction *action, gpointer data)
597 {
598         LayoutWindow *lw = data;
599         GList *list;
600         gint n;
601
602         n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "edit_index"));
603
604         list = layout_selection_list(lw);
605         start_editor_from_path_list(n, list);
606         path_list_free(list);
607 }
608
609 static void layout_menu_edit_update(LayoutWindow *lw)
610 {
611         gint i;
612
613         /* main edit menu */
614
615         if (!lw->action_group) return;
616
617         for (i = 0; i < 10; i++)
618                 {
619                 gchar *key;
620                 GtkAction *action;
621
622                 key = g_strdup_printf("Editor%d", i);
623
624                 action = gtk_action_group_get_action(lw->action_group, key);
625                 g_object_set_data(G_OBJECT(action), "edit_index", GINT_TO_POINTER(i));
626
627                 if (editor_command[i] && strlen(editor_command[i]) > 0)
628                         {
629                         gchar *text;
630
631                         if (editor_name[i] && strlen(editor_name[i]) > 0)
632                                 {
633                                 text = g_strdup_printf(_("in %s..."), editor_name[i]);
634                                 }
635                         else
636                                 {
637                                 text = g_strdup(_("in (unknown)..."));
638                                 }
639                         g_object_set(action, "label", text,
640                                              "sensitive", TRUE, NULL);
641                         g_free(text);
642                         }
643                 else
644                         {
645                         g_object_set(action, "label", _("empty"),
646                                              "sensitive", FALSE, NULL);
647                         }
648
649                 g_free(key);
650                 }
651 }
652
653 void layout_edit_update_all(void)
654 {
655         GList *work;
656
657         work = layout_window_list;
658         while (work)
659                 {
660                 LayoutWindow *lw = work->data;
661                 work = work->next;
662
663                 layout_menu_edit_update(lw);
664                 }
665 }
666
667 /*
668  *-----------------------------------------------------------------------------
669  * recent menu
670  *-----------------------------------------------------------------------------
671  */
672
673 static void layout_menu_recent_cb(GtkWidget *widget, gpointer data)
674 {
675         gint n;
676         gchar *path;
677
678         n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "recent_index"));
679
680         path = g_list_nth_data(history_list_get_by_key("recent"), n);
681
682         if (!path) return;
683
684         /* make a copy of it */
685         path = g_strdup(path);
686         collection_window_new(path);
687         g_free(path);
688 }
689
690 static void layout_menu_recent_update(LayoutWindow *lw)
691 {
692         GtkWidget *menu;
693         GtkWidget *recent;
694         GtkWidget *item;
695         GList *list;
696         gint n;
697
698         if (!lw->ui_manager) return;
699
700         list = history_list_get_by_key("recent");
701         n = 0;
702
703         menu = gtk_menu_new();
704
705         while (list)
706                 {
707                 item = menu_item_add_simple(menu, filename_from_path((gchar *)list->data),
708                                             G_CALLBACK(layout_menu_recent_cb), lw);
709                 g_object_set_data(G_OBJECT(item), "recent_index", GINT_TO_POINTER(n));
710                 list = list->next;
711                 n++;
712                 }
713
714         if (n == 0)
715                 {
716                 menu_item_add(menu, _("Empty"), NULL, NULL);
717                 }
718
719         recent = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/FileMenu/OpenRecent");
720         gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), menu);
721         gtk_widget_set_sensitive(recent, (n != 0));
722 }
723
724 void layout_recent_update_all(void)
725 {
726         GList *work;
727
728         work = layout_window_list;
729         while (work)
730                 {
731                 LayoutWindow *lw = work->data;
732                 work = work->next;
733
734                 layout_menu_recent_update(lw);
735                 }
736 }
737
738 void layout_recent_add_path(const gchar *path)
739 {
740         if (!path) return;
741
742         history_list_add_to_key("recent", path, recent_list_max);
743
744         layout_recent_update_all();
745 }
746
747 /*
748  *-----------------------------------------------------------------------------
749  * menu
750  *-----------------------------------------------------------------------------
751  */ 
752
753 #define CB G_CALLBACK
754
755 static GtkActionEntry menu_entries[] = {
756   { "FileMenu",         NULL,           N_("_File") },
757   { "EditMenu",         NULL,           N_("_Edit") },
758   { "AdjustMenu",       NULL,           N_("_Adjust") },
759   { "ViewMenu",         NULL,           N_("_View") },
760   { "HelpMenu",         NULL,           N_("_Help") },
761
762   { "NewWindow",        GTK_STOCK_NEW,  N_("New _window"),      NULL,           NULL,   CB(layout_menu_new_window_cb) },
763   { "NewCollection",    GTK_STOCK_INDEX,N_("_New collection"),  "C",            NULL,   CB(layout_menu_new_cb) },
764   { "OpenCollection",   GTK_STOCK_OPEN, N_("_Open collection..."),"O",          NULL,   CB(layout_menu_open_cb) },
765   { "OpenRecent",       NULL,           N_("Open _recent") },
766   { "Search",           GTK_STOCK_FIND, N_("_Search..."),       "F3",           NULL,   CB(layout_menu_search_cb) },
767   { "FindDupes",        GTK_STOCK_FIND, N_("_Find duplicates..."),"D",          NULL,   CB(layout_menu_dupes_cb) },
768   { "PanView",          NULL,           N_("Pan _view"),        "<control>J",   NULL,   CB(layout_menu_pan_cb) },
769   { "Print",            GTK_STOCK_PRINT,N_("_Print..."),        "<shift>P",     NULL,   CB(layout_menu_print_cb) },
770   { "NewFolder",        NULL,           N_("N_ew folder..."),   "<control>F",   NULL,   CB(layout_menu_dir_cb) },
771   { "Copy",             NULL,           N_("_Copy..."),         "<control>C",   NULL,   CB(layout_menu_copy_cb) },
772   { "Move",             NULL,           N_("_Move..."),         "<control>M",   NULL,   CB(layout_menu_move_cb) },
773   { "Rename",           NULL,           N_("_Rename..."),       "<control>R",   NULL,   CB(layout_menu_rename_cb) },
774   { "Delete",   GTK_STOCK_DELETE,       N_("_Delete..."),       "<control>D",   NULL,   CB(layout_menu_delete_cb) },
775   { "CloseWindow",      GTK_STOCK_CLOSE,N_("C_lose window"),    "<control>W",   NULL,   CB(layout_menu_close_cb) },
776   { "Quit",             GTK_STOCK_QUIT, N_("_Quit"),            "<control>Q",   NULL,   CB(layout_menu_exit_cb) },
777
778   { "Editor0",          NULL,           "editor0",              "<control>1",   NULL,   CB(layout_menu_edit_cb) },
779   { "Editor1",          NULL,           "editor1",              "<control>2",   NULL,   CB(layout_menu_edit_cb) },
780   { "Editor2",          NULL,           "editor2",              "<control>3",   NULL,   CB(layout_menu_edit_cb) },
781   { "Editor3",          NULL,           "editor3",              "<control>4",   NULL,   CB(layout_menu_edit_cb) },
782   { "Editor4",          NULL,           "editor4",              "<control>5",   NULL,   CB(layout_menu_edit_cb) },
783   { "Editor5",          NULL,           "editor5",              "<control>6",   NULL,   CB(layout_menu_edit_cb) },
784   { "Editor6",          NULL,           "editor6",              "<control>7",   NULL,   CB(layout_menu_edit_cb) },
785   { "Editor7",          NULL,           "editor7",              "<control>8",   NULL,   CB(layout_menu_edit_cb) },
786   { "Editor8",          NULL,           "editor8",              "<control>9",   NULL,   CB(layout_menu_edit_cb) },
787   { "Editor9",          NULL,           "editor9",              "<control>0",   NULL,   CB(layout_menu_edit_cb) },
788   { "RotateCW",         NULL,   N_("_Rotate clockwise"),        "bracketright", NULL,   CB(layout_menu_alter_90_cb) },
789   { "RotateCCW",        NULL,   N_("Rotate _counterclockwise"), "bracketleft",  NULL,   CB(layout_menu_alter_90cc_cb) },
790   { "Rotate180",        NULL,           N_("Rotate 1_80"),      "<shift>R",     NULL,   CB(layout_menu_alter_180_cb) },
791   { "Mirror",           NULL,           N_("_Mirror"),          "<shift>M",     NULL,   CB(layout_menu_alter_mirror_cb) },
792   { "Flip",             NULL,           N_("_Flip"),            "<shift>F",     NULL,   CB(layout_menu_alter_flip_cb) },
793   { "Properties",GTK_STOCK_PROPERTIES,  N_("_Properties"),      "<control>P",   NULL,   CB(layout_menu_info_cb) },
794   { "SelectAll",        NULL,           N_("Select _all"),      "<control>A",   NULL,   CB(layout_menu_select_all_cb) },
795   { "SelectNone",       NULL,           N_("Select _none"), "<control><shift>A",NULL,   CB(layout_menu_unselect_all_cb) },
796   { "Preferences",GTK_STOCK_PREFERENCES,N_("P_references..."),  "<control>O",   NULL,   CB(layout_menu_config_cb) },
797   { "Maintenance",      NULL,           N_("_Thumbnail maintenance..."),NULL,   NULL,   CB(layout_menu_remove_thumb_cb) },
798   { "Wallpaper",        NULL,           N_("Set as _wallpaper"),NULL,           NULL,   CB(layout_menu_wallpaper_cb) },
799
800   { "ZoomIn",   GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),         "equal",        NULL,   CB(layout_menu_zoom_in_cb) },
801   { "ZoomOut",  GTK_STOCK_ZOOM_OUT,     N_("Zoom _out"),        "minus",        NULL,   CB(layout_menu_zoom_out_cb) },
802   { "Zoom100",  GTK_STOCK_ZOOM_100,     N_("Zoom _1:1"),        "Z",            NULL,   CB(layout_menu_zoom_1_1_cb) },
803   { "ZoomFit",  GTK_STOCK_ZOOM_FIT,     N_("_Zoom to fit"),     "X",            NULL,   CB(layout_menu_zoom_fit_cb) },
804   { "FullScreen",       NULL,           N_("F_ull screen"),     "F",            NULL,   CB(layout_menu_fullscreen_cb) },
805   { "HideTools",        NULL,           N_("_Hide file list"),  "<control>H",   NULL,   CB(layout_menu_hide_cb) },
806   { "SlideShow",        NULL,           N_("Toggle _slideshow"),"S",            NULL,   CB(layout_menu_slideshow_cb) },
807   { "Refresh",  GTK_STOCK_REFRESH,      N_("_Refresh"),         "R",            NULL,   CB(layout_menu_refresh_cb) },
808
809   { "HelpContents",     GTK_STOCK_HELP, N_("_Contents"),        "F1",           NULL,   CB(layout_menu_help_cb) },
810   { "HelpShortcuts",    NULL,           N_("_Keyboard shortcuts"),NULL,         NULL,   CB(layout_menu_help_keys_cb) },
811   { "HelpNotes",        NULL,           N_("_Release notes"),   NULL,           NULL,   CB(layout_menu_notes_cb) },
812   { "About",            NULL,           N_("_About"),           NULL,           NULL,   CB(layout_menu_about_cb) }
813 };
814
815 static GtkToggleActionEntry menu_toggle_entries[] = {
816   { "Thumbnails",       NULL,           N_("_Thumbnails"),      "T",            NULL,   CB(layout_menu_thumb_cb) },
817   { "FolderTree",       NULL,           N_("Tr_ee"),            "<control>T",   NULL,   CB(layout_menu_tree_cb) },
818   { "FloatTools",       NULL,           N_("_Float file list"), "L",            NULL,   CB(layout_menu_float_cb) },
819   { "HideToolbar",      NULL,           N_("Hide tool_bar"),    NULL,           NULL,   CB(layout_menu_toolbar_cb) },
820   { "SBarKeywords",     NULL,           N_("_Keywords"),        "<control>K",   NULL,   CB(layout_menu_bar_info_cb) },
821   { "SBarExif",         NULL,           N_("E_xif data"),       "<control>E",   NULL,   CB(layout_menu_bar_exif_cb) },
822   { "SBarSort",         NULL,           N_("Sort _manager"),    "<control>S",   NULL,   CB(layout_menu_bar_sort_cb) }
823 };
824
825 static GtkRadioActionEntry menu_radio_entries[] = {
826   { "ViewList",         NULL,           N_("_List"),            "<control>L",   NULL,   0 },
827   { "ViewIcons",        NULL,           N_("I_cons"),           "<control>I",   NULL,   1 }
828 };
829
830 #undef CB
831
832 static const char *menu_ui_description =
833 "<ui>"
834 "  <menubar name='MainMenu'>"
835 "    <menu action='FileMenu'>"
836 "      <menuitem action='NewWindow'/>"
837 "      <menuitem action='NewCollection'/>"
838 "      <menuitem action='OpenCollection'/>"
839 "      <menuitem action='OpenRecent'/>"
840 "      <separator/>"
841 "      <menuitem action='Search'/>"
842 "      <menuitem action='FindDupes'/>"
843 "      <menuitem action='PanView'/>"
844 "      <separator/>"
845 "      <menuitem action='Print'/>"
846 "      <menuitem action='NewFolder'/>"
847 "      <separator/>"
848 "      <menuitem action='Copy'/>"
849 "      <menuitem action='Move'/>"
850 "      <menuitem action='Rename'/>"
851 "      <menuitem action='Delete'/>"
852 "      <separator/>"
853 "      <menuitem action='CloseWindow'/>"
854 "      <menuitem action='Quit'/>"
855 "    </menu>"
856 "    <menu action='EditMenu'>"
857 "      <menuitem action='Editor0'/>"
858 "      <menuitem action='Editor1'/>"
859 "      <menuitem action='Editor2'/>"
860 "      <menuitem action='Editor3'/>"
861 "      <menuitem action='Editor4'/>"
862 "      <menuitem action='Editor5'/>"
863 "      <menuitem action='Editor6'/>"
864 "      <menuitem action='Editor7'/>"
865 "      <menuitem action='Editor8'/>"
866 "      <menuitem action='Editor9'/>"
867 "      <separator/>"
868 "      <menu action='AdjustMenu'>"
869 "        <menuitem action='RotateCW'/>"
870 "        <menuitem action='RotateCCW'/>"
871 "        <menuitem action='Rotate180'/>"
872 "        <menuitem action='Mirror'/>"
873 "        <menuitem action='Flip'/>"
874 "      </menu>"
875 "      <menuitem action='Properties'/>"
876 "      <separator/>"
877 "      <menuitem action='SelectAll'/>"
878 "      <menuitem action='SelectNone'/>"
879 "      <separator/>"
880 "      <menuitem action='Preferences'/>"
881 "      <menuitem action='Maintenance'/>"
882 "      <separator/>"
883 "      <menuitem action='Wallpaper'/>"
884 "    </menu>"
885 "    <menu action='ViewMenu'>"
886 "      <separator/>"
887 "      <menuitem action='ZoomIn'/>"
888 "      <menuitem action='ZoomOut'/>"
889 "      <menuitem action='Zoom100'/>"
890 "      <menuitem action='ZoomFit'/>"
891 "      <separator/>"
892 "      <menuitem action='Thumbnails'/>"
893 "      <menuitem action='ViewList'/>"
894 "      <menuitem action='ViewIcons'/>"
895 "      <separator/>"
896 "      <menuitem action='FolderTree'/>"
897 "      <menuitem action='FullScreen'/>"
898 "      <separator/>"
899 "      <menuitem action='FloatTools'/>"
900 "      <menuitem action='HideTools'/>"
901 "      <menuitem action='HideToolbar'/>"
902 "      <separator/>"
903 "      <menuitem action='SBarKeywords'/>"
904 "      <menuitem action='SBarExif'/>"
905 "      <menuitem action='SBarSort'/>"
906 "      <separator/>"
907 "      <menuitem action='SlideShow'/>"
908 "      <menuitem action='Refresh'/>"
909 "    </menu>"
910 "    <menu action='HelpMenu'>"
911 "      <separator/>"
912 "      <menuitem action='HelpContents'/>"
913 "      <menuitem action='HelpShortcuts'/>"
914 "      <menuitem action='HelpNotes'/>"
915 "      <separator/>"
916 "      <menuitem action='About'/>"
917 "    </menu>"
918 "  </menubar>"
919 "</ui>";
920
921
922 static gchar *menu_translate(const gchar *path, gpointer data)
923 {
924         return _(path);
925 }
926
927 void layout_actions_setup(LayoutWindow *lw)
928 {
929         GError *error;
930
931         if (lw->ui_manager) return;
932
933         lw->action_group = gtk_action_group_new ("MenuActions");
934         gtk_action_group_set_translate_func(lw->action_group, menu_translate, NULL, NULL);
935
936         gtk_action_group_add_actions(lw->action_group,
937                                      menu_entries, G_N_ELEMENTS(menu_entries), lw);
938         gtk_action_group_add_toggle_actions(lw->action_group,
939                                             menu_toggle_entries, G_N_ELEMENTS(menu_toggle_entries), lw);
940         gtk_action_group_add_radio_actions(lw->action_group,
941                                            menu_radio_entries, G_N_ELEMENTS(menu_radio_entries),
942                                            0, G_CALLBACK(layout_menu_list_cb), lw);
943
944         lw->ui_manager = gtk_ui_manager_new();
945         gtk_ui_manager_set_add_tearoffs(lw->ui_manager, TRUE);
946         gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group, 0);
947
948         error = NULL;
949         if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, menu_ui_description, -1, &error))
950                 {
951                 g_message ("building menus failed: %s", error->message);
952                 g_error_free (error);
953                 exit (EXIT_FAILURE);
954                 }
955 }
956
957 void layout_actions_add_window(LayoutWindow *lw, GtkWidget *window)
958 {
959         GtkAccelGroup *group;
960
961         if (!lw->ui_manager) return;
962
963         group = gtk_ui_manager_get_accel_group(lw->ui_manager);
964         gtk_window_add_accel_group(GTK_WINDOW(window), group);
965 }
966
967 GtkWidget *layout_actions_menu_bar(LayoutWindow *lw)
968 {
969         return gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu");
970 }
971
972
973 /*
974  *-----------------------------------------------------------------------------
975  * toolbar
976  *-----------------------------------------------------------------------------
977  */ 
978
979 static void layout_button_thumb_cb(GtkWidget *widget, gpointer data)
980 {
981         LayoutWindow *lw = data;
982
983         layout_thumb_set(lw, GTK_TOGGLE_BUTTON(widget)->active);
984 }
985
986 static void layout_button_home_cb(GtkWidget *widget, gpointer data)
987 {
988         LayoutWindow *lw = data;
989         const gchar *path = homedir();
990
991         if (path) layout_set_path(lw, path);
992 }
993
994 static void layout_button_refresh_cb(GtkWidget *widget, gpointer data)
995 {
996         LayoutWindow *lw = data;
997
998         layout_refresh(lw);
999 }
1000
1001 static void layout_button_zoom_in_cb(GtkWidget *widget, gpointer data)
1002 {
1003         LayoutWindow *lw = data;
1004
1005         layout_image_zoom_adjust(lw, get_zoom_increment());
1006 }
1007
1008 static void layout_button_zoom_out_cb(GtkWidget *widget, gpointer data)
1009 {
1010         LayoutWindow *lw = data;
1011
1012         layout_image_zoom_adjust(lw, -get_zoom_increment());
1013 }
1014
1015 static void layout_button_zoom_fit_cb(GtkWidget *widget, gpointer data)
1016 {
1017         LayoutWindow *lw = data;
1018
1019         layout_image_zoom_set(lw, 0.0);
1020 }
1021
1022 static void layout_button_zoom_1_1_cb(GtkWidget *widget, gpointer data)
1023 {
1024         LayoutWindow *lw = data;
1025
1026         layout_image_zoom_set(lw, 1.0);
1027 }
1028
1029 static void layout_button_config_cb(GtkWidget *widget, gpointer data)
1030 {
1031         show_config_window();
1032 }
1033
1034 static void layout_button_float_cb(GtkWidget *widget, gpointer data)
1035 {
1036         LayoutWindow *lw = data;
1037
1038         layout_tools_float_toggle(lw);
1039 }
1040
1041 GtkWidget *layout_button(GtkWidget *box, gchar **pixmap_data, const gchar *stock_id, gint toggle,
1042                          GtkTooltips *tooltips, const gchar *tip_text,
1043                          GCallback func, gpointer data)
1044 {
1045         GtkWidget *button;
1046         GtkWidget *icon;
1047
1048         if (toggle)
1049                 {
1050                 button = gtk_toggle_button_new();
1051                 }
1052         else
1053                 {
1054                 button = gtk_button_new();
1055                 }
1056
1057         g_signal_connect(G_OBJECT(button), "clicked", func, data);
1058         gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
1059         gtk_widget_show(button);
1060         gtk_tooltips_set_tip(tooltips, button, tip_text, NULL);
1061
1062         if (stock_id)
1063                 {
1064                 icon = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON);
1065                 }
1066         else
1067                 {
1068                 GdkPixbuf *pixbuf;
1069
1070                 pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)pixmap_data);
1071                 icon = gtk_image_new_from_pixbuf(pixbuf);
1072                 gdk_pixbuf_unref(pixbuf);
1073                 }
1074
1075         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1076
1077         gtk_container_add(GTK_CONTAINER(button), icon);
1078         gtk_widget_show(icon);
1079
1080         return button;
1081 }
1082
1083 GtkWidget *layout_button_bar(LayoutWindow *lw)
1084 {
1085         GtkWidget *box;
1086         GtkTooltips *tooltips;
1087
1088         tooltips = lw->tooltips;
1089
1090         box = gtk_hbox_new(FALSE, 0);
1091
1092         lw->thumb_button = layout_button(box, (gchar **)icon_thumb_xpm, NULL, TRUE,
1093                       tooltips, _("Show thumbnails"), G_CALLBACK(layout_button_thumb_cb), lw);
1094         layout_button(box, NULL, GTK_STOCK_HOME, FALSE,
1095                       tooltips, _("Change to home folder"), G_CALLBACK(layout_button_home_cb), lw);
1096         layout_button(box, NULL, GTK_STOCK_REFRESH, FALSE,
1097                       tooltips, _("Refresh file list"), G_CALLBACK(layout_button_refresh_cb), lw);
1098         layout_button(box, NULL, GTK_STOCK_ZOOM_IN, FALSE,
1099                       tooltips, _("Zoom in"), G_CALLBACK(layout_button_zoom_in_cb), lw);
1100         layout_button(box, NULL, GTK_STOCK_ZOOM_OUT, FALSE,
1101                       tooltips, _("Zoom out"), G_CALLBACK(layout_button_zoom_out_cb), lw);
1102         layout_button(box, NULL, GTK_STOCK_ZOOM_FIT, FALSE,
1103                       tooltips, _("Fit image to window"), G_CALLBACK(layout_button_zoom_fit_cb), lw);
1104         layout_button(box, NULL, GTK_STOCK_ZOOM_100, FALSE,
1105                       tooltips, _("Set zoom 1:1"), G_CALLBACK(layout_button_zoom_1_1_cb), lw);
1106         layout_button(box, NULL, GTK_STOCK_PREFERENCES, FALSE,
1107                       tooltips, _("Configure options"), G_CALLBACK(layout_button_config_cb), lw);
1108         layout_button(box, (gchar **)icon_float_xpm, NULL, FALSE,
1109                       tooltips, _("Float Controls"), G_CALLBACK(layout_button_float_cb), lw);
1110
1111         return box;
1112 }
1113
1114 /*
1115  *-----------------------------------------------------------------------------
1116  * misc
1117  *-----------------------------------------------------------------------------
1118  */
1119
1120 static void layout_util_sync_views(LayoutWindow *lw)
1121 {
1122         GtkAction *action;
1123
1124         if (!lw->action_group) return;
1125
1126         action = gtk_action_group_get_action(lw->action_group, "FolderTree");
1127         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->tree_view);
1128
1129         action = gtk_action_group_get_action(lw->action_group, "ViewIcons");
1130         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->icon_view);
1131
1132         action = gtk_action_group_get_action(lw->action_group, "FloatTools");
1133         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->tools_float);
1134
1135         action = gtk_action_group_get_action(lw->action_group, "SBarKeywords");
1136         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->bar_info_enabled);
1137
1138         action = gtk_action_group_get_action(lw->action_group, "SBarExif");
1139         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->bar_exif_enabled);
1140
1141         action = gtk_action_group_get_action(lw->action_group, "SBarSort");
1142         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->bar_sort_enabled);
1143
1144         action = gtk_action_group_get_action(lw->action_group, "HideToolbar");
1145         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->toolbar_hidden);
1146 }
1147
1148 void layout_util_sync_thumb(LayoutWindow *lw)
1149 {
1150         GtkAction *action;
1151
1152         if (!lw->action_group) return;
1153
1154         action = gtk_action_group_get_action(lw->action_group, "Thumbnails");
1155         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->thumbs_enabled);
1156         g_object_set(action, "sensitive", !lw->icon_view, NULL);
1157
1158         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lw->thumb_button), lw->thumbs_enabled);
1159         gtk_widget_set_sensitive(lw->thumb_button, !lw->icon_view);
1160 }
1161
1162 void layout_util_sync(LayoutWindow *lw)
1163 {
1164         layout_util_sync_views(lw);
1165         layout_util_sync_thumb(lw);
1166         layout_menu_recent_update(lw);
1167         layout_menu_edit_update(lw);
1168 }
1169
1170 /*
1171  *-----------------------------------------------------------------------------
1172  * icons (since all the toolbar icons are included here, best place as any)
1173  *-----------------------------------------------------------------------------
1174  */
1175
1176 PixmapFolders *folder_icons_new(void)
1177 {
1178         PixmapFolders *pf;
1179
1180         pf = g_new0(PixmapFolders, 1);
1181
1182         pf->close = pixbuf_inline(PIXBUF_INLINE_FOLDER_CLOSED);
1183         pf->open = pixbuf_inline(PIXBUF_INLINE_FOLDER_OPEN);
1184         pf->deny = pixbuf_inline(PIXBUF_INLINE_FOLDER_LOCKED);
1185         pf->parent = pixbuf_inline(PIXBUF_INLINE_FOLDER_UP);
1186
1187         return pf;
1188 }
1189
1190 void folder_icons_free(PixmapFolders *pf)
1191 {
1192         if (!pf) return;
1193
1194         g_object_unref(pf->close);
1195         g_object_unref(pf->open);
1196         g_object_unref(pf->deny);
1197         g_object_unref(pf->parent);
1198
1199         g_free(pf);
1200 }
1201
1202 /*
1203  *-----------------------------------------------------------------------------
1204  * sidebars
1205  *-----------------------------------------------------------------------------
1206  */
1207
1208 #define SIDEBAR_WIDTH 288
1209
1210 static void layout_bar_info_destroyed(GtkWidget *widget, gpointer data)
1211 {
1212         LayoutWindow *lw = data;
1213
1214         lw->bar_info = NULL;
1215
1216         if (lw->utility_box)
1217                 {
1218                 /* destroyed from within itself */
1219                 lw->bar_info_enabled = FALSE;
1220                 layout_util_sync_views(lw);
1221                 }
1222 }
1223
1224 static GList *layout_bar_info_list_cb(gpointer data)
1225 {
1226         LayoutWindow *lw = data;
1227
1228         return layout_selection_list(lw);
1229 }
1230
1231 static void layout_bar_info_new(LayoutWindow *lw)
1232 {
1233         if (!lw->utility_box) return;
1234                                                                                                                     
1235         lw->bar_info = bar_info_new(layout_image_get_path(lw), FALSE, lw->utility_box);
1236         bar_info_set_selection_func(lw->bar_info, layout_bar_info_list_cb, lw);
1237         bar_info_selection(lw->bar_info, layout_selection_count(lw, NULL) - 1);
1238         bar_info_size_request(lw->bar_info, SIDEBAR_WIDTH * 3 / 4);
1239         g_signal_connect(G_OBJECT(lw->bar_info), "destroy",
1240                          G_CALLBACK(layout_bar_info_destroyed), lw);
1241         lw->bar_info_enabled = TRUE;
1242
1243         gtk_box_pack_start(GTK_BOX(lw->utility_box), lw->bar_info, FALSE, FALSE, 0);
1244         gtk_widget_show(lw->bar_info);
1245 }
1246                                                                                                                     
1247 static void layout_bar_info_close(LayoutWindow *lw)
1248 {
1249         if (lw->bar_info)
1250                 {
1251                 bar_info_close(lw->bar_info);
1252                 lw->bar_info = NULL;
1253                 }
1254         lw->bar_info_enabled = FALSE;
1255 }
1256
1257 void layout_bar_info_toggle(LayoutWindow *lw)
1258 {
1259         if (lw->bar_info_enabled)
1260                 {
1261                 layout_bar_info_close(lw);
1262                 }
1263         else
1264                 {
1265                 layout_bar_info_new(lw);
1266                 }
1267 }
1268
1269 static void layout_bar_info_new_image(LayoutWindow *lw)
1270 {
1271         if (!lw->bar_info || !lw->bar_info_enabled) return;
1272
1273         bar_info_set(lw->bar_info, layout_image_get_path(lw));
1274 }
1275
1276 static void layout_bar_info_new_selection(LayoutWindow *lw, gint count)
1277 {
1278         if (!lw->bar_info || !lw->bar_info_enabled) return;
1279
1280         bar_info_selection(lw->bar_info, count - 1);
1281 }
1282
1283 static void layout_bar_info_maint_renamed(LayoutWindow *lw)
1284 {
1285         if (!lw->bar_info || !lw->bar_info_enabled) return;
1286
1287         bar_info_maint_renamed(lw->bar_info, layout_image_get_path(lw));
1288 }
1289
1290 static void layout_bar_exif_destroyed(GtkWidget *widget, gpointer data)
1291 {
1292         LayoutWindow *lw = data;
1293
1294         if (lw->bar_exif)
1295                 {
1296                 lw->bar_exif_advanced = bar_exif_is_advanced(lw->bar_exif);
1297                 }
1298
1299         lw->bar_exif = NULL;
1300         if (lw->utility_box)
1301                 {
1302                 /* destroyed from within itself */
1303                 lw->bar_exif_enabled = FALSE;
1304                 layout_util_sync_views(lw);
1305                 }
1306 }
1307
1308 static void layout_bar_exif_sized(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
1309 {
1310         LayoutWindow *lw = data;
1311
1312         if (lw->bar_exif)
1313                 {
1314                 lw->bar_exif_size = allocation->width;
1315                 }
1316 }
1317
1318 static void layout_bar_exif_new(LayoutWindow *lw)
1319 {
1320         if (!lw->utility_box) return;
1321
1322         lw->bar_exif = bar_exif_new(TRUE, layout_image_get_path(lw),
1323                                     lw->bar_exif_advanced, lw->utility_box);
1324         g_signal_connect(G_OBJECT(lw->bar_exif), "destroy",
1325                          G_CALLBACK(layout_bar_exif_destroyed), lw);
1326         g_signal_connect(G_OBJECT(lw->bar_exif), "size_allocate",
1327                          G_CALLBACK(layout_bar_exif_sized), lw);
1328         lw->bar_exif_enabled = TRUE;
1329
1330         if (lw->bar_exif_size < 1) lw->bar_exif_size = SIDEBAR_WIDTH;
1331         gtk_widget_set_size_request(lw->bar_exif, lw->bar_exif_size, -1);
1332         gtk_box_pack_start(GTK_BOX(lw->utility_box), lw->bar_exif, FALSE, FALSE, 0);
1333         if (lw->bar_info) gtk_box_reorder_child(GTK_BOX(lw->utility_box), lw->bar_exif, 1);
1334         gtk_widget_show(lw->bar_exif);
1335 }
1336
1337 static void layout_bar_exif_close(LayoutWindow *lw)
1338 {
1339         if (lw->bar_exif)
1340                 {
1341                 bar_exif_close(lw->bar_exif);
1342                 lw->bar_exif = NULL;
1343                 }
1344         lw->bar_exif_enabled = FALSE;
1345 }
1346
1347 void layout_bar_exif_toggle(LayoutWindow *lw)
1348 {
1349         if (lw->bar_exif_enabled)
1350                 {
1351                 layout_bar_exif_close(lw);
1352                 }
1353         else
1354                 {
1355                 layout_bar_exif_new(lw);
1356                 }
1357 }
1358
1359 static void layout_bar_exif_new_image(LayoutWindow *lw)
1360 {
1361         if (!lw->bar_exif || !lw->bar_exif_enabled) return;
1362
1363         bar_exif_set(lw->bar_exif, layout_image_get_path(lw));
1364 }
1365
1366 static void layout_bar_sort_destroyed(GtkWidget *widget, gpointer data)
1367 {
1368         LayoutWindow *lw = data;
1369
1370         lw->bar_sort = NULL;
1371
1372         if (lw->utility_box)
1373                 {
1374                 /* destroyed from within itself */
1375                 lw->bar_sort_enabled = FALSE;
1376
1377                 layout_util_sync_views(lw);
1378                 }
1379 }
1380
1381 static void layout_bar_sort_new(LayoutWindow *lw)
1382 {
1383         if (!lw->utility_box) return;
1384
1385         lw->bar_sort = bar_sort_new(lw);
1386         g_signal_connect(G_OBJECT(lw->bar_sort), "destroy",
1387                          G_CALLBACK(layout_bar_sort_destroyed), lw);
1388         lw->bar_sort_enabled = TRUE;
1389
1390         gtk_box_pack_end(GTK_BOX(lw->utility_box), lw->bar_sort, FALSE, FALSE, 0);
1391         gtk_widget_show(lw->bar_sort);
1392 }
1393
1394 static void layout_bar_sort_close(LayoutWindow *lw)
1395 {
1396         if (lw->bar_sort)
1397                 {
1398                 bar_sort_close(lw->bar_sort);
1399                 lw->bar_sort = NULL;
1400                 }
1401         lw->bar_sort_enabled = FALSE;
1402 }
1403
1404 void layout_bar_sort_toggle(LayoutWindow *lw)
1405 {
1406         if (lw->bar_sort_enabled)
1407                 {
1408                 layout_bar_sort_close(lw);
1409                 }
1410         else
1411                 {
1412                 layout_bar_sort_new(lw);
1413                 }
1414 }
1415
1416 void layout_bars_new_image(LayoutWindow *lw)
1417 {
1418         layout_bar_info_new_image(lw);
1419         layout_bar_exif_new_image(lw);
1420 }
1421
1422 void layout_bars_new_selection(LayoutWindow *lw, gint count)
1423 {
1424         layout_bar_info_new_selection(lw, count);
1425 }
1426
1427 GtkWidget *layout_bars_prepare(LayoutWindow *lw, GtkWidget *image)
1428 {
1429         lw->utility_box = gtk_hbox_new(FALSE, PREF_PAD_GAP);
1430         gtk_box_pack_start(GTK_BOX(lw->utility_box), image, TRUE, TRUE, 0);
1431         gtk_widget_show(image);
1432
1433         if (lw->bar_sort_enabled)
1434                 {
1435                 layout_bar_sort_new(lw);
1436                 }
1437
1438         if (lw->bar_info_enabled)
1439                 {
1440                 layout_bar_info_new(lw);
1441                 }
1442
1443         if (lw->bar_exif_enabled)
1444                 {
1445                 layout_bar_exif_new(lw);
1446                 }
1447
1448         return lw->utility_box;
1449 }
1450
1451 void layout_bars_close(LayoutWindow *lw)
1452 {
1453         layout_bar_sort_close(lw);
1454         layout_bar_exif_close(lw);
1455         layout_bar_info_close(lw);
1456 }
1457
1458 void layout_bars_maint_renamed(LayoutWindow *lw)
1459 {
1460         layout_bar_info_maint_renamed(lw);
1461 }
1462