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