Simplify OSD settings in Preferences
[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 "bar_keywords.h"
27 #include "cache.h"
28 #include "cache_maint.h"
29 #include "dnd.h"
30 #include "editors.h"
31 #include "exif.h"
32 #include "filedata.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
35 #include "image.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
38 #include "img-view.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
41 #include "metadata.h"
42 #include "pixbuf_util.h"
43 #include "slideshow.h"
44 #include "toolbar.h"
45 #include "trash.h"
46 #include "utilops.h"
47 #include "ui_fileops.h"
48 #include "ui_misc.h"
49 #include "ui_spinner.h"
50 #include "ui_tabcomp.h"
51 #include "ui_utildlg.h"
52 #include "window.h"
53 #include "zonedetect.h"
54
55 #include <math.h>
56
57 #ifdef HAVE_LCMS
58 #ifdef HAVE_LCMS2
59 #include <lcms2.h>
60 #else
61 #include <lcms.h>
62 #endif
63 #endif
64
65 #define EDITOR_NAME_MAX_LENGTH 32
66 #define EDITOR_COMMAND_MAX_LENGTH 1024
67
68 static void image_overlay_set_text_colours();
69
70 GtkWidget *keyword_text;
71 static void config_tab_keywords_save();
72
73 typedef struct _ThumbSize ThumbSize;
74 struct _ThumbSize
75 {
76         gint w;
77         gint h;
78 };
79
80 static ThumbSize thumb_size_list[] =
81 {
82         { 24, 24 },
83         { 32, 32 },
84         { 48, 48 },
85         { 64, 64 },
86         { 96, 72 },
87         { 96, 96 },
88         { 128, 96 },
89         { 128, 128 },
90         { 160, 120 },
91         { 160, 160 },
92         { 192, 144 },
93         { 192, 192 },
94         { 256, 192 },
95         { 256, 256 }
96 };
97
98 enum {
99         FE_ENABLE,
100         FE_EXTENSION,
101         FE_DESCRIPTION,
102         FE_CLASS,
103         FE_WRITABLE,
104         FE_ALLOW_SIDECAR
105 };
106
107 enum {
108         AE_ACTION,
109         AE_KEY,
110         AE_TOOLTIP,
111         AE_ACCEL
112 };
113
114 gchar *format_class_list[] = {
115         N_("Unknown"),
116         N_("Image"),
117         N_("RAW Image"),
118         N_("Metadata"),
119         N_("Video"),
120         N_("Collection"),
121         N_("Pdf")
122         };
123
124 /* config memory values */
125 static ConfOptions *c_options = NULL;
126
127
128 #ifdef DEBUG
129 static gint debug_c;
130 #endif
131
132 static GtkWidget *configwindow = NULL;
133 static GtkListStore *filter_store = NULL;
134 static GtkTreeStore *accel_store = NULL;
135
136 static GtkWidget *safe_delete_path_entry;
137
138 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
139 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
140 static GtkWidget *color_profile_screen_file_entry;
141
142 static GtkWidget *sidecar_ext_entry;
143 static GtkWidget *help_search_engine_entry;
144
145
146 #define CONFIG_WINDOW_DEF_WIDTH         700
147 #define CONFIG_WINDOW_DEF_HEIGHT        600
148
149 /*
150  *-----------------------------------------------------------------------------
151  * option widget callbacks (private)
152  *-----------------------------------------------------------------------------
153  */
154
155 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
156 {
157         c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
158 }
159
160 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
161 {
162         gint mins_secs_tenths, delay;
163
164         mins_secs_tenths = c_options->slideshow.delay %
165                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
166
167         delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
168                                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
169                                                                 mins_secs_tenths);
170
171         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
172                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
173 }
174
175 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
176 {
177         gint hours, secs_tenths, delay;
178
179         hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
180         secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
181
182         delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
183                                         (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
184                                         (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
185
186         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
187                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
188 }
189
190 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
191 {
192         gint hours_mins, delay;
193
194         hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
195
196         delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
197                                                         (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
198                                                         (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
199
200         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
201                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
202 }
203
204 /*
205  *-----------------------------------------------------------------------------
206  * sync progam to config window routine (private)
207  *-----------------------------------------------------------------------------
208  */
209
210 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
211 {
212         const gchar *buf;
213
214         g_free(*option);
215         *option = NULL;
216         buf = gtk_entry_get_text(GTK_ENTRY(entry));
217         if (buf && strlen(buf) > 0)
218                 {
219                 if (func)
220                         *option = func(buf);
221                 else
222                         *option = g_strdup(buf);
223                 }
224 }
225
226
227 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
228 {
229         gchar *accel_path, *accel;
230
231         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
232
233         if (accel_path && accel_path[0])
234                 {
235                 GtkAccelKey key;
236                 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
237                 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
238                 }
239
240         g_free(accel_path);
241         g_free(accel);
242
243         return FALSE;
244 }
245
246
247 static void config_window_apply(void)
248 {
249         gint i;
250         gboolean refresh = FALSE;
251
252         config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
253
254         if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
255         if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
256         if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
257         if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
258         if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
259         if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
260         if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
261
262         options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
263         options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
264         options->file_ops.safe_delete_enable = c_options->file_ops.safe_delete_enable;
265         options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
266         options->tools_restore_state = c_options->tools_restore_state;
267         options->save_window_positions = c_options->save_window_positions;
268         options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
269         options->save_dialog_window_positions = c_options->save_dialog_window_positions;
270         options->show_window_ids = c_options->show_window_ids;
271         options->image.scroll_reset_method = c_options->image.scroll_reset_method;
272         options->image.zoom_2pass = c_options->image.zoom_2pass;
273         options->image.fit_window_to_image = c_options->image.fit_window_to_image;
274         options->image.limit_window_size = c_options->image.limit_window_size;
275         options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
276         options->image.max_window_size = c_options->image.max_window_size;
277         options->image.limit_autofit_size = c_options->image.limit_autofit_size;
278         options->image.max_autofit_size = c_options->image.max_autofit_size;
279         options->image.max_enlargement_size = c_options->image.max_enlargement_size;
280         options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
281         options->progressive_key_scrolling = c_options->progressive_key_scrolling;
282         options->keyboard_scroll_step = c_options->keyboard_scroll_step;
283
284         if (options->thumbnails.max_width != c_options->thumbnails.max_width
285             || options->thumbnails.max_height != c_options->thumbnails.max_height
286             || options->thumbnails.quality != c_options->thumbnails.quality)
287                 {
288                 thumb_format_changed = TRUE;
289                 refresh = TRUE;
290                 options->thumbnails.max_width = c_options->thumbnails.max_width;
291                 options->thumbnails.max_height = c_options->thumbnails.max_height;
292                 options->thumbnails.quality = c_options->thumbnails.quality;
293                 }
294         options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
295         options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
296         options->thumbnails.use_exif = c_options->thumbnails.use_exif;
297         options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
298         options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
299 //      options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
300         options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
301         options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
302         options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
303         options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
304         options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
305         options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
306
307         options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
308         options->file_sort.natural = c_options->file_sort.natural;
309         options->file_filter.disable = c_options->file_filter.disable;
310
311         config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
312         sidecar_ext_parse(options->sidecar.ext);
313
314         options->slideshow.random = c_options->slideshow.random;
315         options->slideshow.repeat = c_options->slideshow.repeat;
316         options->slideshow.delay = c_options->slideshow.delay;
317
318         options->mousewheel_scrolls = c_options->mousewheel_scrolls;
319         options->image_lm_click_nav = c_options->image_lm_click_nav;
320         options->image_l_click_video = c_options->image_l_click_video;
321         options->image_l_click_video_editor = c_options->image_l_click_video_editor;
322
323         options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
324
325         options->image.tile_cache_max = c_options->image.tile_cache_max;
326         options->image.image_cache_max = c_options->image.image_cache_max;
327
328         options->image.zoom_quality = c_options->image.zoom_quality;
329
330         options->image.zoom_increment = c_options->image.zoom_increment;
331
332         options->image.enable_read_ahead = c_options->image.enable_read_ahead;
333
334
335         if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
336             || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
337             || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
338                 {
339                 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
340                 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
341                 options->image.border_color = c_options->image.border_color;
342                 layout_colors_update();
343                 view_window_colors_update();
344                 }
345
346         options->image.alpha_color_1 = c_options->image.alpha_color_1;
347         options->image.alpha_color_2 = c_options->image.alpha_color_2;
348
349         options->fullscreen.screen = c_options->fullscreen.screen;
350         options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
351         options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
352         options->fullscreen.above = c_options->fullscreen.above;
353         if (c_options->image_overlay.template_string)
354                 set_image_overlay_template_string(&options->image_overlay.template_string,
355                                                   c_options->image_overlay.template_string);
356         if (c_options->image_overlay.font)
357                 set_image_overlay_font_string(&options->image_overlay.font,
358                                                   c_options->image_overlay.font);
359         options->image_overlay.text_red = c_options->image_overlay.text_red;
360         options->image_overlay.text_green = c_options->image_overlay.text_green;
361         options->image_overlay.text_blue = c_options->image_overlay.text_blue;
362         options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
363         options->image_overlay.background_red = c_options->image_overlay.background_red;
364         options->image_overlay.background_green = c_options->image_overlay.background_green;
365         options->image_overlay.background_blue = c_options->image_overlay.background_blue;
366         options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
367         options->update_on_time_change = c_options->update_on_time_change;
368         options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
369
370         options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
371         options->rot_invariant_sim = c_options->rot_invariant_sim;
372
373         options->tree_descend_subdirs = c_options->tree_descend_subdirs;
374
375         options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
376
377         options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
378         options->dnd_icon_size = c_options->dnd_icon_size;
379         options->clipboard_selection = c_options->clipboard_selection;
380
381         options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
382         options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
383         options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
384         options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
385         options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
386         options->metadata.confirm_write = c_options->metadata.confirm_write;
387         options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
388         options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
389         options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
390         options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
391         options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
392         options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
393         options->metadata.write_orientation = c_options->metadata.write_orientation;
394         options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
395                                (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
396                                (c_options->stereo.tmp.flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
397                                (c_options->stereo.tmp.mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
398                                (c_options->stereo.tmp.flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
399                                (c_options->stereo.tmp.swap         ? PR_STEREO_SWAP : 0) |
400                                (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
401         options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
402                                (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
403                                (c_options->stereo.tmp.fs_flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
404                                (c_options->stereo.tmp.fs_mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
405                                (c_options->stereo.tmp.fs_flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
406                                (c_options->stereo.tmp.fs_swap         ? PR_STEREO_SWAP : 0) |
407                                (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
408         options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
409         options->stereo.fixed_w = c_options->stereo.fixed_w;
410         options->stereo.fixed_h = c_options->stereo.fixed_h;
411         options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
412         options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
413         options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
414         options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
415
416         options->info_keywords.height = c_options->info_keywords.height;
417         options->info_title.height = c_options->info_title.height;
418         options->info_comment.height = c_options->info_comment.height;
419         options->info_rating.height = c_options->info_rating.height;
420
421         options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
422
423         options->marks_save = c_options->marks_save;
424         options->with_rename = c_options->with_rename;
425         options->collections_on_top = c_options->collections_on_top;
426         config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
427
428         options->read_metadata_in_idle = c_options->read_metadata_in_idle;
429
430         options->star_rating.star = c_options->star_rating.star;
431         options->star_rating.rejected = c_options->star_rating.rejected;
432 #ifdef DEBUG
433         set_debug_level(debug_c);
434 #endif
435
436 #ifdef HAVE_LCMS
437         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
438                 {
439                 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
440                 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
441                 }
442         config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
443         options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
444         if (options->color_profile.render_intent != c_options->color_profile.render_intent)
445                 {
446                 options->color_profile.render_intent = c_options->color_profile.render_intent;
447                 color_man_update();
448                 }
449 #endif
450
451         config_tab_keywords_save();
452
453         image_options_sync();
454
455         if (refresh)
456                 {
457                 filter_rebuild();
458                 layout_refresh(NULL);
459                 }
460
461         if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
462
463         toolbar_apply();
464 }
465
466 /*
467  *-----------------------------------------------------------------------------
468  * config window main button callbacks (private)
469  *-----------------------------------------------------------------------------
470  */
471
472 static void config_window_close_cb(GtkWidget *widget, gpointer data)
473 {
474         gtk_widget_destroy(configwindow);
475         configwindow = NULL;
476         filter_store = NULL;
477 }
478
479 static void config_window_help_cb(GtkWidget *widget, gpointer data)
480 {
481         GtkWidget *notebook = data;
482         gint i;
483
484         static gchar *html_section[] =
485         {
486         "GuideOptionsGeneral.html",
487         "GuideOptionsImage.html",
488         "GuideOptionsOSD.html",
489         "GuideOptionsWindow.html",
490         "GuideOptionsKeyboard.html",
491         "GuideOptionsFiltering.html",
492         "GuideOptionsMetadata.html",
493         "GuideOptionsKeywords.html",
494         "GuideOptionsColor.html",
495         "GuideOptionsStereo.html",
496         "GuideOptionsBehavior.html",
497         "GuideOptionsToolbar.html"
498         };
499
500         i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
501         help_window_show(html_section[i]);
502 }
503
504 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
505 {
506         config_window_close_cb(NULL, NULL);
507         return TRUE;
508 }
509
510 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
511 {
512         config_window_apply();
513         config_window_close_cb(NULL, NULL);
514 }
515
516 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
517 {
518         LayoutWindow *lw;
519         lw = layout_window_list->data;
520
521         config_window_apply();
522         layout_util_sync(lw);
523 }
524
525 static void config_window_save_cb(GtkWidget *widget, gpointer data)
526 {
527         config_window_apply();
528         save_options(options);
529 }
530
531 /*
532  *-----------------------------------------------------------------------------
533  * config window setup (private)
534  *-----------------------------------------------------------------------------
535  */
536
537 static void quality_menu_cb(GtkWidget *combo, gpointer data)
538 {
539         gint *option = data;
540
541         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
542                 {
543                 case 0:
544                 default:
545                         *option = GDK_INTERP_NEAREST;
546                         break;
547                 case 1:
548                         *option = GDK_INTERP_TILES;
549                         break;
550                 case 2:
551                         *option = GDK_INTERP_BILINEAR;
552                         break;
553                 case 3:
554                         *option = GDK_INTERP_HYPER;
555                         break;
556                 }
557 }
558
559 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
560 {
561         gint *option = data;
562
563         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
564                 {
565                 case 0:
566                 default:
567                         *option = PRIMARY;
568                         break;
569                 case 1:
570                         *option = CLIPBOARD;
571                         break;
572                 }
573 }
574
575 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
576                              guint option, guint *option_c)
577 {
578         GtkWidget *combo;
579         gint current = 0;
580
581         *option_c = option;
582
583         pref_table_label(table, column, row, text, 0.0);
584
585         combo = gtk_combo_box_text_new();
586
587         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
588         if (option == GDK_INTERP_NEAREST) current = 0;
589         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
590         if (option == GDK_INTERP_TILES) current = 1;
591         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
592         if (option == GDK_INTERP_BILINEAR) current = 2;
593         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
594         if (option == GDK_INTERP_HYPER) current = 3;
595
596         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
597
598         g_signal_connect(G_OBJECT(combo), "changed",
599                          G_CALLBACK(quality_menu_cb), option_c);
600
601         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
602                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
603         gtk_widget_show(combo);
604 }
605
606 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
607                              gint option, gint *option_c)
608 {
609         GtkWidget *combo;
610         gint current = 0;
611
612         *option_c = option;
613
614         pref_table_label(table, column, row, text, 0.0);
615
616         combo = gtk_combo_box_text_new();
617
618         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
619         if (option == PRIMARY) current = 0;
620         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
621         if (option == CLIPBOARD) current = 1;
622
623         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
624
625         g_signal_connect(G_OBJECT(combo), "changed",
626                          G_CALLBACK(clipboard_selection_menu_cb), option_c);
627
628         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
629                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
630         gtk_widget_show(combo);
631 }
632
633 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
634 {
635         gint n;
636
637         n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
638         if (n < 0) return;
639
640         if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
641                 {
642                 c_options->thumbnails.max_width = thumb_size_list[n].w;
643                 c_options->thumbnails.max_height = thumb_size_list[n].h;
644                 }
645         else
646                 {
647                 c_options->thumbnails.max_width = options->thumbnails.max_width;
648                 c_options->thumbnails.max_height = options->thumbnails.max_height;
649                 }
650 }
651
652 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
653 {
654         GtkWidget *combo;
655         gint current;
656         gint i;
657
658         c_options->thumbnails.max_width = options->thumbnails.max_width;
659         c_options->thumbnails.max_height = options->thumbnails.max_height;
660
661         pref_table_label(table, column, row, text, 0.0);
662
663         combo = gtk_combo_box_text_new();
664
665         current = -1;
666         for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
667                 {
668                 gint w, h;
669                 gchar *buf;
670
671                 w = thumb_size_list[i].w;
672                 h = thumb_size_list[i].h;
673
674                 buf = g_strdup_printf("%d x %d", w, h);
675                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
676                 g_free(buf);
677
678                 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
679                 }
680
681         if (current == -1)
682                 {
683                 gchar *buf;
684
685                 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
686                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
687                 g_free(buf);
688
689                 current = i;
690                 }
691
692         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
693         g_signal_connect(G_OBJECT(combo), "changed",
694                          G_CALLBACK(thumb_size_menu_cb), NULL);
695
696         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
697                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
698         gtk_widget_show(combo);
699 }
700
701 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
702 {
703         gint *option = data;
704
705         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
706                 {
707                 case 0:
708                 default:
709                         *option = PR_STEREO_NONE;
710                         break;
711                 case 1:
712                         *option = PR_STEREO_ANAGLYPH_RC;
713                         break;
714                 case 2:
715                         *option = PR_STEREO_ANAGLYPH_GM;
716                         break;
717                 case 3:
718                         *option = PR_STEREO_ANAGLYPH_YB;
719                         break;
720                 case 4:
721                         *option = PR_STEREO_ANAGLYPH_GRAY_RC;
722                         break;
723                 case 5:
724                         *option = PR_STEREO_ANAGLYPH_GRAY_GM;
725                         break;
726                 case 6:
727                         *option = PR_STEREO_ANAGLYPH_GRAY_YB;
728                         break;
729                 case 7:
730                         *option = PR_STEREO_ANAGLYPH_DB_RC;
731                         break;
732                 case 8:
733                         *option = PR_STEREO_ANAGLYPH_DB_GM;
734                         break;
735                 case 9:
736                         *option = PR_STEREO_ANAGLYPH_DB_YB;
737                         break;
738                 case 10:
739                         *option = PR_STEREO_HORIZ;
740                         break;
741                 case 11:
742                         *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
743                         break;
744                 case 12:
745                         *option = PR_STEREO_VERT;
746                         break;
747                 case 13:
748                         *option = PR_STEREO_VERT | PR_STEREO_HALF;
749                         break;
750                 case 14:
751                         *option = PR_STEREO_FIXED;
752                         break;
753                 }
754 }
755
756 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
757                              gint option, gint *option_c, gboolean add_fixed)
758 {
759         GtkWidget *combo;
760         gint current = 0;
761
762         *option_c = option;
763
764         pref_table_label(table, column, row, text, 0.0);
765
766         combo = gtk_combo_box_text_new();
767
768         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
769
770         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
771         if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
772         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
773         if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
774         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
775         if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
776         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
777         if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
778         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
779         if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
780         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
781         if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
782         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
783         if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
784         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
785         if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
786         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
787         if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
788
789         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
790         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
791         if (option & PR_STEREO_HORIZ)
792                 {
793                 current = 10;
794                 if (option & PR_STEREO_HALF) current = 11;
795                 }
796
797         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
798         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
799         if (option & PR_STEREO_VERT)
800                 {
801                 current = 12;
802                 if (option & PR_STEREO_HALF) current = 13;
803                 }
804
805         if (add_fixed)
806                 {
807                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
808                 if (option & PR_STEREO_FIXED) current = 14;
809                 }
810
811         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
812
813         g_signal_connect(G_OBJECT(combo), "changed",
814                          G_CALLBACK(stereo_mode_menu_cb), option_c);
815
816         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
817                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
818         gtk_widget_show(combo);
819 }
820
821 static void video_menu_cb(GtkWidget *combo, gpointer data)
822 {
823         gchar **option = data;
824
825         EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
826         *option = ed->key;
827 }
828
829 static void video_menu_populate(gpointer data, gpointer user_data)
830 {
831         GtkWidget *combo = user_data;
832         EditorDescription *ed = data;
833
834         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
835 }
836
837 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
838                              gchar *option, gchar **option_c)
839 {
840         GtkWidget *combo;
841         gint current;
842 /* use lists since they are sorted */
843         GList *eds = editor_list_get();
844
845         *option_c = option;
846
847         pref_table_label(table, column, row, text, 0.0);
848
849         combo = gtk_combo_box_text_new();
850         g_list_foreach(eds,video_menu_populate,(gpointer)combo);
851         current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
852
853         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
854
855         g_signal_connect(G_OBJECT(combo), "changed",
856                          G_CALLBACK(video_menu_cb), option_c);
857
858         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
859                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
860         gtk_widget_show(combo);
861 }
862
863 static void filter_store_populate(void)
864 {
865         GList *work;
866
867         if (!filter_store) return;
868
869         gtk_list_store_clear(filter_store);
870
871         work = filter_get_list();
872         while (work)
873                 {
874                 FilterEntry *fe;
875                 GtkTreeIter iter;
876
877                 fe = work->data;
878                 work = work->next;
879
880                 gtk_list_store_append(filter_store, &iter);
881                 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
882                 }
883 }
884
885 static void filter_store_ext_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
893         if (!new_text || strlen(new_text) < 1) return;
894
895         tpath = gtk_tree_path_new_from_string(path_str);
896         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
897         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
898
899         g_free(fe->extensions);
900         fe->extensions = g_strdup(new_text);
901
902         gtk_tree_path_free(tpath);
903         filter_rebuild();
904 }
905
906 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
907                                        gchar *new_text, gpointer data)
908 {
909         GtkWidget *model = data;
910         FilterEntry *fe = data;
911         GtkTreePath *tpath;
912         GtkTreeIter iter;
913         gint i;
914
915         if (!new_text || !new_text[0]) return;
916
917         tpath = gtk_tree_path_new_from_string(path_str);
918         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
919         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
920
921         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
922                 {
923                 if (strcmp(new_text, _(format_class_list[i])) == 0)
924                         {
925                         fe->file_class = i;
926                         break;
927                         }
928                 }
929
930         gtk_tree_path_free(tpath);
931         filter_rebuild();
932 }
933
934 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
935                                       gchar *new_text, gpointer data)
936 {
937         GtkWidget *model = data;
938         FilterEntry *fe;
939         GtkTreePath *tpath;
940         GtkTreeIter iter;
941
942         if (!new_text || !new_text[0]) return;
943
944         tpath = gtk_tree_path_new_from_string(path_str);
945         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
946         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
947
948         g_free(fe->description);
949         fe->description = g_strdup(new_text);
950
951         gtk_tree_path_free(tpath);
952 }
953
954 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
955                                    gchar *path_str, gpointer data)
956 {
957         GtkWidget *model = data;
958         FilterEntry *fe;
959         GtkTreePath *tpath;
960         GtkTreeIter iter;
961
962         tpath = gtk_tree_path_new_from_string(path_str);
963         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
964         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
965
966         fe->enabled = !fe->enabled;
967
968         gtk_tree_path_free(tpath);
969         filter_rebuild();
970 }
971
972 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
973                                      gchar *path_str, gpointer data)
974 {
975         GtkWidget *model = data;
976         FilterEntry *fe;
977         GtkTreePath *tpath;
978         GtkTreeIter iter;
979
980         tpath = gtk_tree_path_new_from_string(path_str);
981         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
982         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
983
984         fe->writable = !fe->writable;
985         if (fe->writable) fe->allow_sidecar = FALSE;
986
987         gtk_tree_path_free(tpath);
988         filter_rebuild();
989 }
990
991 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
992                                     gchar *path_str, gpointer data)
993 {
994         GtkWidget *model = data;
995         FilterEntry *fe;
996         GtkTreePath *tpath;
997         GtkTreeIter iter;
998
999         tpath = gtk_tree_path_new_from_string(path_str);
1000         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1001         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1002
1003         fe->allow_sidecar = !fe->allow_sidecar;
1004         if (fe->allow_sidecar) fe->writable = FALSE;
1005
1006         gtk_tree_path_free(tpath);
1007         filter_rebuild();
1008 }
1009
1010 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1011                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1012 {
1013         FilterEntry *fe;
1014
1015         gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1016
1017         switch (GPOINTER_TO_INT(data))
1018                 {
1019                 case FE_ENABLE:
1020                         g_object_set(GTK_CELL_RENDERER(cell),
1021                                      "active", fe->enabled, NULL);
1022                         break;
1023                 case FE_EXTENSION:
1024                         g_object_set(GTK_CELL_RENDERER(cell),
1025                                      "text", fe->extensions, NULL);
1026                         break;
1027                 case FE_DESCRIPTION:
1028                         g_object_set(GTK_CELL_RENDERER(cell),
1029                                      "text", fe->description, NULL);
1030                         break;
1031                 case FE_CLASS:
1032                         g_object_set(GTK_CELL_RENDERER(cell),
1033                                      "text", _(format_class_list[fe->file_class]), NULL);
1034                         break;
1035                 case FE_WRITABLE:
1036                         g_object_set(GTK_CELL_RENDERER(cell),
1037                                      "active", fe->writable, NULL);
1038                         break;
1039                 case FE_ALLOW_SIDECAR:
1040                         g_object_set(GTK_CELL_RENDERER(cell),
1041                                      "active", fe->allow_sidecar, NULL);
1042                         break;
1043                 }
1044 }
1045
1046 static gboolean filter_add_scroll(gpointer data)
1047 {
1048         GtkTreePath *path;
1049         GList *list_cells;
1050         GtkCellRenderer *cell;
1051         GtkTreeViewColumn *column;
1052         GList *list_columns;
1053         const gchar *title;
1054         guint i = 0;
1055         gint rows;
1056
1057         rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1058         path = gtk_tree_path_new_from_indices(rows-1, -1);
1059
1060         list_columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(data));
1061         do {
1062                 column = g_list_nth(list_columns,i)->data;
1063                 title = gtk_tree_view_column_get_title(GTK_TREE_VIEW_COLUMN(column));
1064                 i++;
1065                 } while (strcmp(title, "Filter") !=0 );
1066
1067         list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1068         cell = g_list_last(list_cells)->data;
1069
1070         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1071                                                                 path, column, FALSE, 0.0, 0.0 );
1072         gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1073                                                                 path, column, cell, TRUE);
1074
1075         gtk_tree_path_free(path);
1076         g_list_free(list_cells);
1077         g_list_free(list_columns);
1078
1079         return(FALSE);
1080 }
1081
1082 static void filter_add_cb(GtkWidget *widget, gpointer data)
1083 {
1084         filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1085         filter_store_populate();
1086
1087         g_idle_add((GSourceFunc)filter_add_scroll, data);
1088 }
1089
1090 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1091 {
1092         GtkWidget *filter_view = data;
1093         GtkTreeSelection *selection;
1094         GtkTreeIter iter;
1095         FilterEntry *fe;
1096
1097         if (!filter_store) return;
1098         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1099         if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1100         gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1101         if (!fe) return;
1102
1103         filter_remove_entry(fe);
1104         filter_rebuild();
1105         filter_store_populate();
1106 }
1107
1108 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1109 {
1110         GtkTreeIter iter;
1111         GtkTreePath *path;
1112         GtkTreeViewColumn *column;
1113
1114         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1115         path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1116         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1117
1118         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1119                                      path, column,
1120                                      FALSE, 0.0, 0.0);
1121
1122         gtk_tree_path_free(path);
1123
1124         return(FALSE);
1125 }
1126
1127 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1128 {
1129         filter_reset();
1130         filter_add_defaults();
1131         filter_rebuild();
1132         filter_store_populate();
1133
1134         g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1135 }
1136
1137 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1138 {
1139         /* no op, only so cancel button appears */
1140 }
1141
1142 static void filter_default_cb(GtkWidget *widget, gpointer data)
1143 {
1144         GenericDialog *gd;
1145
1146         gd = generic_dialog_new(_("Reset filters"),
1147                                 "reset_filter", widget, TRUE,
1148                                 dummy_cancel_cb, data);
1149         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1150                                    _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1151         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1152         gtk_widget_show(gd->dialog);
1153 }
1154
1155 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1156 {
1157         GtkWidget *frame = data;
1158
1159         gtk_widget_set_sensitive(frame,
1160                                  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1161 }
1162
1163 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1164 {
1165         layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1166 }
1167
1168 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1169 {
1170         file_util_trash_clear();
1171 }
1172
1173 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1174 {
1175         GenericDialog *gd;
1176         GtkWidget *entry;
1177         gd = generic_dialog_new(_("Clear trash"),
1178                                 "clear_trash", widget, TRUE,
1179                                 dummy_cancel_cb, NULL);
1180         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1181                                     _("This will remove the trash contents."), FALSE);
1182         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1183         entry = gtk_entry_new();
1184         gtk_widget_set_can_focus(entry, FALSE);
1185         gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1186         if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1187         gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1188         gtk_widget_show(entry);
1189         gtk_widget_show(gd->dialog);
1190 }
1191
1192 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1193 {
1194         GtkWidget *pTextView;
1195         GtkTextBuffer *pTextBuffer;
1196         GtkTextIter iStart;
1197         GtkTextIter iEnd;
1198
1199         pTextView = GTK_WIDGET(data);
1200
1201         pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1202         gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1203         gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1204
1205         set_image_overlay_template_string(&c_options->image_overlay.template_string,
1206                                           gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1207 }
1208
1209 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1210 {
1211         GtkTextView *text_view = data;
1212         GtkTextBuffer *buffer;
1213
1214         set_default_image_overlay_template_string(&options->image_overlay.template_string);
1215         if (!configwindow) return;
1216
1217         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1218         gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1219 }
1220
1221 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1222 {
1223         GenericDialog *gd;
1224
1225         gd = generic_dialog_new(_("Reset image overlay template string"),
1226                                 "reset_image_overlay_template_string", widget, TRUE,
1227                                 dummy_cancel_cb, data);
1228         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1229                                    _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1230         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1231         gtk_widget_show(gd->dialog);
1232 }
1233
1234 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1235 {
1236         help_window_show("GuideOptionsOSD.html");
1237 }
1238
1239 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1240 {
1241 #if GTK_CHECK_VERSION(3,4,0)
1242         GtkWidget *dialog;
1243         char *font;
1244         PangoFontDescription *font_desc;
1245
1246         dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1247         gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1248
1249         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1250                 {
1251                 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1252                 font = pango_font_description_to_string(font_desc);
1253                 g_free(c_options->image_overlay.font);
1254                 c_options->image_overlay.font = g_strdup(font);
1255                 g_free(font);
1256                 }
1257
1258         gtk_widget_destroy(dialog);
1259 #else
1260         const char *font;
1261
1262         font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1263         c_options->image_overlay.font = g_strdup(font);
1264 #endif
1265 }
1266
1267 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1268 {
1269         GtkWidget *dialog;
1270 #if GTK_CHECK_VERSION(3,4,0)
1271         GdkRGBA colour;
1272
1273         dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1274         colour.red = options->image_overlay.text_red;
1275         colour.green = options->image_overlay.text_green;
1276         colour.blue = options->image_overlay.text_blue;
1277         colour.alpha = options->image_overlay.text_alpha;
1278         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1279         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1280
1281         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1282                 {
1283                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1284                 c_options->image_overlay.text_red = colour.red*255;
1285                 c_options->image_overlay.text_green = colour.green*255;
1286                 c_options->image_overlay.text_blue = colour.blue*255;
1287                 c_options->image_overlay.text_alpha = colour.alpha*255;
1288                 }
1289         gtk_widget_destroy(dialog);
1290 #else
1291         GdkColor colour;
1292         GtkColorSelection *colorsel;
1293
1294         dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1295         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1296         colour.red = options->image_overlay.text_red*257;
1297         colour.green = options->image_overlay.text_green*257;
1298         colour.blue = options->image_overlay.text_blue*257;
1299         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1300         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1301         gtk_color_selection_set_current_color(colorsel, &colour);
1302         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1303
1304         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1305                 {
1306                 gtk_color_selection_get_current_color(colorsel, &colour);
1307                 c_options->image_overlay.text_red = colour.red/257;
1308                 c_options->image_overlay.text_green = colour.green/257;
1309                 c_options->image_overlay.text_blue = colour.blue/257;
1310                 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1311                 }
1312         gtk_widget_destroy (dialog);
1313 #endif
1314 }
1315
1316
1317 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1318 {
1319         GtkWidget *dialog;
1320 #if GTK_CHECK_VERSION(3,4,0)
1321         GdkRGBA colour;
1322
1323         dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1324         colour.red = options->image_overlay.background_red;
1325         colour.green = options->image_overlay.background_green;
1326         colour.blue = options->image_overlay.background_blue;
1327         colour.alpha = options->image_overlay.background_alpha;
1328         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1329         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1330
1331         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1332                 {
1333                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1334                 c_options->image_overlay.background_red = colour.red*255;
1335                 c_options->image_overlay.background_green = colour.green*255;
1336                 c_options->image_overlay.background_blue = colour.blue*255;
1337                 c_options->image_overlay.background_alpha = colour.alpha*255;
1338                 }
1339         gtk_widget_destroy(dialog);
1340 #else
1341         GdkColor colour;
1342         GtkColorSelection *colorsel;
1343
1344         dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1345         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1346         colour.red = options->image_overlay.background_red*257;
1347         colour.green = options->image_overlay.background_green*257;
1348         colour.blue = options->image_overlay.background_blue*257;
1349         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1350         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1351         gtk_color_selection_set_current_color(colorsel, &colour);
1352         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1353
1354         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1355                 {
1356                 gtk_color_selection_get_current_color(colorsel, &colour);
1357                 c_options->image_overlay.background_red = colour.red/257;
1358                 c_options->image_overlay.background_green = colour.green/257;
1359                 c_options->image_overlay.background_blue = colour.blue/257;
1360                 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1361                 }
1362         gtk_widget_destroy(dialog);
1363 #endif
1364 }
1365
1366 static void accel_store_populate(void)
1367 {
1368         LayoutWindow *lw;
1369         GList *groups, *actions;
1370         GtkAction *action;
1371         const gchar *accel_path;
1372         GtkAccelKey key;
1373         GtkTreeIter iter;
1374
1375         if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1376
1377         gtk_tree_store_clear(accel_store);
1378         lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1379
1380         g_assert(lw && lw->ui_manager);
1381         groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1382         while (groups)
1383                 {
1384                 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1385                 while (actions)
1386                         {
1387                         action = GTK_ACTION(actions->data);
1388                         accel_path = gtk_action_get_accel_path(action);
1389                         if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1390                                 {
1391                                 gchar *label, *label2, *tooltip, *accel;
1392                                 g_object_get(action,
1393                                              "tooltip", &tooltip,
1394                                              "label", &label,
1395                                              NULL);
1396
1397                                 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1398                                         {
1399                                         g_free(label);
1400                                         label = label2;
1401                                         }
1402
1403                                 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1404
1405                                 if (tooltip)
1406                                         {
1407                                         gtk_tree_store_append(accel_store, &iter, NULL);
1408                                         gtk_tree_store_set(accel_store, &iter,
1409                                                            AE_ACTION, label,
1410                                                            AE_KEY, accel,
1411                                                            AE_TOOLTIP, tooltip ? tooltip : "",
1412                                                            AE_ACCEL, accel_path,
1413                                                            -1);
1414                                         }
1415
1416                                 g_free(accel);
1417                                 g_free(label);
1418                                 g_free(tooltip);
1419                                 }
1420                         actions = actions->next;
1421                         }
1422
1423                 groups = groups->next;
1424                 }
1425 }
1426
1427 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1428 {
1429
1430 }
1431
1432 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1433 {
1434         gchar *accel1 = data;
1435         gchar *accel2;
1436         GtkAccelKey key1;
1437         GtkAccelKey key2;
1438
1439         gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1440
1441         gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1442         gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1443
1444         if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1445                 {
1446                 gtk_tree_store_set(accel_store, iter, AE_KEY, "",  -1);
1447                 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1448                 }
1449
1450         g_free(accel2);
1451
1452         return FALSE;
1453 }
1454
1455
1456 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1457 {
1458         GtkTreeModel *model = (GtkTreeModel *)accel_store;
1459         GtkTreeIter iter;
1460         gchar *acc;
1461         gchar *accel_path;
1462         GtkAccelKey old_key, key;
1463         GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1464
1465         gtk_tree_model_get_iter(model, &iter, path);
1466         gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1467
1468         /* test if the accelerator can be stored without conflicts*/
1469         gtk_accel_map_lookup_entry(accel_path, &old_key);
1470
1471         /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1472         gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1473         gtk_accel_map_lookup_entry(accel_path, &key);
1474
1475         /* restore the original for now, the key will be really changed when the changes are confirmed */
1476         gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1477
1478         acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1479         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1480
1481         gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1482         gtk_tree_path_free(path);
1483         g_free(acc);
1484 }
1485
1486 static gboolean accel_default_scroll(GtkTreeView *data)
1487 {
1488         GtkTreeIter iter;
1489         GtkTreePath *path;
1490         GtkTreeViewColumn *column;
1491
1492         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1493         path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1494         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1495
1496         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1497                                      path, column,
1498                                      FALSE, 0.0, 0.0);
1499
1500         gtk_tree_path_free(path);
1501
1502         return(FALSE);
1503 }
1504
1505 static void accel_default_cb(GtkWidget *widget, gpointer data)
1506 {
1507         accel_store_populate();
1508
1509         g_idle_add((GSourceFunc)accel_default_scroll, data);
1510 }
1511
1512 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1513 {
1514         gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1515 }
1516
1517 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1518 {
1519         GtkAccelKey key;
1520         gchar *accel_path, *accel;
1521
1522         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1523         gtk_accel_map_lookup_entry(accel_path, &key);
1524         accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1525
1526         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1527
1528         gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1529         g_free(accel_path);
1530         g_free(accel);
1531 }
1532
1533 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1534 {
1535         GtkTreeSelection *selection;
1536
1537         if (!accel_store) return;
1538         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1539         gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1540 }
1541
1542
1543
1544 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1545 {
1546         GtkWidget *label;
1547         GtkWidget *vbox;
1548         GtkWidget *scrolled;
1549         GtkWidget *viewport;
1550
1551         scrolled = gtk_scrolled_window_new(NULL, NULL);
1552         gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1553         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1554                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1555         label = gtk_label_new(title);
1556         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1557         gtk_widget_show(scrolled);
1558
1559         viewport = gtk_viewport_new(NULL, NULL);
1560         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1561         gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1562         gtk_widget_show(viewport);
1563
1564         vbox = gtk_vbox_new(FALSE, 0);
1565         gtk_container_add(GTK_CONTAINER(viewport), vbox);
1566         gtk_widget_show(vbox);
1567
1568         return vbox;
1569 }
1570
1571 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1572 {
1573         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1574                 {
1575                 c_options->thumbnails.spec_standard =TRUE;
1576                 c_options->thumbnails.cache_into_dirs = FALSE;
1577                 }
1578 }
1579
1580 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1581 {
1582         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1583                 {
1584                 c_options->thumbnails.spec_standard =FALSE;
1585                 c_options->thumbnails.cache_into_dirs = FALSE;
1586                 }
1587 }
1588
1589 static void cache_local_cb(GtkWidget *widget, gpointer data)
1590 {
1591         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1592                 {
1593                 c_options->thumbnails.cache_into_dirs = TRUE;
1594                 c_options->thumbnails.spec_standard =FALSE;
1595                 }
1596 }
1597
1598 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1599                                                                         GdkEvent *event, gpointer userdata)
1600 {
1601         if (pos == GTK_ENTRY_ICON_PRIMARY)
1602                 {
1603                 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1604                 }
1605         else
1606                 {
1607                 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1608                 }
1609 }
1610
1611 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1612                                                                         GdkEvent *event, gpointer userdata)
1613 {
1614         gchar *rating_symbol;
1615
1616         if (pos == GTK_ENTRY_ICON_PRIMARY)
1617                 {
1618                 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1619                 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1620                 g_free(rating_symbol);
1621                 }
1622         else
1623                 {
1624                 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1625                 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1626                 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1627                 }
1628 }
1629
1630 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1631                                                                         GdkEvent *event, gpointer userdata)
1632 {
1633         gchar *rating_symbol;
1634
1635         if (pos == GTK_ENTRY_ICON_PRIMARY)
1636                 {
1637                 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1638                 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1639                 g_free(rating_symbol);
1640                 }
1641         else
1642                 {
1643                 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1644                 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1645                 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1646                 }
1647 }
1648
1649 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1650 {
1651         GtkContainer *hbox = data;
1652         GString *str = g_string_new(NULL);
1653         GtkEntry *hex_code_entry;
1654         gchar *hex_code_full;
1655         gchar **hex_code;
1656         GList *list;
1657         guint64 hex_value = 0;
1658
1659         list = gtk_container_get_children(hbox);
1660
1661         hex_code_entry = g_list_nth_data(list, 2);
1662         hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1663
1664         hex_code = g_strsplit(hex_code_full, "+", 2);
1665         if (hex_code[0] && hex_code[1])
1666                 {
1667                 hex_value = strtoull(hex_code[1], NULL, 16);
1668                 }
1669         if (!hex_value || hex_value > 0x10FFFF)
1670                 {
1671                 hex_value = 0x003F; // Unicode 'Question Mark'
1672                 }
1673         str = g_string_append_unichar(str, (gunichar)hex_value);
1674         gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1675
1676         g_strfreev(hex_code);
1677         g_string_free(str, TRUE);
1678         g_free(hex_code_full);
1679
1680         return hex_value;
1681 }
1682
1683 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1684 {
1685         guint64 star_symbol;
1686
1687         star_symbol = star_rating_symbol_test(widget, data);
1688         c_options->star_rating.star = star_symbol;
1689 }
1690
1691 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1692 {
1693         guint64 rejected_symbol;
1694
1695         rejected_symbol = star_rating_symbol_test(widget, data);
1696         c_options->star_rating.rejected = rejected_symbol;
1697 }
1698
1699 /* general options tab */
1700 static void config_tab_general(GtkWidget *notebook)
1701 {
1702         GtkWidget *vbox;
1703         GtkWidget *hbox;
1704         GtkWidget *group;
1705         GtkWidget *group_frame;
1706         GtkWidget *subgroup;
1707         GtkWidget *button;
1708         GtkWidget *ct_button;
1709         GtkWidget *table;
1710         GtkWidget *spin;
1711         gint hours, minutes, remainder;
1712         gdouble seconds;
1713         GtkWidget *star_rating_entry;
1714         GString *str;
1715         gchar *rating_symbol;
1716
1717         vbox = scrolled_notebook_page(notebook, _("General"));
1718
1719         group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1720
1721         table = pref_table_new(group, 2, 2, FALSE, FALSE);
1722         add_thumb_size_menu(table, 0, 0, _("Size:"));
1723         add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1724
1725         ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1726                                           options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1727
1728         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1729         pref_checkbox_link_sensitivity(ct_button, subgroup);
1730
1731         c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1732         c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1733         group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1734                                                                                 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1735         button = pref_radiobutton_new(group_frame, NULL,  get_thumbnails_cache_dir(),
1736                                                         !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1737                                                         G_CALLBACK(cache_geeqie_cb), NULL);
1738
1739         group_frame = pref_frame_new(subgroup, TRUE,
1740                                                         _("Store thumbnails local to image folder (non-standard)"),
1741                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1742         pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1743                                                         !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1744                                                         G_CALLBACK(cache_local_cb), NULL);
1745
1746         group_frame = pref_frame_new(subgroup, TRUE,
1747                                                         _("Use standard thumbnail style and cache, shared with other applications"),
1748                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1749         pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1750                                                         options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1751                                                         G_CALLBACK(cache_standard_cb), NULL);
1752
1753         pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1754                               options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1755
1756         spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1757                                  1, 999, 1,
1758                                  options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1759         gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1760
1761 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1762         pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1763                               options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1764
1765 //      pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1766 //                            options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1767 #endif
1768
1769         group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1770
1771         c_options->star_rating.star = options->star_rating.star;
1772         c_options->star_rating.rejected = options->star_rating.rejected;
1773
1774         str = g_string_new(NULL);
1775         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1776         pref_label_new(hbox, "Star character: ");
1777         str = g_string_append_unichar(str, options->star_rating.star);
1778         pref_label_new(hbox, g_strdup(str->str));
1779         rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1780         star_rating_entry = gtk_entry_new();
1781         gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1782         gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1783         gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1784         gtk_widget_show(star_rating_entry);
1785         button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1786                                         G_CALLBACK(star_rating_star_test_cb), hbox);
1787         gtk_widget_set_tooltip_text(button, _("Display selected character"));
1788         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1789         gtk_widget_show(button);
1790         gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
1791         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1792                                                 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1793         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1794                                                 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1795         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1796                                                 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1797         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1798                                                 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1799         g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1800                                                 G_CALLBACK(star_rating_star_icon_cb),
1801                                                 star_rating_entry);
1802
1803         g_string_free(str, TRUE);
1804         g_free(rating_symbol);
1805
1806         str = g_string_new(NULL);
1807         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1808         pref_label_new(hbox, "Rejected character: ");
1809         str = g_string_append_unichar(str, options->star_rating.rejected);
1810         pref_label_new(hbox, g_strdup(str->str));
1811         rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
1812         star_rating_entry = gtk_entry_new();
1813         gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1814         gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1815         gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1816         gtk_widget_show(star_rating_entry);
1817         button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1818                                         G_CALLBACK(star_rating_rejected_test_cb), hbox);
1819         gtk_widget_set_tooltip_text(button, _("Display selected character"));
1820         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1821         gtk_widget_show(button);
1822         gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
1823         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1824                                                 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1825         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1826                                                 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1827         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1828                                                 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1829         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1830                                                 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1831         g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1832                                                 G_CALLBACK(star_rating_rejected_icon_cb),
1833                                                 star_rating_entry);
1834
1835         g_string_free(str, TRUE);
1836         g_free(rating_symbol);
1837
1838         group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
1839
1840         c_options->slideshow.delay = options->slideshow.delay;
1841         hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1842         remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1843         minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
1844         seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
1845                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
1846
1847         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1848
1849         spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
1850                                                                                 0, 23, 1.0, 0,
1851                                                                                 options->slideshow.delay ? hours : 0.0,
1852                                                                                 G_CALLBACK(slideshow_delay_hours_cb), NULL);
1853         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1854         spin = pref_spin_new(hbox, ":" , NULL,
1855                                                                                 0, 59, 1.0, 0,
1856                                                                                 options->slideshow.delay ? minutes: 0.0,
1857                                                                                 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
1858         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1859         spin = pref_spin_new(hbox, ":", NULL,
1860                                                                                 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
1861                                                                                 options->slideshow.delay ? seconds : 10.0,
1862                                                                                 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
1863         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1864
1865         pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
1866         pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
1867
1868         group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
1869
1870         pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
1871                           0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
1872         pref_checkbox_new_int(group, _("Preload next image"),
1873                               options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
1874
1875         pref_checkbox_new_int(group, _("Refresh on file change"),
1876                               options->update_on_time_change, &c_options->update_on_time_change);
1877
1878         group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
1879         pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
1880         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1881         pref_spin_new_int(hbox, _("Keywords:"), NULL,
1882                                  1, 9999, 1,
1883                                  options->info_keywords.height, &c_options->info_keywords.height);
1884         pref_spin_new_int(hbox, _("Title:"), NULL,
1885                                  1, 9999, 1,
1886                                  options->info_title.height, &c_options->info_title.height);
1887         pref_spin_new_int(hbox, _("Comment:"), NULL,
1888                                  1, 9999, 1,
1889                                  options->info_comment.height, &c_options->info_comment.height);
1890         pref_spin_new_int(hbox, _("Rating:"), NULL,
1891                                  1, 9999, 1,
1892                                  options->info_rating.height, &c_options->info_rating.height);
1893
1894         group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
1895
1896         pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
1897                                 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
1898
1899         group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
1900
1901         help_search_engine_entry = gtk_entry_new();
1902         gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
1903         gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
1904         gtk_widget_show(help_search_engine_entry);
1905
1906         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"));
1907
1908         gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
1909                                                 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1910         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
1911                                                 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1912         gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
1913                                                 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1914         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
1915                                                 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1916         g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
1917                                                 G_CALLBACK(help_search_engine_entry_icon_cb),
1918                                                 help_search_engine_entry);
1919 }
1920
1921 /* image tab */
1922 static void config_tab_image(GtkWidget *notebook)
1923 {
1924         GtkWidget *hbox;
1925         GtkWidget *vbox;
1926         GtkWidget *group;
1927         GtkWidget *ct_button;
1928         GtkWidget *enlargement_button;
1929         GtkWidget *table;
1930         GtkWidget *spin;
1931
1932         vbox = scrolled_notebook_page(notebook, _("Image"));
1933
1934         group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
1935
1936         table = pref_table_new(group, 2, 1, FALSE, FALSE);
1937         add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
1938
1939 #ifdef HAVE_CLUTTER
1940         pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
1941                               options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
1942 #endif
1943
1944         pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
1945                               options->image.zoom_2pass, &c_options->image.zoom_2pass);
1946
1947         c_options->image.zoom_increment = options->image.zoom_increment;
1948         spin = pref_spin_new(group, _("Zoom increment:"), NULL,
1949                              0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
1950                              G_CALLBACK(zoom_increment_cb), NULL);
1951         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1952
1953         group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
1954
1955         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1956         enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
1957                               options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
1958         spin = pref_spin_new_int(hbox, NULL, NULL,
1959                                  100, 999, 1,
1960                                  options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
1961         pref_checkbox_link_sensitivity(enlargement_button, spin);
1962         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."));
1963
1964         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1965         ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
1966                                           options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
1967         spin = pref_spin_new_int(hbox, NULL, NULL,
1968                                  10, 150, 1,
1969                                  options->image.max_autofit_size, &c_options->image.max_autofit_size);
1970         pref_checkbox_link_sensitivity(ct_button, spin);
1971         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."));
1972
1973         group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
1974
1975         pref_checkbox_new_int(group, _("Use custom border color in window mode"),
1976                               options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
1977
1978         pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
1979                               options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
1980
1981         pref_color_button_new(group, _("Border color"), &options->image.border_color,
1982                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
1983
1984         c_options->image.border_color = options->image.border_color;
1985
1986         pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
1987                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
1988
1989         pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
1990                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
1991
1992         c_options->image.alpha_color_1 = options->image.alpha_color_1;
1993         c_options->image.alpha_color_2 = options->image.alpha_color_2;
1994
1995         group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
1996
1997         pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
1998                               options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
1999 }
2000
2001 /* windows tab */
2002 static void config_tab_windows(GtkWidget *notebook)
2003 {
2004         GtkWidget *hbox;
2005         GtkWidget *vbox;
2006         GtkWidget *group;
2007         GtkWidget *button;
2008         GtkWidget *ct_button;
2009         GtkWidget *spin;
2010
2011         vbox = scrolled_notebook_page(notebook, _("Windows"));
2012
2013         group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2014
2015         ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2016                                           options->save_window_positions, &c_options->save_window_positions);
2017
2018         button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2019                                        options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2020         pref_checkbox_link_sensitivity(ct_button, button);
2021
2022         pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2023                               options->tools_restore_state, &c_options->tools_restore_state);
2024
2025         pref_checkbox_new_int(group, _("Remember dialog window positions"),
2026                               options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2027
2028         pref_checkbox_new_int(group, _("Show window IDs"),
2029                               options->show_window_ids, &c_options->show_window_ids);
2030
2031         group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2032
2033         pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2034                               options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2035
2036         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2037         ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2038                                           options->image.limit_window_size, &c_options->image.limit_window_size);
2039         spin = pref_spin_new_int(hbox, NULL, NULL,
2040                                  10, 150, 1,
2041                                  options->image.max_window_size, &c_options->image.max_window_size);
2042         pref_checkbox_link_sensitivity(ct_button, spin);
2043
2044         group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2045
2046         c_options->fullscreen.screen = options->fullscreen.screen;
2047         c_options->fullscreen.above = options->fullscreen.above;
2048         hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2049         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2050         gtk_widget_show(hbox);
2051
2052         pref_checkbox_new_int(group, _("Smooth image flip"),
2053                               options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2054         pref_checkbox_new_int(group, _("Disable screen saver"),
2055                               options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2056 }
2057
2058 /* overlay screen display tab */
2059 static const gchar *predefined_tags[][2] = {
2060         {"%name%",                                                      N_("Name")},
2061         {"%path:60%*",                                          N_("Path")},
2062         {"%date%",                                                      N_("Date")},
2063         {"%size%",                                                      N_("Size")},
2064         {"%zoom%",                                                      N_("Zoom")},
2065         {"%dimensions%",                                        N_("Dimensions")},
2066         {"%collection%",                                        N_("Collection")},
2067         {"%number%",                                            N_("Collection number")},
2068         {"%total%",                                                     N_("Collection total")},
2069         {"%file.ctime%",                                        N_("File ctime")},
2070         {"%file.mode%",                                         N_("File mode")},
2071         {"%file.owner%",                                        N_("File owner")},
2072         {"%file.group%",                                        N_("File group")},
2073         {"%file.link%",                                         N_("File link")},
2074         {"%file.class%",                                        N_("File class")},
2075         {"%formatted.DateTime%",                        N_("Image date")},
2076         {"%formatted.DateTimeDigitized%",       N_("Date digitized")},
2077         {"%formatted.ShutterSpeed%",            N_("ShutterSpeed")},
2078         {"%formatted.Aperture%",                        N_("Aperture")},
2079         {"%formatted.ExposureBias%",            N_("Exposure bias")},
2080         {"%formatted.Resolution%",                      N_("Resolution")},
2081         {"%formatted.Camera%",                          N_("Camera")},
2082         {"%formatted.ShutterSpeed%",            N_("Shutter speed")},
2083         {"%formatted.ISOSpeedRating%",          N_("ISO")},
2084         {"%formatted.FocalLength%",                     N_("Focal length")},
2085         {"%formatted.FocalLength35mmFilm%",     N_("Focal len. 35mm")},
2086         {"%formatted.SubjectDistance%",         N_("Subject distance")},
2087         {"%formatted.Flash%",                           N_("Flash")},
2088         {"%formatted.ColorProfile%",            N_("Color profile")},
2089         {"%formatted.GPSPosition%",                     N_("Lat, Long")},
2090         {"%formatted.GPSAltitude%",                     N_("Altitude")},
2091         {"%formatted.localtime%",                       N_("Local time")},
2092         {"%formatted.timezone%",                        N_("Timezone")},
2093         {"%formatted.countryname%",                     N_("Country name")},
2094         {"%formatted.countrycode%",                     N_("Country code")},
2095         {"%formatted.star_rating%",                     N_("Star rating")},
2096         {NULL, NULL}};
2097
2098 static GtkTargetEntry osd_drag_types[] = {
2099         { "text/plain", GTK_TARGET_SAME_APP, TARGET_TEXT_PLAIN }
2100 };
2101
2102 typedef struct _TagData TagData;
2103 struct _TagData
2104 {
2105         gchar *key;
2106         gchar *title;
2107 };
2108
2109 static void tag_button_cb(GtkWidget *widget, gpointer data)
2110 {
2111         GtkTextView *image_overlay_template_view = data;
2112         GtkTextBuffer *buffer;
2113         TagData *td;
2114
2115         buffer = gtk_text_view_get_buffer(image_overlay_template_view);
2116         td = g_object_get_data(G_OBJECT(widget), "tag_data");
2117         gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(buffer), td->key, -1);
2118
2119         gtk_widget_grab_focus(GTK_WIDGET(image_overlay_template_view));
2120 }
2121
2122 static void osd_dnd_get_cb(GtkWidget *btn, GdkDragContext *context,
2123                                                                 GtkSelectionData *selection_data, guint info,
2124                                                                 guint time, gpointer data)
2125 {
2126         TagData *td;
2127         GtkTextView *image_overlay_template_view = data;
2128
2129         td = g_object_get_data(G_OBJECT(btn), "tag_data");
2130         gtk_selection_data_set_text(selection_data, td->key, -1);
2131
2132         gtk_widget_grab_focus(GTK_WIDGET(image_overlay_template_view));
2133 }
2134
2135 static void osd_btn_destroy_cb(GtkWidget *btn, GdkDragContext *context,
2136                                                                 GtkSelectionData *selection_data, guint info,
2137                                                                 guint time, gpointer data)
2138 {
2139         TagData *td;
2140
2141         td = g_object_get_data(G_OBJECT(btn), "tag_data");
2142         g_free(td->key);
2143         g_free(td->title);
2144 }
2145
2146 static void set_osd_button(GtkWidget *widget, const gchar *key, const gchar *title,
2147                                                                                 GtkWidget *image_overlay_template_view)
2148 {
2149         GtkWidget *new_button;
2150         TagData *td;
2151
2152         new_button = pref_button_new(widget, NULL, _(title), TRUE,
2153                                                         G_CALLBACK(tag_button_cb), image_overlay_template_view);
2154
2155         td = g_new0(TagData, 1);
2156         td->key = g_strdup(key);
2157         td->title = g_strdup(title);
2158
2159         g_object_set_data(G_OBJECT(new_button), "tag_data", td);
2160
2161         gtk_drag_source_set(new_button, GDK_BUTTON1_MASK, osd_drag_types, 1, GDK_ACTION_COPY);
2162         g_signal_connect(G_OBJECT(new_button), "drag_data_get",
2163                                                         G_CALLBACK(osd_dnd_get_cb), image_overlay_template_view);
2164         g_signal_connect(G_OBJECT(new_button), "destroy",
2165                                                         G_CALLBACK(osd_btn_destroy_cb), new_button);
2166 }
2167
2168 static void config_tab_osd(GtkWidget *notebook)
2169 {
2170         GtkWidget *hbox;
2171         GtkWidget *vbox;
2172         GtkWidget *vbox_buttons;
2173         GtkWidget *group;
2174         GtkWidget *button;
2175         GtkWidget *image_overlay_template_view;
2176         GtkWidget *scrolled;
2177         GtkTextBuffer *buffer;
2178         GtkWidget *label;
2179         GtkWidget *     subgroup;
2180         gint i = 0;
2181         gint rows = 0;
2182         gint cols = 0;
2183
2184         vbox = scrolled_notebook_page(notebook, _("OSD"));
2185
2186         image_overlay_template_view = gtk_text_view_new();
2187
2188         group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2189
2190         hbox = gtk_hbox_new(FALSE, 0);
2191
2192         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2193         gtk_widget_show(hbox);
2194
2195         pref_label_new(hbox, _("To include predefined tags in the template, click a button or drag-and-drop"));
2196
2197         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2198         hbox = gtk_hbox_new(FALSE, 0);
2199         gtk_box_pack_start(GTK_BOX(subgroup), hbox, FALSE, FALSE, 0);
2200         gtk_widget_show(hbox);
2201
2202         for (cols = 0; cols < 6; cols++)
2203                 {
2204                 vbox_buttons = gtk_vbox_new(FALSE, 0);
2205                 rows = 0;
2206
2207                 gtk_box_pack_start(GTK_BOX(hbox), vbox_buttons, FALSE, FALSE, 0);
2208
2209                 while (rows < 6 && predefined_tags[i][0])
2210                         {
2211                         set_osd_button(vbox_buttons, predefined_tags[i][0], predefined_tags[i][1], image_overlay_template_view);
2212                         i = i + 1;
2213                         rows++;
2214                         }
2215                 gtk_widget_show(vbox_buttons);
2216                 }
2217
2218         pref_line(group, PREF_PAD_GAP);
2219
2220         pref_label_new(group, _("Image overlay template"));
2221
2222         scrolled = gtk_scrolled_window_new(NULL, NULL);
2223         gtk_widget_set_size_request(scrolled, 200, 150);
2224         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2225         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2226                                                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2227         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2228         gtk_widget_show(scrolled);
2229
2230         gtk_widget_set_tooltip_markup(image_overlay_template_view,
2231                                         _("Extensive formatting options are shown in the Help file"));
2232
2233         gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2234         gtk_widget_show(image_overlay_template_view);
2235
2236         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2237
2238 #if GTK_CHECK_VERSION(3,4,0)
2239         button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2240                                  G_CALLBACK(image_overlay_set_font_cb), notebook);
2241 #else
2242         button = gtk_font_button_new();
2243         gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2244         gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2245         g_signal_connect(G_OBJECT(button), "font-set",
2246                                  G_CALLBACK(image_overlay_set_font_cb),NULL);
2247 #endif
2248         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2249         gtk_widget_show(button);
2250
2251         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2252                                  G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2253         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2254         gtk_widget_show(button);
2255
2256         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2257                                  G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2258         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2259         gtk_widget_show(button);
2260         image_overlay_set_text_colours();
2261
2262         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2263                                  G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2264         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2265         gtk_widget_show(button);
2266
2267         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2268                                  G_CALLBACK(image_overlay_help_cb), NULL);
2269         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2270         gtk_widget_show(button);
2271
2272         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2273         if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2274         g_signal_connect(G_OBJECT(buffer), "changed",
2275                          G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2276
2277         pref_line(group, PREF_PAD_GAP);
2278
2279         group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2280         hbox = gtk_hbox_new(FALSE, 0);
2281         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2282         gtk_widget_show(hbox);
2283         label = gtk_label_new(_("%Exif.Image.Orientation%"));
2284         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2285         gtk_widget_show(label);
2286         pref_spacer(group,TRUE);
2287
2288         group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2289         hbox = gtk_hbox_new(FALSE, 0);
2290         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2291         gtk_widget_show(hbox);
2292         label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2293         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2294         gtk_widget_show(label);
2295         pref_spacer(group,TRUE);
2296
2297         group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2298         hbox = gtk_hbox_new(FALSE, 0);
2299         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2300         gtk_widget_show(hbox);
2301         label = gtk_label_new(_("%path:39%"));
2302         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2303         gtk_widget_show(label);
2304         pref_spacer(group,TRUE);
2305
2306         group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2307         hbox = gtk_hbox_new(FALSE, 0);
2308         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2309         gtk_widget_show(hbox);
2310         label = gtk_label_new(_("Text shown only if the field is non-null:\n%formatted.Aperture:F no. * setting%\n %formatted.Aperture:10:F no. * setting%"));
2311         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2312         gtk_widget_show(label);
2313         pref_spacer(group,TRUE);
2314
2315         group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2316         hbox = gtk_hbox_new(FALSE, 0);
2317         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2318         gtk_widget_show(hbox);
2319         label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2320         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2321         gtk_widget_show(label);
2322 }
2323
2324 static GtkTreeModel *create_class_model(void)
2325 {
2326         GtkListStore *model;
2327         GtkTreeIter iter;
2328         gint i;
2329
2330         /* create list store */
2331         model = gtk_list_store_new(1, G_TYPE_STRING);
2332         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2333                 {
2334                 gtk_list_store_append(model, &iter);
2335                 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2336                 }
2337         return GTK_TREE_MODEL (model);
2338 }
2339
2340
2341 /* filtering tab */
2342 static void config_tab_files(GtkWidget *notebook)
2343 {
2344         GtkWidget *hbox;
2345         GtkWidget *frame;
2346         GtkWidget *vbox;
2347         GtkWidget *group;
2348         GtkWidget *button;
2349         GtkWidget *ct_button;
2350         GtkWidget *scrolled;
2351         GtkWidget *filter_view;
2352         GtkCellRenderer *renderer;
2353         GtkTreeSelection *selection;
2354         GtkTreeViewColumn *column;
2355
2356         vbox = scrolled_notebook_page(notebook, _("Files"));
2357
2358         group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2359
2360         pref_checkbox_new_int(group, _("Show hidden files or folders"),
2361                               options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2362         pref_checkbox_new_int(group, _("Show parent folder (..)"),
2363                               options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2364         pref_checkbox_new_int(group, _("Case sensitive sort"),
2365                               options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2366         pref_checkbox_new_int(group, _("Natural sort order"),
2367                                           options->file_sort.natural, &c_options->file_sort.natural);
2368         pref_checkbox_new_int(group, _("Disable file extension checks"),
2369                               options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2370
2371         ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2372                                           options->file_filter.disable, &c_options->file_filter.disable);
2373
2374
2375         group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2376
2377         sidecar_ext_entry = gtk_entry_new();
2378         gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2379         gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2380         gtk_widget_show(sidecar_ext_entry);
2381
2382         group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2383
2384         frame = pref_group_parent(group);
2385         g_signal_connect(G_OBJECT(ct_button), "toggled",
2386                          G_CALLBACK(filter_disable_cb), frame);
2387         gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2388
2389         scrolled = gtk_scrolled_window_new(NULL, NULL);
2390         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2391         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2392         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2393         gtk_widget_show(scrolled);
2394
2395         filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2396         filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2397         g_object_unref(filter_store);
2398         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2399         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2400
2401         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2402
2403         column = gtk_tree_view_column_new();
2404         gtk_tree_view_column_set_title(column, _("Filter"));
2405         gtk_tree_view_column_set_resizable(column, TRUE);
2406
2407         renderer = gtk_cell_renderer_toggle_new();
2408         g_signal_connect(G_OBJECT(renderer), "toggled",
2409                          G_CALLBACK(filter_store_enable_cb), filter_store);
2410         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2411         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2412                                                 GINT_TO_POINTER(FE_ENABLE), NULL);
2413
2414         renderer = gtk_cell_renderer_text_new();
2415         g_signal_connect(G_OBJECT(renderer), "edited",
2416                          G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2417         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2418         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2419         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2420                                                 GINT_TO_POINTER(FE_EXTENSION), NULL);
2421         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2422
2423         column = gtk_tree_view_column_new();
2424         gtk_tree_view_column_set_title(column, _("Description"));
2425         gtk_tree_view_column_set_resizable(column, TRUE);
2426         gtk_tree_view_column_set_fixed_width(column, 200);
2427         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2428
2429         renderer = gtk_cell_renderer_text_new();
2430         g_signal_connect(G_OBJECT(renderer), "edited",
2431                          G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2432         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2433         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2434         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2435                                                 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2436         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2437
2438         column = gtk_tree_view_column_new();
2439         gtk_tree_view_column_set_title(column, _("Class"));
2440         gtk_tree_view_column_set_resizable(column, TRUE);
2441         renderer = gtk_cell_renderer_combo_new();
2442         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2443                                          "model", create_class_model(),
2444                                          "text-column", 0,
2445                                          "has-entry", FALSE,
2446                                          NULL);
2447
2448         g_signal_connect(G_OBJECT(renderer), "edited",
2449                          G_CALLBACK(filter_store_class_edit_cb), filter_store);
2450         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2451         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2452                                                 GINT_TO_POINTER(FE_CLASS), NULL);
2453         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2454
2455         column = gtk_tree_view_column_new();
2456         gtk_tree_view_column_set_title(column, _("Writable"));
2457         gtk_tree_view_column_set_resizable(column, FALSE);
2458         renderer = gtk_cell_renderer_toggle_new();
2459         g_signal_connect(G_OBJECT(renderer), "toggled",
2460                          G_CALLBACK(filter_store_writable_cb), filter_store);
2461         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2462         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2463                                                 GINT_TO_POINTER(FE_WRITABLE), NULL);
2464         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2465
2466         column = gtk_tree_view_column_new();
2467         gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2468         gtk_tree_view_column_set_resizable(column, FALSE);
2469         renderer = gtk_cell_renderer_toggle_new();
2470         g_signal_connect(G_OBJECT(renderer), "toggled",
2471                          G_CALLBACK(filter_store_sidecar_cb), filter_store);
2472         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2473         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2474                                                 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2475         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2476
2477
2478         filter_store_populate();
2479         gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2480         gtk_widget_show(filter_view);
2481
2482         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2483
2484         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2485                                  G_CALLBACK(filter_default_cb), filter_view);
2486         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2487         gtk_widget_show(button);
2488
2489         button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2490                                  G_CALLBACK(filter_remove_cb), filter_view);
2491         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2492         gtk_widget_show(button);
2493
2494         button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2495                                  G_CALLBACK(filter_add_cb), filter_view);
2496         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2497         gtk_widget_show(button);
2498 }
2499
2500 /* metadata tab */
2501 static void config_tab_metadata(GtkWidget *notebook)
2502 {
2503         GtkWidget *vbox;
2504         GtkWidget *hbox;
2505         GtkWidget *group;
2506         GtkWidget *ct_button;
2507         GtkWidget *label;
2508         gchar *text;
2509
2510         vbox = scrolled_notebook_page(notebook, _("Metadata"));
2511
2512
2513         group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2514 #ifndef HAVE_EXIV2
2515         label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2516 #endif
2517         label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2518         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2519
2520         ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2521                               options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2522 #ifndef HAVE_EXIV2
2523         gtk_widget_set_sensitive(ct_button, FALSE);
2524 #endif
2525
2526         pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2527                               options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2528
2529         text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2530         label = pref_label_new(group, text);
2531         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2532         gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2533         g_free(text);
2534
2535         group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2536 #ifndef HAVE_EXIV2
2537         gtk_widget_set_sensitive(group, FALSE);
2538 #endif
2539
2540         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2541         pref_checkbox_link_sensitivity(ct_button, hbox);
2542
2543         pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2544                               options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2545
2546         pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2547                               options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2548
2549         pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2550                               options->metadata.confirm_write, &c_options->metadata.confirm_write);
2551
2552         pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2553                               options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2554
2555         group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2556 #ifndef HAVE_EXIV2
2557         gtk_widget_set_sensitive(group, FALSE);
2558 #endif
2559
2560         pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2561                               options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2562
2563
2564         group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2565         pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2566                               options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2567
2568         pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2569                               options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2570
2571         ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2572                               options->metadata.write_orientation, &c_options->metadata.write_orientation);
2573 #ifndef HAVE_EXIV2
2574         gtk_widget_set_sensitive(ct_button, FALSE);
2575 #endif
2576
2577         group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2578
2579         ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2580                               options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2581
2582         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2583         pref_checkbox_link_sensitivity(ct_button, hbox);
2584
2585         pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2586                               options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2587
2588         pref_checkbox_new_int(group, _("Write metadata on image change"),
2589                               options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2590
2591         pref_checkbox_new_int(group, _("Write metadata on directory change"),
2592                               options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2593
2594         group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2595
2596         ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2597                                           options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2598         gtk_widget_set_tooltip_text(ct_button,"On folder change, read DateTimeOriginal, DateTimeDigitized and Star Rating in the idle loop.\nIf this is not selected, initial loading of the folder will be faster but sorting on these items will be slower");
2599 }
2600
2601 /* keywords tab */
2602
2603 typedef struct _KeywordFindData KeywordFindData;
2604 struct _KeywordFindData
2605 {
2606         GenericDialog *gd;
2607
2608         GList *list;
2609         GList *list_dir;
2610
2611         GtkWidget *button_close;
2612         GtkWidget *button_stop;
2613         GtkWidget *button_start;
2614         GtkWidget *progress;
2615         GtkWidget *spinner;
2616
2617         GtkWidget *group;
2618         GtkWidget *entry;
2619
2620         gboolean recurse;
2621
2622         guint idle_id; /* event source id */
2623 };
2624
2625 #define KEYWORD_DIALOG_WIDTH 400
2626
2627 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2628 {
2629         GList *list_d = NULL;
2630         GList *list_f = NULL;
2631
2632         if (kfd->recurse)
2633                 {
2634                 filelist_read(dir_fd, &list_f, &list_d);
2635                 }
2636         else
2637                 {
2638                 filelist_read(dir_fd, &list_f, NULL);
2639                 }
2640
2641         list_f = filelist_filter(list_f, FALSE);
2642         list_d = filelist_filter(list_d, TRUE);
2643
2644         kfd->list = g_list_concat(list_f, kfd->list);
2645         kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2646 }
2647
2648 static void keywords_find_reset(KeywordFindData *kfd)
2649 {
2650         filelist_free(kfd->list);
2651         kfd->list = NULL;
2652
2653         filelist_free(kfd->list_dir);
2654         kfd->list_dir = NULL;
2655 }
2656
2657 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2658 {
2659         KeywordFindData *kfd = data;
2660
2661         if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2662
2663         keywords_find_reset(kfd);
2664         generic_dialog_close(kfd->gd);
2665         g_free(kfd);
2666 }
2667
2668 static void keywords_find_finish(KeywordFindData *kfd)
2669 {
2670         keywords_find_reset(kfd);
2671
2672         gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2673         spinner_set_interval(kfd->spinner, -1);
2674
2675         gtk_widget_set_sensitive(kfd->group, TRUE);
2676         gtk_widget_set_sensitive(kfd->button_start, TRUE);
2677         gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2678         gtk_widget_set_sensitive(kfd->button_close, TRUE);
2679 }
2680
2681 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2682 {
2683         KeywordFindData *kfd = data;
2684
2685         g_idle_remove_by_data(kfd);
2686
2687         keywords_find_finish(kfd);
2688 }
2689
2690 static gboolean keywords_find_file(gpointer data)
2691 {
2692         KeywordFindData *kfd = data;
2693         GtkTextIter iter;
2694         GtkTextBuffer *buffer;
2695         gchar *tmp;
2696         GList *keywords;
2697
2698         if (kfd->list)
2699                 {
2700                 FileData *fd;
2701
2702                 fd = kfd->list->data;
2703                 kfd->list = g_list_remove(kfd->list, fd);
2704
2705                 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2706                 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2707
2708                 while (keywords)
2709                         {
2710                         gtk_text_buffer_get_end_iter(buffer, &iter);
2711                         tmp = g_strconcat(keywords->data, "\n", NULL);
2712                         gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2713                         g_free(tmp);
2714                         keywords = keywords->next;
2715                         }
2716
2717                 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2718                 file_data_unref(fd);
2719                 string_list_free(keywords);
2720
2721                 return (TRUE);
2722                 }
2723         else if (kfd->list_dir)
2724                 {
2725                 FileData *fd;
2726
2727                 fd = kfd->list_dir->data;
2728                 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2729
2730                 keywords_find_folder(kfd, fd);
2731
2732                 file_data_unref(fd);
2733
2734                 return TRUE;
2735                 }
2736
2737         keywords_find_finish(kfd);
2738
2739         return FALSE;
2740 }
2741
2742 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2743 {
2744         KeywordFindData *kfd = data;
2745         gchar *path;
2746
2747         if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2748
2749         path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2750         parse_out_relatives(path);
2751
2752         if (!isdir(path))
2753                 {
2754                 warning_dialog(_("Invalid folder"),
2755                                 _("The specified folder can not be found."),
2756                                 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2757                 }
2758         else
2759                 {
2760                 FileData *dir_fd;
2761
2762                 gtk_widget_set_sensitive(kfd->group, FALSE);
2763                 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2764                 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2765                 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2766                 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2767
2768                 dir_fd = file_data_new_dir(path);
2769                 keywords_find_folder(kfd, dir_fd);
2770                 file_data_unref(dir_fd);
2771                 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2772                 }
2773
2774         g_free(path);
2775 }
2776
2777 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2778 {
2779         KeywordFindData *kfd;
2780         GtkWidget *hbox;
2781         GtkWidget *label;
2782
2783         kfd = g_new0(KeywordFindData, 1);
2784
2785         kfd->gd = generic_dialog_new(_("Search for keywords"),
2786                                                                         "search_for_keywords",
2787                                                                         widget, FALSE,
2788                                                                         NULL, kfd);
2789         gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2790         kfd->gd->cancel_cb = keywords_find_close_cb;
2791         kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2792                                                      keywords_find_close_cb, FALSE);
2793         kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2794                                                      keywords_find_start_cb, FALSE);
2795         kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2796                                                     keywords_find_stop_cb, FALSE);
2797         gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2798
2799         generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2800
2801         hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2802         pref_spacer(hbox, PREF_PAD_INDENT);
2803         kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2804
2805         hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2806         pref_label_new(hbox, _("Folder:"));
2807
2808         label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2809         tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2810         gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2811         gtk_widget_show(label);
2812
2813         pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2814
2815         pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2816         hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2817
2818         kfd->progress = gtk_entry_new();
2819         gtk_widget_set_can_focus(kfd->progress, FALSE);
2820         gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2821         gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2822         gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2823         gtk_widget_show(kfd->progress);
2824
2825         kfd->spinner = spinner_new(NULL, -1);
2826         gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2827         gtk_widget_show(kfd->spinner);
2828
2829         kfd->list = NULL;
2830
2831         gtk_widget_show(kfd->gd->dialog);
2832 }
2833
2834 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2835 {
2836         const gchar *path = layout_get_path(NULL);
2837
2838         if (!path || !*path) path = homedir();
2839         keywords_find_dialog(widget, path);
2840 }
2841
2842 static void config_tab_keywords_save()
2843 {
2844         GtkTextIter start, end;
2845         GtkTextBuffer *buffer;
2846         GList *kw_list = NULL;
2847         GList *work;
2848         gchar *buffer_text;
2849         gchar *kw_split;
2850         gboolean found;
2851
2852         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2853         gtk_text_buffer_get_bounds(buffer, &start, &end);
2854
2855         buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
2856
2857         kw_split = strtok(buffer_text, "\n");
2858         while (kw_split != NULL)
2859                 {
2860                 work = kw_list;
2861                 found = FALSE;
2862                 while (work)
2863                         {
2864                         if (g_strcmp0(work->data, kw_split) == 0)
2865                                 {
2866                                 found = TRUE;
2867                                 break;
2868                                 }
2869                         work = work->next;
2870                         }
2871                 if (!found)
2872                         {
2873                         kw_list = g_list_append(kw_list, g_strdup(kw_split));
2874                         }
2875                 kw_split = strtok(NULL, "\n");
2876                 }
2877
2878         keyword_list_set(kw_list);
2879
2880         string_list_free(kw_list);
2881         g_free(buffer_text);
2882 }
2883
2884 static void config_tab_keywords(GtkWidget *notebook)
2885 {
2886         GtkWidget *hbox;
2887         GtkWidget *vbox;
2888         GtkWidget *group;
2889         GtkWidget *button;
2890         GtkWidget *scrolled;
2891         GtkTextIter iter;
2892         GtkTextBuffer *buffer;
2893         gchar *tmp;
2894
2895         vbox = scrolled_notebook_page(notebook, _("Keywords"));
2896
2897         group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
2898
2899         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2900
2901         button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
2902                                    G_CALLBACK(keywords_find_cb), keyword_text);
2903         gtk_widget_set_tooltip_text(button, "Search for existing keywords");
2904
2905
2906         keyword_text = gtk_text_view_new();
2907         gtk_widget_set_size_request(keyword_text, 20, 20);
2908         scrolled = gtk_scrolled_window_new(NULL, NULL);
2909         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2910         gtk_widget_show(scrolled);
2911
2912         gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
2913         gtk_widget_show(keyword_text);
2914
2915         gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
2916
2917         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2918         gtk_text_buffer_create_tag(buffer, "monospace",
2919                                 "family", "monospace", NULL);
2920
2921         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
2922         gtk_text_buffer_get_start_iter(buffer, &iter);
2923         gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
2924         gchar *path;
2925
2926         path = g_build_filename(get_rc_dir(), "keywords", NULL);
2927
2928         GList *kwl = keyword_list_get();
2929         kwl = g_list_first(kwl);
2930         while (kwl)
2931         {
2932                 gtk_text_buffer_get_end_iter (buffer, &iter);
2933             tmp = g_strconcat(kwl->data, "\n", NULL);
2934                 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2935                 kwl = kwl->next;
2936                 g_free(tmp);
2937         }
2938
2939         gtk_text_buffer_set_modified(buffer, FALSE);
2940
2941         g_free(path);
2942 }
2943
2944 /* metadata tab */
2945 #ifdef HAVE_LCMS
2946 static void intent_menu_cb(GtkWidget *combo, gpointer data)
2947 {
2948         gint *option = data;
2949
2950         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
2951                 {
2952                 case 0:
2953                 default:
2954                         *option = INTENT_PERCEPTUAL;
2955                         break;
2956                 case 1:
2957                         *option = INTENT_RELATIVE_COLORIMETRIC;
2958                         break;
2959                 case 2:
2960                         *option = INTENT_SATURATION;
2961                         break;
2962                 case 3:
2963                         *option = INTENT_ABSOLUTE_COLORIMETRIC;
2964                         break;
2965                 }
2966 }
2967
2968 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
2969                              gint option, gint *option_c)
2970 {
2971         GtkWidget *combo;
2972         gint current = 0;
2973
2974         *option_c = option;
2975
2976         pref_table_label(table, column, row, text, 0.0);
2977
2978         combo = gtk_combo_box_text_new();
2979
2980         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
2981         if (option == INTENT_PERCEPTUAL) current = 0;
2982         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
2983         if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
2984         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
2985         if (option == INTENT_SATURATION) current = 2;
2986         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
2987         if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
2988
2989         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
2990
2991         gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
2992
2993         g_signal_connect(G_OBJECT(combo), "changed",
2994                          G_CALLBACK(intent_menu_cb), option_c);
2995
2996         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
2997                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
2998         gtk_widget_show(combo);
2999 }
3000 #endif
3001
3002 static void config_tab_color(GtkWidget *notebook)
3003 {
3004         GtkWidget *label;
3005         GtkWidget *vbox;
3006         GtkWidget *group;
3007         GtkWidget *tabcomp;
3008         GtkWidget *table;
3009         gint i;
3010
3011         vbox = scrolled_notebook_page(notebook, _("Color management"));
3012
3013         group =  pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3014 #ifndef HAVE_LCMS
3015         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3016 #endif
3017
3018         table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3019         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3020
3021         label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3022         pref_label_bold(label, TRUE, FALSE);
3023
3024         label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3025         pref_label_bold(label, TRUE, FALSE);
3026
3027         label = pref_table_label(table, 2, 0, _("File"), 0.0);
3028         pref_label_bold(label, TRUE, FALSE);
3029
3030         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3031                 {
3032                 GtkWidget *entry;
3033                 gchar *buf;
3034
3035                 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3036                 pref_table_label(table, 0, i + 1, buf, 1.0);
3037                 g_free(buf);
3038
3039                 entry = gtk_entry_new();
3040                 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3041                 if (options->color_profile.input_name[i])
3042                         {
3043                         gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3044                         }
3045                 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3046                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
3047                 gtk_widget_show(entry);
3048                 color_profile_input_name_entry[i] = entry;
3049
3050                 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3051                 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3052                 gtk_widget_set_size_request(entry, 160, -1);
3053                 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3054                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
3055                 gtk_widget_show(tabcomp);
3056                 color_profile_input_file_entry[i] = entry;
3057                 }
3058
3059         group =  pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3060 #ifndef HAVE_LCMS
3061         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3062 #endif
3063         pref_checkbox_new_int(group, _("Use system screen profile if available"),
3064                               options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3065
3066         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3067
3068         pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3069         tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3070                                      options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3071         tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3072         gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3073 #ifdef HAVE_LCMS
3074         add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3075 #endif
3076         gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3077                          0, 1,
3078                          GTK_FILL | GTK_EXPAND, 0, 0, 0);
3079
3080         gtk_widget_show(tabcomp);
3081 }
3082
3083 /* advanced entry tab */
3084 static void config_tab_behavior(GtkWidget *notebook)
3085 {
3086         GtkWidget *hbox;
3087         GtkWidget *vbox;
3088         GtkWidget *group;
3089         GtkWidget *button;
3090         GtkWidget *tabcomp;
3091         GtkWidget *ct_button;
3092         GtkWidget *spin;
3093         GtkWidget *table;
3094         GtkWidget *marks;
3095         GtkWidget *with_rename;
3096         GtkWidget *collections_on_top;
3097
3098         vbox = scrolled_notebook_page(notebook, _("Behavior"));
3099
3100         group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3101
3102         pref_checkbox_new_int(group, _("Confirm file delete"),
3103                               options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3104         pref_checkbox_new_int(group, _("Enable Delete key"),
3105                               options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3106
3107         ct_button = pref_checkbox_new_int(group, _("Safe delete"),
3108                                           options->file_ops.safe_delete_enable, &c_options->file_ops.safe_delete_enable);
3109
3110         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3111         pref_checkbox_link_sensitivity(ct_button, hbox);
3112
3113         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3114         pref_label_new(hbox, _("Folder:"));
3115
3116         tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3117         tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3118         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3119         gtk_widget_show(tabcomp);
3120
3121         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3122         pref_checkbox_link_sensitivity(ct_button, hbox);
3123
3124         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3125         spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3126                                  0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3127         gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3128         button = pref_button_new(NULL, NULL, _("View"), FALSE,
3129                                  G_CALLBACK(safe_delete_view_cb), NULL);
3130         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3131         gtk_widget_show(button);
3132
3133         button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3134                                  G_CALLBACK(safe_delete_clear_cb), NULL);
3135         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3136         gtk_widget_show(button);
3137
3138
3139         group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3140
3141         pref_checkbox_new_int(group, _("Descend folders in tree view"),
3142                               options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3143
3144         pref_checkbox_new_int(group, _("In place renaming"),
3145                               options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3146
3147         pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3148                               options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3149
3150         marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3151                                 options->marks_save, &c_options->marks_save);
3152         gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3153
3154         with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3155                                 options->with_rename, &c_options->with_rename);
3156         gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3157
3158         collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3159                                 options->collections_on_top, &c_options->collections_on_top);
3160         gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3161
3162         pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3163                           1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3164
3165         pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3166                           16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3167
3168         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3169         add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3170
3171         group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3172
3173         pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3174                               options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3175         pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3176                           1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3177         pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3178                               options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3179         pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3180                               options->image_lm_click_nav, &c_options->image_lm_click_nav);
3181         pref_checkbox_new_int(group, _("Play video by left click on image"),
3182                               options->image_l_click_video, &c_options->image_l_click_video);
3183         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3184         add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3185
3186
3187 #ifdef DEBUG
3188         group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3189
3190         pref_spin_new_int(group, _("Debug level:"), NULL,
3191                           DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3192
3193         pref_checkbox_new_int(group, _("Timer data"),
3194                         options->log_window.timer_data, &c_options->log_window.timer_data);
3195
3196         pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3197                           1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3198 #endif
3199 }
3200
3201 /* accelerators tab */
3202 static void config_tab_accelerators(GtkWidget *notebook)
3203 {
3204         GtkWidget *hbox;
3205         GtkWidget *vbox;
3206         GtkWidget *group;
3207         GtkWidget *button;
3208         GtkWidget *scrolled;
3209         GtkWidget *accel_view;
3210         GtkCellRenderer *renderer;
3211         GtkTreeSelection *selection;
3212         GtkTreeViewColumn *column;
3213
3214         vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3215
3216         group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3217
3218         scrolled = gtk_scrolled_window_new(NULL, NULL);
3219         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3220         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3221         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3222         gtk_widget_show(scrolled);
3223
3224         accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3225
3226         accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3227         g_object_unref(accel_store);
3228         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3229         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3230
3231         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3232
3233         renderer = gtk_cell_renderer_text_new();
3234
3235         column = gtk_tree_view_column_new_with_attributes(_("Action"),
3236                                                           renderer,
3237                                                           "text", AE_ACTION,
3238                                                           NULL);
3239
3240         gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3241         gtk_tree_view_column_set_resizable(column, TRUE);
3242         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3243
3244
3245         renderer = gtk_cell_renderer_accel_new();
3246         g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3247                          G_CALLBACK(accel_store_cleared_cb), accel_store);
3248         g_signal_connect(G_OBJECT(renderer), "accel-edited",
3249                          G_CALLBACK(accel_store_edited_cb), accel_store);
3250
3251
3252         g_object_set (renderer,
3253                       "editable", TRUE,
3254                       "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3255                       NULL);
3256
3257         column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3258                                                           renderer,
3259                                                           "text", AE_KEY,
3260                                                           NULL);
3261
3262         gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3263         gtk_tree_view_column_set_resizable(column, TRUE);
3264         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3265
3266         renderer = gtk_cell_renderer_text_new();
3267
3268         column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3269                                                           renderer,
3270                                                           "text", AE_TOOLTIP,
3271                                                           NULL);
3272
3273         gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3274         gtk_tree_view_column_set_resizable(column, TRUE);
3275         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3276
3277         renderer = gtk_cell_renderer_text_new();
3278
3279         column = gtk_tree_view_column_new_with_attributes("Accel",
3280                                                           renderer,
3281                                                           "text", AE_ACCEL,
3282                                                           NULL);
3283
3284         gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3285         gtk_tree_view_column_set_resizable(column, TRUE);
3286         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3287
3288         accel_store_populate();
3289         gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3290         gtk_widget_show(accel_view);
3291
3292         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3293
3294         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3295                                  G_CALLBACK(accel_default_cb), accel_view);
3296         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3297         gtk_widget_show(button);
3298
3299         button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3300                                  G_CALLBACK(accel_reset_cb), accel_view);
3301         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3302         gtk_widget_show(button);
3303 }
3304
3305 /* toolbar tab */
3306 static void config_tab_toolbar(GtkWidget *notebook)
3307 {
3308         GtkWidget *vbox;
3309         GtkWidget *toolbardata;
3310         LayoutWindow *lw;
3311
3312         lw = layout_window_list->data;
3313
3314         vbox = scrolled_notebook_page(notebook, _("Toolbar"));
3315
3316         toolbardata = toolbar_select_new(lw);
3317         gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3318         gtk_widget_show(vbox);
3319 }
3320
3321 /* stereo tab */
3322 static void config_tab_stereo(GtkWidget *notebook)
3323 {
3324         GtkWidget *vbox;
3325         GtkWidget *group;
3326         GtkWidget *group2;
3327         GtkWidget *table;
3328         GtkWidget *box;
3329         GtkWidget *box2;
3330         GtkWidget *fs_button;
3331         vbox = scrolled_notebook_page(notebook, _("Stereo"));
3332
3333         group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3334
3335         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3336         add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3337
3338         table = pref_table_new(group, 2, 2, TRUE, FALSE);
3339         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3340         pref_checkbox_new_int(box, _("Mirror left image"),
3341                               options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3342         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3343         pref_checkbox_new_int(box, _("Flip left image"),
3344                               options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3345         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3346         pref_checkbox_new_int(box, _("Mirror right image"),
3347                               options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3348         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3349         pref_checkbox_new_int(box, _("Flip right image"),
3350                               options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3351         pref_checkbox_new_int(group, _("Swap left and right images"),
3352                               options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3353         pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3354                               options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3355
3356         group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3357         fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3358                               options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3359         box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3360         pref_checkbox_link_sensitivity(fs_button, box2);
3361         table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3362         add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3363         table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3364         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3365         pref_checkbox_new_int(box, _("Mirror left image"),
3366                               options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3367         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3368         pref_checkbox_new_int(box, _("Flip left image"),
3369                               options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3370         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3371         pref_checkbox_new_int(box, _("Mirror right image"),
3372                               options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3373         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3374         pref_checkbox_new_int(box, _("Flip right image"),
3375                               options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3376         pref_checkbox_new_int(box2, _("Swap left and right images"),
3377                               options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3378         pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3379                               options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3380
3381         group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3382         table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3383         pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3384                           1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3385         pref_table_spin_new_int(table, 3, 0,  _("Height"), NULL,
3386                           1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3387         pref_table_spin_new_int(table, 0, 1,  _("Left X"), NULL,
3388                           0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3389         pref_table_spin_new_int(table, 3, 1,  _("Left Y"), NULL,
3390                           0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3391         pref_table_spin_new_int(table, 0, 2,  _("Right X"), NULL,
3392                           0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3393         pref_table_spin_new_int(table, 3, 2,  _("Right Y"), NULL,
3394                           0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3395
3396 }
3397
3398 /* Main preferences window */
3399 static void config_window_create(void)
3400 {
3401         GtkWidget *win_vbox;
3402         GtkWidget *hbox;
3403         GtkWidget *notebook;
3404         GtkWidget *button;
3405         GtkWidget *ct_button;
3406
3407         if (!c_options) c_options = init_options(NULL);
3408
3409         configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3410         gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3411         g_signal_connect(G_OBJECT(configwindow), "delete_event",
3412                          G_CALLBACK(config_window_delete), NULL);
3413         gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3414         gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3415         gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3416
3417         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3418         gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3419         gtk_widget_show(win_vbox);
3420
3421         notebook = gtk_notebook_new();
3422         gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
3423         gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3424         gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3425
3426         config_tab_general(notebook);
3427         config_tab_image(notebook);
3428         config_tab_osd(notebook);
3429         config_tab_windows(notebook);
3430         config_tab_accelerators(notebook);
3431         config_tab_files(notebook);
3432         config_tab_metadata(notebook);
3433         config_tab_keywords(notebook);
3434         config_tab_color(notebook);
3435         config_tab_stereo(notebook);
3436         config_tab_behavior(notebook);
3437         config_tab_toolbar(notebook);
3438
3439         hbox = gtk_hbutton_box_new();
3440         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3441         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3442         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3443         gtk_widget_show(hbox);
3444
3445         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3446                                  G_CALLBACK(config_window_help_cb), notebook);
3447         gtk_container_add(GTK_CONTAINER(hbox), button);
3448         gtk_widget_set_can_default(button, TRUE);
3449         gtk_widget_show(button);
3450
3451         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3452                                  G_CALLBACK(config_window_ok_cb), NULL);
3453         gtk_container_add(GTK_CONTAINER(hbox), button);
3454         gtk_widget_set_can_default(button, TRUE);
3455         gtk_widget_grab_default(button);
3456         gtk_widget_show(button);
3457
3458         ct_button = button;
3459
3460         button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
3461                                  G_CALLBACK(config_window_save_cb), NULL);
3462         gtk_container_add(GTK_CONTAINER(hbox), button);
3463         gtk_widget_set_can_default(button, TRUE);
3464         gtk_widget_show(button);
3465
3466         button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
3467                                  G_CALLBACK(config_window_apply_cb), NULL);
3468         gtk_container_add(GTK_CONTAINER(hbox), button);
3469         gtk_widget_set_can_default(button, TRUE);
3470         gtk_widget_show(button);
3471
3472         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3473                                  G_CALLBACK(config_window_close_cb), NULL);
3474         gtk_container_add(GTK_CONTAINER(hbox), button);
3475         gtk_widget_set_can_default(button, TRUE);
3476         gtk_widget_show(button);
3477
3478         if (!generic_dialog_get_alternative_button_order(configwindow))
3479                 {
3480                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3481                 }
3482
3483         gtk_widget_show(notebook);
3484
3485         gtk_widget_show(configwindow);
3486 }
3487
3488 /*
3489  *-----------------------------------------------------------------------------
3490  * config window show (public)
3491  *-----------------------------------------------------------------------------
3492  */
3493
3494 void show_config_window(void)
3495 {
3496         if (configwindow)
3497                 {
3498                 gtk_window_present(GTK_WINDOW(configwindow));
3499                 return;
3500                 }
3501
3502         config_window_create();
3503 }
3504
3505 /*
3506  *-----------------
3507  * about window
3508  *-----------------
3509  */
3510
3511 void show_about_window(LayoutWindow *lw)
3512 {
3513         GdkPixbuf *pixbuf_logo;
3514         GdkPixbuf *pixbuf_icon;
3515         gchar *authors[1000];
3516         gchar *comment;
3517         gint i_authors = 0;
3518         gchar *path;
3519         GString *copyright;
3520         gchar *zd_path;
3521         ZoneDetect *cd;
3522         FILE *fp = NULL;
3523 #define LINE_LENGTH 1000
3524         gchar line[LINE_LENGTH];
3525
3526         copyright = g_string_new(NULL);
3527         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");
3528
3529         zd_path = g_build_filename(GQ_BIN_DIR, TIMEZONE_DATABASE, NULL);
3530         cd = ZDOpenDatabase(zd_path);
3531         if (cd)
3532                 {
3533                 copyright = g_string_append(copyright, ZDGetNotice(cd));
3534                 }
3535         ZDCloseDatabase(cd);
3536         g_free(zd_path);
3537
3538         authors[0] = NULL;
3539         path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3540         fp = fopen(path, "r");
3541         if (fp)
3542                 {
3543                 while(fgets(line, LINE_LENGTH, fp))
3544                         {
3545                         /* get rid of ending \n from fgets */
3546                         line[strlen(line) - 1] = '\0';
3547                         authors[i_authors] = g_strdup(line);
3548                         i_authors++;
3549                         }
3550                 authors[i_authors] = NULL;
3551                 fclose(fp);
3552                 }
3553         g_free(path);
3554
3555         comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3556                                                 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3557
3558         pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3559         pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3560         gtk_show_about_dialog(GTK_WINDOW(lw->window),
3561                 "title", _("About Geeqie"),
3562                 "resizable", TRUE,
3563                 "program-name", GQ_APPNAME,
3564                 "version", VERSION,
3565                 "logo", pixbuf_logo,
3566                 "icon", pixbuf_icon,
3567                 "website", GQ_WEBSITE,
3568                 "website-label", "Website",
3569                 "comments", comment,
3570                 "authors", authors,
3571                 "translator-credits", _("translator-credits"),
3572                 "wrap-license", TRUE,
3573                 "license", copyright->str,
3574                 NULL);
3575
3576         g_string_free(copyright, TRUE);
3577
3578         gint n = 0;
3579         while(n < i_authors)
3580                 {
3581                 g_free(authors[n]);
3582                 n++;
3583                 }
3584         g_free(comment);
3585
3586         return;
3587 }
3588
3589 static void image_overlay_set_text_colours()
3590 {
3591         c_options->image_overlay.text_red = options->image_overlay.text_red;
3592         c_options->image_overlay.text_green = options->image_overlay.text_green;
3593         c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3594         c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3595         c_options->image_overlay.background_red = options->image_overlay.background_red;
3596         c_options->image_overlay.background_green = options->image_overlay.background_green;
3597         c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3598         c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3599 }
3600 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */