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