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