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