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",
504 "GuideOptionsToolbar.html"
507 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
508 help_window_show(html_section[i]);
511 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
513 config_window_close_cb(NULL, NULL);
517 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
520 lw = layout_window_list->data;
522 config_window_apply();
523 layout_util_sync(lw);
524 save_options(options);
525 config_window_close_cb(NULL, NULL);
529 *-----------------------------------------------------------------------------
530 * config window setup (private)
531 *-----------------------------------------------------------------------------
534 static void quality_menu_cb(GtkWidget *combo, gpointer data)
538 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
542 *option = GDK_INTERP_NEAREST;
545 *option = GDK_INTERP_TILES;
548 *option = GDK_INTERP_BILINEAR;
551 *option = GDK_INTERP_HYPER;
556 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
560 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
564 *option = DND_ACTION_ASK;
567 *option = DND_ACTION_COPY;
570 *option = DND_ACTION_MOVE;
574 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
578 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
590 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
591 guint option, guint *option_c)
598 pref_table_label(table, column, row, text, 0.0);
600 combo = gtk_combo_box_text_new();
602 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
603 if (option == GDK_INTERP_NEAREST) current = 0;
604 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
605 if (option == GDK_INTERP_TILES) current = 1;
606 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
607 if (option == GDK_INTERP_BILINEAR) current = 2;
608 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
609 if (option == GDK_INTERP_HYPER) current = 3;
611 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
613 g_signal_connect(G_OBJECT(combo), "changed",
614 G_CALLBACK(quality_menu_cb), option_c);
616 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
617 gtk_widget_show(combo);
620 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
627 pref_table_label(table, column, row, text, 0.0);
629 combo = gtk_combo_box_text_new();
631 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
632 if (option == DND_ACTION_ASK) current = 0;
633 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
634 if (option == DND_ACTION_COPY) current = 1;
635 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
636 if (option == DND_ACTION_MOVE) current = 2;
638 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
640 g_signal_connect(G_OBJECT(combo), "changed",
641 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
643 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
644 gtk_widget_show(combo);
647 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
648 gint option, gint *option_c)
655 pref_table_label(table, column, row, text, 0.0);
657 combo = gtk_combo_box_text_new();
659 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
660 if (option == PRIMARY) current = 0;
661 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
662 if (option == CLIPBOARD) current = 1;
664 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
666 g_signal_connect(G_OBJECT(combo), "changed",
667 G_CALLBACK(clipboard_selection_menu_cb), option_c);
669 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
670 gtk_widget_show(combo);
673 typedef struct _UseableMouseItems UseableMouseItems;
674 struct _UseableMouseItems
676 gchar *name; /* GtkActionEntry terminology */
681 static const UseableMouseItems useable_mouse_items[] = {
683 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
684 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
685 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
686 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
687 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
688 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
689 {"Home", N_("Home"), GTK_STOCK_HOME},
690 {"Up", N_("Up"), GTK_STOCK_GO_UP},
691 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
692 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
693 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
694 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
695 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
696 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
697 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
698 {"Search", N_("Search"), GTK_STOCK_FIND},
699 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
700 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
701 {"Copy", N_("Copy"), GTK_STOCK_COPY},
702 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
703 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
704 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
705 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
706 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
707 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
708 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
709 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
710 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
711 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
712 {"Print", N_("Print"), GTK_STOCK_PRINT},
713 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
714 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
715 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
716 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
717 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
718 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
719 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
720 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
721 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
722 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
723 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
724 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
725 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
726 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
727 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
728 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
729 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
730 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
731 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
732 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
733 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
734 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
735 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
736 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
737 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
738 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
739 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
740 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
741 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
742 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
743 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
744 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
745 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
746 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
747 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
748 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
749 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
750 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
751 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
752 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
756 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
758 gchar **option = data;
761 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
763 const UseableMouseItems *list = useable_mouse_items;
767 if (g_strcmp0(list->label, label) == 0)
775 *option = g_strdup(list->name);
779 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
780 gchar *option, gchar **option_c)
788 pref_table_label(table, column, row, text, 0.0);
790 combo = gtk_combo_box_text_new();
792 const UseableMouseItems *list = useable_mouse_items;
796 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
797 if (g_strcmp0(list->name, option) == 0)
805 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
807 g_signal_connect(G_OBJECT(combo), "changed",
808 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
810 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
811 gtk_widget_show(combo);
814 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
818 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
821 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
823 c_options->thumbnails.max_width = thumb_size_list[n].w;
824 c_options->thumbnails.max_height = thumb_size_list[n].h;
828 c_options->thumbnails.max_width = options->thumbnails.max_width;
829 c_options->thumbnails.max_height = options->thumbnails.max_height;
833 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
839 c_options->thumbnails.max_width = options->thumbnails.max_width;
840 c_options->thumbnails.max_height = options->thumbnails.max_height;
842 pref_table_label(table, column, row, text, 0.0);
844 combo = gtk_combo_box_text_new();
847 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
852 w = thumb_size_list[i].w;
853 h = thumb_size_list[i].h;
855 buf = g_strdup_printf("%d x %d", w, h);
856 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
859 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
866 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
867 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
873 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
874 g_signal_connect(G_OBJECT(combo), "changed",
875 G_CALLBACK(thumb_size_menu_cb), NULL);
877 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
878 gtk_widget_show(combo);
881 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
885 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
889 *option = PR_STEREO_NONE;
892 *option = PR_STEREO_ANAGLYPH_RC;
895 *option = PR_STEREO_ANAGLYPH_GM;
898 *option = PR_STEREO_ANAGLYPH_YB;
901 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
904 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
907 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
910 *option = PR_STEREO_ANAGLYPH_DB_RC;
913 *option = PR_STEREO_ANAGLYPH_DB_GM;
916 *option = PR_STEREO_ANAGLYPH_DB_YB;
919 *option = PR_STEREO_HORIZ;
922 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
925 *option = PR_STEREO_VERT;
928 *option = PR_STEREO_VERT | PR_STEREO_HALF;
931 *option = PR_STEREO_FIXED;
936 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
937 gint option, gint *option_c, gboolean add_fixed)
944 pref_table_label(table, column, row, text, 0.0);
946 combo = gtk_combo_box_text_new();
948 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
950 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
951 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
952 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
953 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
954 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
955 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
956 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
957 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
958 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
959 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
960 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
961 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
962 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
963 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
964 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
965 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
966 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
967 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
969 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
970 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
971 if (option & PR_STEREO_HORIZ)
974 if (option & PR_STEREO_HALF) current = 11;
977 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
978 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
979 if (option & PR_STEREO_VERT)
982 if (option & PR_STEREO_HALF) current = 13;
987 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
988 if (option & PR_STEREO_FIXED) current = 14;
991 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
993 g_signal_connect(G_OBJECT(combo), "changed",
994 G_CALLBACK(stereo_mode_menu_cb), option_c);
996 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
997 gtk_widget_show(combo);
1000 static void video_menu_cb(GtkWidget *combo, gpointer data)
1002 gchar **option = data;
1004 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1008 static void video_menu_populate(gpointer data, gpointer user_data)
1010 GtkWidget *combo = user_data;
1011 EditorDescription *ed = data;
1013 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1016 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1017 gchar *option, gchar **option_c)
1021 /* use lists since they are sorted */
1022 GList *eds = editor_list_get();
1026 pref_table_label(table, column, row, text, 0.0);
1028 combo = gtk_combo_box_text_new();
1029 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1030 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1032 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1034 g_signal_connect(G_OBJECT(combo), "changed",
1035 G_CALLBACK(video_menu_cb), option_c);
1037 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1038 gtk_widget_show(combo);
1041 static void filter_store_populate(void)
1045 if (!filter_store) return;
1047 gtk_list_store_clear(filter_store);
1049 work = filter_get_list();
1058 gtk_list_store_append(filter_store, &iter);
1059 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1063 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1064 gchar *new_text, gpointer data)
1066 GtkWidget *model = data;
1067 FilterEntry *fe = data;
1071 if (!new_text || strlen(new_text) < 1) return;
1073 tpath = gtk_tree_path_new_from_string(path_str);
1074 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1075 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1077 g_free(fe->extensions);
1078 fe->extensions = g_strdup(new_text);
1080 gtk_tree_path_free(tpath);
1084 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1085 gchar *new_text, gpointer data)
1087 GtkWidget *model = data;
1088 FilterEntry *fe = data;
1093 if (!new_text || !new_text[0]) return;
1095 tpath = gtk_tree_path_new_from_string(path_str);
1096 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1097 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1099 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1101 if (strcmp(new_text, _(format_class_list[i])) == 0)
1108 gtk_tree_path_free(tpath);
1112 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1113 gchar *new_text, gpointer data)
1115 GtkWidget *model = data;
1120 if (!new_text || !new_text[0]) return;
1122 tpath = gtk_tree_path_new_from_string(path_str);
1123 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1124 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1126 g_free(fe->description);
1127 fe->description = g_strdup(new_text);
1129 gtk_tree_path_free(tpath);
1132 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1133 gchar *path_str, gpointer data)
1135 GtkWidget *model = data;
1140 tpath = gtk_tree_path_new_from_string(path_str);
1141 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1142 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1144 fe->enabled = !fe->enabled;
1146 gtk_tree_path_free(tpath);
1150 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1151 gchar *path_str, gpointer data)
1153 GtkWidget *model = data;
1158 tpath = gtk_tree_path_new_from_string(path_str);
1159 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1160 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1162 fe->writable = !fe->writable;
1163 if (fe->writable) fe->allow_sidecar = FALSE;
1165 gtk_tree_path_free(tpath);
1169 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1170 gchar *path_str, gpointer data)
1172 GtkWidget *model = data;
1177 tpath = gtk_tree_path_new_from_string(path_str);
1178 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1179 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1181 fe->allow_sidecar = !fe->allow_sidecar;
1182 if (fe->allow_sidecar) fe->writable = FALSE;
1184 gtk_tree_path_free(tpath);
1188 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1189 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1193 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1195 switch (GPOINTER_TO_INT(data))
1198 g_object_set(GTK_CELL_RENDERER(cell),
1199 "active", fe->enabled, NULL);
1202 g_object_set(GTK_CELL_RENDERER(cell),
1203 "text", fe->extensions, NULL);
1205 case FE_DESCRIPTION:
1206 g_object_set(GTK_CELL_RENDERER(cell),
1207 "text", fe->description, NULL);
1210 g_object_set(GTK_CELL_RENDERER(cell),
1211 "text", _(format_class_list[fe->file_class]), NULL);
1214 g_object_set(GTK_CELL_RENDERER(cell),
1215 "active", fe->writable, NULL);
1217 case FE_ALLOW_SIDECAR:
1218 g_object_set(GTK_CELL_RENDERER(cell),
1219 "active", fe->allow_sidecar, NULL);
1224 static gboolean filter_add_scroll(gpointer data)
1228 GtkCellRenderer *cell;
1229 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 and sim. files"),
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 (Requires restart)"),
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)
2312 GtkWidget *image_overlay_template_view;
2313 GtkWidget *scrolled;
2314 GtkWidget *scrolled_pre_formatted;
2315 GtkTextBuffer *buffer;
2317 GtkWidget *subgroup;
2319 vbox = scrolled_notebook_page(notebook, _("OSD"));
2321 image_overlay_template_view = gtk_text_view_new();
2323 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2325 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2327 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2328 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2329 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2330 gtk_widget_show(scrolled_pre_formatted);
2331 gtk_widget_show(subgroup);
2333 pref_line(group, PREF_PAD_GAP);
2335 pref_label_new(group, _("Image overlay template"));
2337 scrolled = gtk_scrolled_window_new(NULL, NULL);
2338 gtk_widget_set_size_request(scrolled, 200, 150);
2339 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2340 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2341 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2342 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2343 gtk_widget_show(scrolled);
2345 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2346 _("Extensive formatting options are shown in the Help file"));
2348 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2349 gtk_widget_show(image_overlay_template_view);
2351 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2353 #if GTK_CHECK_VERSION(3,4,0)
2354 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2355 G_CALLBACK(image_overlay_set_font_cb), notebook);
2357 button = gtk_font_button_new();
2358 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2359 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2360 g_signal_connect(G_OBJECT(button), "font-set",
2361 G_CALLBACK(image_overlay_set_font_cb),NULL);
2363 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2364 gtk_widget_show(button);
2366 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2367 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2368 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2369 gtk_widget_show(button);
2371 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2372 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2373 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2374 gtk_widget_show(button);
2375 image_overlay_set_text_colours();
2377 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2378 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2379 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2380 gtk_widget_show(button);
2382 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2383 G_CALLBACK(image_overlay_help_cb), NULL);
2384 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2385 gtk_widget_show(button);
2387 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2388 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2389 g_signal_connect(G_OBJECT(buffer), "changed",
2390 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2392 pref_line(group, PREF_PAD_GAP);
2394 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2395 hbox = gtk_hbox_new(FALSE, 0);
2396 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2397 gtk_widget_show(hbox);
2398 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2399 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2400 gtk_widget_show(label);
2401 pref_spacer(group,TRUE);
2403 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2404 hbox = gtk_hbox_new(FALSE, 0);
2405 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2406 gtk_widget_show(hbox);
2407 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2408 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2409 gtk_widget_show(label);
2410 pref_spacer(group,TRUE);
2412 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2413 hbox = gtk_hbox_new(FALSE, 0);
2414 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2415 gtk_widget_show(hbox);
2416 label = gtk_label_new(_("%path:39%"));
2417 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2418 gtk_widget_show(label);
2419 pref_spacer(group,TRUE);
2421 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2422 hbox = gtk_hbox_new(FALSE, 0);
2423 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2424 gtk_widget_show(hbox);
2425 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%"));
2426 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2427 gtk_widget_show(label);
2428 pref_spacer(group,TRUE);
2430 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2431 hbox = gtk_hbox_new(FALSE, 0);
2432 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2433 gtk_widget_show(hbox);
2434 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2435 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2436 gtk_widget_show(label);
2439 static GtkTreeModel *create_class_model(void)
2441 GtkListStore *model;
2445 /* create list store */
2446 model = gtk_list_store_new(1, G_TYPE_STRING);
2447 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2449 gtk_list_store_append(model, &iter);
2450 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2452 return GTK_TREE_MODEL (model);
2457 static void config_tab_files(GtkWidget *notebook)
2464 GtkWidget *ct_button;
2465 GtkWidget *scrolled;
2466 GtkWidget *filter_view;
2467 GtkCellRenderer *renderer;
2468 GtkTreeSelection *selection;
2469 GtkTreeViewColumn *column;
2471 vbox = scrolled_notebook_page(notebook, _("Files"));
2473 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2475 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2476 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2477 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2478 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2479 pref_checkbox_new_int(group, _("Case sensitive sort"),
2480 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2481 pref_checkbox_new_int(group, _("Natural sort order"),
2482 options->file_sort.natural, &c_options->file_sort.natural);
2483 pref_checkbox_new_int(group, _("Disable file extension checks"),
2484 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2486 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2487 options->file_filter.disable, &c_options->file_filter.disable);
2490 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2492 sidecar_ext_entry = gtk_entry_new();
2493 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2494 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2495 gtk_widget_show(sidecar_ext_entry);
2497 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2499 frame = pref_group_parent(group);
2500 g_signal_connect(G_OBJECT(ct_button), "toggled",
2501 G_CALLBACK(filter_disable_cb), frame);
2502 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2504 scrolled = gtk_scrolled_window_new(NULL, NULL);
2505 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2506 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2507 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2508 gtk_widget_show(scrolled);
2510 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2511 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2512 g_object_unref(filter_store);
2513 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2514 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2516 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2518 column = gtk_tree_view_column_new();
2519 gtk_tree_view_column_set_title(column, _("Filter"));
2520 gtk_tree_view_column_set_resizable(column, TRUE);
2522 renderer = gtk_cell_renderer_toggle_new();
2523 g_signal_connect(G_OBJECT(renderer), "toggled",
2524 G_CALLBACK(filter_store_enable_cb), filter_store);
2525 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2526 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2527 GINT_TO_POINTER(FE_ENABLE), NULL);
2529 renderer = gtk_cell_renderer_text_new();
2530 g_signal_connect(G_OBJECT(renderer), "edited",
2531 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2532 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2533 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2534 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2535 GINT_TO_POINTER(FE_EXTENSION), NULL);
2536 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2538 column = gtk_tree_view_column_new();
2539 gtk_tree_view_column_set_title(column, _("Description"));
2540 gtk_tree_view_column_set_resizable(column, TRUE);
2541 gtk_tree_view_column_set_fixed_width(column, 200);
2542 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2544 renderer = gtk_cell_renderer_text_new();
2545 g_signal_connect(G_OBJECT(renderer), "edited",
2546 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2547 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2548 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2549 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2550 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2551 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2553 column = gtk_tree_view_column_new();
2554 gtk_tree_view_column_set_title(column, _("Class"));
2555 gtk_tree_view_column_set_resizable(column, TRUE);
2556 renderer = gtk_cell_renderer_combo_new();
2557 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2558 "model", create_class_model(),
2563 g_signal_connect(G_OBJECT(renderer), "edited",
2564 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2565 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2566 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2567 GINT_TO_POINTER(FE_CLASS), NULL);
2568 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2570 column = gtk_tree_view_column_new();
2571 gtk_tree_view_column_set_title(column, _("Writable"));
2572 gtk_tree_view_column_set_resizable(column, FALSE);
2573 renderer = gtk_cell_renderer_toggle_new();
2574 g_signal_connect(G_OBJECT(renderer), "toggled",
2575 G_CALLBACK(filter_store_writable_cb), filter_store);
2576 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2577 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2578 GINT_TO_POINTER(FE_WRITABLE), NULL);
2579 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2581 column = gtk_tree_view_column_new();
2582 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2583 gtk_tree_view_column_set_resizable(column, FALSE);
2584 renderer = gtk_cell_renderer_toggle_new();
2585 g_signal_connect(G_OBJECT(renderer), "toggled",
2586 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2587 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2588 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2589 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2590 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2593 filter_store_populate();
2594 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2595 gtk_widget_show(filter_view);
2597 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2599 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2600 G_CALLBACK(filter_default_cb), filter_view);
2601 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2602 gtk_widget_show(button);
2604 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2605 G_CALLBACK(filter_remove_cb), filter_view);
2606 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2607 gtk_widget_show(button);
2609 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2610 G_CALLBACK(filter_add_cb), filter_view);
2611 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2612 gtk_widget_show(button);
2616 static void config_tab_metadata(GtkWidget *notebook)
2621 GtkWidget *ct_button;
2625 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2628 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2630 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2632 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2633 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2635 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2636 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2638 gtk_widget_set_sensitive(ct_button, FALSE);
2641 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2642 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2644 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2645 label = pref_label_new(group, text);
2646 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2647 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2650 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2652 gtk_widget_set_sensitive(group, FALSE);
2655 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2656 pref_checkbox_link_sensitivity(ct_button, hbox);
2658 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2659 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2661 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2662 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2664 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2665 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2667 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2668 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2670 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2672 gtk_widget_set_sensitive(group, FALSE);
2675 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2676 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2679 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2680 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2681 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2683 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2684 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2686 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2687 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2689 gtk_widget_set_sensitive(ct_button, FALSE);
2692 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2694 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2695 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2697 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2698 pref_checkbox_link_sensitivity(ct_button, hbox);
2700 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2701 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2703 pref_checkbox_new_int(group, _("Write metadata on image change"),
2704 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2706 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2707 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2709 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2711 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2712 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2713 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");
2718 typedef struct _KeywordFindData KeywordFindData;
2719 struct _KeywordFindData
2726 GtkWidget *button_close;
2727 GtkWidget *button_stop;
2728 GtkWidget *button_start;
2729 GtkWidget *progress;
2737 guint idle_id; /* event source id */
2740 #define KEYWORD_DIALOG_WIDTH 400
2742 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2744 GList *list_d = NULL;
2745 GList *list_f = NULL;
2749 filelist_read(dir_fd, &list_f, &list_d);
2753 filelist_read(dir_fd, &list_f, NULL);
2756 list_f = filelist_filter(list_f, FALSE);
2757 list_d = filelist_filter(list_d, TRUE);
2759 kfd->list = g_list_concat(list_f, kfd->list);
2760 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2763 static void keywords_find_reset(KeywordFindData *kfd)
2765 filelist_free(kfd->list);
2768 filelist_free(kfd->list_dir);
2769 kfd->list_dir = NULL;
2772 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2774 KeywordFindData *kfd = data;
2776 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2778 keywords_find_reset(kfd);
2779 generic_dialog_close(kfd->gd);
2783 static void keywords_find_finish(KeywordFindData *kfd)
2785 keywords_find_reset(kfd);
2787 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2788 spinner_set_interval(kfd->spinner, -1);
2790 gtk_widget_set_sensitive(kfd->group, TRUE);
2791 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2792 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2793 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2796 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2798 KeywordFindData *kfd = data;
2800 g_idle_remove_by_data(kfd);
2802 keywords_find_finish(kfd);
2805 static gboolean keywords_find_file(gpointer data)
2807 KeywordFindData *kfd = data;
2809 GtkTextBuffer *buffer;
2817 fd = kfd->list->data;
2818 kfd->list = g_list_remove(kfd->list, fd);
2820 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2821 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2825 gtk_text_buffer_get_end_iter(buffer, &iter);
2826 tmp = g_strconcat(keywords->data, "\n", NULL);
2827 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2829 keywords = keywords->next;
2832 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2833 file_data_unref(fd);
2834 string_list_free(keywords);
2838 else if (kfd->list_dir)
2842 fd = kfd->list_dir->data;
2843 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2845 keywords_find_folder(kfd, fd);
2847 file_data_unref(fd);
2852 keywords_find_finish(kfd);
2857 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2859 KeywordFindData *kfd = data;
2862 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2864 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2865 parse_out_relatives(path);
2869 warning_dialog(_("Invalid folder"),
2870 _("The specified folder can not be found."),
2871 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2877 gtk_widget_set_sensitive(kfd->group, FALSE);
2878 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2879 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2880 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2881 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2883 dir_fd = file_data_new_dir(path);
2884 keywords_find_folder(kfd, dir_fd);
2885 file_data_unref(dir_fd);
2886 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2892 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2894 KeywordFindData *kfd;
2898 kfd = g_new0(KeywordFindData, 1);
2900 kfd->gd = generic_dialog_new(_("Search for keywords"),
2901 "search_for_keywords",
2904 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2905 kfd->gd->cancel_cb = keywords_find_close_cb;
2906 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2907 keywords_find_close_cb, FALSE);
2908 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2909 keywords_find_start_cb, FALSE);
2910 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2911 keywords_find_stop_cb, FALSE);
2912 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2914 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2916 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2917 pref_spacer(hbox, PREF_PAD_INDENT);
2918 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2920 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2921 pref_label_new(hbox, _("Folder:"));
2923 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2924 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2925 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2926 gtk_widget_show(label);
2928 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2930 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2931 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2933 kfd->progress = gtk_entry_new();
2934 gtk_widget_set_can_focus(kfd->progress, FALSE);
2935 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2936 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2937 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2938 gtk_widget_show(kfd->progress);
2940 kfd->spinner = spinner_new(NULL, -1);
2941 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2942 gtk_widget_show(kfd->spinner);
2946 gtk_widget_show(kfd->gd->dialog);
2949 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2951 const gchar *path = layout_get_path(NULL);
2953 if (!path || !*path) path = homedir();
2954 keywords_find_dialog(widget, path);
2957 static void config_tab_keywords_save()
2959 GtkTextIter start, end;
2960 GtkTextBuffer *buffer;
2961 GList *kw_list = NULL;
2967 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2968 gtk_text_buffer_get_bounds(buffer, &start, &end);
2970 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
2972 kw_split = strtok(buffer_text, "\n");
2973 while (kw_split != NULL)
2979 if (g_strcmp0(work->data, kw_split) == 0)
2988 kw_list = g_list_append(kw_list, g_strdup(kw_split));
2990 kw_split = strtok(NULL, "\n");
2993 keyword_list_set(kw_list);
2995 string_list_free(kw_list);
2996 g_free(buffer_text);
2999 static void config_tab_keywords(GtkWidget *notebook)
3005 GtkWidget *scrolled;
3007 GtkTextBuffer *buffer;
3010 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3012 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3014 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3016 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3017 G_CALLBACK(keywords_find_cb), keyword_text);
3018 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3021 keyword_text = gtk_text_view_new();
3022 gtk_widget_set_size_request(keyword_text, 20, 20);
3023 scrolled = gtk_scrolled_window_new(NULL, NULL);
3024 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3025 gtk_widget_show(scrolled);
3027 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3028 gtk_widget_show(keyword_text);
3030 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3032 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3033 gtk_text_buffer_create_tag(buffer, "monospace",
3034 "family", "monospace", NULL);
3036 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3037 gtk_text_buffer_get_start_iter(buffer, &iter);
3038 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3041 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3043 GList *kwl = keyword_list_get();
3044 kwl = g_list_first(kwl);
3047 gtk_text_buffer_get_end_iter (buffer, &iter);
3048 tmp = g_strconcat(kwl->data, "\n", NULL);
3049 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3054 gtk_text_buffer_set_modified(buffer, FALSE);
3061 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3063 gint *option = data;
3065 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3069 *option = INTENT_PERCEPTUAL;
3072 *option = INTENT_RELATIVE_COLORIMETRIC;
3075 *option = INTENT_SATURATION;
3078 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3083 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3084 gint option, gint *option_c)
3091 pref_table_label(table, column, row, text, 0.0);
3093 combo = gtk_combo_box_text_new();
3095 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3096 if (option == INTENT_PERCEPTUAL) current = 0;
3097 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3098 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3099 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3100 if (option == INTENT_SATURATION) current = 2;
3101 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3102 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3104 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3106 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3108 g_signal_connect(G_OBJECT(combo), "changed",
3109 G_CALLBACK(intent_menu_cb), option_c);
3111 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3112 gtk_widget_show(combo);
3116 static void config_tab_color(GtkWidget *notebook)
3125 vbox = scrolled_notebook_page(notebook, _("Color management"));
3127 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3129 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3132 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3133 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3135 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3136 pref_label_bold(label, TRUE, FALSE);
3138 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3139 pref_label_bold(label, TRUE, FALSE);
3141 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3142 pref_label_bold(label, TRUE, FALSE);
3144 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3149 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3150 pref_table_label(table, 0, i + 1, buf, 1.0);
3153 entry = gtk_entry_new();
3154 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3155 if (options->color_profile.input_name[i])
3157 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3159 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3160 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3161 gtk_widget_show(entry);
3162 color_profile_input_name_entry[i] = entry;
3164 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3165 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3166 gtk_widget_set_size_request(entry, 160, -1);
3167 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3168 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3169 gtk_widget_show(tabcomp);
3170 color_profile_input_file_entry[i] = entry;
3173 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3175 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3177 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3178 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3180 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3182 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3183 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3184 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3185 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3186 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3188 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3190 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3192 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3194 gtk_widget_show(tabcomp);
3197 /* advanced entry tab */
3198 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3200 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3202 c_options->file_ops.use_system_trash = FALSE;
3203 c_options->file_ops.no_trash = FALSE;
3207 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3209 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3211 c_options->file_ops.use_system_trash = TRUE;
3212 c_options->file_ops.no_trash = FALSE;
3216 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3218 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3220 c_options->file_ops.no_trash = TRUE;
3224 static void config_tab_behavior(GtkWidget *notebook)
3231 GtkWidget *ct_button;
3235 GtkWidget *with_rename;
3236 GtkWidget *collections_on_top;
3238 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3240 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3242 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3243 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3244 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3245 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3246 pref_checkbox_new_int(group, _("Enable Delete key"),
3247 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3249 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3250 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3252 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3253 pref_checkbox_link_sensitivity(ct_button, hbox);
3255 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3256 pref_label_new(hbox, _("Folder:"));
3258 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3259 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3260 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3261 gtk_widget_show(tabcomp);
3263 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3264 pref_checkbox_link_sensitivity(ct_button, hbox);
3266 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3267 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3268 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3269 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3270 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3271 G_CALLBACK(safe_delete_view_cb), NULL);
3272 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3273 gtk_widget_show(button);
3275 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3276 G_CALLBACK(safe_delete_clear_cb), NULL);
3277 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3278 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3279 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3281 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3282 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3284 gtk_widget_show(button);
3286 pref_spacer(group, PREF_PAD_GROUP);
3289 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3291 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3292 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3294 pref_checkbox_new_int(group, _("In place renaming"),
3295 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3297 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3298 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3300 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3301 options->marks_save, &c_options->marks_save);
3302 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3304 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3305 options->with_rename, &c_options->with_rename);
3306 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3308 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3309 options->collections_on_top, &c_options->collections_on_top);
3310 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3312 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3313 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3315 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3316 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3318 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3319 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3321 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3322 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3324 pref_spacer(group, PREF_PAD_GROUP);
3326 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3328 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3329 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3330 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3331 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3332 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3333 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3334 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3335 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3336 pref_checkbox_new_int(group, _("Play video by left click on image"),
3337 options->image_l_click_video, &c_options->image_l_click_video);
3338 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3339 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3341 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3342 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3343 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3344 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3345 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3348 pref_spacer(group, PREF_PAD_GROUP);
3350 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3352 pref_spin_new_int(group, _("Debug level:"), NULL,
3353 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3355 pref_checkbox_new_int(group, _("Timer data"),
3356 options->log_window.timer_data, &c_options->log_window.timer_data);
3358 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3359 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3363 /* accelerators tab */
3364 static void config_tab_accelerators(GtkWidget *notebook)
3370 GtkWidget *scrolled;
3371 GtkWidget *accel_view;
3372 GtkCellRenderer *renderer;
3373 GtkTreeSelection *selection;
3374 GtkTreeViewColumn *column;
3376 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3378 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3380 scrolled = gtk_scrolled_window_new(NULL, NULL);
3381 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3382 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3383 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3384 gtk_widget_show(scrolled);
3386 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3388 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3389 g_object_unref(accel_store);
3390 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3391 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3393 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3395 renderer = gtk_cell_renderer_text_new();
3397 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3402 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3403 gtk_tree_view_column_set_resizable(column, TRUE);
3404 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3407 renderer = gtk_cell_renderer_accel_new();
3408 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3409 G_CALLBACK(accel_store_cleared_cb), accel_store);
3410 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3411 G_CALLBACK(accel_store_edited_cb), accel_store);
3414 g_object_set (renderer,
3416 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3419 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3424 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3425 gtk_tree_view_column_set_resizable(column, TRUE);
3426 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3428 renderer = gtk_cell_renderer_text_new();
3430 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3435 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3436 gtk_tree_view_column_set_resizable(column, TRUE);
3437 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3439 renderer = gtk_cell_renderer_text_new();
3441 column = gtk_tree_view_column_new_with_attributes("Accel",
3446 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3447 gtk_tree_view_column_set_resizable(column, TRUE);
3448 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3450 accel_store_populate();
3451 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3452 gtk_widget_show(accel_view);
3454 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3456 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3457 G_CALLBACK(accel_default_cb), accel_view);
3458 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3459 gtk_widget_show(button);
3461 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3462 G_CALLBACK(accel_reset_cb), accel_view);
3463 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3464 gtk_widget_show(button);
3467 /* toolbar main tab */
3468 static void config_tab_toolbar_main(GtkWidget *notebook)
3471 GtkWidget *toolbardata;
3474 lw = layout_window_list->data;
3476 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3478 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3479 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3480 gtk_widget_show(vbox);
3483 /* toolbar status tab */
3484 static void config_tab_toolbar_status(GtkWidget *notebook)
3487 GtkWidget *toolbardata;
3490 lw = layout_window_list->data;
3492 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3494 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3495 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3496 gtk_widget_show(vbox);
3500 static void config_tab_stereo(GtkWidget *notebook)
3508 GtkWidget *fs_button;
3509 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3511 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3513 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3514 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3516 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3517 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3518 pref_checkbox_new_int(box, _("Mirror left image"),
3519 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3520 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3521 pref_checkbox_new_int(box, _("Flip left image"),
3522 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3523 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3524 pref_checkbox_new_int(box, _("Mirror right image"),
3525 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3526 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3527 pref_checkbox_new_int(box, _("Flip right image"),
3528 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3529 pref_checkbox_new_int(group, _("Swap left and right images"),
3530 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3531 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3532 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3534 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3535 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3536 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3537 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3538 pref_checkbox_link_sensitivity(fs_button, box2);
3539 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3540 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3541 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3542 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3543 pref_checkbox_new_int(box, _("Mirror left image"),
3544 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3545 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3546 pref_checkbox_new_int(box, _("Flip left image"),
3547 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3548 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3549 pref_checkbox_new_int(box, _("Mirror right image"),
3550 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3551 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3552 pref_checkbox_new_int(box, _("Flip right image"),
3553 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3554 pref_checkbox_new_int(box2, _("Swap left and right images"),
3555 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3556 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3557 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3559 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3560 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3561 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3562 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3563 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3564 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3565 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3566 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3567 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3568 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3569 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3570 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3571 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3572 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3576 /* Main preferences window */
3577 static void config_window_create(void)
3579 GtkWidget *win_vbox;
3581 GtkWidget *notebook;
3583 GtkWidget *ct_button;
3585 if (!c_options) c_options = init_options(NULL);
3587 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3588 DEBUG_NAME(configwindow);
3589 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3590 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3591 G_CALLBACK(config_window_delete), NULL);
3592 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3593 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3594 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3596 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3597 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3598 gtk_widget_show(win_vbox);
3600 notebook = gtk_notebook_new();
3601 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3602 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3603 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3605 config_tab_general(notebook);
3606 config_tab_image(notebook);
3607 config_tab_osd(notebook);
3608 config_tab_windows(notebook);
3609 config_tab_accelerators(notebook);
3610 config_tab_files(notebook);
3611 config_tab_metadata(notebook);
3612 config_tab_keywords(notebook);
3613 config_tab_color(notebook);
3614 config_tab_stereo(notebook);
3615 config_tab_behavior(notebook);
3616 config_tab_toolbar_main(notebook);
3617 config_tab_toolbar_status(notebook);
3619 hbox = gtk_hbutton_box_new();
3620 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3621 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3622 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3623 gtk_widget_show(hbox);
3625 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3626 G_CALLBACK(config_window_help_cb), notebook);
3627 gtk_container_add(GTK_CONTAINER(hbox), button);
3628 gtk_widget_set_can_default(button, TRUE);
3629 gtk_widget_show(button);
3631 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3632 G_CALLBACK(config_window_ok_cb), NULL);
3633 gtk_container_add(GTK_CONTAINER(hbox), button);
3634 gtk_widget_set_can_default(button, TRUE);
3635 gtk_widget_grab_default(button);
3636 gtk_widget_show(button);
3640 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3641 G_CALLBACK(config_window_close_cb), NULL);
3642 gtk_container_add(GTK_CONTAINER(hbox), button);
3643 gtk_widget_set_can_default(button, TRUE);
3644 gtk_widget_show(button);
3646 if (!generic_dialog_get_alternative_button_order(configwindow))
3648 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3651 gtk_widget_show(notebook);
3653 gtk_widget_show(configwindow);
3657 *-----------------------------------------------------------------------------
3658 * config window show (public)
3659 *-----------------------------------------------------------------------------
3662 void show_config_window(void)
3666 gtk_window_present(GTK_WINDOW(configwindow));
3670 config_window_create();
3679 void show_about_window(LayoutWindow *lw)
3681 GdkPixbuf *pixbuf_logo;
3682 GdkPixbuf *pixbuf_icon;
3683 gchar *authors[1000];
3688 gchar *timezone_path;
3692 #define LINE_LENGTH 1000
3693 gchar line[LINE_LENGTH];
3695 copyright = g_string_new(NULL);
3696 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");
3698 path = path_from_utf8(TIMEZONE_DATABASE);
3699 basename = g_path_get_basename(path);
3700 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3701 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3703 cd = ZDOpenDatabase(timezone_path);
3706 copyright = g_string_append(copyright, ZDGetNotice(cd));
3707 ZDCloseDatabase(cd);
3711 g_free(timezone_path);
3715 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3716 fp = fopen(path, "r");
3719 while(fgets(line, LINE_LENGTH, fp))
3721 /* get rid of ending \n from fgets */
3722 line[strlen(line) - 1] = '\0';
3723 authors[i_authors] = g_strdup(line);
3726 authors[i_authors] = NULL;
3731 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3732 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3734 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3735 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3736 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3737 "title", _("About Geeqie"),
3739 "program-name", GQ_APPNAME,
3741 "logo", pixbuf_logo,
3742 "icon", pixbuf_icon,
3743 "website", GQ_WEBSITE,
3744 "website-label", "Website",
3745 "comments", comment,
3747 "translator-credits", _("translator-credits"),
3748 "wrap-license", TRUE,
3749 "license", copyright->str,
3752 g_string_free(copyright, TRUE);
3755 while(n < i_authors)
3765 static void image_overlay_set_text_colours()
3767 c_options->image_overlay.text_red = options->image_overlay.text_red;
3768 c_options->image_overlay.text_green = options->image_overlay.text_green;
3769 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3770 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3771 c_options->image_overlay.background_red = options->image_overlay.background_red;
3772 c_options->image_overlay.background_green = options->image_overlay.background_green;
3773 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3774 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3778 *-----------------------------------------------------------------------------
3779 * timezone database routines
3780 *-----------------------------------------------------------------------------
3783 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3785 GError *error = NULL;
3787 gchar *tmp_filename;
3789 if (!g_cancellable_is_cancelled(tz->cancellable))
3791 generic_dialog_close(tz->gd);
3795 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3797 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3798 move_file(tmp_filename, tz->timezone_database_user);
3799 g_free(tmp_filename);
3803 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3806 g_file_delete(tz->tmp_g_file, NULL, &error);
3807 g_object_unref(tz->tmp_g_file);
3808 tz->tmp_g_file = NULL;
3809 g_object_unref(tz->cancellable);
3810 g_object_unref(tz->timezone_database_gq);
3813 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3817 if (!g_cancellable_is_cancelled(tz->cancellable))
3819 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3823 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3827 g_cancellable_cancel(tz->cancellable);
3830 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3833 GError *error = NULL;
3834 GFileIOStream *io_stream;
3841 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3845 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3846 log_printf("Error: Download timezone database failed:\n%s", error->message);
3847 g_error_free(error);
3848 g_object_unref(tz->tmp_g_file);
3852 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3854 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3856 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3858 tz->progress = gtk_progress_bar_new();
3859 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3860 gtk_widget_show(tz->progress);
3862 gtk_widget_show(tz->gd->dialog);
3863 tz->cancellable = g_cancellable_new();
3864 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);
3866 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3869 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */