2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
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.
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.
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.
23 #include "preferences.h"
26 #include "bar_keywords.h"
28 #include "cache_maint.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
43 #include "pixbuf_util.h"
44 #include "slideshow.h"
48 #include "ui_fileops.h"
50 #include "ui_spinner.h"
51 #include "ui_tabcomp.h"
52 #include "ui_utildlg.h"
54 #include "zonedetect.h"
64 #define EDITOR_NAME_MAX_LENGTH 32
65 #define EDITOR_COMMAND_MAX_LENGTH 1024
67 static void image_overlay_set_text_colours();
69 GtkWidget *keyword_text;
70 static void config_tab_keywords_save();
72 typedef struct _ThumbSize ThumbSize;
79 static ThumbSize thumb_size_list[] =
113 gchar *format_class_list[] = {
123 /* config memory values */
124 static ConfOptions *c_options = NULL;
131 static GtkWidget *configwindow = NULL;
132 static GtkListStore *filter_store = NULL;
133 static GtkTreeStore *accel_store = NULL;
135 static GtkWidget *safe_delete_path_entry;
137 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
138 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
139 static GtkWidget *color_profile_screen_file_entry;
141 static GtkWidget *sidecar_ext_entry;
142 static GtkWidget *help_search_engine_entry;
145 #define CONFIG_WINDOW_DEF_WIDTH 700
146 #define CONFIG_WINDOW_DEF_HEIGHT 600
149 *-----------------------------------------------------------------------------
150 * option widget callbacks (private)
151 *-----------------------------------------------------------------------------
154 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
156 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
159 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
161 gint mins_secs_tenths, delay;
163 mins_secs_tenths = c_options->slideshow.delay %
164 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
166 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
167 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
170 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
171 SLIDESHOW_SUBSECOND_PRECISION;
174 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
176 gint hours, secs_tenths, delay;
178 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
179 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
181 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
182 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
183 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
185 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
186 SLIDESHOW_SUBSECOND_PRECISION;
189 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
191 gint hours_mins, delay;
193 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
195 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
196 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
197 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
199 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
200 SLIDESHOW_SUBSECOND_PRECISION;
204 *-----------------------------------------------------------------------------
205 * sync progam to config window routine (private)
206 *-----------------------------------------------------------------------------
209 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
215 buf = gtk_entry_get_text(GTK_ENTRY(entry));
216 if (buf && strlen(buf) > 0)
221 *option = g_strdup(buf);
226 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
228 gchar *accel_path, *accel;
230 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
232 if (accel_path && accel_path[0])
235 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
236 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
246 static void config_window_apply(void)
249 gboolean refresh = FALSE;
251 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
253 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
254 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
255 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
256 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
257 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
258 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
259 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
261 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
262 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
263 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
264 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
265 options->file_ops.no_trash = c_options->file_ops.no_trash;
266 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
267 options->tools_restore_state = c_options->tools_restore_state;
268 options->save_window_positions = c_options->save_window_positions;
269 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
270 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
271 options->show_window_ids = c_options->show_window_ids;
272 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
273 options->image.zoom_2pass = c_options->image.zoom_2pass;
274 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
275 options->image.limit_window_size = c_options->image.limit_window_size;
276 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
277 options->image.max_window_size = c_options->image.max_window_size;
278 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
279 options->image.max_autofit_size = c_options->image.max_autofit_size;
280 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
281 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
282 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
283 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
285 if (options->thumbnails.max_width != c_options->thumbnails.max_width
286 || options->thumbnails.max_height != c_options->thumbnails.max_height
287 || options->thumbnails.quality != c_options->thumbnails.quality)
289 thumb_format_changed = TRUE;
291 options->thumbnails.max_width = c_options->thumbnails.max_width;
292 options->thumbnails.max_height = c_options->thumbnails.max_height;
293 options->thumbnails.quality = c_options->thumbnails.quality;
295 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
296 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
297 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
298 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
299 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
300 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
301 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
302 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
303 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
304 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
305 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
306 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
308 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
309 options->file_sort.natural = c_options->file_sort.natural;
310 options->file_filter.disable = c_options->file_filter.disable;
312 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
313 sidecar_ext_parse(options->sidecar.ext);
315 options->slideshow.random = c_options->slideshow.random;
316 options->slideshow.repeat = c_options->slideshow.repeat;
317 options->slideshow.delay = c_options->slideshow.delay;
319 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
320 options->image_lm_click_nav = c_options->image_lm_click_nav;
321 options->image_l_click_video = c_options->image_l_click_video;
322 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
324 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
326 options->image.tile_cache_max = c_options->image.tile_cache_max;
327 options->image.image_cache_max = c_options->image.image_cache_max;
329 options->image.zoom_quality = c_options->image.zoom_quality;
331 options->image.zoom_increment = c_options->image.zoom_increment;
333 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
336 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
337 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
338 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
340 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
341 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
342 options->image.border_color = c_options->image.border_color;
343 layout_colors_update();
344 view_window_colors_update();
347 options->image.alpha_color_1 = c_options->image.alpha_color_1;
348 options->image.alpha_color_2 = c_options->image.alpha_color_2;
350 options->fullscreen.screen = c_options->fullscreen.screen;
351 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
352 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
353 options->fullscreen.above = c_options->fullscreen.above;
354 if (c_options->image_overlay.template_string)
355 set_image_overlay_template_string(&options->image_overlay.template_string,
356 c_options->image_overlay.template_string);
357 if (c_options->image_overlay.font)
358 set_image_overlay_font_string(&options->image_overlay.font,
359 c_options->image_overlay.font);
360 options->image_overlay.text_red = c_options->image_overlay.text_red;
361 options->image_overlay.text_green = c_options->image_overlay.text_green;
362 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
363 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
364 options->image_overlay.background_red = c_options->image_overlay.background_red;
365 options->image_overlay.background_green = c_options->image_overlay.background_green;
366 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
367 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
368 options->update_on_time_change = c_options->update_on_time_change;
369 options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
371 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
372 options->rot_invariant_sim = c_options->rot_invariant_sim;
374 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
376 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
378 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
379 options->dnd_icon_size = c_options->dnd_icon_size;
380 options->clipboard_selection = c_options->clipboard_selection;
381 options->dnd_default_action = c_options->dnd_default_action;
383 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
384 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
385 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
386 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
387 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
388 options->metadata.confirm_write = c_options->metadata.confirm_write;
389 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
390 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
391 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
392 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
393 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
394 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
395 options->metadata.write_orientation = c_options->metadata.write_orientation;
396 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
397 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
398 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
399 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
400 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
401 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
402 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
403 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
404 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
405 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
406 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
407 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
408 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
409 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
410 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
411 options->stereo.fixed_w = c_options->stereo.fixed_w;
412 options->stereo.fixed_h = c_options->stereo.fixed_h;
413 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
414 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
415 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
416 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
418 options->info_keywords.height = c_options->info_keywords.height;
419 options->info_title.height = c_options->info_title.height;
420 options->info_comment.height = c_options->info_comment.height;
421 options->info_rating.height = c_options->info_rating.height;
423 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
425 options->marks_save = c_options->marks_save;
426 options->with_rename = c_options->with_rename;
427 options->collections_on_top = c_options->collections_on_top;
428 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
430 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
432 options->star_rating.star = c_options->star_rating.star;
433 options->star_rating.rejected = c_options->star_rating.rejected;
435 set_debug_level(debug_c);
439 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
441 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
442 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
444 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
445 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
446 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
448 options->color_profile.render_intent = c_options->color_profile.render_intent;
453 options->mouse_button_8 = c_options->mouse_button_8;
454 options->mouse_button_9 = c_options->mouse_button_9;
456 config_tab_keywords_save();
458 image_options_sync();
463 layout_refresh(NULL);
466 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
468 toolbar_apply(TOOLBAR_MAIN);
469 toolbar_apply(TOOLBAR_STATUS);
473 *-----------------------------------------------------------------------------
474 * config window main button callbacks (private)
475 *-----------------------------------------------------------------------------
478 static void config_window_close_cb(GtkWidget *widget, gpointer data)
480 gtk_widget_destroy(configwindow);
485 static void config_window_help_cb(GtkWidget *widget, gpointer data)
487 GtkWidget *notebook = data;
490 static gchar *html_section[] =
492 "GuideOptionsGeneral.html",
493 "GuideOptionsImage.html",
494 "GuideOptionsOSD.html",
495 "GuideOptionsWindow.html",
496 "GuideOptionsKeyboard.html",
497 "GuideOptionsFiltering.html",
498 "GuideOptionsMetadata.html",
499 "GuideOptionsKeywords.html",
500 "GuideOptionsColor.html",
501 "GuideOptionsStereo.html",
502 "GuideOptionsBehavior.html",
503 "GuideOptionsToolbar.html"
506 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
507 help_window_show(html_section[i]);
510 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
512 config_window_close_cb(NULL, NULL);
516 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
519 lw = layout_window_list->data;
521 config_window_apply();
522 layout_util_sync(lw);
523 save_options(options);
524 config_window_close_cb(NULL, NULL);
528 *-----------------------------------------------------------------------------
529 * config window setup (private)
530 *-----------------------------------------------------------------------------
533 static void quality_menu_cb(GtkWidget *combo, gpointer data)
537 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
541 *option = GDK_INTERP_NEAREST;
544 *option = GDK_INTERP_TILES;
547 *option = GDK_INTERP_BILINEAR;
550 *option = GDK_INTERP_HYPER;
555 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
559 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
563 *option = DND_ACTION_ASK;
566 *option = DND_ACTION_COPY;
569 *option = DND_ACTION_MOVE;
573 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
577 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
589 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
590 guint option, guint *option_c)
597 pref_table_label(table, column, row, text, 0.0);
599 combo = gtk_combo_box_text_new();
601 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
602 if (option == GDK_INTERP_NEAREST) current = 0;
603 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
604 if (option == GDK_INTERP_TILES) current = 1;
605 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
606 if (option == GDK_INTERP_BILINEAR) current = 2;
607 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
608 if (option == GDK_INTERP_HYPER) current = 3;
610 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
612 g_signal_connect(G_OBJECT(combo), "changed",
613 G_CALLBACK(quality_menu_cb), option_c);
615 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
616 gtk_widget_show(combo);
619 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
626 pref_table_label(table, column, row, text, 0.0);
628 combo = gtk_combo_box_text_new();
630 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
631 if (option == DND_ACTION_ASK) current = 0;
632 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
633 if (option == DND_ACTION_COPY) current = 1;
634 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
635 if (option == DND_ACTION_MOVE) current = 2;
637 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
639 g_signal_connect(G_OBJECT(combo), "changed",
640 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
642 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
643 gtk_widget_show(combo);
646 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
647 gint option, gint *option_c)
654 pref_table_label(table, column, row, text, 0.0);
656 combo = gtk_combo_box_text_new();
658 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
659 if (option == PRIMARY) current = 0;
660 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
661 if (option == CLIPBOARD) current = 1;
663 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
665 g_signal_connect(G_OBJECT(combo), "changed",
666 G_CALLBACK(clipboard_selection_menu_cb), option_c);
668 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
669 gtk_widget_show(combo);
672 typedef struct _UseableMouseItems UseableMouseItems;
673 struct _UseableMouseItems
675 gchar *name; /* GtkActionEntry terminology */
680 static const UseableMouseItems useable_mouse_items[] = {
682 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
683 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
684 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
685 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
686 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
687 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
688 {"Home", N_("Home"), GTK_STOCK_HOME},
689 {"Up", N_("Up"), GTK_STOCK_GO_UP},
690 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
691 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
692 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
693 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
694 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
695 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
696 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
697 {"Search", N_("Search"), GTK_STOCK_FIND},
698 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
699 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
700 {"Copy", N_("Copy"), GTK_STOCK_COPY},
701 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
702 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
703 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
704 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
705 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
706 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
707 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
708 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
709 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
710 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
711 {"Print", N_("Print"), GTK_STOCK_PRINT},
712 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
713 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
714 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
715 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
716 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
717 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
718 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
719 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
720 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
721 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
722 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
723 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
724 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
725 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
726 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
727 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
728 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
729 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
730 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
731 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
732 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
733 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
734 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
735 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
736 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
737 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
738 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
739 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
740 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
741 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
742 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
743 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
744 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
745 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
746 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
747 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
748 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
749 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
750 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
754 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
756 gchar **option = data;
759 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
761 const UseableMouseItems *list = useable_mouse_items;
765 if (g_strcmp0(list->label, label) == 0)
773 *option = g_strdup(list->name);
777 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
778 gchar *option, gchar **option_c)
786 pref_table_label(table, column, row, text, 0.0);
788 combo = gtk_combo_box_text_new();
790 const UseableMouseItems *list = useable_mouse_items;
794 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
795 if (g_strcmp0(list->name, option) == 0)
803 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
805 g_signal_connect(G_OBJECT(combo), "changed",
806 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
808 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
809 gtk_widget_show(combo);
812 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
816 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
819 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
821 c_options->thumbnails.max_width = thumb_size_list[n].w;
822 c_options->thumbnails.max_height = thumb_size_list[n].h;
826 c_options->thumbnails.max_width = options->thumbnails.max_width;
827 c_options->thumbnails.max_height = options->thumbnails.max_height;
831 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
837 c_options->thumbnails.max_width = options->thumbnails.max_width;
838 c_options->thumbnails.max_height = options->thumbnails.max_height;
840 pref_table_label(table, column, row, text, 0.0);
842 combo = gtk_combo_box_text_new();
845 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
850 w = thumb_size_list[i].w;
851 h = thumb_size_list[i].h;
853 buf = g_strdup_printf("%d x %d", w, h);
854 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
857 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
864 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
865 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
871 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
872 g_signal_connect(G_OBJECT(combo), "changed",
873 G_CALLBACK(thumb_size_menu_cb), NULL);
875 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
876 gtk_widget_show(combo);
879 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
883 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
887 *option = PR_STEREO_NONE;
890 *option = PR_STEREO_ANAGLYPH_RC;
893 *option = PR_STEREO_ANAGLYPH_GM;
896 *option = PR_STEREO_ANAGLYPH_YB;
899 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
902 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
905 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
908 *option = PR_STEREO_ANAGLYPH_DB_RC;
911 *option = PR_STEREO_ANAGLYPH_DB_GM;
914 *option = PR_STEREO_ANAGLYPH_DB_YB;
917 *option = PR_STEREO_HORIZ;
920 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
923 *option = PR_STEREO_VERT;
926 *option = PR_STEREO_VERT | PR_STEREO_HALF;
929 *option = PR_STEREO_FIXED;
934 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
935 gint option, gint *option_c, gboolean add_fixed)
942 pref_table_label(table, column, row, text, 0.0);
944 combo = gtk_combo_box_text_new();
946 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
948 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
949 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
950 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
951 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
952 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
953 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
954 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
955 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
956 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
957 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
958 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
959 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
960 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
961 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
962 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
963 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
964 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
965 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
967 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
968 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
969 if (option & PR_STEREO_HORIZ)
972 if (option & PR_STEREO_HALF) current = 11;
975 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
976 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
977 if (option & PR_STEREO_VERT)
980 if (option & PR_STEREO_HALF) current = 13;
985 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
986 if (option & PR_STEREO_FIXED) current = 14;
989 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
991 g_signal_connect(G_OBJECT(combo), "changed",
992 G_CALLBACK(stereo_mode_menu_cb), option_c);
994 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
995 gtk_widget_show(combo);
998 static void video_menu_cb(GtkWidget *combo, gpointer data)
1000 gchar **option = data;
1002 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1006 static void video_menu_populate(gpointer data, gpointer user_data)
1008 GtkWidget *combo = user_data;
1009 EditorDescription *ed = data;
1011 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1014 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1015 gchar *option, gchar **option_c)
1019 /* use lists since they are sorted */
1020 GList *eds = editor_list_get();
1024 pref_table_label(table, column, row, text, 0.0);
1026 combo = gtk_combo_box_text_new();
1027 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1028 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1030 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1032 g_signal_connect(G_OBJECT(combo), "changed",
1033 G_CALLBACK(video_menu_cb), option_c);
1035 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1036 gtk_widget_show(combo);
1039 static void filter_store_populate(void)
1043 if (!filter_store) return;
1045 gtk_list_store_clear(filter_store);
1047 work = filter_get_list();
1056 gtk_list_store_append(filter_store, &iter);
1057 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1061 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1062 gchar *new_text, gpointer data)
1064 GtkWidget *model = data;
1065 FilterEntry *fe = data;
1069 if (!new_text || strlen(new_text) < 1) return;
1071 tpath = gtk_tree_path_new_from_string(path_str);
1072 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1073 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1075 g_free(fe->extensions);
1076 fe->extensions = g_strdup(new_text);
1078 gtk_tree_path_free(tpath);
1082 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1083 gchar *new_text, gpointer data)
1085 GtkWidget *model = data;
1086 FilterEntry *fe = data;
1091 if (!new_text || !new_text[0]) return;
1093 tpath = gtk_tree_path_new_from_string(path_str);
1094 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1095 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1097 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1099 if (strcmp(new_text, _(format_class_list[i])) == 0)
1106 gtk_tree_path_free(tpath);
1110 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1111 gchar *new_text, gpointer data)
1113 GtkWidget *model = data;
1118 if (!new_text || !new_text[0]) return;
1120 tpath = gtk_tree_path_new_from_string(path_str);
1121 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1122 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1124 g_free(fe->description);
1125 fe->description = g_strdup(new_text);
1127 gtk_tree_path_free(tpath);
1130 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1131 gchar *path_str, gpointer data)
1133 GtkWidget *model = data;
1138 tpath = gtk_tree_path_new_from_string(path_str);
1139 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1140 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1142 fe->enabled = !fe->enabled;
1144 gtk_tree_path_free(tpath);
1148 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1149 gchar *path_str, gpointer data)
1151 GtkWidget *model = data;
1156 tpath = gtk_tree_path_new_from_string(path_str);
1157 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1158 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1160 fe->writable = !fe->writable;
1161 if (fe->writable) fe->allow_sidecar = FALSE;
1163 gtk_tree_path_free(tpath);
1167 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1168 gchar *path_str, gpointer data)
1170 GtkWidget *model = data;
1175 tpath = gtk_tree_path_new_from_string(path_str);
1176 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1177 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1179 fe->allow_sidecar = !fe->allow_sidecar;
1180 if (fe->allow_sidecar) fe->writable = FALSE;
1182 gtk_tree_path_free(tpath);
1186 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1187 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1191 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1193 switch (GPOINTER_TO_INT(data))
1196 g_object_set(GTK_CELL_RENDERER(cell),
1197 "active", fe->enabled, NULL);
1200 g_object_set(GTK_CELL_RENDERER(cell),
1201 "text", fe->extensions, NULL);
1203 case FE_DESCRIPTION:
1204 g_object_set(GTK_CELL_RENDERER(cell),
1205 "text", fe->description, NULL);
1208 g_object_set(GTK_CELL_RENDERER(cell),
1209 "text", _(format_class_list[fe->file_class]), NULL);
1212 g_object_set(GTK_CELL_RENDERER(cell),
1213 "active", fe->writable, NULL);
1215 case FE_ALLOW_SIDECAR:
1216 g_object_set(GTK_CELL_RENDERER(cell),
1217 "active", fe->allow_sidecar, NULL);
1222 static gboolean filter_add_scroll(gpointer data)
1226 GtkCellRenderer *cell;
1227 GtkTreeViewColumn *column;
1232 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1233 path = gtk_tree_path_new_from_indices(rows-1, -1);
1235 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1237 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1238 cell = g_list_last(list_cells)->data;
1240 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1241 path, column, FALSE, 0.0, 0.0 );
1242 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1243 path, column, cell, TRUE);
1245 gtk_tree_path_free(path);
1246 g_list_free(list_cells);
1251 static void filter_add_cb(GtkWidget *widget, gpointer data)
1253 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1254 filter_store_populate();
1256 g_idle_add((GSourceFunc)filter_add_scroll, data);
1259 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1261 GtkWidget *filter_view = data;
1262 GtkTreeSelection *selection;
1266 if (!filter_store) return;
1267 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1268 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1269 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1272 filter_remove_entry(fe);
1274 filter_store_populate();
1277 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1281 GtkTreeViewColumn *column;
1283 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1284 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1285 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1287 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1291 gtk_tree_path_free(path);
1296 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1299 filter_add_defaults();
1301 filter_store_populate();
1303 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1306 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1308 /* no op, only so cancel button appears */
1311 static void filter_default_cb(GtkWidget *widget, gpointer data)
1315 gd = generic_dialog_new(_("Reset filters"),
1316 "reset_filter", widget, TRUE,
1317 dummy_cancel_cb, data);
1318 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1319 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1320 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1321 gtk_widget_show(gd->dialog);
1324 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1326 GtkWidget *frame = data;
1328 gtk_widget_set_sensitive(frame,
1329 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1332 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1334 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1337 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1339 file_util_trash_clear();
1342 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1346 gd = generic_dialog_new(_("Clear trash"),
1347 "clear_trash", widget, TRUE,
1348 dummy_cancel_cb, NULL);
1349 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1350 _("This will remove the trash contents."), FALSE);
1351 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1352 entry = gtk_entry_new();
1353 gtk_widget_set_can_focus(entry, FALSE);
1354 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1355 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1356 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1357 gtk_widget_show(entry);
1358 gtk_widget_show(gd->dialog);
1361 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1363 GtkWidget *pTextView;
1364 GtkTextBuffer *pTextBuffer;
1368 pTextView = GTK_WIDGET(data);
1370 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1371 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1372 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1374 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1375 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1378 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1380 GtkTextView *text_view = data;
1381 GtkTextBuffer *buffer;
1383 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1384 if (!configwindow) return;
1386 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1387 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1390 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1394 gd = generic_dialog_new(_("Reset image overlay template string"),
1395 "reset_image_overlay_template_string", widget, TRUE,
1396 dummy_cancel_cb, data);
1397 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1398 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1399 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1400 gtk_widget_show(gd->dialog);
1403 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1405 help_window_show("GuideOptionsOSD.html");
1408 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1410 #if GTK_CHECK_VERSION(3,4,0)
1413 PangoFontDescription *font_desc;
1415 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1416 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1418 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1420 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1421 font = pango_font_description_to_string(font_desc);
1422 g_free(c_options->image_overlay.font);
1423 c_options->image_overlay.font = g_strdup(font);
1427 gtk_widget_destroy(dialog);
1431 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1432 c_options->image_overlay.font = g_strdup(font);
1436 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1439 #if GTK_CHECK_VERSION(3,4,0)
1442 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1443 colour.red = options->image_overlay.text_red;
1444 colour.green = options->image_overlay.text_green;
1445 colour.blue = options->image_overlay.text_blue;
1446 colour.alpha = options->image_overlay.text_alpha;
1447 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1448 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1450 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1452 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1453 c_options->image_overlay.text_red = colour.red*255;
1454 c_options->image_overlay.text_green = colour.green*255;
1455 c_options->image_overlay.text_blue = colour.blue*255;
1456 c_options->image_overlay.text_alpha = colour.alpha*255;
1458 gtk_widget_destroy(dialog);
1461 GtkColorSelection *colorsel;
1463 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1464 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1465 colour.red = options->image_overlay.text_red*257;
1466 colour.green = options->image_overlay.text_green*257;
1467 colour.blue = options->image_overlay.text_blue*257;
1468 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1469 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1470 gtk_color_selection_set_current_color(colorsel, &colour);
1471 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1473 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1475 gtk_color_selection_get_current_color(colorsel, &colour);
1476 c_options->image_overlay.text_red = colour.red/257;
1477 c_options->image_overlay.text_green = colour.green/257;
1478 c_options->image_overlay.text_blue = colour.blue/257;
1479 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1481 gtk_widget_destroy (dialog);
1486 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1489 #if GTK_CHECK_VERSION(3,4,0)
1492 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1493 colour.red = options->image_overlay.background_red;
1494 colour.green = options->image_overlay.background_green;
1495 colour.blue = options->image_overlay.background_blue;
1496 colour.alpha = options->image_overlay.background_alpha;
1497 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1498 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1500 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1502 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1503 c_options->image_overlay.background_red = colour.red*255;
1504 c_options->image_overlay.background_green = colour.green*255;
1505 c_options->image_overlay.background_blue = colour.blue*255;
1506 c_options->image_overlay.background_alpha = colour.alpha*255;
1508 gtk_widget_destroy(dialog);
1511 GtkColorSelection *colorsel;
1513 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1514 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1515 colour.red = options->image_overlay.background_red*257;
1516 colour.green = options->image_overlay.background_green*257;
1517 colour.blue = options->image_overlay.background_blue*257;
1518 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1519 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1520 gtk_color_selection_set_current_color(colorsel, &colour);
1521 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1523 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1525 gtk_color_selection_get_current_color(colorsel, &colour);
1526 c_options->image_overlay.background_red = colour.red/257;
1527 c_options->image_overlay.background_green = colour.green/257;
1528 c_options->image_overlay.background_blue = colour.blue/257;
1529 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1531 gtk_widget_destroy(dialog);
1535 static void accel_store_populate(void)
1538 GList *groups, *actions;
1540 const gchar *accel_path;
1544 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1546 gtk_tree_store_clear(accel_store);
1547 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1549 g_assert(lw && lw->ui_manager);
1550 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1553 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1556 action = GTK_ACTION(actions->data);
1557 accel_path = gtk_action_get_accel_path(action);
1558 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1560 gchar *label, *label2, *tooltip, *accel;
1561 g_object_get(action,
1562 "tooltip", &tooltip,
1566 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1572 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1576 gtk_tree_store_append(accel_store, &iter, NULL);
1577 gtk_tree_store_set(accel_store, &iter,
1580 AE_TOOLTIP, tooltip ? tooltip : "",
1581 AE_ACCEL, accel_path,
1589 actions = actions->next;
1592 groups = groups->next;
1596 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1601 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1603 gchar *accel1 = data;
1608 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1610 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1611 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1613 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1615 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1616 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1625 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1627 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1631 GtkAccelKey old_key, key;
1632 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1634 gtk_tree_model_get_iter(model, &iter, path);
1635 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1637 /* test if the accelerator can be stored without conflicts*/
1638 gtk_accel_map_lookup_entry(accel_path, &old_key);
1640 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1641 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1642 gtk_accel_map_lookup_entry(accel_path, &key);
1644 /* restore the original for now, the key will be really changed when the changes are confirmed */
1645 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1647 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1648 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1650 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1651 gtk_tree_path_free(path);
1655 static gboolean accel_default_scroll(GtkTreeView *data)
1659 GtkTreeViewColumn *column;
1661 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1662 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1663 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1665 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1669 gtk_tree_path_free(path);
1674 static void accel_default_cb(GtkWidget *widget, gpointer data)
1676 accel_store_populate();
1678 g_idle_add((GSourceFunc)accel_default_scroll, data);
1681 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1683 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1686 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1689 gchar *accel_path, *accel;
1691 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1692 gtk_accel_map_lookup_entry(accel_path, &key);
1693 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1695 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1697 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1702 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1704 GtkTreeSelection *selection;
1706 if (!accel_store) return;
1707 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1708 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1713 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1717 GtkWidget *scrolled;
1718 GtkWidget *viewport;
1720 scrolled = gtk_scrolled_window_new(NULL, NULL);
1721 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1722 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1723 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1724 label = gtk_label_new(title);
1725 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1726 gtk_widget_show(scrolled);
1728 viewport = gtk_viewport_new(NULL, NULL);
1729 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1730 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1731 gtk_widget_show(viewport);
1733 vbox = gtk_vbox_new(FALSE, 0);
1734 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1735 gtk_widget_show(vbox);
1740 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1742 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1744 c_options->thumbnails.spec_standard =TRUE;
1745 c_options->thumbnails.cache_into_dirs = FALSE;
1749 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1751 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1753 c_options->thumbnails.spec_standard =FALSE;
1754 c_options->thumbnails.cache_into_dirs = FALSE;
1758 static void cache_local_cb(GtkWidget *widget, gpointer data)
1760 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1762 c_options->thumbnails.cache_into_dirs = TRUE;
1763 c_options->thumbnails.spec_standard =FALSE;
1767 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1768 GdkEvent *event, gpointer userdata)
1770 if (pos == GTK_ENTRY_ICON_PRIMARY)
1772 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1776 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1780 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1781 GdkEvent *event, gpointer userdata)
1783 gchar *rating_symbol;
1785 if (pos == GTK_ENTRY_ICON_PRIMARY)
1787 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1788 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1789 g_free(rating_symbol);
1793 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1794 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1795 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1799 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1800 GdkEvent *event, gpointer userdata)
1802 gchar *rating_symbol;
1804 if (pos == GTK_ENTRY_ICON_PRIMARY)
1806 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1807 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1808 g_free(rating_symbol);
1812 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1813 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1814 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1818 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1820 GtkContainer *hbox = data;
1821 GString *str = g_string_new(NULL);
1822 GtkEntry *hex_code_entry;
1823 gchar *hex_code_full;
1826 guint64 hex_value = 0;
1828 list = gtk_container_get_children(hbox);
1830 hex_code_entry = g_list_nth_data(list, 2);
1831 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1833 hex_code = g_strsplit(hex_code_full, "+", 2);
1834 if (hex_code[0] && hex_code[1])
1836 hex_value = strtoull(hex_code[1], NULL, 16);
1838 if (!hex_value || hex_value > 0x10FFFF)
1840 hex_value = 0x003F; // Unicode 'Question Mark'
1842 str = g_string_append_unichar(str, (gunichar)hex_value);
1843 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1845 g_strfreev(hex_code);
1846 g_string_free(str, TRUE);
1847 g_free(hex_code_full);
1852 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1854 guint64 star_symbol;
1856 star_symbol = star_rating_symbol_test(widget, data);
1857 c_options->star_rating.star = star_symbol;
1860 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1862 guint64 rejected_symbol;
1864 rejected_symbol = star_rating_symbol_test(widget, data);
1865 c_options->star_rating.rejected = rejected_symbol;
1868 /* general options tab */
1869 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1870 typedef struct _TZData TZData;
1874 GCancellable *cancellable;
1876 GtkWidget *progress;
1878 GFile *timezone_database_gq;
1879 gchar *timezone_database_user;
1882 static void config_tab_general(GtkWidget *notebook)
1887 GtkWidget *group_frame;
1888 GtkWidget *subgroup;
1890 GtkWidget *ct_button;
1893 gint hours, minutes, remainder;
1895 GtkWidget *star_rating_entry;
1897 gchar *rating_symbol;
1900 GNetworkMonitor *net_mon;
1901 GSocketConnectable *geeqie_org;
1902 gboolean internet_available;
1905 vbox = scrolled_notebook_page(notebook, _("General"));
1907 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1909 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1910 add_thumb_size_menu(table, 0, 0, _("Size:"));
1911 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1913 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1914 pref_label_new(hbox, _("Custom size: "));
1915 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1916 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1918 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1919 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1921 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1922 pref_checkbox_link_sensitivity(ct_button, subgroup);
1924 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1925 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1926 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1927 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1928 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1929 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1930 G_CALLBACK(cache_geeqie_cb), NULL);
1932 group_frame = pref_frame_new(subgroup, TRUE,
1933 _("Store thumbnails local to image folder (non-standard)"),
1934 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1935 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1936 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1937 G_CALLBACK(cache_local_cb), NULL);
1939 group_frame = pref_frame_new(subgroup, TRUE,
1940 _("Use standard thumbnail style and cache, shared with other applications"),
1941 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1942 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1943 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1944 G_CALLBACK(cache_standard_cb), NULL);
1946 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1947 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1949 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1951 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1952 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1954 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1955 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1956 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1958 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1959 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1962 pref_spacer(group, PREF_PAD_GROUP);
1964 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1966 c_options->star_rating.star = options->star_rating.star;
1967 c_options->star_rating.rejected = options->star_rating.rejected;
1969 str = g_string_new(NULL);
1970 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1971 pref_label_new(hbox, "Star character: ");
1972 str = g_string_append_unichar(str, options->star_rating.star);
1973 pref_label_new(hbox, g_strdup(str->str));
1974 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1975 star_rating_entry = gtk_entry_new();
1976 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1977 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1978 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1979 gtk_widget_show(star_rating_entry);
1980 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1981 G_CALLBACK(star_rating_star_test_cb), hbox);
1982 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1983 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1984 gtk_widget_show(button);
1985 gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
1986 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1987 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1988 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1989 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1990 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1991 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1992 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1993 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1994 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1995 G_CALLBACK(star_rating_star_icon_cb),
1998 g_string_free(str, TRUE);
1999 g_free(rating_symbol);
2001 str = g_string_new(NULL);
2002 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2003 pref_label_new(hbox, "Rejected character: ");
2004 str = g_string_append_unichar(str, options->star_rating.rejected);
2005 pref_label_new(hbox, g_strdup(str->str));
2006 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2007 star_rating_entry = gtk_entry_new();
2008 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2009 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2010 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2011 gtk_widget_show(star_rating_entry);
2012 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2013 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2014 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2015 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2016 gtk_widget_show(button);
2017 gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
2018 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2019 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2020 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2021 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2022 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2023 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2024 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2025 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2026 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2027 G_CALLBACK(star_rating_rejected_icon_cb),
2030 g_string_free(str, TRUE);
2031 g_free(rating_symbol);
2033 pref_spacer(group, PREF_PAD_GROUP);
2035 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2037 c_options->slideshow.delay = options->slideshow.delay;
2038 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2039 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2040 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2041 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2042 SLIDESHOW_SUBSECOND_PRECISION;
2044 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2046 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2048 options->slideshow.delay ? hours : 0.0,
2049 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2050 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2051 spin = pref_spin_new(hbox, ":" , NULL,
2053 options->slideshow.delay ? minutes: 0.0,
2054 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2055 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2056 spin = pref_spin_new(hbox, ":", NULL,
2057 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2058 options->slideshow.delay ? seconds : 10.0,
2059 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2060 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2062 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2063 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2065 pref_spacer(group, PREF_PAD_GROUP);
2067 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2069 pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
2070 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2071 pref_checkbox_new_int(group, _("Preload next image"),
2072 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2074 pref_checkbox_new_int(group, _("Refresh on file change"),
2075 options->update_on_time_change, &c_options->update_on_time_change);
2077 pref_spacer(group, PREF_PAD_GROUP);
2079 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2080 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2081 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2082 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2084 options->info_keywords.height, &c_options->info_keywords.height);
2085 pref_spin_new_int(hbox, _("Title:"), NULL,
2087 options->info_title.height, &c_options->info_title.height);
2088 pref_spin_new_int(hbox, _("Comment:"), NULL,
2090 options->info_comment.height, &c_options->info_comment.height);
2091 pref_spin_new_int(hbox, _("Rating:"), NULL,
2093 options->info_rating.height, &c_options->info_rating.height);
2095 pref_spacer(group, PREF_PAD_GROUP);
2097 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2099 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2100 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2102 pref_spacer(group, PREF_PAD_GROUP);
2104 net_mon = g_network_monitor_get_default();
2105 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2106 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2107 g_object_unref(geeqie_org);
2109 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2110 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2112 if (!internet_available)
2114 gtk_widget_set_sensitive(group, FALSE);
2117 tz = g_new0(TZData, 1);
2119 path = path_from_utf8(TIMEZONE_DATABASE);
2120 basename = g_path_get_basename(path);
2121 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2125 if (isfile(tz->timezone_database_user))
2127 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2131 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2134 if (!internet_available)
2136 gtk_widget_set_tooltip_text(button, _("No Internet connection!\nThe timezone database is used to display exif time and date\ncorrected for UTC offset and Daylight Saving Time"));
2140 gtk_widget_set_tooltip_text(button, _("The timezone database is used to display exif time and date\ncorrected for UTC offset and Daylight Saving Time"));
2142 gtk_widget_show(button);
2144 pref_spacer(group, PREF_PAD_GROUP);
2146 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2148 help_search_engine_entry = gtk_entry_new();
2149 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2150 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2151 gtk_widget_show(help_search_engine_entry);
2153 gtk_widget_set_tooltip_text(help_search_engine_entry, _("The format varies between search engines, e.g the format may be:\nhttps://www.search_engine.com/search?q=site:geeqie.org/help\nhttps://www.search_engine.com/?q=site:geeqie.org/help"));
2155 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2156 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2157 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2158 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2159 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2160 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2161 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2162 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2163 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2164 G_CALLBACK(help_search_engine_entry_icon_cb),
2165 help_search_engine_entry);
2169 static void config_tab_image(GtkWidget *notebook)
2174 GtkWidget *ct_button;
2175 GtkWidget *enlargement_button;
2179 vbox = scrolled_notebook_page(notebook, _("Image"));
2181 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2183 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2184 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2187 pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
2188 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2191 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2192 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2194 c_options->image.zoom_increment = options->image.zoom_increment;
2195 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2196 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2197 G_CALLBACK(zoom_increment_cb), NULL);
2198 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2200 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2202 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2203 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2204 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2205 spin = pref_spin_new_int(hbox, NULL, NULL,
2207 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2208 pref_checkbox_link_sensitivity(enlargement_button, spin);
2209 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."));
2211 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2212 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2213 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2214 spin = pref_spin_new_int(hbox, NULL, NULL,
2216 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2217 pref_checkbox_link_sensitivity(ct_button, spin);
2218 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."));
2220 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2222 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2223 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2225 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2226 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2228 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2229 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2231 c_options->image.border_color = options->image.border_color;
2233 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2234 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2236 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2237 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2239 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2240 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2242 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2244 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2245 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2249 static void config_tab_windows(GtkWidget *notebook)
2255 GtkWidget *ct_button;
2258 vbox = scrolled_notebook_page(notebook, _("Windows"));
2260 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2262 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2263 options->save_window_positions, &c_options->save_window_positions);
2265 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2266 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2267 pref_checkbox_link_sensitivity(ct_button, button);
2269 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2270 options->tools_restore_state, &c_options->tools_restore_state);
2272 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2273 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2275 pref_checkbox_new_int(group, _("Show window IDs"),
2276 options->show_window_ids, &c_options->show_window_ids);
2278 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2280 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2281 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2283 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2284 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2285 options->image.limit_window_size, &c_options->image.limit_window_size);
2286 spin = pref_spin_new_int(hbox, NULL, NULL,
2288 options->image.max_window_size, &c_options->image.max_window_size);
2289 pref_checkbox_link_sensitivity(ct_button, spin);
2291 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2293 c_options->fullscreen.screen = options->fullscreen.screen;
2294 c_options->fullscreen.above = options->fullscreen.above;
2295 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2296 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2297 gtk_widget_show(hbox);
2299 pref_checkbox_new_int(group, _("Smooth image flip"),
2300 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2301 pref_checkbox_new_int(group, _("Disable screen saver"),
2302 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2305 #define PRE_FORMATTED_COLUMNS 5
2306 static void config_tab_osd(GtkWidget *notebook)
2310 GtkWidget *vbox_buttons;
2313 GtkWidget *image_overlay_template_view;
2314 GtkWidget *scrolled;
2315 GtkWidget *scrolled_pre_formatted;
2316 GtkTextBuffer *buffer;
2318 GtkWidget * subgroup;
2323 vbox = scrolled_notebook_page(notebook, _("OSD"));
2325 image_overlay_template_view = gtk_text_view_new();
2327 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2329 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2331 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2332 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2333 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2334 gtk_widget_show(scrolled_pre_formatted);
2335 gtk_widget_show(subgroup);
2337 pref_line(group, PREF_PAD_GAP);
2339 pref_label_new(group, _("Image overlay template"));
2341 scrolled = gtk_scrolled_window_new(NULL, NULL);
2342 gtk_widget_set_size_request(scrolled, 200, 150);
2343 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2344 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2345 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2346 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2347 gtk_widget_show(scrolled);
2349 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2350 _("Extensive formatting options are shown in the Help file"));
2352 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2353 gtk_widget_show(image_overlay_template_view);
2355 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2357 #if GTK_CHECK_VERSION(3,4,0)
2358 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2359 G_CALLBACK(image_overlay_set_font_cb), notebook);
2361 button = gtk_font_button_new();
2362 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2363 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2364 g_signal_connect(G_OBJECT(button), "font-set",
2365 G_CALLBACK(image_overlay_set_font_cb),NULL);
2367 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2368 gtk_widget_show(button);
2370 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2371 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2372 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2373 gtk_widget_show(button);
2375 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2376 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2377 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2378 gtk_widget_show(button);
2379 image_overlay_set_text_colours();
2381 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2382 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2383 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2384 gtk_widget_show(button);
2386 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2387 G_CALLBACK(image_overlay_help_cb), NULL);
2388 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2389 gtk_widget_show(button);
2391 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2392 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2393 g_signal_connect(G_OBJECT(buffer), "changed",
2394 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2396 pref_line(group, PREF_PAD_GAP);
2398 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2399 hbox = gtk_hbox_new(FALSE, 0);
2400 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2401 gtk_widget_show(hbox);
2402 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2403 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2404 gtk_widget_show(label);
2405 pref_spacer(group,TRUE);
2407 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2408 hbox = gtk_hbox_new(FALSE, 0);
2409 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2410 gtk_widget_show(hbox);
2411 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2412 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2413 gtk_widget_show(label);
2414 pref_spacer(group,TRUE);
2416 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2417 hbox = gtk_hbox_new(FALSE, 0);
2418 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2419 gtk_widget_show(hbox);
2420 label = gtk_label_new(_("%path:39%"));
2421 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2422 gtk_widget_show(label);
2423 pref_spacer(group,TRUE);
2425 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2426 hbox = gtk_hbox_new(FALSE, 0);
2427 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2428 gtk_widget_show(hbox);
2429 label = gtk_label_new(_("Text shown only if the field is non-null:\n%formatted.Aperture:F no. * setting%\n %formatted.Aperture:10:F no. * setting%"));
2430 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2431 gtk_widget_show(label);
2432 pref_spacer(group,TRUE);
2434 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2435 hbox = gtk_hbox_new(FALSE, 0);
2436 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2437 gtk_widget_show(hbox);
2438 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2439 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2440 gtk_widget_show(label);
2443 static GtkTreeModel *create_class_model(void)
2445 GtkListStore *model;
2449 /* create list store */
2450 model = gtk_list_store_new(1, G_TYPE_STRING);
2451 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2453 gtk_list_store_append(model, &iter);
2454 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2456 return GTK_TREE_MODEL (model);
2461 static void config_tab_files(GtkWidget *notebook)
2468 GtkWidget *ct_button;
2469 GtkWidget *scrolled;
2470 GtkWidget *filter_view;
2471 GtkCellRenderer *renderer;
2472 GtkTreeSelection *selection;
2473 GtkTreeViewColumn *column;
2475 vbox = scrolled_notebook_page(notebook, _("Files"));
2477 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2479 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2480 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2481 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2482 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2483 pref_checkbox_new_int(group, _("Case sensitive sort"),
2484 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2485 pref_checkbox_new_int(group, _("Natural sort order"),
2486 options->file_sort.natural, &c_options->file_sort.natural);
2487 pref_checkbox_new_int(group, _("Disable file extension checks"),
2488 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2490 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2491 options->file_filter.disable, &c_options->file_filter.disable);
2494 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2496 sidecar_ext_entry = gtk_entry_new();
2497 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2498 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2499 gtk_widget_show(sidecar_ext_entry);
2501 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2503 frame = pref_group_parent(group);
2504 g_signal_connect(G_OBJECT(ct_button), "toggled",
2505 G_CALLBACK(filter_disable_cb), frame);
2506 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2508 scrolled = gtk_scrolled_window_new(NULL, NULL);
2509 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2510 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2511 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2512 gtk_widget_show(scrolled);
2514 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2515 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2516 g_object_unref(filter_store);
2517 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2518 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2520 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2522 column = gtk_tree_view_column_new();
2523 gtk_tree_view_column_set_title(column, _("Filter"));
2524 gtk_tree_view_column_set_resizable(column, TRUE);
2526 renderer = gtk_cell_renderer_toggle_new();
2527 g_signal_connect(G_OBJECT(renderer), "toggled",
2528 G_CALLBACK(filter_store_enable_cb), filter_store);
2529 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2530 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2531 GINT_TO_POINTER(FE_ENABLE), NULL);
2533 renderer = gtk_cell_renderer_text_new();
2534 g_signal_connect(G_OBJECT(renderer), "edited",
2535 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2536 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2537 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2538 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2539 GINT_TO_POINTER(FE_EXTENSION), NULL);
2540 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2542 column = gtk_tree_view_column_new();
2543 gtk_tree_view_column_set_title(column, _("Description"));
2544 gtk_tree_view_column_set_resizable(column, TRUE);
2545 gtk_tree_view_column_set_fixed_width(column, 200);
2546 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2548 renderer = gtk_cell_renderer_text_new();
2549 g_signal_connect(G_OBJECT(renderer), "edited",
2550 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2551 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2552 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2553 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2554 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2555 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2557 column = gtk_tree_view_column_new();
2558 gtk_tree_view_column_set_title(column, _("Class"));
2559 gtk_tree_view_column_set_resizable(column, TRUE);
2560 renderer = gtk_cell_renderer_combo_new();
2561 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2562 "model", create_class_model(),
2567 g_signal_connect(G_OBJECT(renderer), "edited",
2568 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2569 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2570 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2571 GINT_TO_POINTER(FE_CLASS), NULL);
2572 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2574 column = gtk_tree_view_column_new();
2575 gtk_tree_view_column_set_title(column, _("Writable"));
2576 gtk_tree_view_column_set_resizable(column, FALSE);
2577 renderer = gtk_cell_renderer_toggle_new();
2578 g_signal_connect(G_OBJECT(renderer), "toggled",
2579 G_CALLBACK(filter_store_writable_cb), filter_store);
2580 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2581 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2582 GINT_TO_POINTER(FE_WRITABLE), NULL);
2583 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2585 column = gtk_tree_view_column_new();
2586 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2587 gtk_tree_view_column_set_resizable(column, FALSE);
2588 renderer = gtk_cell_renderer_toggle_new();
2589 g_signal_connect(G_OBJECT(renderer), "toggled",
2590 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2591 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2592 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2593 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2594 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2597 filter_store_populate();
2598 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2599 gtk_widget_show(filter_view);
2601 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2603 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2604 G_CALLBACK(filter_default_cb), filter_view);
2605 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2606 gtk_widget_show(button);
2608 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2609 G_CALLBACK(filter_remove_cb), filter_view);
2610 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2611 gtk_widget_show(button);
2613 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2614 G_CALLBACK(filter_add_cb), filter_view);
2615 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2616 gtk_widget_show(button);
2620 static void config_tab_metadata(GtkWidget *notebook)
2625 GtkWidget *ct_button;
2629 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2632 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2634 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2636 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2637 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2639 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2640 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2642 gtk_widget_set_sensitive(ct_button, FALSE);
2645 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2646 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2648 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2649 label = pref_label_new(group, text);
2650 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2651 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2654 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2656 gtk_widget_set_sensitive(group, FALSE);
2659 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2660 pref_checkbox_link_sensitivity(ct_button, hbox);
2662 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2663 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2665 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2666 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2668 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2669 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2671 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2672 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2674 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2676 gtk_widget_set_sensitive(group, FALSE);
2679 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2680 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2683 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2684 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2685 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2687 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2688 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2690 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2691 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2693 gtk_widget_set_sensitive(ct_button, FALSE);
2696 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2698 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2699 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2701 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2702 pref_checkbox_link_sensitivity(ct_button, hbox);
2704 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2705 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2707 pref_checkbox_new_int(group, _("Write metadata on image change"),
2708 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2710 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2711 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2713 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2715 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2716 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2717 gtk_widget_set_tooltip_text(ct_button,"On folder change, read DateTimeOriginal, DateTimeDigitized and Star Rating in the idle loop.\nIf this is not selected, initial loading of the folder will be faster but sorting on these items will be slower");
2722 typedef struct _KeywordFindData KeywordFindData;
2723 struct _KeywordFindData
2730 GtkWidget *button_close;
2731 GtkWidget *button_stop;
2732 GtkWidget *button_start;
2733 GtkWidget *progress;
2741 guint idle_id; /* event source id */
2744 #define KEYWORD_DIALOG_WIDTH 400
2746 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2748 GList *list_d = NULL;
2749 GList *list_f = NULL;
2753 filelist_read(dir_fd, &list_f, &list_d);
2757 filelist_read(dir_fd, &list_f, NULL);
2760 list_f = filelist_filter(list_f, FALSE);
2761 list_d = filelist_filter(list_d, TRUE);
2763 kfd->list = g_list_concat(list_f, kfd->list);
2764 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2767 static void keywords_find_reset(KeywordFindData *kfd)
2769 filelist_free(kfd->list);
2772 filelist_free(kfd->list_dir);
2773 kfd->list_dir = NULL;
2776 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2778 KeywordFindData *kfd = data;
2780 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2782 keywords_find_reset(kfd);
2783 generic_dialog_close(kfd->gd);
2787 static void keywords_find_finish(KeywordFindData *kfd)
2789 keywords_find_reset(kfd);
2791 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2792 spinner_set_interval(kfd->spinner, -1);
2794 gtk_widget_set_sensitive(kfd->group, TRUE);
2795 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2796 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2797 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2800 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2802 KeywordFindData *kfd = data;
2804 g_idle_remove_by_data(kfd);
2806 keywords_find_finish(kfd);
2809 static gboolean keywords_find_file(gpointer data)
2811 KeywordFindData *kfd = data;
2813 GtkTextBuffer *buffer;
2821 fd = kfd->list->data;
2822 kfd->list = g_list_remove(kfd->list, fd);
2824 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2825 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2829 gtk_text_buffer_get_end_iter(buffer, &iter);
2830 tmp = g_strconcat(keywords->data, "\n", NULL);
2831 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2833 keywords = keywords->next;
2836 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2837 file_data_unref(fd);
2838 string_list_free(keywords);
2842 else if (kfd->list_dir)
2846 fd = kfd->list_dir->data;
2847 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2849 keywords_find_folder(kfd, fd);
2851 file_data_unref(fd);
2856 keywords_find_finish(kfd);
2861 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2863 KeywordFindData *kfd = data;
2866 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2868 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2869 parse_out_relatives(path);
2873 warning_dialog(_("Invalid folder"),
2874 _("The specified folder can not be found."),
2875 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2881 gtk_widget_set_sensitive(kfd->group, FALSE);
2882 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2883 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2884 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2885 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2887 dir_fd = file_data_new_dir(path);
2888 keywords_find_folder(kfd, dir_fd);
2889 file_data_unref(dir_fd);
2890 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2896 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2898 KeywordFindData *kfd;
2902 kfd = g_new0(KeywordFindData, 1);
2904 kfd->gd = generic_dialog_new(_("Search for keywords"),
2905 "search_for_keywords",
2908 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2909 kfd->gd->cancel_cb = keywords_find_close_cb;
2910 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2911 keywords_find_close_cb, FALSE);
2912 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2913 keywords_find_start_cb, FALSE);
2914 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2915 keywords_find_stop_cb, FALSE);
2916 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2918 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2920 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2921 pref_spacer(hbox, PREF_PAD_INDENT);
2922 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2924 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2925 pref_label_new(hbox, _("Folder:"));
2927 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2928 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2929 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2930 gtk_widget_show(label);
2932 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2934 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2935 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2937 kfd->progress = gtk_entry_new();
2938 gtk_widget_set_can_focus(kfd->progress, FALSE);
2939 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2940 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2941 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2942 gtk_widget_show(kfd->progress);
2944 kfd->spinner = spinner_new(NULL, -1);
2945 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2946 gtk_widget_show(kfd->spinner);
2950 gtk_widget_show(kfd->gd->dialog);
2953 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2955 const gchar *path = layout_get_path(NULL);
2957 if (!path || !*path) path = homedir();
2958 keywords_find_dialog(widget, path);
2961 static void config_tab_keywords_save()
2963 GtkTextIter start, end;
2964 GtkTextBuffer *buffer;
2965 GList *kw_list = NULL;
2971 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2972 gtk_text_buffer_get_bounds(buffer, &start, &end);
2974 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
2976 kw_split = strtok(buffer_text, "\n");
2977 while (kw_split != NULL)
2983 if (g_strcmp0(work->data, kw_split) == 0)
2992 kw_list = g_list_append(kw_list, g_strdup(kw_split));
2994 kw_split = strtok(NULL, "\n");
2997 keyword_list_set(kw_list);
2999 string_list_free(kw_list);
3000 g_free(buffer_text);
3003 static void config_tab_keywords(GtkWidget *notebook)
3009 GtkWidget *scrolled;
3011 GtkTextBuffer *buffer;
3014 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3016 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3018 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3020 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3021 G_CALLBACK(keywords_find_cb), keyword_text);
3022 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3025 keyword_text = gtk_text_view_new();
3026 gtk_widget_set_size_request(keyword_text, 20, 20);
3027 scrolled = gtk_scrolled_window_new(NULL, NULL);
3028 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3029 gtk_widget_show(scrolled);
3031 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3032 gtk_widget_show(keyword_text);
3034 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3036 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3037 gtk_text_buffer_create_tag(buffer, "monospace",
3038 "family", "monospace", NULL);
3040 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3041 gtk_text_buffer_get_start_iter(buffer, &iter);
3042 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3045 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3047 GList *kwl = keyword_list_get();
3048 kwl = g_list_first(kwl);
3051 gtk_text_buffer_get_end_iter (buffer, &iter);
3052 tmp = g_strconcat(kwl->data, "\n", NULL);
3053 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3058 gtk_text_buffer_set_modified(buffer, FALSE);
3065 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3067 gint *option = data;
3069 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3073 *option = INTENT_PERCEPTUAL;
3076 *option = INTENT_RELATIVE_COLORIMETRIC;
3079 *option = INTENT_SATURATION;
3082 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3087 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3088 gint option, gint *option_c)
3095 pref_table_label(table, column, row, text, 0.0);
3097 combo = gtk_combo_box_text_new();
3099 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3100 if (option == INTENT_PERCEPTUAL) current = 0;
3101 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3102 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3103 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3104 if (option == INTENT_SATURATION) current = 2;
3105 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3106 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3108 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3110 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3112 g_signal_connect(G_OBJECT(combo), "changed",
3113 G_CALLBACK(intent_menu_cb), option_c);
3115 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3116 gtk_widget_show(combo);
3120 static void config_tab_color(GtkWidget *notebook)
3129 vbox = scrolled_notebook_page(notebook, _("Color management"));
3131 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3133 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3136 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3137 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3139 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3140 pref_label_bold(label, TRUE, FALSE);
3142 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3143 pref_label_bold(label, TRUE, FALSE);
3145 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3146 pref_label_bold(label, TRUE, FALSE);
3148 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3153 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3154 pref_table_label(table, 0, i + 1, buf, 1.0);
3157 entry = gtk_entry_new();
3158 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3159 if (options->color_profile.input_name[i])
3161 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3163 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3164 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3165 gtk_widget_show(entry);
3166 color_profile_input_name_entry[i] = entry;
3168 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3169 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3170 gtk_widget_set_size_request(entry, 160, -1);
3171 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3172 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3173 gtk_widget_show(tabcomp);
3174 color_profile_input_file_entry[i] = entry;
3177 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3179 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3181 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3182 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3184 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3186 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3187 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3188 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3189 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3190 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3192 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3194 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3196 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3198 gtk_widget_show(tabcomp);
3201 /* advanced entry tab */
3202 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3204 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3206 c_options->file_ops.use_system_trash = FALSE;
3207 c_options->file_ops.no_trash = FALSE;
3211 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3213 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3215 c_options->file_ops.use_system_trash = TRUE;
3216 c_options->file_ops.no_trash = FALSE;
3220 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3222 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3224 c_options->file_ops.no_trash = TRUE;
3228 static void config_tab_behavior(GtkWidget *notebook)
3235 GtkWidget *ct_button;
3239 GtkWidget *with_rename;
3240 GtkWidget *collections_on_top;
3242 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3244 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3246 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3247 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3248 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3249 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3250 pref_checkbox_new_int(group, _("Enable Delete key"),
3251 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3253 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3254 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3256 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3257 pref_checkbox_link_sensitivity(ct_button, hbox);
3259 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3260 pref_label_new(hbox, _("Folder:"));
3262 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3263 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3264 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3265 gtk_widget_show(tabcomp);
3267 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3268 pref_checkbox_link_sensitivity(ct_button, hbox);
3270 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3271 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3272 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3273 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3274 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3275 G_CALLBACK(safe_delete_view_cb), NULL);
3276 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3277 gtk_widget_show(button);
3279 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3280 G_CALLBACK(safe_delete_clear_cb), NULL);
3281 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3282 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3283 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3285 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3286 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3288 gtk_widget_show(button);
3290 pref_spacer(group, PREF_PAD_GROUP);
3293 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3295 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3296 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3298 pref_checkbox_new_int(group, _("In place renaming"),
3299 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3301 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3302 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3304 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3305 options->marks_save, &c_options->marks_save);
3306 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3308 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3309 options->with_rename, &c_options->with_rename);
3310 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3312 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3313 options->collections_on_top, &c_options->collections_on_top);
3314 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3316 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3317 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3319 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3320 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3322 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3323 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3325 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3326 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3328 pref_spacer(group, PREF_PAD_GROUP);
3330 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3332 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3333 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3334 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3335 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3336 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3337 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3338 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3339 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3340 pref_checkbox_new_int(group, _("Play video by left click on image"),
3341 options->image_l_click_video, &c_options->image_l_click_video);
3342 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3343 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3345 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3346 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3347 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3348 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3349 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3352 pref_spacer(group, PREF_PAD_GROUP);
3354 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3356 pref_spin_new_int(group, _("Debug level:"), NULL,
3357 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3359 pref_checkbox_new_int(group, _("Timer data"),
3360 options->log_window.timer_data, &c_options->log_window.timer_data);
3362 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3363 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3367 /* accelerators tab */
3368 static void config_tab_accelerators(GtkWidget *notebook)
3374 GtkWidget *scrolled;
3375 GtkWidget *accel_view;
3376 GtkCellRenderer *renderer;
3377 GtkTreeSelection *selection;
3378 GtkTreeViewColumn *column;
3380 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3382 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3384 scrolled = gtk_scrolled_window_new(NULL, NULL);
3385 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3386 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3387 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3388 gtk_widget_show(scrolled);
3390 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3392 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3393 g_object_unref(accel_store);
3394 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3395 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3397 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3399 renderer = gtk_cell_renderer_text_new();
3401 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3406 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3407 gtk_tree_view_column_set_resizable(column, TRUE);
3408 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3411 renderer = gtk_cell_renderer_accel_new();
3412 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3413 G_CALLBACK(accel_store_cleared_cb), accel_store);
3414 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3415 G_CALLBACK(accel_store_edited_cb), accel_store);
3418 g_object_set (renderer,
3420 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3423 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3428 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3429 gtk_tree_view_column_set_resizable(column, TRUE);
3430 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3432 renderer = gtk_cell_renderer_text_new();
3434 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3439 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3440 gtk_tree_view_column_set_resizable(column, TRUE);
3441 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3443 renderer = gtk_cell_renderer_text_new();
3445 column = gtk_tree_view_column_new_with_attributes("Accel",
3450 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3451 gtk_tree_view_column_set_resizable(column, TRUE);
3452 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3454 accel_store_populate();
3455 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3456 gtk_widget_show(accel_view);
3458 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3460 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3461 G_CALLBACK(accel_default_cb), accel_view);
3462 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3463 gtk_widget_show(button);
3465 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3466 G_CALLBACK(accel_reset_cb), accel_view);
3467 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3468 gtk_widget_show(button);
3471 /* toolbar main tab */
3472 static void config_tab_toolbar_main(GtkWidget *notebook)
3475 GtkWidget *toolbardata;
3478 lw = layout_window_list->data;
3480 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3482 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3483 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3484 gtk_widget_show(vbox);
3487 /* toolbar status tab */
3488 static void config_tab_toolbar_status(GtkWidget *notebook)
3491 GtkWidget *toolbardata;
3494 lw = layout_window_list->data;
3496 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3498 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3499 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3500 gtk_widget_show(vbox);
3504 static void config_tab_stereo(GtkWidget *notebook)
3512 GtkWidget *fs_button;
3513 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3515 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3517 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3518 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3520 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3521 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3522 pref_checkbox_new_int(box, _("Mirror left image"),
3523 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3524 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3525 pref_checkbox_new_int(box, _("Flip left image"),
3526 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3527 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3528 pref_checkbox_new_int(box, _("Mirror right image"),
3529 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3530 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3531 pref_checkbox_new_int(box, _("Flip right image"),
3532 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3533 pref_checkbox_new_int(group, _("Swap left and right images"),
3534 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3535 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3536 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3538 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3539 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3540 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3541 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3542 pref_checkbox_link_sensitivity(fs_button, box2);
3543 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3544 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3545 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3546 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3547 pref_checkbox_new_int(box, _("Mirror left image"),
3548 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3549 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3550 pref_checkbox_new_int(box, _("Flip left image"),
3551 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3552 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3553 pref_checkbox_new_int(box, _("Mirror right image"),
3554 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3555 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3556 pref_checkbox_new_int(box, _("Flip right image"),
3557 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3558 pref_checkbox_new_int(box2, _("Swap left and right images"),
3559 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3560 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3561 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3563 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3564 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3565 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3566 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3567 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3568 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3569 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3570 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3571 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3572 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3573 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3574 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3575 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3576 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3580 /* Main preferences window */
3581 static void config_window_create(void)
3583 GtkWidget *win_vbox;
3585 GtkWidget *notebook;
3587 GtkWidget *ct_button;
3589 if (!c_options) c_options = init_options(NULL);
3591 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3592 DEBUG_NAME(configwindow);
3593 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3594 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3595 G_CALLBACK(config_window_delete), NULL);
3596 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3597 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3598 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3600 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3601 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3602 gtk_widget_show(win_vbox);
3604 notebook = gtk_notebook_new();
3605 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3606 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3607 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3609 config_tab_general(notebook);
3610 config_tab_image(notebook);
3611 config_tab_osd(notebook);
3612 config_tab_windows(notebook);
3613 config_tab_accelerators(notebook);
3614 config_tab_files(notebook);
3615 config_tab_metadata(notebook);
3616 config_tab_keywords(notebook);
3617 config_tab_color(notebook);
3618 config_tab_stereo(notebook);
3619 config_tab_behavior(notebook);
3620 config_tab_toolbar_main(notebook);
3621 config_tab_toolbar_status(notebook);
3623 hbox = gtk_hbutton_box_new();
3624 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3625 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3626 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3627 gtk_widget_show(hbox);
3629 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3630 G_CALLBACK(config_window_help_cb), notebook);
3631 gtk_container_add(GTK_CONTAINER(hbox), button);
3632 gtk_widget_set_can_default(button, TRUE);
3633 gtk_widget_show(button);
3635 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3636 G_CALLBACK(config_window_ok_cb), NULL);
3637 gtk_container_add(GTK_CONTAINER(hbox), button);
3638 gtk_widget_set_can_default(button, TRUE);
3639 gtk_widget_grab_default(button);
3640 gtk_widget_show(button);
3644 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3645 G_CALLBACK(config_window_close_cb), NULL);
3646 gtk_container_add(GTK_CONTAINER(hbox), button);
3647 gtk_widget_set_can_default(button, TRUE);
3648 gtk_widget_show(button);
3650 if (!generic_dialog_get_alternative_button_order(configwindow))
3652 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3655 gtk_widget_show(notebook);
3657 gtk_widget_show(configwindow);
3661 *-----------------------------------------------------------------------------
3662 * config window show (public)
3663 *-----------------------------------------------------------------------------
3666 void show_config_window(void)
3670 gtk_window_present(GTK_WINDOW(configwindow));
3674 config_window_create();
3683 void show_about_window(LayoutWindow *lw)
3685 GdkPixbuf *pixbuf_logo;
3686 GdkPixbuf *pixbuf_icon;
3687 gchar *authors[1000];
3692 gchar *timezone_path;
3696 #define LINE_LENGTH 1000
3697 gchar line[LINE_LENGTH];
3699 copyright = g_string_new(NULL);
3700 copyright = g_string_append(copyright, "This program comes with absolutely no warranty.\nGNU General Public License, version 2 or later.\nSee https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n\n");
3702 path = path_from_utf8(TIMEZONE_DATABASE);
3703 basename = g_path_get_basename(path);
3704 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3705 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3707 cd = ZDOpenDatabase(timezone_path);
3710 copyright = g_string_append(copyright, ZDGetNotice(cd));
3711 ZDCloseDatabase(cd);
3715 g_free(timezone_path);
3719 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3720 fp = fopen(path, "r");
3723 while(fgets(line, LINE_LENGTH, fp))
3725 /* get rid of ending \n from fgets */
3726 line[strlen(line) - 1] = '\0';
3727 authors[i_authors] = g_strdup(line);
3730 authors[i_authors] = NULL;
3735 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3736 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3738 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3739 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3740 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3741 "title", _("About Geeqie"),
3743 "program-name", GQ_APPNAME,
3745 "logo", pixbuf_logo,
3746 "icon", pixbuf_icon,
3747 "website", GQ_WEBSITE,
3748 "website-label", "Website",
3749 "comments", comment,
3751 "translator-credits", _("translator-credits"),
3752 "wrap-license", TRUE,
3753 "license", copyright->str,
3756 g_string_free(copyright, TRUE);
3759 while(n < i_authors)
3769 static void image_overlay_set_text_colours()
3771 c_options->image_overlay.text_red = options->image_overlay.text_red;
3772 c_options->image_overlay.text_green = options->image_overlay.text_green;
3773 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3774 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3775 c_options->image_overlay.background_red = options->image_overlay.background_red;
3776 c_options->image_overlay.background_green = options->image_overlay.background_green;
3777 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3778 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3782 *-----------------------------------------------------------------------------
3783 * timezone database routines
3784 *-----------------------------------------------------------------------------
3787 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3789 GError *error = NULL;
3791 gchar *tmp_filename;
3793 if (!g_cancellable_is_cancelled(tz->cancellable))
3795 generic_dialog_close(tz->gd);
3799 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3801 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3802 move_file(tmp_filename, tz->timezone_database_user);
3803 g_free(tmp_filename);
3807 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3810 g_file_delete(tz->tmp_g_file, NULL, &error);
3811 g_object_unref(tz->tmp_g_file);
3812 tz->tmp_g_file = NULL;
3813 g_object_unref(tz->cancellable);
3814 g_object_unref(tz->timezone_database_gq);
3817 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3821 if (!g_cancellable_is_cancelled(tz->cancellable))
3823 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3827 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3830 GError *error = NULL;
3832 g_cancellable_cancel(tz->cancellable);
3835 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3838 GError *error = NULL;
3839 GFileIOStream *io_stream;
3846 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3850 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3851 log_printf("Error: Download timezone database failed:\n%s", error->message);
3852 g_error_free(error);
3853 g_object_unref(tz->tmp_g_file);
3857 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3859 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3861 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3863 tz->progress = gtk_progress_bar_new();
3864 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3865 gtk_widget_show(tz->progress);
3867 gtk_widget_show(tz->gd->dialog);
3868 tz->cancellable = g_cancellable_new();
3869 g_file_copy_async(tz->timezone_database_gq, tz->tmp_g_file, G_FILE_COPY_OVERWRITE, G_PRIORITY_LOW, tz->cancellable, timezone_progress_cb, tz, timezone_async_ready_cb, tz);
3871 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3874 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */