Shorten config_window_apply() a bit, reduce code redunancy.
[geeqie.git] / src / preferences.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  * Copyright (C) 2008 The Geeqie Team
5  *
6  * Author: John Ellis
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13
14 #include "main.h"
15 #include "preferences.h"
16
17 #include "bar_exif.h"
18 #include "cache_maint.h"
19 #include "editors.h"
20 #include "exif.h"
21 #include "filedata.h"
22 #include "filefilter.h"
23 #include "fullscreen.h"
24 #include "image.h"
25 #include "image-overlay.h"
26 #include "color-man.h"
27 #include "img-view.h"
28 #include "layout_config.h"
29 #include "layout_util.h"
30 #include "pixbuf_util.h"
31 #include "slideshow.h"
32 #include "trash.h"
33 #include "utilops.h"
34 #include "ui_fileops.h"
35 #include "ui_misc.h"
36 #include "ui_tabcomp.h"
37 #include "ui_utildlg.h"
38 #include "window.h"
39
40 #include <math.h>
41
42
43 #define EDITOR_NAME_MAX_LENGTH 32
44 #define EDITOR_COMMAND_MAX_LENGTH 1024
45
46
47 typedef struct _ThumbSize ThumbSize;
48 struct _ThumbSize
49 {
50         gint w;
51         gint h;
52 };
53
54 static ThumbSize thumb_size_list[] =
55 {
56         { 24, 24 },
57         { 32, 32 },
58         { 48, 48 },
59         { 64, 64 },
60         { 96, 72 },
61         { 96, 96 },
62         { 128, 96 },
63         { 128, 128 },
64         { 160, 120 },
65         { 160, 160 },
66         { 192, 144 },
67         { 192, 192 },
68         { 256, 192 },
69         { 256, 256 }
70 };
71
72 enum {
73         FE_ENABLE,
74         FE_EXTENSION,
75         FE_DESCRIPTION
76 };
77
78 /* config memory values */
79 static ConfOptions *c_options = NULL;
80
81
82 #ifdef DEBUG
83 static gint debug_c;
84 #endif
85
86 static GtkWidget *configwindow = NULL;
87 static GtkWidget *startup_path_entry;
88 static GtkWidget *home_path_entry;
89 static GtkListStore *filter_store = NULL;
90 static GtkWidget *editor_name_entry[GQ_EDITOR_SLOTS];
91 static GtkWidget *editor_command_entry[GQ_EDITOR_SLOTS];
92
93 static GtkWidget *layout_widget;
94
95 static GtkWidget *safe_delete_path_entry;
96
97 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
98 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
99 static GtkWidget *color_profile_screen_file_entry;
100
101 static GtkWidget *sidecar_ext_entry;
102
103
104 #define CONFIG_WINDOW_DEF_WIDTH         700
105 #define CONFIG_WINDOW_DEF_HEIGHT        600
106
107 /*
108  *-----------------------------------------------------------------------------
109  * option widget callbacks (private)
110  *-----------------------------------------------------------------------------
111  */
112
113 static void startup_path_set_current(GtkWidget *widget, gpointer data)
114 {
115         gtk_entry_set_text(GTK_ENTRY(startup_path_entry), layout_get_path(NULL));
116 }
117
118 static void home_path_set_current(GtkWidget *widget, gpointer data)
119 {
120         gtk_entry_set_text(GTK_ENTRY(home_path_entry), layout_get_path(NULL));
121 }
122
123 static void zoom_mode_cb(GtkWidget *widget, gpointer data)
124 {
125         if (GTK_TOGGLE_BUTTON (widget)->active)
126                 c_options->image.zoom_mode = GPOINTER_TO_INT(data);
127 }
128
129 static void scroll_reset_cb(GtkWidget *widget, gpointer data)
130 {
131         if (GTK_TOGGLE_BUTTON (widget)->active)
132                 c_options->image.scroll_reset_method = GPOINTER_TO_INT(data);
133 }
134
135 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
136 {
137         c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 10.0 + 0.01);
138 }
139
140 static void slideshow_delay_cb(GtkWidget *spin, gpointer data)
141 {
142         c_options->slideshow.delay = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
143                                    (gdouble)SLIDESHOW_SUBSECOND_PRECISION + 0.01);
144 }
145
146 /*
147  *-----------------------------------------------------------------------------
148  * sync progam to config window routine (private)
149  *-----------------------------------------------------------------------------
150  */
151
152 static void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
153 {
154         const gchar *buf;
155
156         g_free(*option);
157         *option = NULL;
158         buf = gtk_entry_get_text(GTK_ENTRY(entry));
159         if (buf && strlen(buf) > 0)
160                 {
161                 if (func)
162                         *option = func(buf);
163                 else
164                         *option = g_strdup(buf);
165                 }
166 }
167
168 static void config_parse_editor_entries(GtkWidget **editor_name_entry, GtkWidget **editor_command_entry)
169 {
170         gint i;
171         const gchar *buf;
172         GString *errmsg = g_string_new("");
173
174         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
175                 {
176                 gchar *command = NULL;
177
178                 if (i < GQ_EDITOR_GENERIC_SLOTS)
179                         {
180                         gchar *name = NULL;
181
182                         buf = gtk_entry_get_text(GTK_ENTRY(editor_name_entry[i]));
183                         if (buf && strlen(buf) > 0) name = g_strdup(buf);
184                         editor_set_name(i, name);
185                         g_free(name);
186                         }
187
188                 buf = gtk_entry_get_text(GTK_ENTRY(editor_command_entry[i]));
189                 if (buf && strlen(buf) > 0)
190                         {
191                         gint flags = editor_command_parse(buf, NULL, NULL);
192                 
193                         if (flags & EDITOR_ERROR_MASK)
194                                 {
195                                 if (errmsg->str[0]) g_string_append(errmsg, "\n\n");
196                                 g_string_append_printf(errmsg, _("%s\n#%d \"%s\":\n%s"), editor_get_error_str(flags),
197                                                        i+1, options->editor[i].name, buf);
198
199                                 }
200                         command = g_strdup(buf);
201                         }
202
203                 editor_set_command(i, command);
204                 g_free(command);
205                 }
206         
207         if (errmsg->str[0])
208                 {
209                 file_util_warning_dialog(_("Invalid editor command"), errmsg->str, GTK_STOCK_DIALOG_ERROR, NULL);
210                 }
211
212         g_string_free(errmsg, TRUE);
213 }
214
215
216 static void config_window_apply(void)
217 {
218         gint new_style;
219         gint i;
220         gint refresh = FALSE;
221
222         config_parse_editor_entries(editor_name_entry, editor_command_entry); 
223         layout_edit_update_all();
224
225         config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
226         
227         if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
228         if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
229         if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
230         if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
231
232         options->startup.restore_path = c_options->startup.restore_path;
233         options->startup.use_last_path = c_options->startup.use_last_path;
234         config_entry_to_option(startup_path_entry, &options->startup.path, remove_trailing_slash);
235         config_entry_to_option(home_path_entry, &options->layout.home_path, remove_trailing_slash);
236
237         options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
238         options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
239         options->file_ops.safe_delete_enable = c_options->file_ops.safe_delete_enable;
240         options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
241         options->layout.tools_restore_state = c_options->layout.tools_restore_state;
242         options->layout.save_window_positions = c_options->layout.save_window_positions;
243         options->image.zoom_mode = c_options->image.zoom_mode;
244         options->image.scroll_reset_method = c_options->image.scroll_reset_method;
245         options->image.zoom_2pass = c_options->image.zoom_2pass;
246         options->image.fit_window_to_image = c_options->image.fit_window_to_image;
247         options->image.limit_window_size = c_options->image.limit_window_size;
248         options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
249         options->image.max_window_size = c_options->image.max_window_size;
250         options->image.limit_autofit_size = c_options->image.limit_autofit_size;
251         options->image.max_autofit_size = c_options->image.max_autofit_size;
252         options->progressive_key_scrolling = c_options->progressive_key_scrolling;
253         options->thumbnails.max_width = c_options->thumbnails.max_width;
254         options->thumbnails.max_height = c_options->thumbnails.max_height;
255         options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
256         options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
257         options->thumbnails.fast = c_options->thumbnails.fast;
258 #if 0
259         options->thumbnails.use_xvpics = c_options->thumbnails.use_xvpics;
260 #endif
261         options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
262         options->enable_metadata_dirs = c_options->enable_metadata_dirs;
263         options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
264         options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
265
266         options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
267         options->file_filter.disable = c_options->file_filter.disable;
268
269         sidecar_ext_parse(gtk_entry_get_text(GTK_ENTRY(sidecar_ext_entry)), FALSE);
270
271         options->slideshow.random = c_options->slideshow.random;
272         options->slideshow.repeat = c_options->slideshow.repeat;
273         options->slideshow.delay = c_options->slideshow.delay;
274
275         options->mousewheel_scrolls = c_options->mousewheel_scrolls;
276
277         options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
278
279         options->collections.rectangular_selection = c_options->collections.rectangular_selection;
280
281         options->image.tile_cache_max = c_options->image.tile_cache_max;
282         options->image.image_cache_max = c_options->image.image_cache_max;
283
284         options->image.read_buffer_size = c_options->image.read_buffer_size;
285         options->image.idle_read_loop_count = c_options->image.idle_read_loop_count;
286
287         options->thumbnails.quality = c_options->thumbnails.quality;
288         options->image.zoom_quality = c_options->image.zoom_quality;
289
290         options->image.zoom_increment = c_options->image.zoom_increment;
291
292         options->image.enable_read_ahead = c_options->image.enable_read_ahead;
293
294         if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
295             || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
296                 {
297                 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
298                 options->image.border_color = c_options->image.border_color;
299                 layout_colors_update();
300                 view_window_colors_update();
301                 }
302
303         options->fullscreen.screen = c_options->fullscreen.screen;
304         options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
305         options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
306         options->fullscreen.above = c_options->fullscreen.above;
307         options->image_overlay.common.show_at_startup = c_options->image_overlay.common.show_at_startup;
308         if (c_options->image_overlay.common.template_string)
309                 set_image_overlay_template_string(&options->image_overlay.common.template_string,
310                                                   c_options->image_overlay.common.template_string);
311                 
312         options->update_on_time_change = c_options->update_on_time_change;
313         options->image.exif_rotate_enable = c_options->image.exif_rotate_enable;
314
315         options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
316
317         options->tree_descend_subdirs = c_options->tree_descend_subdirs;
318
319         options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
320         options->dnd_icon_size = c_options->dnd_icon_size;
321         
322         if (options->show_copy_path != c_options->show_copy_path)
323                 {
324                 options->show_copy_path = c_options->show_copy_path;
325                 layout_copy_path_update_all();
326                 }
327
328         options->save_metadata_in_image_file = c_options->save_metadata_in_image_file;
329
330 #ifdef DEBUG
331         set_debug_level(debug_c);
332 #endif
333
334 #ifdef HAVE_LCMS
335         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
336                 {
337                 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
338                 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
339                 }
340         config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
341 #endif
342
343         for (i = 0; ExifUIList[i].key; i++)
344                 {
345                 ExifUIList[i].current = ExifUIList[i].temp;
346                 }
347
348         {
349         gchar *layout_order = layout_config_get(layout_widget, &new_style);
350
351         if (new_style != options->layout.style ||
352             (layout_order == NULL) != (options->layout.order == NULL) ||
353             !options->layout.order ||
354             strcmp(layout_order, options->layout.order) != 0)
355                 {
356                 if (refresh) filter_rebuild();
357                 refresh = FALSE;
358
359                 g_free(options->layout.order);
360                 options->layout.order = layout_order;
361                 layout_order = NULL; /* g_free() later */
362
363                 options->layout.style = new_style;
364
365                 layout_styles_update();
366                 }
367
368         g_free(layout_order);
369         }
370
371         if (options->layout.show_directory_date != c_options->layout.show_directory_date)
372                 {
373                 options->layout.show_directory_date = c_options->layout.show_directory_date;
374                 refresh = TRUE;
375                 }
376
377         image_options_sync();
378
379         if (refresh)
380                 {
381                 filter_rebuild();
382                 layout_refresh(NULL);
383                 }
384 }
385
386 /*
387  *-----------------------------------------------------------------------------
388  * config window main button callbacks (private)
389  *-----------------------------------------------------------------------------
390  */
391
392 static void config_window_close_cb(GtkWidget *widget, gpointer data)
393 {
394         gtk_widget_destroy(configwindow);
395         configwindow = NULL;
396         filter_store = NULL;
397 }
398
399 static gint config_window_delete(GtkWidget *w, GdkEventAny *event, gpointer data)
400 {
401         config_window_close_cb(NULL, NULL);
402         return TRUE;
403 }
404
405 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
406 {
407         config_window_apply();
408         config_window_close_cb(NULL, NULL);
409 }
410
411 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
412 {
413         config_window_apply();
414 }
415
416 static void config_window_save_cb(GtkWidget *widget, gpointer data)
417 {
418         config_window_apply();
419         save_options(options);
420 }
421
422 /*
423  *-----------------------------------------------------------------------------
424  * config window setup (private)
425  *-----------------------------------------------------------------------------
426  */
427
428 static void exif_item_cb(GtkWidget *combo, gpointer data)
429 {
430         gint *option = data;
431         *option = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
432 }
433
434 static void exif_item(GtkWidget *table, gint column, gint row,
435                       const gchar *text, gint option, gint *option_c)
436 {
437         GtkWidget *combo;
438
439         *option_c = option;
440
441         pref_table_label(table, column, row, text, 0.0);
442
443         combo = gtk_combo_box_new_text();
444
445         /* note: the order is important, it must match the values of
446          * EXIF_UI_OFF, _IFSET, _ON */
447         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Never"));
448         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("If set"));
449         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Always"));
450
451         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), option);
452
453         g_signal_connect(G_OBJECT(combo), "changed",
454                          G_CALLBACK(exif_item_cb), option_c);
455
456         gtk_table_attach(GTK_TABLE(table), combo,
457                          column + 1, column + 2, row, row + 1,
458                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
459         gtk_widget_show(combo);
460 }
461
462 static void quality_menu_cb(GtkWidget *combo, gpointer data)
463 {
464         gint *option = data;
465
466         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
467                 {
468                 case 0:
469                 default:
470                         *option = GDK_INTERP_NEAREST;
471                         break;
472                 case 1:
473                         *option = GDK_INTERP_TILES;
474                         break;
475                 case 2:
476                         *option = GDK_INTERP_BILINEAR;
477                         break;
478                 case 3:
479                         *option = GDK_INTERP_HYPER;
480                         break;
481                 }
482 }
483
484 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
485                              gint option, gint *option_c)
486 {
487         GtkWidget *combo;
488         gint current = 0;
489
490         *option_c = option;
491
492         pref_table_label(table, column, row, text, 0.0);
493
494         combo = gtk_combo_box_new_text();
495
496         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Nearest (worst, but fastest)"));
497         if (option == GDK_INTERP_NEAREST) current = 0;
498         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Tiles"));
499         if (option == GDK_INTERP_TILES) current = 1;
500         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Bilinear"));
501         if (option == GDK_INTERP_BILINEAR) current = 2;
502         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Hyper (best, but slowest)"));
503         if (option == GDK_INTERP_HYPER) current = 3;
504
505         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
506
507         g_signal_connect(G_OBJECT(combo), "changed",
508                          G_CALLBACK(quality_menu_cb), option_c);
509
510         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
511                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
512         gtk_widget_show(combo);
513 }
514
515 #if 0
516 static void add_dither_menu(gint option, gint *option_c, gchar *text, GtkWidget *box)
517 {
518         GtkWidget *hbox;
519         GtkWidget *omenu;
520         GtkWidget *menu;
521
522         *option_c = option;
523
524         hbox = pref_box_new(box, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
525         pref_label_new(hbox, text);
526
527         omenu = gtk_option_menu_new();
528         menu = gtk_menu_new();
529
530         add_menu_item(menu, _("None"), option_c, (gint)GDK_RGB_DITHER_NONE);
531         add_menu_item(menu, _("Normal"), option_c, (gint)GDK_RGB_DITHER_NORMAL);
532         add_menu_item(menu, _("Best"), option_c, (gint)GDK_RGB_DITHER_MAX);
533
534         gtk_option_menu_set_menu(GTK_OPTION_MENU(omenu), menu);
535         gtk_option_menu_set_history(GTK_OPTION_MENU(omenu), *option_c);
536
537         gtk_box_pack_start(GTK_BOX(hbox), omenu, FALSE, FALSE, 0);
538         gtk_widget_show(omenu);
539 }
540 #endif
541
542 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
543 {
544         gint n;
545
546         n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
547         if (n < 0) return;
548
549         if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
550                 {
551                 c_options->thumbnails.max_width = thumb_size_list[n].w;
552                 c_options->thumbnails.max_height = thumb_size_list[n].h;
553                 }
554         else
555                 {
556                 c_options->thumbnails.max_width = options->thumbnails.max_width;
557                 c_options->thumbnails.max_height = options->thumbnails.max_height;
558                 }
559 }
560
561 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
562 {
563         GtkWidget *combo;
564         gint current;
565         gint i;
566
567         c_options->thumbnails.max_width = options->thumbnails.max_width;
568         c_options->thumbnails.max_height = options->thumbnails.max_height;
569
570         pref_table_label(table, column, row, text, 0.0);
571
572         combo = gtk_combo_box_new_text();
573
574         current = -1;
575         for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
576                 {
577                 gint w, h;
578                 gchar *buf;
579
580                 w = thumb_size_list[i].w;
581                 h = thumb_size_list[i].h;
582
583                 buf = g_strdup_printf("%d x %d", w, h);
584                 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), buf);
585                 g_free(buf);
586
587                 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
588                 }
589
590         if (current == -1)
591                 {
592                 gchar *buf;
593
594                 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
595                 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), buf);
596                 g_free(buf);
597
598                 current = i;
599                 }
600
601         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
602         g_signal_connect(G_OBJECT(combo), "changed",
603                          G_CALLBACK(thumb_size_menu_cb), NULL);
604
605         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
606                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
607         gtk_widget_show(combo);
608 }
609
610 static void filter_store_populate(void)
611 {
612         GList *work;
613
614         if (!filter_store) return;
615
616         gtk_list_store_clear(filter_store);
617
618         work = filter_get_list();
619         while (work)
620                 {
621                 FilterEntry *fe;
622                 GtkTreeIter iter;
623
624                 fe = work->data;
625                 work = work->next;
626
627                 gtk_list_store_append(filter_store, &iter);
628                 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
629                 }
630 }
631
632 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
633                                      gchar *new_text, gpointer data)
634 {
635         GtkWidget *model = data;
636         FilterEntry *fe = data;
637         GtkTreePath *tpath;
638         GtkTreeIter iter;
639
640         if (!new_text || strlen(new_text) < 1) return;
641
642         tpath = gtk_tree_path_new_from_string(path_str);
643         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
644         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
645
646         g_free(fe->extensions);
647         fe->extensions = g_strdup(new_text);
648
649         gtk_tree_path_free(tpath);
650         filter_rebuild();
651 }
652
653 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
654                                       gchar *new_text, gpointer data)
655 {
656         GtkWidget *model = data;
657         FilterEntry *fe;
658         GtkTreePath *tpath;
659         GtkTreeIter iter;
660
661         if (!new_text || strlen(new_text) < 1) return;
662
663         tpath = gtk_tree_path_new_from_string(path_str);
664         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
665         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
666
667         g_free(fe->description);
668         fe->description = g_strdup(new_text);
669
670         gtk_tree_path_free(tpath);
671 }
672
673 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
674                                    gchar *path_str, gpointer data)
675 {
676         GtkWidget *model = data;
677         FilterEntry *fe;
678         GtkTreePath *tpath;
679         GtkTreeIter iter;
680
681         tpath = gtk_tree_path_new_from_string(path_str);
682         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
683         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
684
685         fe->enabled = !fe->enabled;
686
687         gtk_tree_path_free(tpath);
688         filter_rebuild();
689 }
690
691 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
692                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
693 {
694         FilterEntry *fe;
695
696         gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
697
698         switch(GPOINTER_TO_INT(data))
699                 {
700                 case FE_ENABLE:
701                         g_object_set(GTK_CELL_RENDERER(cell),
702                                      "active", fe->enabled, NULL);
703                         break;
704                 case FE_EXTENSION:
705                         g_object_set(GTK_CELL_RENDERER(cell),
706                                      "text", fe->extensions, NULL);
707                         break;
708                 case FE_DESCRIPTION:
709                         g_object_set(GTK_CELL_RENDERER(cell),
710                                      "text", fe->description, NULL);
711                         break;
712                 }
713 }
714
715 static void filter_add_cb(GtkWidget *widget, gpointer data)
716 {
717         filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE);
718         filter_store_populate();
719
720         /* FIXME: implement the scroll to/select row stuff for tree view */
721 }
722
723 static void filter_remove_cb(GtkWidget *widget, gpointer data)
724 {
725         GtkWidget *filter_view = data;
726         GtkTreeSelection *selection;
727         GtkTreeIter iter;
728         FilterEntry *fe;
729
730         if (!filter_store) return;
731         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
732         if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
733         gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
734         if (!fe) return;
735
736         filter_remove_entry(fe);
737         filter_rebuild();
738         filter_store_populate();
739 }
740
741 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
742 {
743         filter_reset();
744         filter_add_defaults();
745         filter_rebuild();
746         filter_store_populate();
747 }
748
749 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
750 {
751         /* no op, only so cancel button appears */
752 }
753
754 static void filter_default_cb(GtkWidget *widget, gpointer data)
755 {
756         GenericDialog *gd;
757
758         gd = generic_dialog_new(_("Reset filters"),
759                                 GQ_WMCLASS, "reset_filter", widget, TRUE,
760                                 dummy_cancel_cb, NULL);
761         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
762                                    _("This will reset the file filters to the defaults.\nContinue?"));
763         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
764         gtk_widget_show(gd->dialog);
765 }
766
767 static void filter_disable_cb(GtkWidget *widget, gpointer data)
768 {
769         GtkWidget *frame = data;
770
771         gtk_widget_set_sensitive(frame,
772                                  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
773 }
774
775 static void editor_default_ok_cb(GenericDialog *gd, gpointer data)
776 {
777         gint i;
778
779         editor_reset_defaults();
780         if (!configwindow) return;
781
782         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
783                 {
784                 if (i < GQ_EDITOR_GENERIC_SLOTS)
785                         gtk_entry_set_text(GTK_ENTRY(editor_name_entry[i]),
786                                    (options->editor[i].name) ? options->editor[i].name : "");
787                 gtk_entry_set_text(GTK_ENTRY(editor_command_entry[i]),
788                                    (options->editor[i].command) ? options->editor[i].command : "");
789                 }
790 }
791
792 static void editor_default_cb(GtkWidget *widget, gpointer data)
793 {
794         GenericDialog *gd;
795
796         gd = generic_dialog_new(_("Reset editors"),
797                                 GQ_WMCLASS, "reset_filter", widget, TRUE,
798                                 dummy_cancel_cb, NULL);
799         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset editors"),
800                                    _("This will reset the edit commands to the defaults.\nContinue?"));
801         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, editor_default_ok_cb, TRUE);
802         gtk_widget_show(gd->dialog);
803 }
804
805 static void editor_help_cb(GtkWidget *widget, gpointer data)
806 {
807         help_window_show("editors");
808 }
809
810 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
811 {
812         layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
813 }
814
815 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
816 {
817         file_util_trash_clear();
818 }
819
820 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
821 {
822         GenericDialog *gd;
823         GtkWidget *entry;
824         gd = generic_dialog_new(_("Clear trash"),
825                                 GQ_WMCLASS, "clear_trash", widget, TRUE,
826                                 dummy_cancel_cb, NULL);
827         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
828                                     _("This will remove the trash contents."));
829         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
830         entry = gtk_entry_new();
831         GTK_WIDGET_UNSET_FLAGS(entry, GTK_CAN_FOCUS);
832         gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
833         if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
834         gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
835         gtk_widget_show(entry);
836         gtk_widget_show(gd->dialog);
837 }
838
839 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
840 {
841         GtkWidget *pTextView;
842         GtkTextBuffer *pTextBuffer;
843         GtkTextIter iStart;
844         GtkTextIter iEnd;
845
846         pTextView = GTK_WIDGET(data);
847
848         pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
849         gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
850         gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
851
852         set_image_overlay_template_string(&c_options->image_overlay.common.template_string,
853                                           gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
854 }
855
856 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
857 {
858         GtkTextView *text_view = data;
859         GtkTextBuffer *buffer;
860
861         set_default_image_overlay_template_string(&options->image_overlay.common.template_string);
862         if (!configwindow) return;
863
864         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
865         gtk_text_buffer_set_text(buffer, options->image_overlay.common.template_string, -1);
866 }
867
868 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
869 {
870         GenericDialog *gd;
871
872         gd = generic_dialog_new(_("Reset image overlay template string"),
873                                 GQ_WMCLASS, "reset_image_overlay_template_string", widget, TRUE,
874                                 dummy_cancel_cb, data);
875         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
876                                    _("This will reset the image overlay template string to the default.\nContinue?"));
877         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
878         gtk_widget_show(gd->dialog);
879 }
880
881 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
882 {
883         help_window_show("overlay");
884 }
885
886 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
887 {
888         GtkWidget *label;
889         GtkWidget *vbox;
890         GtkWidget *scrolled;
891         GtkWidget *viewport;
892
893         scrolled = gtk_scrolled_window_new(NULL, NULL);
894         gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
895         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
896                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
897         label = gtk_label_new(title);
898         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
899         gtk_widget_show(scrolled);
900
901         viewport = gtk_viewport_new(NULL, NULL);
902         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
903         gtk_container_add(GTK_CONTAINER(scrolled), viewport);
904         gtk_widget_show(viewport);
905
906         vbox = gtk_vbox_new(FALSE, 0);
907         gtk_container_add(GTK_CONTAINER(viewport), vbox);
908         gtk_widget_show(vbox);
909
910         return vbox;
911 }
912
913 /* general options tab */
914 static void config_tab_general(GtkWidget *notebook)
915 {
916         GtkWidget *hbox;
917         GtkWidget *vbox;
918         GtkWidget *subvbox;
919         GtkWidget *group;
920         GtkWidget *subgroup;
921         GtkWidget *button;
922         GtkWidget *tabcomp;
923         GtkWidget *ct_button;
924         GtkWidget *table;
925         GtkWidget *spin;
926
927         vbox = scrolled_notebook_page(notebook, _("General"));
928
929         group = pref_group_new(vbox, FALSE, _("Startup"), GTK_ORIENTATION_VERTICAL);
930
931         button = pref_checkbox_new_int(group, _("Restore folder on startup"),
932                                        options->startup.restore_path, &c_options->startup.restore_path);
933
934         subvbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
935         pref_checkbox_link_sensitivity(button, subvbox);
936
937         hbox = pref_box_new(subvbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
938
939         tabcomp = tab_completion_new(&startup_path_entry, options->startup.path, NULL, NULL);
940         tab_completion_add_select_button(startup_path_entry, NULL, TRUE);
941         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
942         gtk_widget_show(tabcomp);
943
944         button = pref_button_new(hbox, NULL, _("Use current"), FALSE,
945                                  G_CALLBACK(startup_path_set_current), NULL);
946
947         button = pref_checkbox_new_int(subvbox, _("Use last path"),
948                                        options->startup.use_last_path, &c_options->startup.use_last_path);
949         pref_checkbox_link_sensitivity_swap(button, hbox);
950
951
952         group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
953
954         table = pref_table_new(group, 2, 2, FALSE, FALSE);
955         add_thumb_size_menu(table, 0, 0, _("Size:"));
956         add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
957
958         ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
959                                           options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
960
961         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
962         pref_checkbox_link_sensitivity(ct_button, subgroup);
963
964         button = pref_checkbox_new_int(subgroup, _("Use shared thumbnail cache"),
965                                        options->thumbnails.spec_standard, &c_options->thumbnails.spec_standard);
966
967         subgroup = pref_box_new(subgroup, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
968         pref_checkbox_link_sensitivity_swap(button, subgroup);
969
970         pref_checkbox_new_int(subgroup, _("Cache thumbnails into .thumbnails"),
971                               options->thumbnails.cache_into_dirs, &c_options->thumbnails.cache_into_dirs);
972
973 #if 0
974         pref_checkbox_new_int(subgroup, _("Use xvpics thumbnails when found (read only)"),
975                               options->thumbnails.use_xvpics, &c_options->thumbnails.use_xvpics);
976 #endif
977
978         pref_checkbox_new_int(group, _("Faster jpeg thumbnailing (may reduce quality)"),
979                               options->thumbnails.fast, &c_options->thumbnails.fast);
980
981         group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
982
983         c_options->slideshow.delay = options->slideshow.delay;
984         spin = pref_spin_new(group, _("Delay between image change:"), _("seconds"),
985                              SLIDESHOW_MIN_SECONDS, SLIDESHOW_MAX_SECONDS, 1.0, 1,
986                              options->slideshow.delay ? (gdouble)options->slideshow.delay / SLIDESHOW_SUBSECOND_PRECISION : 10.0,
987                              G_CALLBACK(slideshow_delay_cb), NULL);
988         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
989
990         pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
991         pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
992 }
993
994 /* image tab */
995 static void config_tab_image(GtkWidget *notebook)
996 {
997         GtkWidget *hbox;
998         GtkWidget *vbox;
999         GtkWidget *group;
1000         GtkWidget *button;
1001         GtkWidget *ct_button;
1002         GtkWidget *table;
1003         GtkWidget *spin;
1004
1005         vbox = scrolled_notebook_page(notebook, _("Image"));
1006
1007         group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
1008
1009 #if 0
1010         add_dither_menu(dither_quality, &c_options->image.dither_quality, _("Dithering method:"), group);
1011 #endif
1012         table = pref_table_new(group, 2, 1, FALSE, FALSE);
1013         add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
1014
1015         pref_checkbox_new_int(group, _("Two pass zooming"),
1016                               options->image.zoom_2pass, &c_options->image.zoom_2pass);
1017
1018         pref_checkbox_new_int(group, _("Allow enlargement of image for zoom to fit"),
1019                               options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
1020
1021         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1022         ct_button = pref_checkbox_new_int(hbox, _("Limit image size when autofitting (%):"),
1023                                           options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
1024         spin = pref_spin_new_int(hbox, NULL, NULL,
1025                                  10, 150, 1,
1026                                  options->image.max_autofit_size, &c_options->image.max_autofit_size);
1027         pref_checkbox_link_sensitivity(ct_button, spin);
1028
1029         c_options->image.zoom_increment = options->image.zoom_increment;
1030         spin = pref_spin_new(group, _("Zoom increment:"), NULL,
1031                              0.1, 4.0, 0.1, 1, (gdouble)options->image.zoom_increment / 10.0,
1032                              G_CALLBACK(zoom_increment_cb), NULL);
1033         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1034
1035         group = pref_group_new(vbox, FALSE, _("When new image is selected:"), GTK_ORIENTATION_VERTICAL);
1036
1037         c_options->image.zoom_mode = options->image.zoom_mode;
1038         button = pref_radiobutton_new(group, NULL, _("Zoom to original size"),
1039                                       (options->image.zoom_mode == ZOOM_RESET_ORIGINAL),
1040                                       G_CALLBACK(zoom_mode_cb), GINT_TO_POINTER(ZOOM_RESET_ORIGINAL));
1041         button = pref_radiobutton_new(group, button, _("Fit image to window"),
1042                                       (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW),
1043                                       G_CALLBACK(zoom_mode_cb), GINT_TO_POINTER(ZOOM_RESET_FIT_WINDOW));
1044         button = pref_radiobutton_new(group, button, _("Leave Zoom at previous setting"),
1045                                       (options->image.zoom_mode == ZOOM_RESET_NONE),
1046                                       G_CALLBACK(zoom_mode_cb), GINT_TO_POINTER(ZOOM_RESET_NONE));
1047
1048         group = pref_group_new(vbox, FALSE, _("Scroll reset method:"), GTK_ORIENTATION_VERTICAL);
1049
1050         c_options->image.scroll_reset_method = options->image.scroll_reset_method;
1051         button = pref_radiobutton_new(group, NULL, _("Top left"),
1052                                       (options->image.scroll_reset_method == SCROLL_RESET_TOPLEFT),
1053                                       G_CALLBACK(scroll_reset_cb), GINT_TO_POINTER(SCROLL_RESET_TOPLEFT));
1054         button = pref_radiobutton_new(group, button, _("Center"),
1055                                       (options->image.scroll_reset_method == SCROLL_RESET_CENTER),
1056                                       G_CALLBACK(scroll_reset_cb), GINT_TO_POINTER(SCROLL_RESET_CENTER));
1057         button = pref_radiobutton_new(group, button, _("No change"),
1058                                       (options->image.scroll_reset_method == SCROLL_RESET_NOCHANGE),
1059                                       G_CALLBACK(scroll_reset_cb), GINT_TO_POINTER(SCROLL_RESET_NOCHANGE));
1060
1061
1062         group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
1063
1064         pref_checkbox_new_int(group, _("Custom border color"),
1065                               options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
1066
1067         pref_color_button_new(group, _("Border color"), &options->image.border_color,
1068                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
1069
1070         group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
1071
1072         pref_checkbox_new_int(group, _("Refresh on file change"),
1073                               options->update_on_time_change, &c_options->update_on_time_change);
1074         pref_checkbox_new_int(group, _("Preload next image"),
1075                               options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
1076         pref_checkbox_new_int(group, _("Auto rotate image using Exif information"),
1077                               options->image.exif_rotate_enable, &c_options->image.exif_rotate_enable);
1078 }
1079
1080 /* windows tab */
1081 static void config_tab_windows(GtkWidget *notebook)
1082 {
1083         GtkWidget *hbox;
1084         GtkWidget *vbox;
1085         GtkWidget *group;
1086         GtkWidget *ct_button;
1087         GtkWidget *spin;
1088
1089         vbox = scrolled_notebook_page(notebook, _("Windows"));
1090
1091         group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
1092
1093         pref_checkbox_new_int(group, _("Remember window positions"),
1094                               options->layout.save_window_positions, &c_options->layout.save_window_positions);
1095         pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
1096                               options->layout.tools_restore_state, &c_options->layout.tools_restore_state);
1097
1098         group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
1099
1100         pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
1101                               options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
1102
1103         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1104         ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
1105                                           options->image.limit_window_size, &c_options->image.limit_window_size);
1106         spin = pref_spin_new_int(hbox, NULL, NULL,
1107                                  10, 150, 1,
1108                                  options->image.max_window_size, &c_options->image.max_window_size);
1109         pref_checkbox_link_sensitivity(ct_button, spin);
1110
1111         group = pref_group_new(vbox, FALSE, _("Layout"), GTK_ORIENTATION_VERTICAL);
1112
1113         layout_widget = layout_config_new();
1114         layout_config_set(layout_widget, options->layout.style, options->layout.order);
1115         gtk_box_pack_start(GTK_BOX(group), layout_widget, FALSE, FALSE, 0);
1116         gtk_widget_show(layout_widget);
1117 }
1118
1119 /* filtering tab */
1120 static void config_tab_filtering(GtkWidget *notebook)
1121 {
1122         GtkWidget *hbox;
1123         GtkWidget *frame;
1124         GtkWidget *vbox;
1125         GtkWidget *group;
1126         GtkWidget *button;
1127         GtkWidget *ct_button;
1128         GtkWidget *scrolled;
1129         GtkWidget *filter_view;
1130         GtkCellRenderer *renderer;
1131         GtkTreeSelection *selection;
1132         GtkTreeViewColumn *column;
1133
1134         vbox = scrolled_notebook_page(notebook, _("Filtering"));
1135
1136         group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1137
1138         pref_checkbox_new_int(group, _("Show hidden files or folders"),
1139                               options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
1140         pref_checkbox_new_int(group, _("Show dot directory"),
1141                               options->file_filter.show_dot_directory, &c_options->file_filter.show_dot_directory);
1142         pref_checkbox_new_int(group, _("Case sensitive sort"),
1143                               options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
1144
1145         ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
1146                                           options->file_filter.disable, &c_options->file_filter.disable);
1147
1148
1149         group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
1150
1151         sidecar_ext_entry = gtk_entry_new();
1152         gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), sidecar_ext_to_string());
1153         gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
1154         gtk_widget_show(sidecar_ext_entry);
1155
1156         group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
1157
1158         frame = pref_group_parent(group);
1159         g_signal_connect(G_OBJECT(ct_button), "toggled",
1160                          G_CALLBACK(filter_disable_cb), frame);
1161         gtk_widget_set_sensitive(frame, !options->file_filter.disable);
1162
1163         scrolled = gtk_scrolled_window_new(NULL, NULL);
1164         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1165         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1166         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
1167         gtk_widget_show(scrolled);
1168
1169         filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
1170         filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
1171         g_object_unref(filter_store);
1172         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1173         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
1174
1175         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
1176
1177         column = gtk_tree_view_column_new();
1178         gtk_tree_view_column_set_title(column, _("Filter"));
1179         gtk_tree_view_column_set_resizable(column, TRUE);
1180
1181         renderer = gtk_cell_renderer_toggle_new();
1182         g_signal_connect(G_OBJECT(renderer), "toggled",
1183                          G_CALLBACK(filter_store_enable_cb), filter_store);
1184         gtk_tree_view_column_pack_start(column, renderer, FALSE);
1185         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
1186                                                 GINT_TO_POINTER(FE_ENABLE), NULL);
1187
1188         renderer = gtk_cell_renderer_text_new();
1189         g_signal_connect(G_OBJECT(renderer), "edited",
1190                          G_CALLBACK(filter_store_ext_edit_cb), filter_store);
1191         gtk_tree_view_column_pack_start(column, renderer, TRUE);
1192         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
1193         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
1194                                                 GINT_TO_POINTER(FE_EXTENSION), NULL);
1195         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
1196
1197         column = gtk_tree_view_column_new();
1198         gtk_tree_view_column_set_title(column, _("Description"));
1199         gtk_tree_view_column_set_resizable(column, TRUE);
1200         renderer = gtk_cell_renderer_text_new();
1201         g_signal_connect(G_OBJECT(renderer), "edited",
1202                          G_CALLBACK(filter_store_desc_edit_cb), filter_store);
1203         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
1204         gtk_tree_view_column_pack_start(column, renderer, FALSE);
1205         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
1206                                                 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
1207         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
1208
1209         filter_store_populate();
1210         gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
1211         gtk_widget_show(filter_view);
1212
1213         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1214
1215         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
1216                                  G_CALLBACK(filter_default_cb), NULL);
1217         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1218         gtk_widget_show(button);
1219
1220         button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
1221                                  G_CALLBACK(filter_remove_cb), filter_view);
1222         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1223         gtk_widget_show(button);
1224
1225         button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
1226                                  G_CALLBACK(filter_add_cb), NULL);
1227         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1228         gtk_widget_show(button);
1229 }
1230
1231 /* editors tab */
1232 static void config_tab_editors(GtkWidget *notebook)
1233 {
1234         GtkWidget *hbox;
1235         GtkWidget *label;
1236         GtkWidget *vbox;
1237         GtkWidget *button;
1238         GtkWidget *table;
1239         gint i;
1240
1241         vbox = scrolled_notebook_page(notebook, _("Editors"));
1242
1243         table = pref_table_new(vbox, 3, 9, FALSE, FALSE);
1244         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
1245
1246         label = pref_table_label(table, 0, 0, _("#"), 1.0);
1247         pref_label_bold(label, TRUE, FALSE);
1248
1249         label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
1250         pref_label_bold(label, TRUE, FALSE);
1251
1252         label = pref_table_label(table, 2, 0, _("Command Line"), 0.0);
1253         pref_label_bold(label, TRUE, FALSE);
1254
1255         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
1256                 {
1257                 GtkWidget *entry;
1258
1259                 if (i < GQ_EDITOR_GENERIC_SLOTS)
1260                         {
1261                         gchar *buf;
1262
1263                         buf = g_strdup_printf("%d", i+1);
1264                         pref_table_label(table, 0, i+1, buf, 1.0);
1265                         g_free(buf);
1266                         entry = gtk_entry_new();
1267                         gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
1268                         gtk_widget_set_size_request(entry, 80, -1);
1269                         if (options->editor[i].name)
1270                                 gtk_entry_set_text(GTK_ENTRY(entry), options->editor[i].name);
1271                         }
1272                 else
1273                         {
1274                         entry = gtk_label_new(options->editor[i].name);
1275                         gtk_misc_set_alignment(GTK_MISC(entry), 0.0, 0.5);
1276                         }
1277
1278                 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i+1, i+2,
1279                                  GTK_FILL | GTK_SHRINK, 0, 0, 0);
1280                 gtk_widget_show(entry);
1281                 editor_name_entry[i] = entry;
1282
1283                 entry = gtk_entry_new();
1284                 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_COMMAND_MAX_LENGTH);
1285                 gtk_widget_set_size_request(entry, 160, -1);
1286                 tab_completion_add_to_entry(entry, NULL, NULL);
1287                 if (options->editor[i].command)
1288                         gtk_entry_set_text(GTK_ENTRY(entry), options->editor[i].command);
1289                 gtk_table_attach(GTK_TABLE(table), entry, 2, 3, i+1, i+2,
1290                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
1291                 gtk_widget_show(entry);
1292                 editor_command_entry[i] = entry;
1293                 }
1294
1295         hbox = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1296
1297         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
1298                                  G_CALLBACK(editor_default_cb), NULL);
1299         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1300         gtk_widget_show(button);
1301
1302         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
1303                                  G_CALLBACK(editor_help_cb), NULL);
1304         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1305         gtk_widget_show(button);
1306 }
1307
1308 /* properties tab */
1309 static void config_tab_properties(GtkWidget *notebook)
1310 {
1311         GtkWidget *label;
1312         GtkWidget *vbox;
1313         GtkWidget *group;
1314         GtkWidget *table;
1315         gint i;
1316
1317         vbox = scrolled_notebook_page(notebook, _("Properties"));
1318
1319         group = pref_group_new(vbox, FALSE, _("Exif"),
1320                                GTK_ORIENTATION_VERTICAL);
1321
1322
1323         pref_spacer(group, PREF_PAD_INDENT - PREF_PAD_SPACE);
1324         label = pref_label_new(group, _("What to show in properties dialog:"));
1325         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1326
1327         table = pref_table_new(group, 2, 2, FALSE, FALSE);
1328
1329         for (i = 0; ExifUIList[i].key; i++)
1330                 {
1331                 const gchar *title;
1332
1333                 title = exif_get_description_by_key(ExifUIList[i].key);
1334                 exif_item(table, 0, i, title, ExifUIList[i].current,
1335                           &ExifUIList[i].temp);
1336                 }
1337 }
1338
1339 /* advanced entry tab */
1340 static void config_tab_advanced(GtkWidget *notebook)
1341 {
1342         GtkWidget *label;
1343         GtkWidget *hbox;
1344         GtkWidget *vbox;
1345         GtkWidget *group;
1346         GtkWidget *button;
1347         GtkWidget *tabcomp;
1348         GtkWidget *ct_button;
1349         GtkWidget *table;
1350         GtkWidget *spin;
1351         GtkWidget *image_overlay_template_view;
1352         GtkWidget *scrolled;
1353         GtkTextBuffer *buffer;
1354         gint i;
1355
1356         vbox = scrolled_notebook_page(notebook, _("Advanced"));
1357
1358         group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
1359
1360         c_options->fullscreen.screen = options->fullscreen.screen;
1361         c_options->fullscreen.above = options->fullscreen.above;
1362         hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
1363         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
1364         gtk_widget_show(hbox);
1365
1366         pref_checkbox_new_int(group, _("Smooth image flip"),
1367                               options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
1368         pref_checkbox_new_int(group, _("Disable screen saver"),
1369                               options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
1370
1371
1372         group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
1373
1374         pref_checkbox_new_int(group, _("Always show image overlay at startup"),
1375                               options->image_overlay.common.show_at_startup, &c_options->image_overlay.common.show_at_startup);
1376         pref_label_new(group, _("Image overlay template"));
1377
1378         scrolled = gtk_scrolled_window_new(NULL, NULL);
1379         gtk_widget_set_size_request(scrolled, 200, 150);
1380         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1381         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1382                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1383         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
1384         gtk_widget_show(scrolled);
1385
1386         image_overlay_template_view = gtk_text_view_new();
1387
1388 #if GTK_CHECK_VERSION(2,12,0)
1389         gtk_widget_set_tooltip_markup(image_overlay_template_view,
1390         _("<i>%name%</i> results in the filename of the picture.\n"
1391           "Also available: <i>%collection%</i>, <i>%number%</i>, <i>%total%</i>, <i>%date%</i>,\n"
1392           "<i>%size%</i> (filesize), <i>%width%</i>, <i>%height%</i>, <i>%res%</i> (resolution)\n"
1393           "To access exif data use the exif name, e. g. <i>%formatted.Camera%</i> is the formatted camera name,\n"
1394           "<i>%Exif.Photo.DateTimeOriginal%</i> the date of the original shot.\n"
1395           "<i>%formatted.Camera:20</i> notation will truncate the displayed data to 20 characters and will add 3 dots at the end to denote the truncation.\n"
1396           "If two or more variables are connected with the |-sign, it prints available variables with a separator.\n"
1397           "<i>%formatted.ShutterSpeed%</i>|<i>%formatted.ISOSpeedRating%</i>|<i>%formatted.FocalLength%</i> could show \"1/20s - 400 - 80 mm\" or \"1/200 - 80 mm\",\n"
1398           "if there's no ISO information in the Exif data.\n"
1399           "If a line is empty, it is removed. This allows to add lines that totally disappear when no data is available.\n"
1400 ));
1401 #endif
1402         gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
1403         gtk_widget_show(image_overlay_template_view);
1404
1405         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1406
1407         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
1408                                  G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
1409         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1410         gtk_widget_show(button);
1411
1412         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
1413                                  G_CALLBACK(image_overlay_help_cb), NULL);
1414         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1415         gtk_widget_show(button);
1416
1417         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
1418         if (options->image_overlay.common.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.common.template_string, -1);
1419         g_signal_connect(G_OBJECT(buffer), "changed",
1420                          G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
1421
1422         group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
1423
1424         pref_checkbox_new_int(group, _("Confirm file delete"),
1425                               options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
1426         pref_checkbox_new_int(group, _("Enable Delete key"),
1427                               options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
1428
1429         ct_button = pref_checkbox_new_int(group, _("Safe delete"),
1430                                           options->file_ops.safe_delete_enable, &c_options->file_ops.safe_delete_enable);
1431
1432         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1433         pref_checkbox_link_sensitivity(ct_button, hbox);
1434
1435         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
1436         pref_label_new(hbox, _("Folder:"));
1437
1438         tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL);
1439         tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
1440         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
1441         gtk_widget_show(tabcomp);
1442
1443         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1444         pref_checkbox_link_sensitivity(ct_button, hbox);
1445
1446         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
1447         spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
1448                                  0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
1449 #if GTK_CHECK_VERSION(2,12,0)
1450         gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
1451 #endif
1452         button = pref_button_new(NULL, NULL, _("View"), FALSE,
1453                                  G_CALLBACK(safe_delete_view_cb), NULL);
1454         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1455         gtk_widget_show(button);
1456
1457         button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
1458                                  G_CALLBACK(safe_delete_clear_cb), NULL);
1459         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1460         gtk_widget_show(button);
1461
1462
1463         group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
1464
1465         pref_checkbox_new_int(group, _("Rectangular selection in icon view"),
1466                               options->collections.rectangular_selection, &c_options->collections.rectangular_selection);
1467
1468         pref_checkbox_new_int(group, _("Descend folders in tree view"),
1469                               options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
1470
1471         pref_checkbox_new_int(group, _("Show date in directories list view"),
1472                               options->layout.show_directory_date, &c_options->layout.show_directory_date);
1473
1474         pref_checkbox_new_int(group, _("In place renaming"),
1475                               options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
1476
1477         pref_checkbox_new_int(group, _("Show \"Copy path\" menu item which write the path of selected files to clipboard"),
1478                               options->show_copy_path, &c_options->show_copy_path);
1479
1480         pref_spin_new_int(group, _("Open recent list maximum size"), NULL,
1481                           1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
1482         
1483         pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
1484                           16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
1485
1486         group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
1487
1488         pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
1489                               options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
1490         pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
1491                               options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
1492
1493         pref_label_new(group, _("Home button path (empty to use your home directory)"));
1494         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1495
1496         tabcomp = tab_completion_new(&home_path_entry, options->layout.home_path, NULL, NULL);
1497         tab_completion_add_select_button(home_path_entry, NULL, TRUE);
1498         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
1499         gtk_widget_show(tabcomp);
1500
1501         button = pref_button_new(hbox, NULL, _("Use current"), FALSE,
1502                                  G_CALLBACK(home_path_set_current), NULL);
1503
1504
1505         group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
1506
1507         pref_checkbox_new_int(group, _("Store metadata and cache files in source image's directory"),
1508                               options->enable_metadata_dirs, &c_options->enable_metadata_dirs);
1509
1510         pref_checkbox_new_int(group, _("Store keywords and comments as XMP tags in image files"),
1511                               options->save_metadata_in_image_file, &c_options->save_metadata_in_image_file);
1512
1513         pref_spin_new_int(group, _("Custom similarity threshold:"), NULL,
1514                           0, 100, 1, options->duplicates_similarity_threshold, &c_options->duplicates_similarity_threshold);
1515
1516         group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
1517
1518         pref_spin_new_int(group, _("Offscreen cache size (Mb per image):"), NULL,
1519                           0, 128, 1, options->image.tile_cache_max, &c_options->image.tile_cache_max);
1520
1521         pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
1522                           0, 1024, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
1523
1524         pref_spin_new_int(group, _("Image read buffer size (bytes):"), NULL,
1525                           IMAGE_LOADER_READ_BUFFER_SIZE_MIN, IMAGE_LOADER_READ_BUFFER_SIZE_MAX, 512,
1526                           options->image.read_buffer_size, &c_options->image.read_buffer_size);
1527
1528         pref_spin_new_int(group, _("Image idle loop read count:"), NULL,
1529                           IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MIN, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MAX, 1,
1530                           options->image.idle_read_loop_count, &c_options->image.idle_read_loop_count);
1531
1532
1533         group =  pref_group_new(vbox, FALSE, _("Color profiles"), GTK_ORIENTATION_VERTICAL);
1534 #ifndef HAVE_LCMS
1535         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
1536 #endif
1537
1538         table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 2, FALSE, FALSE);
1539         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
1540
1541         label = pref_table_label(table, 0, 0, _("Type"), 0.0);
1542         pref_label_bold(label, TRUE, FALSE);
1543
1544         label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
1545         pref_label_bold(label, TRUE, FALSE);
1546
1547         label = pref_table_label(table, 2, 0, _("File"), 0.0);
1548         pref_label_bold(label, TRUE, FALSE);
1549
1550         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
1551                 {
1552                 GtkWidget *entry;
1553                 gchar *buf;
1554
1555                 buf = g_strdup_printf("Input %d:", i + COLOR_PROFILE_FILE);
1556                 pref_table_label(table, 0, i + 1, buf, 1.0);
1557                 g_free(buf);
1558
1559                 entry = gtk_entry_new();
1560                 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
1561                 gtk_widget_set_size_request(editor_name_entry[i], 30, -1);
1562                 if (options->color_profile.input_name[i])
1563                         {
1564                         gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
1565                         }
1566                 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
1567                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
1568                 gtk_widget_show(entry);
1569                 color_profile_input_name_entry[i] = entry;
1570
1571                 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, NULL);
1572                 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
1573                 gtk_widget_set_size_request(entry, 160, -1);
1574                 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
1575                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
1576                 gtk_widget_show(tabcomp);
1577                 color_profile_input_file_entry[i] = entry;
1578                 }
1579
1580         pref_table_label(table, 0, COLOR_PROFILE_INPUTS + 1, _("Screen:"), 1.0);
1581         tabcomp = tab_completion_new(&color_profile_screen_file_entry,
1582                                      options->color_profile.screen_file, NULL, NULL);
1583         tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
1584         gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
1585         gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3,
1586                          COLOR_PROFILE_INPUTS + 1, COLOR_PROFILE_INPUTS + 2,
1587                          GTK_FILL | GTK_EXPAND, 0, 0, 0);
1588         gtk_widget_show(tabcomp);
1589
1590 #ifdef DEBUG
1591         group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
1592
1593         pref_spin_new_int(group, _("Debug level:"), NULL,
1594                           DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
1595 #endif
1596 }
1597
1598 /* Main preferences window */
1599 static void config_window_create(void)
1600 {
1601         GtkWidget *win_vbox;
1602         GtkWidget *hbox;
1603         GtkWidget *notebook;
1604         GtkWidget *button;
1605         GtkWidget *ct_button;
1606
1607         if (!c_options) c_options = init_options(NULL);
1608
1609         configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
1610         gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
1611         g_signal_connect(G_OBJECT(configwindow), "delete_event",
1612                          G_CALLBACK(config_window_delete), NULL);
1613         gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
1614         gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
1615         gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
1616
1617         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
1618         gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
1619         gtk_widget_show(win_vbox);
1620
1621         hbox = gtk_hbutton_box_new();
1622         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
1623         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
1624         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
1625         gtk_widget_show(hbox);
1626
1627         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
1628                                  G_CALLBACK(config_window_ok_cb), NULL);
1629         gtk_container_add(GTK_CONTAINER(hbox), button);
1630         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1631         gtk_widget_grab_default(button);
1632         gtk_widget_show(button);
1633
1634         ct_button = button;
1635
1636         button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
1637                                  G_CALLBACK(config_window_save_cb), NULL);
1638         gtk_container_add(GTK_CONTAINER(hbox), button);
1639         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1640         gtk_widget_show(button);
1641         
1642         button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
1643                                  G_CALLBACK(config_window_apply_cb), NULL);
1644         gtk_container_add(GTK_CONTAINER(hbox), button);
1645         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1646         gtk_widget_show(button);
1647
1648         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
1649                                  G_CALLBACK(config_window_close_cb), NULL);
1650         gtk_container_add(GTK_CONTAINER(hbox), button);
1651         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1652         gtk_widget_show(button);
1653
1654         if (!generic_dialog_get_alternative_button_order(configwindow))
1655                 {
1656                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
1657                 }
1658
1659         notebook = gtk_notebook_new();
1660         gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
1661         gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
1662
1663         config_tab_general(notebook);
1664         config_tab_image(notebook);
1665         config_tab_windows(notebook);
1666         config_tab_filtering(notebook);
1667         config_tab_editors(notebook);
1668         config_tab_properties(notebook);
1669         config_tab_advanced(notebook);
1670
1671         gtk_widget_show(notebook);
1672
1673         gtk_widget_show(configwindow);
1674 }
1675
1676 /*
1677  *-----------------------------------------------------------------------------
1678  * config window show (public)
1679  *-----------------------------------------------------------------------------
1680  */
1681
1682 void show_config_window(void)
1683 {
1684         if (configwindow)
1685                 {
1686                 gtk_window_present(GTK_WINDOW(configwindow));
1687                 return;
1688                 }
1689
1690         config_window_create();
1691 }
1692
1693 /*
1694  *-----------------
1695  * about window
1696  *-----------------
1697  */
1698
1699 static GtkWidget *about = NULL;
1700
1701 static gint about_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1702 {
1703         gtk_widget_destroy(about);
1704         about = NULL;
1705
1706         return TRUE;
1707 }
1708
1709 static void about_window_close(GtkWidget *widget, gpointer data)
1710 {
1711         if (!about) return;
1712
1713         gtk_widget_destroy(about);
1714         about = NULL;
1715 }
1716
1717 static void about_credits_cb(GtkWidget *widget, gpointer data)
1718 {
1719         help_window_show("credits");
1720 }
1721
1722 void show_about_window(void)
1723 {
1724         GtkWidget *vbox;
1725         GtkWidget *hbox;
1726         GtkWidget *label;
1727         GtkWidget *button;
1728         GdkPixbuf *pixbuf;
1729
1730         gchar *buf;
1731
1732         if (about)
1733                 {
1734                 gtk_window_present(GTK_WINDOW(about));
1735                 return;
1736                 }
1737
1738         about = window_new(GTK_WINDOW_TOPLEVEL, "about", NULL, NULL, _("About"));
1739         gtk_window_set_type_hint(GTK_WINDOW(about), GDK_WINDOW_TYPE_HINT_DIALOG);
1740         g_signal_connect(G_OBJECT(about), "delete_event",
1741                          G_CALLBACK(about_delete_cb), NULL);
1742
1743         gtk_container_set_border_width(GTK_CONTAINER(about), PREF_PAD_BORDER);
1744
1745         vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
1746         gtk_container_add(GTK_CONTAINER(about), vbox);
1747         gtk_widget_show(vbox);
1748
1749         pixbuf = pixbuf_inline(PIXBUF_INLINE_LOGO);
1750         button = gtk_image_new_from_pixbuf(pixbuf);
1751         g_object_unref(pixbuf);
1752         gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 0);
1753         gtk_widget_show(button);
1754
1755         buf = g_strdup_printf(_("%s %s\n\nCopyright (c) 2006 John Ellis\nCopyright (c) %s The Geeqie Team\nwebsite: %s\nemail: %s\n\nReleased under the GNU General Public License"),
1756                               GQ_APPNAME,
1757                               VERSION,
1758                               "2008",
1759                               GQ_WEBSITE,
1760                               GQ_EMAIL_ADDRESS);
1761         label = gtk_label_new(buf);
1762         g_free(buf);
1763
1764         gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
1765         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1766         gtk_widget_show(label);
1767
1768         hbox = gtk_hbutton_box_new();
1769         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
1770         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
1771         gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1772         gtk_widget_show(hbox);
1773
1774         button = pref_button_new(NULL, NULL, _("Credits..."), FALSE,
1775                                  G_CALLBACK(about_credits_cb), NULL);
1776         gtk_container_add(GTK_CONTAINER(hbox), button);
1777         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1778         gtk_widget_show(button);
1779
1780         button = pref_button_new(NULL, GTK_STOCK_CLOSE, NULL, FALSE,
1781                                  G_CALLBACK(about_window_close), NULL);
1782         gtk_container_add(GTK_CONTAINER(hbox), button);
1783         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1784         gtk_widget_grab_default(button);
1785         gtk_widget_show(button);
1786
1787         gtk_widget_show(about);
1788 }