Option to display window ID
[geeqie.git] / src / preferences.c
1 /*
2  * Copyright (C) 2006 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "preferences.h"
24
25 #include "bar_exif.h"
26 #include "cache.h"
27 #include "cache_maint.h"
28 #include "editors.h"
29 #include "exif.h"
30 #include "filedata.h"
31 #include "filefilter.h"
32 #include "fullscreen.h"
33 #include "image.h"
34 #include "image-overlay.h"
35 #include "color-man.h"
36 #include "img-view.h"
37 #include "layout_config.h"
38 #include "layout_util.h"
39 #include "pixbuf_util.h"
40 #include "slideshow.h"
41 #include "toolbar.h"
42 #include "trash.h"
43 #include "utilops.h"
44 #include "ui_fileops.h"
45 #include "ui_misc.h"
46 #include "ui_tabcomp.h"
47 #include "ui_utildlg.h"
48 #include "window.h"
49
50 #include <math.h>
51
52 #ifdef HAVE_LCMS
53 #ifdef HAVE_LCMS2
54 #include <lcms2.h>
55 #else
56 #include <lcms.h>
57 #endif
58 #endif
59
60 #define EDITOR_NAME_MAX_LENGTH 32
61 #define EDITOR_COMMAND_MAX_LENGTH 1024
62
63 static void image_overlay_set_text_colours();
64
65 typedef struct _ThumbSize ThumbSize;
66 struct _ThumbSize
67 {
68         gint w;
69         gint h;
70 };
71
72 static ThumbSize thumb_size_list[] =
73 {
74         { 24, 24 },
75         { 32, 32 },
76         { 48, 48 },
77         { 64, 64 },
78         { 96, 72 },
79         { 96, 96 },
80         { 128, 96 },
81         { 128, 128 },
82         { 160, 120 },
83         { 160, 160 },
84         { 192, 144 },
85         { 192, 192 },
86         { 256, 192 },
87         { 256, 256 }
88 };
89
90 enum {
91         FE_ENABLE,
92         FE_EXTENSION,
93         FE_DESCRIPTION,
94         FE_CLASS,
95         FE_WRITABLE,
96         FE_ALLOW_SIDECAR
97 };
98
99 enum {
100         AE_ACTION,
101         AE_KEY,
102         AE_TOOLTIP,
103         AE_ACCEL
104 };
105
106 static gchar *format_class_list[] = {
107         N_("Unknown"),
108         N_("Image"),
109         N_("RAW Image"),
110         N_("Metadata"),
111         N_("Video")
112         };
113
114 /* config memory values */
115 static ConfOptions *c_options = NULL;
116
117
118 #ifdef DEBUG
119 static gint debug_c;
120 #endif
121
122 static GtkWidget *configwindow = NULL;
123 static GtkListStore *filter_store = NULL;
124 static GtkTreeStore *accel_store = NULL;
125
126 static GtkWidget *safe_delete_path_entry;
127
128 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
129 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
130 static GtkWidget *color_profile_screen_file_entry;
131
132 static GtkWidget *sidecar_ext_entry;
133
134
135 #define CONFIG_WINDOW_DEF_WIDTH         700
136 #define CONFIG_WINDOW_DEF_HEIGHT        600
137
138 /*
139  *-----------------------------------------------------------------------------
140  * option widget callbacks (private)
141  *-----------------------------------------------------------------------------
142  */
143
144 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
145 {
146         c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
147 }
148
149 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
150 {
151         gint mins_secs_tenths, delay;
152
153         mins_secs_tenths = c_options->slideshow.delay %
154                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
155
156         delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
157                                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
158                                                                 mins_secs_tenths);
159
160         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
161                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
162 }
163
164 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
165 {
166         gint hours, secs_tenths, delay;
167
168         hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
169         secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
170
171         delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
172                                         (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
173                                         (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
174
175         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
176                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
177 }
178
179 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
180 {
181         gint hours_mins, delay;
182
183         hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
184
185         delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
186                                                         (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
187                                                         (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
188
189         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
190                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
191 }
192
193 /*
194  *-----------------------------------------------------------------------------
195  * sync progam to config window routine (private)
196  *-----------------------------------------------------------------------------
197  */
198
199 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
200 {
201         const gchar *buf;
202
203         g_free(*option);
204         *option = NULL;
205         buf = gtk_entry_get_text(GTK_ENTRY(entry));
206         if (buf && strlen(buf) > 0)
207                 {
208                 if (func)
209                         *option = func(buf);
210                 else
211                         *option = g_strdup(buf);
212                 }
213 }
214
215
216 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
217 {
218         gchar *accel_path, *accel;
219
220         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
221
222         if (accel_path && accel_path[0])
223                 {
224                 GtkAccelKey key;
225                 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
226                 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
227                 }
228
229         g_free(accel_path);
230         g_free(accel);
231
232         return FALSE;
233 }
234
235
236 static void config_window_apply(void)
237 {
238         gint i;
239         gboolean refresh = FALSE;
240
241         config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
242
243         if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
244         if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
245         if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
246         if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
247         if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
248         if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
249         if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
250
251         options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
252         options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
253         options->file_ops.safe_delete_enable = c_options->file_ops.safe_delete_enable;
254         options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
255         options->tools_restore_state = c_options->tools_restore_state;
256         options->save_window_positions = c_options->save_window_positions;
257         options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
258         options->save_dialog_window_positions = c_options->save_dialog_window_positions;
259         options->show_window_ids = c_options->show_window_ids;
260         options->image.scroll_reset_method = c_options->image.scroll_reset_method;
261         options->image.zoom_2pass = c_options->image.zoom_2pass;
262         options->image.fit_window_to_image = c_options->image.fit_window_to_image;
263         options->image.limit_window_size = c_options->image.limit_window_size;
264         options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
265         options->image.max_window_size = c_options->image.max_window_size;
266         options->image.limit_autofit_size = c_options->image.limit_autofit_size;
267         options->image.max_autofit_size = c_options->image.max_autofit_size;
268         options->image.max_enlargement_size = c_options->image.max_enlargement_size;
269         options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
270         options->progressive_key_scrolling = c_options->progressive_key_scrolling;
271         options->keyboard_scroll_step = c_options->keyboard_scroll_step;
272
273         if (options->thumbnails.max_width != c_options->thumbnails.max_width
274             || options->thumbnails.max_height != c_options->thumbnails.max_height
275             || options->thumbnails.quality != c_options->thumbnails.quality)
276                 {
277                 thumb_format_changed = TRUE;
278                 refresh = TRUE;
279                 options->thumbnails.max_width = c_options->thumbnails.max_width;
280                 options->thumbnails.max_height = c_options->thumbnails.max_height;
281                 options->thumbnails.quality = c_options->thumbnails.quality;
282                 }
283         options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
284         options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
285         options->thumbnails.use_exif = c_options->thumbnails.use_exif;
286         options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
287 //      options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
288         options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
289         options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
290         options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
291         options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
292         options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
293         options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
294
295         options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
296         options->file_sort.natural = c_options->file_sort.natural;
297         options->file_filter.disable = c_options->file_filter.disable;
298
299         config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
300         sidecar_ext_parse(options->sidecar.ext);
301
302         options->slideshow.random = c_options->slideshow.random;
303         options->slideshow.repeat = c_options->slideshow.repeat;
304         options->slideshow.delay = c_options->slideshow.delay;
305
306         options->mousewheel_scrolls = c_options->mousewheel_scrolls;
307         options->image_lm_click_nav = c_options->image_lm_click_nav;
308         options->image_l_click_video = c_options->image_l_click_video;
309         options->image_l_click_video_editor = c_options->image_l_click_video_editor;
310
311         options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
312
313         options->image.tile_cache_max = c_options->image.tile_cache_max;
314         options->image.image_cache_max = c_options->image.image_cache_max;
315
316         options->image.zoom_quality = c_options->image.zoom_quality;
317
318         options->image.zoom_increment = c_options->image.zoom_increment;
319
320         options->image.enable_read_ahead = c_options->image.enable_read_ahead;
321
322
323         if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
324             || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
325             || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
326                 {
327                 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
328                 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
329                 options->image.border_color = c_options->image.border_color;
330                 layout_colors_update();
331                 view_window_colors_update();
332                 }
333
334         options->image.alpha_color_1 = c_options->image.alpha_color_1;
335         options->image.alpha_color_2 = c_options->image.alpha_color_2;
336
337         options->fullscreen.screen = c_options->fullscreen.screen;
338         options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
339         options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
340         options->fullscreen.above = c_options->fullscreen.above;
341         if (c_options->image_overlay.template_string)
342                 set_image_overlay_template_string(&options->image_overlay.template_string,
343                                                   c_options->image_overlay.template_string);
344         if (c_options->image_overlay.font)
345                 set_image_overlay_font_string(&options->image_overlay.font,
346                                                   c_options->image_overlay.font);
347         options->image_overlay.text_red = c_options->image_overlay.text_red;
348         options->image_overlay.text_green = c_options->image_overlay.text_green;
349         options->image_overlay.text_blue = c_options->image_overlay.text_blue;
350         options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
351         options->image_overlay.background_red = c_options->image_overlay.background_red;
352         options->image_overlay.background_green = c_options->image_overlay.background_green;
353         options->image_overlay.background_blue = c_options->image_overlay.background_blue;
354         options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
355         options->update_on_time_change = c_options->update_on_time_change;
356         options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
357
358         options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
359         options->rot_invariant_sim = c_options->rot_invariant_sim;
360
361         options->tree_descend_subdirs = c_options->tree_descend_subdirs;
362
363         options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
364
365         options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
366         options->dnd_icon_size = c_options->dnd_icon_size;
367         options->clipboard_selection = c_options->clipboard_selection;
368
369         options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
370         options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
371         options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
372         options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
373         options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
374         options->metadata.confirm_write = c_options->metadata.confirm_write;
375         options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
376         options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
377         options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
378         options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
379         options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
380         options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
381         options->metadata.write_orientation = c_options->metadata.write_orientation;
382         options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
383                                (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
384                                (c_options->stereo.tmp.flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
385                                (c_options->stereo.tmp.mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
386                                (c_options->stereo.tmp.flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
387                                (c_options->stereo.tmp.swap         ? PR_STEREO_SWAP : 0) |
388                                (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
389         options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
390                                (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
391                                (c_options->stereo.tmp.fs_flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
392                                (c_options->stereo.tmp.fs_mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
393                                (c_options->stereo.tmp.fs_flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
394                                (c_options->stereo.tmp.fs_swap         ? PR_STEREO_SWAP : 0) |
395                                (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
396         options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
397         options->stereo.fixed_w = c_options->stereo.fixed_w;
398         options->stereo.fixed_h = c_options->stereo.fixed_h;
399         options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
400         options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
401         options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
402         options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
403
404         options->info_keywords.height = c_options->info_keywords.height;
405         options->info_title.height = c_options->info_title.height;
406         options->info_comment.height = c_options->info_comment.height;
407         options->info_rating.height = c_options->info_rating.height;
408
409 #ifdef DEBUG
410         set_debug_level(debug_c);
411 #endif
412
413 #ifdef HAVE_LCMS
414         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
415                 {
416                 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
417                 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
418                 }
419         config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
420         options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
421         if (options->color_profile.render_intent != c_options->color_profile.render_intent)
422                 {
423                 options->color_profile.render_intent = c_options->color_profile.render_intent;
424                 color_man_update();
425                 }
426 #endif
427
428         image_options_sync();
429
430         if (refresh)
431                 {
432                 filter_rebuild();
433                 layout_refresh(NULL);
434                 }
435
436         if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
437
438         toolbar_apply();
439 }
440
441 /*
442  *-----------------------------------------------------------------------------
443  * config window main button callbacks (private)
444  *-----------------------------------------------------------------------------
445  */
446
447 static void config_window_close_cb(GtkWidget *widget, gpointer data)
448 {
449         gtk_widget_destroy(configwindow);
450         configwindow = NULL;
451         filter_store = NULL;
452 }
453
454 static void config_window_help_cb(GtkWidget *widget, gpointer data)
455 {
456         GtkWidget *notebook = data;
457         gint i;
458
459         static gchar *html_section[] =
460         {
461         "GuideOptionsGeneral.html",
462         "GuideOptionsImage.html",
463         "GuideOptionsWindow.html",
464         "GuideOptionsKeyboard.html",
465         "GuideOptionsFiltering.html",
466         "GuideOptionsMetadata.html",
467         "GuideOptionsColor.html",
468         "GuideOptionsStereo.html",
469         "GuideOptionsBehavior.html",
470         "GuideOptionsToolbar.html"
471         };
472
473         i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
474         help_window_show(html_section[i]);
475 }
476
477 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
478 {
479         config_window_close_cb(NULL, NULL);
480         return TRUE;
481 }
482
483 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
484 {
485         config_window_apply();
486         config_window_close_cb(NULL, NULL);
487 }
488
489 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
490 {
491         LayoutWindow *lw;
492         lw = layout_window_list->data;
493
494         config_window_apply();
495         layout_util_sync(lw);
496 }
497
498 static void config_window_save_cb(GtkWidget *widget, gpointer data)
499 {
500         config_window_apply();
501         save_options(options);
502 }
503
504 /*
505  *-----------------------------------------------------------------------------
506  * config window setup (private)
507  *-----------------------------------------------------------------------------
508  */
509
510 static void quality_menu_cb(GtkWidget *combo, gpointer data)
511 {
512         gint *option = data;
513
514         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
515                 {
516                 case 0:
517                 default:
518                         *option = GDK_INTERP_NEAREST;
519                         break;
520                 case 1:
521                         *option = GDK_INTERP_TILES;
522                         break;
523                 case 2:
524                         *option = GDK_INTERP_BILINEAR;
525                         break;
526                 case 3:
527                         *option = GDK_INTERP_HYPER;
528                         break;
529                 }
530 }
531
532 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
533 {
534         gint *option = data;
535
536         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
537                 {
538                 case 0:
539                 default:
540                         *option = PRIMARY;
541                         break;
542                 case 1:
543                         *option = CLIPBOARD;
544                         break;
545                 }
546 }
547
548 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
549                              guint option, guint *option_c)
550 {
551         GtkWidget *combo;
552         gint current = 0;
553
554         *option_c = option;
555
556         pref_table_label(table, column, row, text, 0.0);
557
558         combo = gtk_combo_box_text_new();
559
560         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
561         if (option == GDK_INTERP_NEAREST) current = 0;
562         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
563         if (option == GDK_INTERP_TILES) current = 1;
564         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
565         if (option == GDK_INTERP_BILINEAR) current = 2;
566         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
567         if (option == GDK_INTERP_HYPER) current = 3;
568
569         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
570
571         g_signal_connect(G_OBJECT(combo), "changed",
572                          G_CALLBACK(quality_menu_cb), option_c);
573
574         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
575                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
576         gtk_widget_show(combo);
577 }
578
579 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
580                              gint option, gint *option_c)
581 {
582         GtkWidget *combo;
583         gint current = 0;
584
585         *option_c = option;
586
587         pref_table_label(table, column, row, text, 0.0);
588
589         combo = gtk_combo_box_text_new();
590
591         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
592         if (option == PRIMARY) current = 0;
593         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
594         if (option == CLIPBOARD) current = 1;
595
596         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
597
598         g_signal_connect(G_OBJECT(combo), "changed",
599                          G_CALLBACK(clipboard_selection_menu_cb), option_c);
600
601         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
602                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
603         gtk_widget_show(combo);
604 }
605
606 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
607 {
608         gint n;
609
610         n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
611         if (n < 0) return;
612
613         if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
614                 {
615                 c_options->thumbnails.max_width = thumb_size_list[n].w;
616                 c_options->thumbnails.max_height = thumb_size_list[n].h;
617                 }
618         else
619                 {
620                 c_options->thumbnails.max_width = options->thumbnails.max_width;
621                 c_options->thumbnails.max_height = options->thumbnails.max_height;
622                 }
623 }
624
625 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
626 {
627         GtkWidget *combo;
628         gint current;
629         gint i;
630
631         c_options->thumbnails.max_width = options->thumbnails.max_width;
632         c_options->thumbnails.max_height = options->thumbnails.max_height;
633
634         pref_table_label(table, column, row, text, 0.0);
635
636         combo = gtk_combo_box_text_new();
637
638         current = -1;
639         for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
640                 {
641                 gint w, h;
642                 gchar *buf;
643
644                 w = thumb_size_list[i].w;
645                 h = thumb_size_list[i].h;
646
647                 buf = g_strdup_printf("%d x %d", w, h);
648                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
649                 g_free(buf);
650
651                 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
652                 }
653
654         if (current == -1)
655                 {
656                 gchar *buf;
657
658                 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
659                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
660                 g_free(buf);
661
662                 current = i;
663                 }
664
665         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
666         g_signal_connect(G_OBJECT(combo), "changed",
667                          G_CALLBACK(thumb_size_menu_cb), NULL);
668
669         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
670                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
671         gtk_widget_show(combo);
672 }
673
674 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
675 {
676         gint *option = data;
677
678         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
679                 {
680                 case 0:
681                 default:
682                         *option = PR_STEREO_NONE;
683                         break;
684                 case 1:
685                         *option = PR_STEREO_ANAGLYPH_RC;
686                         break;
687                 case 2:
688                         *option = PR_STEREO_ANAGLYPH_GM;
689                         break;
690                 case 3:
691                         *option = PR_STEREO_ANAGLYPH_YB;
692                         break;
693                 case 4:
694                         *option = PR_STEREO_ANAGLYPH_GRAY_RC;
695                         break;
696                 case 5:
697                         *option = PR_STEREO_ANAGLYPH_GRAY_GM;
698                         break;
699                 case 6:
700                         *option = PR_STEREO_ANAGLYPH_GRAY_YB;
701                         break;
702                 case 7:
703                         *option = PR_STEREO_ANAGLYPH_DB_RC;
704                         break;
705                 case 8:
706                         *option = PR_STEREO_ANAGLYPH_DB_GM;
707                         break;
708                 case 9:
709                         *option = PR_STEREO_ANAGLYPH_DB_YB;
710                         break;
711                 case 10:
712                         *option = PR_STEREO_HORIZ;
713                         break;
714                 case 11:
715                         *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
716                         break;
717                 case 12:
718                         *option = PR_STEREO_VERT;
719                         break;
720                 case 13:
721                         *option = PR_STEREO_VERT | PR_STEREO_HALF;
722                         break;
723                 case 14:
724                         *option = PR_STEREO_FIXED;
725                         break;
726                 }
727 }
728
729 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
730                              gint option, gint *option_c, gboolean add_fixed)
731 {
732         GtkWidget *combo;
733         gint current = 0;
734
735         *option_c = option;
736
737         pref_table_label(table, column, row, text, 0.0);
738
739         combo = gtk_combo_box_text_new();
740
741         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
742
743         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
744         if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
745         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
746         if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
747         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
748         if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
749         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
750         if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
751         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
752         if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
753         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
754         if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
755         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
756         if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
757         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
758         if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
759         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
760         if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
761
762         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
763         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
764         if (option & PR_STEREO_HORIZ)
765                 {
766                 current = 10;
767                 if (option & PR_STEREO_HALF) current = 11;
768                 }
769
770         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
771         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
772         if (option & PR_STEREO_VERT)
773                 {
774                 current = 12;
775                 if (option & PR_STEREO_HALF) current = 13;
776                 }
777
778         if (add_fixed)
779                 {
780                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
781                 if (option & PR_STEREO_FIXED) current = 14;
782                 }
783
784         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
785
786         g_signal_connect(G_OBJECT(combo), "changed",
787                          G_CALLBACK(stereo_mode_menu_cb), option_c);
788
789         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
790                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
791         gtk_widget_show(combo);
792 }
793
794 static void video_menu_cb(GtkWidget *combo, gpointer data)
795 {
796         gchar **option = data;
797
798         EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
799         *option = ed->key;
800 }
801
802 static void video_menu_populate(gpointer data, gpointer user_data)
803 {
804         GtkWidget *combo = user_data;
805         EditorDescription *ed = data;
806
807         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
808 }
809
810 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
811                              gchar *option, gchar **option_c)
812 {
813         GtkWidget *combo;
814         gint current;
815 /* use lists since they are sorted */
816         GList *eds = editor_list_get();
817
818         *option_c = option;
819
820         pref_table_label(table, column, row, text, 0.0);
821
822         combo = gtk_combo_box_text_new();
823         g_list_foreach(eds,video_menu_populate,(gpointer)combo);
824         current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
825
826         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
827
828         g_signal_connect(G_OBJECT(combo), "changed",
829                          G_CALLBACK(video_menu_cb), option_c);
830
831         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
832                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
833         gtk_widget_show(combo);
834 }
835
836 static void filter_store_populate(void)
837 {
838         GList *work;
839
840         if (!filter_store) return;
841
842         gtk_list_store_clear(filter_store);
843
844         work = filter_get_list();
845         while (work)
846                 {
847                 FilterEntry *fe;
848                 GtkTreeIter iter;
849
850                 fe = work->data;
851                 work = work->next;
852
853                 gtk_list_store_append(filter_store, &iter);
854                 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
855                 }
856 }
857
858 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
859                                      gchar *new_text, gpointer data)
860 {
861         GtkWidget *model = data;
862         FilterEntry *fe = data;
863         GtkTreePath *tpath;
864         GtkTreeIter iter;
865
866         if (!new_text || strlen(new_text) < 1) return;
867
868         tpath = gtk_tree_path_new_from_string(path_str);
869         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
870         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
871
872         g_free(fe->extensions);
873         fe->extensions = g_strdup(new_text);
874
875         gtk_tree_path_free(tpath);
876         filter_rebuild();
877 }
878
879 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
880                                        gchar *new_text, gpointer data)
881 {
882         GtkWidget *model = data;
883         FilterEntry *fe = data;
884         GtkTreePath *tpath;
885         GtkTreeIter iter;
886         gint i;
887
888         if (!new_text || !new_text[0]) return;
889
890         tpath = gtk_tree_path_new_from_string(path_str);
891         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
892         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
893
894         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
895                 {
896                 if (strcmp(new_text, _(format_class_list[i])) == 0)
897                         {
898                         fe->file_class = i;
899                         break;
900                         }
901                 }
902
903         gtk_tree_path_free(tpath);
904         filter_rebuild();
905 }
906
907 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
908                                       gchar *new_text, gpointer data)
909 {
910         GtkWidget *model = data;
911         FilterEntry *fe;
912         GtkTreePath *tpath;
913         GtkTreeIter iter;
914
915         if (!new_text || !new_text[0]) return;
916
917         tpath = gtk_tree_path_new_from_string(path_str);
918         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
919         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
920
921         g_free(fe->description);
922         fe->description = g_strdup(new_text);
923
924         gtk_tree_path_free(tpath);
925 }
926
927 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
928                                    gchar *path_str, gpointer data)
929 {
930         GtkWidget *model = data;
931         FilterEntry *fe;
932         GtkTreePath *tpath;
933         GtkTreeIter iter;
934
935         tpath = gtk_tree_path_new_from_string(path_str);
936         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
937         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
938
939         fe->enabled = !fe->enabled;
940
941         gtk_tree_path_free(tpath);
942         filter_rebuild();
943 }
944
945 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
946                                      gchar *path_str, gpointer data)
947 {
948         GtkWidget *model = data;
949         FilterEntry *fe;
950         GtkTreePath *tpath;
951         GtkTreeIter iter;
952
953         tpath = gtk_tree_path_new_from_string(path_str);
954         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
955         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
956
957         fe->writable = !fe->writable;
958         if (fe->writable) fe->allow_sidecar = FALSE;
959
960         gtk_tree_path_free(tpath);
961         filter_rebuild();
962 }
963
964 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
965                                     gchar *path_str, gpointer data)
966 {
967         GtkWidget *model = data;
968         FilterEntry *fe;
969         GtkTreePath *tpath;
970         GtkTreeIter iter;
971
972         tpath = gtk_tree_path_new_from_string(path_str);
973         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
974         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
975
976         fe->allow_sidecar = !fe->allow_sidecar;
977         if (fe->allow_sidecar) fe->writable = FALSE;
978
979         gtk_tree_path_free(tpath);
980         filter_rebuild();
981 }
982
983 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
984                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
985 {
986         FilterEntry *fe;
987
988         gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
989
990         switch (GPOINTER_TO_INT(data))
991                 {
992                 case FE_ENABLE:
993                         g_object_set(GTK_CELL_RENDERER(cell),
994                                      "active", fe->enabled, NULL);
995                         break;
996                 case FE_EXTENSION:
997                         g_object_set(GTK_CELL_RENDERER(cell),
998                                      "text", fe->extensions, NULL);
999                         break;
1000                 case FE_DESCRIPTION:
1001                         g_object_set(GTK_CELL_RENDERER(cell),
1002                                      "text", fe->description, NULL);
1003                         break;
1004                 case FE_CLASS:
1005                         g_object_set(GTK_CELL_RENDERER(cell),
1006                                      "text", _(format_class_list[fe->file_class]), NULL);
1007                         break;
1008                 case FE_WRITABLE:
1009                         g_object_set(GTK_CELL_RENDERER(cell),
1010                                      "active", fe->writable, NULL);
1011                         break;
1012                 case FE_ALLOW_SIDECAR:
1013                         g_object_set(GTK_CELL_RENDERER(cell),
1014                                      "active", fe->allow_sidecar, NULL);
1015                         break;
1016                 }
1017 }
1018
1019 static gboolean filter_add_scroll(gpointer data)
1020 {
1021         GtkTreePath *path;
1022         GList *list_cells;
1023         GtkCellRenderer *cell;
1024         GtkTreeViewColumn *column;
1025         GList *list_columns;
1026         const gchar *title;
1027         guint i = 0;
1028         gint rows;
1029
1030         rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1031         path = gtk_tree_path_new_from_indices(rows-1, -1);
1032
1033         list_columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(data));
1034         do {
1035                 column = g_list_nth(list_columns,i)->data;
1036                 title = gtk_tree_view_column_get_title(GTK_TREE_VIEW_COLUMN(column));
1037                 i++;
1038                 } while (strcmp(title, "Filter") !=0 );
1039
1040         list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1041         cell = g_list_last(list_cells)->data;
1042
1043         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1044                                                                 path, column, FALSE, 0.0, 0.0 );
1045         gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1046                                                                 path, column, cell, TRUE);
1047
1048         gtk_tree_path_free(path);
1049         g_list_free(list_cells);
1050         g_list_free(list_columns);
1051
1052         return(FALSE);
1053 }
1054
1055 static void filter_add_cb(GtkWidget *widget, gpointer data)
1056 {
1057         filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1058         filter_store_populate();
1059
1060         g_idle_add((GSourceFunc)filter_add_scroll, data);
1061 }
1062
1063 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1064 {
1065         GtkWidget *filter_view = data;
1066         GtkTreeSelection *selection;
1067         GtkTreeIter iter;
1068         FilterEntry *fe;
1069
1070         if (!filter_store) return;
1071         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1072         if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1073         gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1074         if (!fe) return;
1075
1076         filter_remove_entry(fe);
1077         filter_rebuild();
1078         filter_store_populate();
1079 }
1080
1081 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1082 {
1083         GtkTreeIter iter;
1084         GtkTreePath *path;
1085         GtkTreeViewColumn *column;
1086
1087         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1088         path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1089         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1090
1091         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1092                                      path, column,
1093                                      FALSE, 0.0, 0.0);
1094
1095         gtk_tree_path_free(path);
1096
1097         return(FALSE);
1098 }
1099
1100 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1101 {
1102         filter_reset();
1103         filter_add_defaults();
1104         filter_rebuild();
1105         filter_store_populate();
1106
1107         g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1108 }
1109
1110 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1111 {
1112         /* no op, only so cancel button appears */
1113 }
1114
1115 static void filter_default_cb(GtkWidget *widget, gpointer data)
1116 {
1117         GenericDialog *gd;
1118
1119         gd = generic_dialog_new(_("Reset filters"),
1120                                 "reset_filter", widget, TRUE,
1121                                 dummy_cancel_cb, data);
1122         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1123                                    _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1124         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1125         gtk_widget_show(gd->dialog);
1126 }
1127
1128 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1129 {
1130         GtkWidget *frame = data;
1131
1132         gtk_widget_set_sensitive(frame,
1133                                  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1134 }
1135
1136 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1137 {
1138         layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1139 }
1140
1141 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1142 {
1143         file_util_trash_clear();
1144 }
1145
1146 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1147 {
1148         GenericDialog *gd;
1149         GtkWidget *entry;
1150         gd = generic_dialog_new(_("Clear trash"),
1151                                 "clear_trash", widget, TRUE,
1152                                 dummy_cancel_cb, NULL);
1153         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1154                                     _("This will remove the trash contents."), FALSE);
1155         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1156         entry = gtk_entry_new();
1157         gtk_widget_set_can_focus(entry, FALSE);
1158         gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1159         if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1160         gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1161         gtk_widget_show(entry);
1162         gtk_widget_show(gd->dialog);
1163 }
1164
1165 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1166 {
1167         GtkWidget *pTextView;
1168         GtkTextBuffer *pTextBuffer;
1169         GtkTextIter iStart;
1170         GtkTextIter iEnd;
1171
1172         pTextView = GTK_WIDGET(data);
1173
1174         pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1175         gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1176         gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1177
1178         set_image_overlay_template_string(&c_options->image_overlay.template_string,
1179                                           gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1180 }
1181
1182 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1183 {
1184         GtkTextView *text_view = data;
1185         GtkTextBuffer *buffer;
1186
1187         set_default_image_overlay_template_string(&options->image_overlay.template_string);
1188         if (!configwindow) return;
1189
1190         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1191         gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1192 }
1193
1194 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1195 {
1196         GenericDialog *gd;
1197
1198         gd = generic_dialog_new(_("Reset image overlay template string"),
1199                                 "reset_image_overlay_template_string", widget, TRUE,
1200                                 dummy_cancel_cb, data);
1201         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1202                                    _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1203         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1204         gtk_widget_show(gd->dialog);
1205 }
1206
1207 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1208 {
1209         help_window_show("GuideOptionsWindow.html#OverlayScreenDisplay");
1210 }
1211
1212 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1213 {
1214 #if GTK_CHECK_VERSION(3,4,0)
1215         GtkWidget *dialog;
1216         char *font;
1217         PangoFontDescription *font_desc;
1218
1219         dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1220         gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1221
1222         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1223                 {
1224                 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1225                 font = pango_font_description_to_string(font_desc);
1226                 g_free(c_options->image_overlay.font);
1227                 c_options->image_overlay.font = g_strdup(font);
1228                 g_free(font);
1229                 }
1230
1231         gtk_widget_destroy(dialog);
1232 #else
1233         const char *font;
1234
1235         font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1236         c_options->image_overlay.font = g_strdup(font);
1237 #endif
1238 }
1239
1240 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1241 {
1242         GtkWidget *dialog;
1243 #if GTK_CHECK_VERSION(3,4,0)
1244         GdkRGBA colour;
1245
1246         dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1247         colour.red = options->image_overlay.text_red;
1248         colour.green = options->image_overlay.text_green;
1249         colour.blue = options->image_overlay.text_blue;
1250         colour.alpha = options->image_overlay.text_alpha;
1251         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1252         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1253
1254         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1255                 {
1256                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1257                 c_options->image_overlay.text_red = colour.red*255;
1258                 c_options->image_overlay.text_green = colour.green*255;
1259                 c_options->image_overlay.text_blue = colour.blue*255;
1260                 c_options->image_overlay.text_alpha = colour.alpha*255;
1261                 }
1262         gtk_widget_destroy(dialog);
1263 #else
1264         GdkColor colour;
1265         GtkColorSelection *colorsel;
1266
1267         dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1268         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1269         colour.red = options->image_overlay.text_red*257;
1270         colour.green = options->image_overlay.text_green*257;
1271         colour.blue = options->image_overlay.text_blue*257;
1272         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1273         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1274         gtk_color_selection_set_current_color(colorsel, &colour);
1275         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1276
1277         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1278                 {
1279                 gtk_color_selection_get_current_color(colorsel, &colour);
1280                 c_options->image_overlay.text_red = colour.red/257;
1281                 c_options->image_overlay.text_green = colour.green/257;
1282                 c_options->image_overlay.text_blue = colour.blue/257;
1283                 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1284                 }
1285         gtk_widget_destroy (dialog);
1286 #endif
1287 }
1288
1289
1290 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1291 {
1292         GtkWidget *dialog;
1293 #if GTK_CHECK_VERSION(3,4,0)
1294         GdkRGBA colour;
1295
1296         dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1297         colour.red = options->image_overlay.background_red;
1298         colour.green = options->image_overlay.background_green;
1299         colour.blue = options->image_overlay.background_blue;
1300         colour.alpha = options->image_overlay.background_alpha;
1301         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1302         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1303
1304         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1305                 {
1306                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1307                 c_options->image_overlay.background_red = colour.red*255;
1308                 c_options->image_overlay.background_green = colour.green*255;
1309                 c_options->image_overlay.background_blue = colour.blue*255;
1310                 c_options->image_overlay.background_alpha = colour.alpha*255;
1311                 }
1312         gtk_widget_destroy(dialog);
1313 #else
1314         GdkColor colour;
1315         GtkColorSelection *colorsel;
1316
1317         dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1318         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1319         colour.red = options->image_overlay.background_red*257;
1320         colour.green = options->image_overlay.background_green*257;
1321         colour.blue = options->image_overlay.background_blue*257;
1322         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1323         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1324         gtk_color_selection_set_current_color(colorsel, &colour);
1325         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1326
1327         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1328                 {
1329                 gtk_color_selection_get_current_color(colorsel, &colour);
1330                 c_options->image_overlay.background_red = colour.red/257;
1331                 c_options->image_overlay.background_green = colour.green/257;
1332                 c_options->image_overlay.background_blue = colour.blue/257;
1333                 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1334                 }
1335         gtk_widget_destroy(dialog);
1336 #endif
1337 }
1338
1339 static void accel_store_populate(void)
1340 {
1341         LayoutWindow *lw;
1342         GList *groups, *actions;
1343         GtkAction *action;
1344         const gchar *accel_path;
1345         GtkAccelKey key;
1346         GtkTreeIter iter;
1347
1348         if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1349
1350         gtk_tree_store_clear(accel_store);
1351         lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1352
1353         g_assert(lw && lw->ui_manager);
1354         groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1355         while (groups)
1356                 {
1357                 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1358                 while (actions)
1359                         {
1360                         action = GTK_ACTION(actions->data);
1361                         accel_path = gtk_action_get_accel_path(action);
1362                         if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1363                                 {
1364                                 gchar *label, *label2, *tooltip, *accel;
1365                                 g_object_get(action,
1366                                              "tooltip", &tooltip,
1367                                              "label", &label,
1368                                              NULL);
1369
1370                                 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1371                                         {
1372                                         g_free(label);
1373                                         label = label2;
1374                                         }
1375
1376                                 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1377
1378                                 if (tooltip)
1379                                         {
1380                                         gtk_tree_store_append(accel_store, &iter, NULL);
1381                                         gtk_tree_store_set(accel_store, &iter,
1382                                                            AE_ACTION, label,
1383                                                            AE_KEY, accel,
1384                                                            AE_TOOLTIP, tooltip ? tooltip : "",
1385                                                            AE_ACCEL, accel_path,
1386                                                            -1);
1387                                         }
1388
1389                                 g_free(accel);
1390                                 g_free(label);
1391                                 g_free(tooltip);
1392                                 }
1393                         actions = actions->next;
1394                         }
1395
1396                 groups = groups->next;
1397                 }
1398 }
1399
1400 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1401 {
1402
1403 }
1404
1405 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1406 {
1407         gchar *accel1 = data;
1408         gchar *accel2;
1409         GtkAccelKey key1;
1410         GtkAccelKey key2;
1411
1412         gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1413
1414         gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1415         gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1416
1417         if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1418                 {
1419                 gtk_tree_store_set(accel_store, iter, AE_KEY, "",  -1);
1420                 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1421                 }
1422
1423         g_free(accel2);
1424
1425         return FALSE;
1426 }
1427
1428
1429 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1430 {
1431         GtkTreeModel *model = (GtkTreeModel *)accel_store;
1432         GtkTreeIter iter;
1433         gchar *acc;
1434         gchar *accel_path;
1435         GtkAccelKey old_key, key;
1436         GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1437
1438         gtk_tree_model_get_iter(model, &iter, path);
1439         gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1440
1441         /* test if the accelerator can be stored without conflicts*/
1442         gtk_accel_map_lookup_entry(accel_path, &old_key);
1443
1444         /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1445         gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1446         gtk_accel_map_lookup_entry(accel_path, &key);
1447
1448         /* restore the original for now, the key will be really changed when the changes are confirmed */
1449         gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1450
1451         acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1452         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1453
1454         gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1455         gtk_tree_path_free(path);
1456         g_free(acc);
1457 }
1458
1459 static gboolean accel_default_scroll(GtkTreeView *data)
1460 {
1461         GtkTreeIter iter;
1462         GtkTreePath *path;
1463         GtkTreeViewColumn *column;
1464
1465         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1466         path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1467         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1468
1469         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1470                                      path, column,
1471                                      FALSE, 0.0, 0.0);
1472
1473         gtk_tree_path_free(path);
1474
1475         return(FALSE);
1476 }
1477
1478 static void accel_default_cb(GtkWidget *widget, gpointer data)
1479 {
1480         accel_store_populate();
1481
1482         g_idle_add((GSourceFunc)accel_default_scroll, data);
1483 }
1484
1485 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1486 {
1487         gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1488 }
1489
1490 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1491 {
1492         GtkAccelKey key;
1493         gchar *accel_path, *accel;
1494
1495         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1496         gtk_accel_map_lookup_entry(accel_path, &key);
1497         accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1498
1499         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1500
1501         gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1502         g_free(accel_path);
1503         g_free(accel);
1504 }
1505
1506 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1507 {
1508         GtkTreeSelection *selection;
1509
1510         if (!accel_store) return;
1511         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1512         gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1513 }
1514
1515
1516
1517 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1518 {
1519         GtkWidget *label;
1520         GtkWidget *vbox;
1521         GtkWidget *scrolled;
1522         GtkWidget *viewport;
1523
1524         scrolled = gtk_scrolled_window_new(NULL, NULL);
1525         gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1526         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1527                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1528         label = gtk_label_new(title);
1529         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1530         gtk_widget_show(scrolled);
1531
1532         viewport = gtk_viewport_new(NULL, NULL);
1533         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1534         gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1535         gtk_widget_show(viewport);
1536
1537         vbox = gtk_vbox_new(FALSE, 0);
1538         gtk_container_add(GTK_CONTAINER(viewport), vbox);
1539         gtk_widget_show(vbox);
1540
1541         return vbox;
1542 }
1543
1544 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1545 {
1546         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1547                 {
1548                 c_options->thumbnails.spec_standard =TRUE;
1549                 c_options->thumbnails.cache_into_dirs = FALSE;
1550                 }
1551         else
1552                 {
1553                 c_options->thumbnails.spec_standard =FALSE;
1554                 }
1555 }
1556
1557 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1558 {
1559         if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1560                 {
1561                 c_options->thumbnails.spec_standard =TRUE;
1562                 c_options->thumbnails.cache_into_dirs = FALSE;
1563                 }
1564         else
1565                 {
1566                 c_options->thumbnails.spec_standard =FALSE;
1567                 }
1568 }
1569
1570 static void cache_local_cb(GtkWidget *widget, gpointer data)
1571 {
1572         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1573                 {
1574                 c_options->thumbnails.cache_into_dirs = TRUE;
1575                 c_options->thumbnails.spec_standard =FALSE;
1576                 }
1577         else
1578                 {
1579                 c_options->thumbnails.cache_into_dirs = FALSE;
1580                 }
1581 }
1582
1583 /* general options tab */
1584 static void config_tab_general(GtkWidget *notebook)
1585 {
1586         GtkWidget *vbox;
1587         GtkWidget *hbox;
1588         GtkWidget *group;
1589         GtkWidget *group_frame;
1590         GtkWidget *subgroup;
1591         GtkWidget *button;
1592         GtkWidget *ct_button;
1593         GtkWidget *table;
1594         GtkWidget *spin;
1595         gint hours, minutes, remainder;
1596         gdouble seconds;
1597
1598         vbox = scrolled_notebook_page(notebook, _("General"));
1599
1600         group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1601
1602         table = pref_table_new(group, 2, 2, FALSE, FALSE);
1603         add_thumb_size_menu(table, 0, 0, _("Size:"));
1604         add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1605
1606         ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1607                                           options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1608
1609         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1610         pref_checkbox_link_sensitivity(ct_button, subgroup);
1611
1612         group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1613                                                                                 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1614         button = pref_radiobutton_new(group_frame, NULL,  get_thumbnails_cache_dir(),
1615                                                         !options->thumbnails.spec_standard,
1616                                                         G_CALLBACK(cache_geeqie_cb), NULL);
1617
1618         group_frame = pref_frame_new(subgroup, TRUE,
1619                                                         _("Store thumbnails local to image folder (non-standard)"),
1620                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1621         pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1622                                                         options->thumbnails.cache_into_dirs,
1623                                                         G_CALLBACK(cache_local_cb), NULL);
1624
1625         group_frame = pref_frame_new(subgroup, TRUE,
1626                                                         _("Use standard thumbnail style and cache, shared with other applications"),
1627                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1628         pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1629                                                         options->thumbnails.spec_standard,
1630                                                         G_CALLBACK(cache_standard_cb), NULL);
1631
1632         pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1633                               options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1634
1635 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1636         pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1637                               options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1638
1639 //      pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1640 //                            options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1641 #endif
1642
1643         group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
1644
1645         c_options->slideshow.delay = options->slideshow.delay;
1646         hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1647         remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1648         minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
1649         seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
1650                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
1651
1652         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1653
1654         spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
1655                                                                                 0, 23, 1.0, 0,
1656                                                                                 options->slideshow.delay ? hours : 0.0,
1657                                                                                 G_CALLBACK(slideshow_delay_hours_cb), NULL);
1658         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1659         spin = pref_spin_new(hbox, ":" , NULL,
1660                                                                                 0, 59, 1.0, 0,
1661                                                                                 options->slideshow.delay ? minutes: 0.0,
1662                                                                                 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
1663         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1664         spin = pref_spin_new(hbox, ":", NULL,
1665                                                                                 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
1666                                                                                 options->slideshow.delay ? seconds : 10.0,
1667                                                                                 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
1668         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1669
1670         pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
1671         pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
1672
1673         group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
1674
1675         pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
1676                           0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
1677         pref_checkbox_new_int(group, _("Preload next image"),
1678                               options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
1679
1680         pref_checkbox_new_int(group, _("Refresh on file change"),
1681                               options->update_on_time_change, &c_options->update_on_time_change);
1682
1683         group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
1684         pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
1685         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1686         pref_spin_new_int(hbox, _("Keywords:"), NULL,
1687                                  1, 9999, 1,
1688                                  options->info_keywords.height, &c_options->info_keywords.height);
1689         pref_spin_new_int(hbox, _("Title:"), NULL,
1690                                  1, 9999, 1,
1691                                  options->info_title.height, &c_options->info_title.height);
1692         pref_spin_new_int(hbox, _("Comment:"), NULL,
1693                                  1, 9999, 1,
1694                                  options->info_comment.height, &c_options->info_comment.height);
1695         pref_spin_new_int(hbox, _("Rating:"), NULL,
1696                                  1, 9999, 1,
1697                                  options->info_rating.height, &c_options->info_rating.height);
1698 }
1699
1700 /* image tab */
1701 static void config_tab_image(GtkWidget *notebook)
1702 {
1703         GtkWidget *hbox;
1704         GtkWidget *vbox;
1705         GtkWidget *group;
1706         GtkWidget *ct_button;
1707         GtkWidget *enlargement_button;
1708         GtkWidget *table;
1709         GtkWidget *spin;
1710
1711         vbox = scrolled_notebook_page(notebook, _("Image"));
1712
1713         group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
1714
1715         table = pref_table_new(group, 2, 1, FALSE, FALSE);
1716         add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
1717
1718 #ifdef HAVE_CLUTTER
1719         pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
1720                               options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
1721 #endif
1722
1723         pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
1724                               options->image.zoom_2pass, &c_options->image.zoom_2pass);
1725
1726         c_options->image.zoom_increment = options->image.zoom_increment;
1727         spin = pref_spin_new(group, _("Zoom increment:"), NULL,
1728                              0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
1729                              G_CALLBACK(zoom_increment_cb), NULL);
1730         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1731
1732         group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
1733
1734         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1735         enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
1736                               options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
1737         spin = pref_spin_new_int(hbox, NULL, NULL,
1738                                  100, 999, 1,
1739                                  options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
1740         pref_checkbox_link_sensitivity(enlargement_button, spin);
1741         gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("Enable this to allow Geeqie to increase the image size for images that are smaller than the current view area when the zoom is set to \"Fit image to window\". This value sets the maximum expansion permitted in percent i.e. 100% is full-size."));
1742
1743         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1744         ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
1745                                           options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
1746         spin = pref_spin_new_int(hbox, NULL, NULL,
1747                                  10, 150, 1,
1748                                  options->image.max_autofit_size, &c_options->image.max_autofit_size);
1749         pref_checkbox_link_sensitivity(ct_button, spin);
1750         gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value will set the virtual size of the window when \"Fit image to window\" is set. Instead of using the actual size of the window, the specified percentage of the window will be used. It allows one to keep a border around the image (values lower than 100%) or to auto zoom the image (values greater than 100%). It affects fullscreen mode too."));
1751
1752         group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
1753
1754         pref_checkbox_new_int(group, _("Use custom border color in window mode"),
1755                               options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
1756
1757         pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
1758                               options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
1759
1760         pref_color_button_new(group, _("Border color"), &options->image.border_color,
1761                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
1762
1763         c_options->image.border_color = options->image.border_color;
1764
1765         pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
1766                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
1767
1768         pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
1769                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
1770
1771         c_options->image.alpha_color_1 = options->image.alpha_color_1;
1772         c_options->image.alpha_color_2 = options->image.alpha_color_2;
1773
1774         group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
1775
1776         pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
1777                               options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
1778 }
1779
1780 /* windows tab */
1781 static void config_tab_windows(GtkWidget *notebook)
1782 {
1783         GtkWidget *hbox;
1784         GtkWidget *vbox;
1785         GtkWidget *group;
1786         GtkWidget *button;
1787         GtkWidget *ct_button;
1788         GtkWidget *spin;
1789         GtkWidget *image_overlay_template_view;
1790         GtkWidget *scrolled;
1791         GtkTextBuffer *buffer;
1792
1793         vbox = scrolled_notebook_page(notebook, _("Windows"));
1794
1795         group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
1796
1797         ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
1798                                           options->save_window_positions, &c_options->save_window_positions);
1799
1800         button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
1801                                        options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
1802         pref_checkbox_link_sensitivity(ct_button, button);
1803
1804         pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
1805                               options->tools_restore_state, &c_options->tools_restore_state);
1806
1807         pref_checkbox_new_int(group, _("Remember dialog window positions"),
1808                               options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
1809
1810         pref_checkbox_new_int(group, _("Show window IDs"),
1811                               options->show_window_ids, &c_options->show_window_ids);
1812
1813         group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
1814
1815         pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
1816                               options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
1817
1818         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1819         ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
1820                                           options->image.limit_window_size, &c_options->image.limit_window_size);
1821         spin = pref_spin_new_int(hbox, NULL, NULL,
1822                                  10, 150, 1,
1823                                  options->image.max_window_size, &c_options->image.max_window_size);
1824         pref_checkbox_link_sensitivity(ct_button, spin);
1825
1826         group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
1827
1828         c_options->fullscreen.screen = options->fullscreen.screen;
1829         c_options->fullscreen.above = options->fullscreen.above;
1830         hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
1831         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
1832         gtk_widget_show(hbox);
1833
1834         pref_checkbox_new_int(group, _("Smooth image flip"),
1835                               options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
1836         pref_checkbox_new_int(group, _("Disable screen saver"),
1837                               options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
1838
1839
1840         group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
1841
1842         pref_label_new(group, _("Image overlay template"));
1843
1844         scrolled = gtk_scrolled_window_new(NULL, NULL);
1845         gtk_widget_set_size_request(scrolled, 200, 150);
1846         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1847         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1848                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1849         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
1850         gtk_widget_show(scrolled);
1851
1852         image_overlay_template_view = gtk_text_view_new();
1853
1854         gtk_widget_set_tooltip_markup(image_overlay_template_view,
1855         _("<i>%name%</i> results in the filename of the picture.\n"
1856           "Also available: <i>%collection%</i>, <i>%number%</i>, <i>%total%</i>, <i>%date%</i>,\n"
1857           "<i>%size%</i> (filesize), <i>%width%</i>, <i>%height%</i>, <i>%res%</i> (resolution),\n"
1858           "<i>%rating%</i>, <i>%keywords%</i>, <i>%comment%</i> (XMP), <i>%imagecomment%</i> (JPEG)\n"
1859           "To access exif data use the exif name, e. g. <i>%formatted.Camera%</i> is the formatted camera name,\n"
1860           "<i>%Exif.Photo.DateTimeOriginal%</i> the date of the original shot.\n"
1861           "<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"
1862           "If two or more variables are connected with the |-sign, it prints available variables with a separator.\n"
1863           "<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"
1864           "if there's no ISO information in the Exif data.\n"
1865           "If a line is empty, it is removed. This allows one to add lines that totally disappear when no data is available.\n"
1866         ));
1867         gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
1868         gtk_widget_show(image_overlay_template_view);
1869
1870         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1871
1872 #if GTK_CHECK_VERSION(3,4,0)
1873         button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
1874                                  G_CALLBACK(image_overlay_set_font_cb), notebook);
1875 #else
1876         button = gtk_font_button_new();
1877         gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
1878         gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
1879         g_signal_connect(G_OBJECT(button), "font-set",
1880                                  G_CALLBACK(image_overlay_set_font_cb),NULL);
1881 #endif
1882         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1883         gtk_widget_show(button);
1884
1885         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
1886                                  G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
1887         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1888         gtk_widget_show(button);
1889
1890         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
1891                                  G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
1892         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1893         gtk_widget_show(button);
1894         image_overlay_set_text_colours();
1895
1896         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
1897                                  G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
1898         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1899         gtk_widget_show(button);
1900
1901         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
1902                                  G_CALLBACK(image_overlay_help_cb), NULL);
1903         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1904         gtk_widget_show(button);
1905
1906         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
1907         if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1908         g_signal_connect(G_OBJECT(buffer), "changed",
1909                          G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
1910
1911
1912 }
1913
1914 static GtkTreeModel *create_class_model(void)
1915 {
1916         GtkListStore *model;
1917         GtkTreeIter iter;
1918         gint i;
1919
1920         /* create list store */
1921         model = gtk_list_store_new(1, G_TYPE_STRING);
1922         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1923                 {
1924                 gtk_list_store_append(model, &iter);
1925                 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
1926                 }
1927         return GTK_TREE_MODEL (model);
1928 }
1929
1930
1931 /* filtering tab */
1932 static void config_tab_files(GtkWidget *notebook)
1933 {
1934         GtkWidget *hbox;
1935         GtkWidget *frame;
1936         GtkWidget *vbox;
1937         GtkWidget *group;
1938         GtkWidget *button;
1939         GtkWidget *ct_button;
1940         GtkWidget *scrolled;
1941         GtkWidget *filter_view;
1942         GtkCellRenderer *renderer;
1943         GtkTreeSelection *selection;
1944         GtkTreeViewColumn *column;
1945
1946         vbox = scrolled_notebook_page(notebook, _("Files"));
1947
1948         group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1949
1950         pref_checkbox_new_int(group, _("Show hidden files or folders"),
1951                               options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
1952         pref_checkbox_new_int(group, _("Show parent folder (..)"),
1953                               options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
1954         pref_checkbox_new_int(group, _("Case sensitive sort"),
1955                               options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
1956         pref_checkbox_new_int(group, _("Natural sort order"),
1957                                           options->file_sort.natural, &c_options->file_sort.natural);
1958         pref_checkbox_new_int(group, _("Disable file extension checks"),
1959                               options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
1960
1961         ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
1962                                           options->file_filter.disable, &c_options->file_filter.disable);
1963
1964
1965         group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
1966
1967         sidecar_ext_entry = gtk_entry_new();
1968         gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
1969         gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
1970         gtk_widget_show(sidecar_ext_entry);
1971
1972         group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
1973
1974         frame = pref_group_parent(group);
1975         g_signal_connect(G_OBJECT(ct_button), "toggled",
1976                          G_CALLBACK(filter_disable_cb), frame);
1977         gtk_widget_set_sensitive(frame, !options->file_filter.disable);
1978
1979         scrolled = gtk_scrolled_window_new(NULL, NULL);
1980         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1981         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1982         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
1983         gtk_widget_show(scrolled);
1984
1985         filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
1986         filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
1987         g_object_unref(filter_store);
1988         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1989         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
1990
1991         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
1992
1993         column = gtk_tree_view_column_new();
1994         gtk_tree_view_column_set_title(column, _("Filter"));
1995         gtk_tree_view_column_set_resizable(column, TRUE);
1996
1997         renderer = gtk_cell_renderer_toggle_new();
1998         g_signal_connect(G_OBJECT(renderer), "toggled",
1999                          G_CALLBACK(filter_store_enable_cb), filter_store);
2000         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2001         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2002                                                 GINT_TO_POINTER(FE_ENABLE), NULL);
2003
2004         renderer = gtk_cell_renderer_text_new();
2005         g_signal_connect(G_OBJECT(renderer), "edited",
2006                          G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2007         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2008         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2009         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2010                                                 GINT_TO_POINTER(FE_EXTENSION), NULL);
2011         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2012
2013         column = gtk_tree_view_column_new();
2014         gtk_tree_view_column_set_title(column, _("Description"));
2015         gtk_tree_view_column_set_resizable(column, TRUE);
2016         gtk_tree_view_column_set_fixed_width(column, 200);
2017         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2018
2019         renderer = gtk_cell_renderer_text_new();
2020         g_signal_connect(G_OBJECT(renderer), "edited",
2021                          G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2022         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2023         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2024         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2025                                                 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2026         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2027
2028         column = gtk_tree_view_column_new();
2029         gtk_tree_view_column_set_title(column, _("Class"));
2030         gtk_tree_view_column_set_resizable(column, TRUE);
2031         renderer = gtk_cell_renderer_combo_new();
2032         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2033                                          "model", create_class_model(),
2034                                          "text-column", 0,
2035                                          "has-entry", FALSE,
2036                                          NULL);
2037
2038         g_signal_connect(G_OBJECT(renderer), "edited",
2039                          G_CALLBACK(filter_store_class_edit_cb), filter_store);
2040         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2041         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2042                                                 GINT_TO_POINTER(FE_CLASS), NULL);
2043         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2044
2045         column = gtk_tree_view_column_new();
2046         gtk_tree_view_column_set_title(column, _("Writable"));
2047         gtk_tree_view_column_set_resizable(column, FALSE);
2048         renderer = gtk_cell_renderer_toggle_new();
2049         g_signal_connect(G_OBJECT(renderer), "toggled",
2050                          G_CALLBACK(filter_store_writable_cb), filter_store);
2051         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2052         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2053                                                 GINT_TO_POINTER(FE_WRITABLE), NULL);
2054         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2055
2056         column = gtk_tree_view_column_new();
2057         gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2058         gtk_tree_view_column_set_resizable(column, FALSE);
2059         renderer = gtk_cell_renderer_toggle_new();
2060         g_signal_connect(G_OBJECT(renderer), "toggled",
2061                          G_CALLBACK(filter_store_sidecar_cb), filter_store);
2062         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2063         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2064                                                 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2065         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2066
2067
2068         filter_store_populate();
2069         gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2070         gtk_widget_show(filter_view);
2071
2072         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2073
2074         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2075                                  G_CALLBACK(filter_default_cb), filter_view);
2076         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2077         gtk_widget_show(button);
2078
2079         button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2080                                  G_CALLBACK(filter_remove_cb), filter_view);
2081         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2082         gtk_widget_show(button);
2083
2084         button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2085                                  G_CALLBACK(filter_add_cb), filter_view);
2086         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2087         gtk_widget_show(button);
2088 }
2089
2090 /* metadata tab */
2091 static void config_tab_metadata(GtkWidget *notebook)
2092 {
2093         GtkWidget *vbox;
2094         GtkWidget *hbox;
2095         GtkWidget *group;
2096         GtkWidget *ct_button;
2097         GtkWidget *label;
2098         gchar *text;
2099
2100         vbox = scrolled_notebook_page(notebook, _("Metadata"));
2101
2102
2103         group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2104 #ifndef HAVE_EXIV2
2105         label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2106 #endif
2107         label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2108         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2109
2110         ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2111                               options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2112 #ifndef HAVE_EXIV2
2113         gtk_widget_set_sensitive(ct_button, FALSE);
2114 #endif
2115
2116         pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2117                               options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2118
2119         text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2120         label = pref_label_new(group, text);
2121         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2122         gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2123         g_free(text);
2124
2125         group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2126 #ifndef HAVE_EXIV2
2127         gtk_widget_set_sensitive(group, FALSE);
2128 #endif
2129
2130         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2131         pref_checkbox_link_sensitivity(ct_button, hbox);
2132
2133         pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2134                               options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2135
2136         pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2137                               options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2138
2139         pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2140                               options->metadata.confirm_write, &c_options->metadata.confirm_write);
2141
2142         pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2143                               options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2144
2145         group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2146 #ifndef HAVE_EXIV2
2147         gtk_widget_set_sensitive(group, FALSE);
2148 #endif
2149
2150         pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2151                               options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2152
2153
2154         group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2155         pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2156                               options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2157
2158         pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2159                               options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2160
2161         ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2162                               options->metadata.write_orientation, &c_options->metadata.write_orientation);
2163 #ifndef HAVE_EXIV2
2164         gtk_widget_set_sensitive(ct_button, FALSE);
2165 #endif
2166
2167         group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2168
2169         ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2170                               options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2171
2172         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2173         pref_checkbox_link_sensitivity(ct_button, hbox);
2174
2175         pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2176                               options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2177
2178         pref_checkbox_new_int(group, _("Write metadata on image change"),
2179                               options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2180
2181         pref_checkbox_new_int(group, _("Write metadata on directory change"),
2182                               options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2183 }
2184
2185 /* metadata tab */
2186 #ifdef HAVE_LCMS
2187 static void intent_menu_cb(GtkWidget *combo, gpointer data)
2188 {
2189         gint *option = data;
2190
2191         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
2192                 {
2193                 case 0:
2194                 default:
2195                         *option = INTENT_PERCEPTUAL;
2196                         break;
2197                 case 1:
2198                         *option = INTENT_RELATIVE_COLORIMETRIC;
2199                         break;
2200                 case 2:
2201                         *option = INTENT_SATURATION;
2202                         break;
2203                 case 3:
2204                         *option = INTENT_ABSOLUTE_COLORIMETRIC;
2205                         break;
2206                 }
2207 }
2208
2209 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
2210                              gint option, gint *option_c)
2211 {
2212         GtkWidget *combo;
2213         gint current = 0;
2214
2215         *option_c = option;
2216
2217         pref_table_label(table, column, row, text, 0.0);
2218
2219         combo = gtk_combo_box_text_new();
2220
2221         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
2222         if (option == INTENT_PERCEPTUAL) current = 0;
2223         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
2224         if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
2225         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
2226         if (option == INTENT_SATURATION) current = 2;
2227         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
2228         if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
2229
2230         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
2231
2232         gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
2233
2234         g_signal_connect(G_OBJECT(combo), "changed",
2235                          G_CALLBACK(intent_menu_cb), option_c);
2236
2237         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
2238                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
2239         gtk_widget_show(combo);
2240 }
2241 #endif
2242
2243 static void config_tab_color(GtkWidget *notebook)
2244 {
2245         GtkWidget *label;
2246         GtkWidget *vbox;
2247         GtkWidget *group;
2248         GtkWidget *tabcomp;
2249         GtkWidget *table;
2250         gint i;
2251
2252         vbox = scrolled_notebook_page(notebook, _("Color management"));
2253
2254         group =  pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
2255 #ifndef HAVE_LCMS
2256         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
2257 #endif
2258
2259         table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
2260         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
2261
2262         label = pref_table_label(table, 0, 0, _("Type"), 0.0);
2263         pref_label_bold(label, TRUE, FALSE);
2264
2265         label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
2266         pref_label_bold(label, TRUE, FALSE);
2267
2268         label = pref_table_label(table, 2, 0, _("File"), 0.0);
2269         pref_label_bold(label, TRUE, FALSE);
2270
2271         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
2272                 {
2273                 GtkWidget *entry;
2274                 gchar *buf;
2275
2276                 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
2277                 pref_table_label(table, 0, i + 1, buf, 1.0);
2278                 g_free(buf);
2279
2280                 entry = gtk_entry_new();
2281                 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
2282                 if (options->color_profile.input_name[i])
2283                         {
2284                         gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
2285                         }
2286                 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
2287                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
2288                 gtk_widget_show(entry);
2289                 color_profile_input_name_entry[i] = entry;
2290
2291                 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
2292                 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
2293                 gtk_widget_set_size_request(entry, 160, -1);
2294                 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
2295                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
2296                 gtk_widget_show(tabcomp);
2297                 color_profile_input_file_entry[i] = entry;
2298                 }
2299
2300         group =  pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
2301 #ifndef HAVE_LCMS
2302         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
2303 #endif
2304         pref_checkbox_new_int(group, _("Use system screen profile if available"),
2305                               options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
2306
2307         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2308
2309         pref_table_label(table, 0, 0, _("Screen:"), 1.0);
2310         tabcomp = tab_completion_new(&color_profile_screen_file_entry,
2311                                      options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
2312         tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
2313         gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
2314 #ifdef HAVE_LCMS
2315         add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
2316 #endif
2317         gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
2318                          0, 1,
2319                          GTK_FILL | GTK_EXPAND, 0, 0, 0);
2320
2321         gtk_widget_show(tabcomp);
2322 }
2323
2324 /* advanced entry tab */
2325 static void config_tab_behavior(GtkWidget *notebook)
2326 {
2327         GtkWidget *hbox;
2328         GtkWidget *vbox;
2329         GtkWidget *group;
2330         GtkWidget *button;
2331         GtkWidget *tabcomp;
2332         GtkWidget *ct_button;
2333         GtkWidget *spin;
2334         GtkWidget *table;
2335
2336         vbox = scrolled_notebook_page(notebook, _("Behavior"));
2337
2338         group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
2339
2340         pref_checkbox_new_int(group, _("Confirm file delete"),
2341                               options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
2342         pref_checkbox_new_int(group, _("Enable Delete key"),
2343                               options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
2344
2345         ct_button = pref_checkbox_new_int(group, _("Safe delete"),
2346                                           options->file_ops.safe_delete_enable, &c_options->file_ops.safe_delete_enable);
2347
2348         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2349         pref_checkbox_link_sensitivity(ct_button, hbox);
2350
2351         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
2352         pref_label_new(hbox, _("Folder:"));
2353
2354         tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
2355         tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
2356         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
2357         gtk_widget_show(tabcomp);
2358
2359         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2360         pref_checkbox_link_sensitivity(ct_button, hbox);
2361
2362         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
2363         spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
2364                                  0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
2365         gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
2366         button = pref_button_new(NULL, NULL, _("View"), FALSE,
2367                                  G_CALLBACK(safe_delete_view_cb), NULL);
2368         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2369         gtk_widget_show(button);
2370
2371         button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
2372                                  G_CALLBACK(safe_delete_clear_cb), NULL);
2373         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2374         gtk_widget_show(button);
2375
2376
2377         group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
2378
2379         pref_checkbox_new_int(group, _("Descend folders in tree view"),
2380                               options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
2381
2382         pref_checkbox_new_int(group, _("In place renaming"),
2383                               options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
2384
2385         pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
2386                               options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
2387
2388         pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
2389                           1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
2390
2391         pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
2392                           16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
2393
2394         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2395         add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
2396
2397         group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
2398
2399         pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
2400                               options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
2401         pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
2402                           1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
2403         pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
2404                               options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
2405         pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
2406                               options->image_lm_click_nav, &c_options->image_lm_click_nav);
2407         pref_checkbox_new_int(group, _("Play video by left click on image"),
2408                               options->image_l_click_video, &c_options->image_l_click_video);
2409         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2410         add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
2411
2412
2413 #ifdef DEBUG
2414         group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
2415
2416         pref_spin_new_int(group, _("Debug level:"), NULL,
2417                           DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
2418
2419         pref_checkbox_new_int(group, _("Timer data"),
2420                         options->log_window.timer_data, &c_options->log_window.timer_data);
2421
2422         pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
2423                           1, 99999, 1, options->log_window_lines, &options->log_window_lines);
2424 #endif
2425 }
2426
2427 /* accelerators tab */
2428 static void config_tab_accelerators(GtkWidget *notebook)
2429 {
2430         GtkWidget *hbox;
2431         GtkWidget *vbox;
2432         GtkWidget *group;
2433         GtkWidget *button;
2434         GtkWidget *scrolled;
2435         GtkWidget *accel_view;
2436         GtkCellRenderer *renderer;
2437         GtkTreeSelection *selection;
2438         GtkTreeViewColumn *column;
2439
2440         vbox = scrolled_notebook_page(notebook, _("Keyboard"));
2441
2442         group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
2443
2444         scrolled = gtk_scrolled_window_new(NULL, NULL);
2445         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2446         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2447         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2448         gtk_widget_show(scrolled);
2449
2450         accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
2451
2452         accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
2453         g_object_unref(accel_store);
2454         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
2455         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
2456
2457         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
2458
2459         renderer = gtk_cell_renderer_text_new();
2460
2461         column = gtk_tree_view_column_new_with_attributes(_("Action"),
2462                                                           renderer,
2463                                                           "text", AE_ACTION,
2464                                                           NULL);
2465
2466         gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
2467         gtk_tree_view_column_set_resizable(column, TRUE);
2468         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2469
2470
2471         renderer = gtk_cell_renderer_accel_new();
2472         g_signal_connect(G_OBJECT(renderer), "accel-cleared",
2473                          G_CALLBACK(accel_store_cleared_cb), accel_store);
2474         g_signal_connect(G_OBJECT(renderer), "accel-edited",
2475                          G_CALLBACK(accel_store_edited_cb), accel_store);
2476
2477
2478         g_object_set (renderer,
2479                       "editable", TRUE,
2480                       "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
2481                       NULL);
2482
2483         column = gtk_tree_view_column_new_with_attributes(_("KEY"),
2484                                                           renderer,
2485                                                           "text", AE_KEY,
2486                                                           NULL);
2487
2488         gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
2489         gtk_tree_view_column_set_resizable(column, TRUE);
2490         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2491
2492         renderer = gtk_cell_renderer_text_new();
2493
2494         column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
2495                                                           renderer,
2496                                                           "text", AE_TOOLTIP,
2497                                                           NULL);
2498
2499         gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
2500         gtk_tree_view_column_set_resizable(column, TRUE);
2501         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2502
2503         renderer = gtk_cell_renderer_text_new();
2504
2505         column = gtk_tree_view_column_new_with_attributes("Accel",
2506                                                           renderer,
2507                                                           "text", AE_ACCEL,
2508                                                           NULL);
2509
2510         gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
2511         gtk_tree_view_column_set_resizable(column, TRUE);
2512         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2513
2514         accel_store_populate();
2515         gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
2516         gtk_widget_show(accel_view);
2517
2518         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2519
2520         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2521                                  G_CALLBACK(accel_default_cb), accel_view);
2522         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2523         gtk_widget_show(button);
2524
2525         button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
2526                                  G_CALLBACK(accel_reset_cb), accel_view);
2527         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2528         gtk_widget_show(button);
2529 }
2530
2531 /* toolbar tab */
2532 static void config_tab_toolbar(GtkWidget *notebook)
2533 {
2534         GtkWidget *vbox;
2535         GtkWidget *toolbardata;
2536         LayoutWindow *lw;
2537
2538         lw = layout_window_list->data;
2539
2540         vbox = scrolled_notebook_page(notebook, _("Toolbar"));
2541
2542         toolbardata = toolbar_select_new(lw);
2543         gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
2544         gtk_widget_show(vbox);
2545 }
2546
2547 /* stereo tab */
2548 static void config_tab_stereo(GtkWidget *notebook)
2549 {
2550         GtkWidget *vbox;
2551         GtkWidget *group;
2552         GtkWidget *group2;
2553         GtkWidget *table;
2554         GtkWidget *box;
2555         GtkWidget *box2;
2556         GtkWidget *fs_button;
2557         vbox = scrolled_notebook_page(notebook, _("Stereo"));
2558
2559         group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
2560
2561         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2562         add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
2563
2564         table = pref_table_new(group, 2, 2, TRUE, FALSE);
2565         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2566         pref_checkbox_new_int(box, _("Mirror left image"),
2567                               options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
2568         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2569         pref_checkbox_new_int(box, _("Flip left image"),
2570                               options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
2571         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2572         pref_checkbox_new_int(box, _("Mirror right image"),
2573                               options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
2574         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2575         pref_checkbox_new_int(box, _("Flip right image"),
2576                               options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
2577         pref_checkbox_new_int(group, _("Swap left and right images"),
2578                               options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
2579         pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
2580                               options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
2581
2582         group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
2583         fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
2584                               options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
2585         box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2586         pref_checkbox_link_sensitivity(fs_button, box2);
2587         table = pref_table_new(box2, 2, 1, FALSE, FALSE);
2588         add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
2589         table = pref_table_new(box2, 2, 2, TRUE, FALSE);
2590         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2591         pref_checkbox_new_int(box, _("Mirror left image"),
2592                               options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
2593         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2594         pref_checkbox_new_int(box, _("Flip left image"),
2595                               options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
2596         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2597         pref_checkbox_new_int(box, _("Mirror right image"),
2598                               options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
2599         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2600         pref_checkbox_new_int(box, _("Flip right image"),
2601                               options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
2602         pref_checkbox_new_int(box2, _("Swap left and right images"),
2603                               options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
2604         pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
2605                               options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
2606
2607         group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
2608         table = pref_table_new(group2, 5, 3, FALSE, FALSE);
2609         pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
2610                           1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
2611         pref_table_spin_new_int(table, 3, 0,  _("Height"), NULL,
2612                           1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
2613         pref_table_spin_new_int(table, 0, 1,  _("Left X"), NULL,
2614                           0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
2615         pref_table_spin_new_int(table, 3, 1,  _("Left Y"), NULL,
2616                           0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
2617         pref_table_spin_new_int(table, 0, 2,  _("Right X"), NULL,
2618                           0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
2619         pref_table_spin_new_int(table, 3, 2,  _("Right Y"), NULL,
2620                           0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
2621
2622 }
2623
2624 /* Main preferences window */
2625 static void config_window_create(void)
2626 {
2627         GtkWidget *win_vbox;
2628         GtkWidget *hbox;
2629         GtkWidget *notebook;
2630         GtkWidget *button;
2631         GtkWidget *ct_button;
2632
2633         if (!c_options) c_options = init_options(NULL);
2634
2635         configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
2636         gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
2637         g_signal_connect(G_OBJECT(configwindow), "delete_event",
2638                          G_CALLBACK(config_window_delete), NULL);
2639         gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
2640         gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
2641         gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
2642
2643         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
2644         gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
2645         gtk_widget_show(win_vbox);
2646
2647         notebook = gtk_notebook_new();
2648         gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
2649         gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
2650
2651         config_tab_general(notebook);
2652         config_tab_image(notebook);
2653         config_tab_windows(notebook);
2654         config_tab_accelerators(notebook);
2655         config_tab_files(notebook);
2656         config_tab_metadata(notebook);
2657         config_tab_color(notebook);
2658         config_tab_stereo(notebook);
2659         config_tab_behavior(notebook);
2660         config_tab_toolbar(notebook);
2661
2662         hbox = gtk_hbutton_box_new();
2663         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
2664         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
2665         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
2666         gtk_widget_show(hbox);
2667
2668         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2669                                  G_CALLBACK(config_window_help_cb), notebook);
2670         gtk_container_add(GTK_CONTAINER(hbox), button);
2671         gtk_widget_set_can_default(button, TRUE);
2672         gtk_widget_show(button);
2673
2674         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
2675                                  G_CALLBACK(config_window_ok_cb), NULL);
2676         gtk_container_add(GTK_CONTAINER(hbox), button);
2677         gtk_widget_set_can_default(button, TRUE);
2678         gtk_widget_grab_default(button);
2679         gtk_widget_show(button);
2680
2681         ct_button = button;
2682
2683         button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
2684                                  G_CALLBACK(config_window_save_cb), NULL);
2685         gtk_container_add(GTK_CONTAINER(hbox), button);
2686         gtk_widget_set_can_default(button, TRUE);
2687         gtk_widget_show(button);
2688
2689         button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
2690                                  G_CALLBACK(config_window_apply_cb), NULL);
2691         gtk_container_add(GTK_CONTAINER(hbox), button);
2692         gtk_widget_set_can_default(button, TRUE);
2693         gtk_widget_show(button);
2694
2695         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
2696                                  G_CALLBACK(config_window_close_cb), NULL);
2697         gtk_container_add(GTK_CONTAINER(hbox), button);
2698         gtk_widget_set_can_default(button, TRUE);
2699         gtk_widget_show(button);
2700
2701         if (!generic_dialog_get_alternative_button_order(configwindow))
2702                 {
2703                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
2704                 }
2705
2706         gtk_widget_show(notebook);
2707
2708         gtk_widget_show(configwindow);
2709 }
2710
2711 /*
2712  *-----------------------------------------------------------------------------
2713  * config window show (public)
2714  *-----------------------------------------------------------------------------
2715  */
2716
2717 void show_config_window(void)
2718 {
2719         if (configwindow)
2720                 {
2721                 gtk_window_present(GTK_WINDOW(configwindow));
2722                 return;
2723                 }
2724
2725         config_window_create();
2726 }
2727
2728 /*
2729  *-----------------
2730  * about window
2731  *-----------------
2732  */
2733
2734 void show_about_window(LayoutWindow *lw)
2735 {
2736         GdkPixbuf *pixbuf_logo;
2737         GdkPixbuf *pixbuf_icon;
2738         gchar *authors[1000];
2739         gchar *comment;
2740         gint i_authors = 0;
2741         gchar *path;
2742         FILE *fp = NULL;
2743 #define LINE_LENGTH 1000
2744         gchar line[LINE_LENGTH];
2745
2746 #if !GTK_CHECK_VERSION(3,0,0)
2747         GString *copyright;
2748
2749         copyright = g_string_new(NULL);
2750         path = g_build_filename(GQ_HELPDIR, "COPYING", NULL);
2751         fp = fopen(path, "r");
2752         if (fp)
2753                 {
2754                 while(fgets(line, LINE_LENGTH, fp))
2755                         {
2756                         copyright = g_string_append(copyright, line);
2757                         }
2758                 fclose(fp);
2759                 }
2760         g_free(path);
2761 #endif
2762
2763         authors[0] = NULL;
2764         path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
2765         fp = fopen(path, "r");
2766         if (fp)
2767                 {
2768                 while(fgets(line, LINE_LENGTH, fp))
2769                         {
2770                         /* get rid of ending \n from fgets */
2771                         line[strlen(line) - 1] = '\0';
2772                         authors[i_authors] = g_strdup(line);
2773                         i_authors++;
2774                         }
2775                 authors[i_authors] = NULL;
2776                 fclose(fp);
2777                 }
2778         g_free(path);
2779
2780         comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
2781                                                 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
2782
2783         pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
2784         pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
2785         gtk_show_about_dialog(GTK_WINDOW(lw->window),
2786                 "title", _("About Geeqie"),
2787                 "resizable", TRUE,
2788                 "program-name", GQ_APPNAME,
2789                 "version", VERSION,
2790                 "logo", pixbuf_logo,
2791                 "icon", pixbuf_icon,
2792                 "website", GQ_WEBSITE,
2793                 "website-label", "Website",
2794                 "comments", comment,
2795                 "authors", authors,
2796                 "translator-credits", _("translator-credits"),
2797 #if GTK_CHECK_VERSION(3,0,0)
2798                 "license-type", GTK_LICENSE_GPL_2_0,
2799 #else
2800                 "license",  copyright->str,
2801 #endif
2802                 NULL);
2803
2804 #if !GTK_CHECK_VERSION(3,0,0)
2805         g_string_free(copyright, TRUE);
2806 #endif
2807         gint n = 0;
2808         while(n < i_authors)
2809                 {
2810                 g_free(authors[n]);
2811                 n++;
2812                 }
2813         g_free(comment);
2814
2815         return;
2816 }
2817
2818 static void image_overlay_set_text_colours()
2819 {
2820         c_options->image_overlay.text_red = options->image_overlay.text_red;
2821         c_options->image_overlay.text_green = options->image_overlay.text_green;
2822         c_options->image_overlay.text_blue = options->image_overlay.text_blue;
2823         c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
2824         c_options->image_overlay.background_red = options->image_overlay.background_red;
2825         c_options->image_overlay.background_green = options->image_overlay.background_green;
2826         c_options->image_overlay.background_blue = options->image_overlay.background_blue;
2827         c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
2828 }
2829 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */