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;
382 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
383 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
384 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
385 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
386 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
387 options->metadata.confirm_write = c_options->metadata.confirm_write;
388 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
389 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
390 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
391 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
392 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
393 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
394 options->metadata.write_orientation = c_options->metadata.write_orientation;
395 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
396 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
397 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
398 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
399 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
400 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
401 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
402 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
403 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
404 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
405 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
406 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
407 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
408 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
409 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
410 options->stereo.fixed_w = c_options->stereo.fixed_w;
411 options->stereo.fixed_h = c_options->stereo.fixed_h;
412 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
413 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
414 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
415 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
417 options->info_keywords.height = c_options->info_keywords.height;
418 options->info_title.height = c_options->info_title.height;
419 options->info_comment.height = c_options->info_comment.height;
420 options->info_rating.height = c_options->info_rating.height;
422 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
424 options->marks_save = c_options->marks_save;
425 options->with_rename = c_options->with_rename;
426 options->collections_on_top = c_options->collections_on_top;
427 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
429 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
431 options->star_rating.star = c_options->star_rating.star;
432 options->star_rating.rejected = c_options->star_rating.rejected;
434 set_debug_level(debug_c);
438 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
440 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
441 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
443 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
444 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
445 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
447 options->color_profile.render_intent = c_options->color_profile.render_intent;
452 options->mouse_button_8 = c_options->mouse_button_8;
453 options->mouse_button_9 = c_options->mouse_button_9;
455 config_tab_keywords_save();
457 image_options_sync();
462 layout_refresh(NULL);
465 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
467 toolbar_apply(TOOLBAR_MAIN);
468 toolbar_apply(TOOLBAR_STATUS);
472 *-----------------------------------------------------------------------------
473 * config window main button callbacks (private)
474 *-----------------------------------------------------------------------------
477 static void config_window_close_cb(GtkWidget *widget, gpointer data)
479 gtk_widget_destroy(configwindow);
484 static void config_window_help_cb(GtkWidget *widget, gpointer data)
486 GtkWidget *notebook = data;
489 static gchar *html_section[] =
491 "GuideOptionsGeneral.html",
492 "GuideOptionsImage.html",
493 "GuideOptionsOSD.html",
494 "GuideOptionsWindow.html",
495 "GuideOptionsKeyboard.html",
496 "GuideOptionsFiltering.html",
497 "GuideOptionsMetadata.html",
498 "GuideOptionsKeywords.html",
499 "GuideOptionsColor.html",
500 "GuideOptionsStereo.html",
501 "GuideOptionsBehavior.html",
502 "GuideOptionsToolbar.html"
505 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
506 help_window_show(html_section[i]);
509 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
511 config_window_close_cb(NULL, NULL);
515 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
517 config_window_apply();
518 config_window_close_cb(NULL, NULL);
521 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
524 lw = layout_window_list->data;
526 config_window_apply();
527 layout_util_sync(lw);
530 static void config_window_save_cb(GtkWidget *widget, gpointer data)
532 config_window_apply();
533 save_options(options);
537 *-----------------------------------------------------------------------------
538 * config window setup (private)
539 *-----------------------------------------------------------------------------
542 static void quality_menu_cb(GtkWidget *combo, gpointer data)
546 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
550 *option = GDK_INTERP_NEAREST;
553 *option = GDK_INTERP_TILES;
556 *option = GDK_INTERP_BILINEAR;
559 *option = GDK_INTERP_HYPER;
564 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
568 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
580 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
581 guint option, guint *option_c)
588 pref_table_label(table, column, row, text, 0.0);
590 combo = gtk_combo_box_text_new();
592 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
593 if (option == GDK_INTERP_NEAREST) current = 0;
594 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
595 if (option == GDK_INTERP_TILES) current = 1;
596 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
597 if (option == GDK_INTERP_BILINEAR) current = 2;
598 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
599 if (option == GDK_INTERP_HYPER) current = 3;
601 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
603 g_signal_connect(G_OBJECT(combo), "changed",
604 G_CALLBACK(quality_menu_cb), option_c);
606 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
607 GTK_EXPAND | GTK_FILL, 0, 0, 0);
608 gtk_widget_show(combo);
611 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
612 gint option, gint *option_c)
619 pref_table_label(table, column, row, text, 0.0);
621 combo = gtk_combo_box_text_new();
623 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
624 if (option == PRIMARY) current = 0;
625 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
626 if (option == CLIPBOARD) current = 1;
628 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
630 g_signal_connect(G_OBJECT(combo), "changed",
631 G_CALLBACK(clipboard_selection_menu_cb), option_c);
633 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
634 GTK_EXPAND | GTK_FILL, 0, 0, 0);
635 gtk_widget_show(combo);
638 typedef struct _UseableMouseItems UseableMouseItems;
639 struct _UseableMouseItems
641 gchar *name; /* GtkActionEntry terminology */
646 static const UseableMouseItems useable_mouse_items[] = {
648 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
649 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
650 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
651 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
652 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
653 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
654 {"Home", N_("Home"), GTK_STOCK_HOME},
655 {"Up", N_("Up"), GTK_STOCK_GO_UP},
656 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
657 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
658 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
659 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
660 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
661 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
662 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
663 {"Search", N_("Search"), GTK_STOCK_FIND},
664 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
665 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
666 {"Copy", N_("Copy"), GTK_STOCK_COPY},
667 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
668 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
669 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
670 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
671 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
672 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
673 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
674 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
675 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
676 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
677 {"Print", N_("Print"), GTK_STOCK_PRINT},
678 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
679 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
680 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
681 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
682 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
683 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
684 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
685 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
686 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
687 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
688 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
689 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
690 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
691 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
692 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
693 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
694 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
695 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
696 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
697 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
698 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
699 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
700 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
701 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
702 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
703 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
704 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
705 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
706 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
707 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
708 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
709 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
710 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
711 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
712 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
713 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
714 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
715 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
716 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
720 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
722 gchar **option = data;
725 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
727 const UseableMouseItems *list = useable_mouse_items;
731 if (g_strcmp0(list->label, label) == 0)
739 *option = g_strdup(list->name);
743 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
744 gchar *option, gchar **option_c)
752 pref_table_label(table, column, row, text, 0.0);
754 combo = gtk_combo_box_text_new();
756 const UseableMouseItems *list = useable_mouse_items;
760 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
761 if (g_strcmp0(list->name, option) == 0)
769 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
771 g_signal_connect(G_OBJECT(combo), "changed",
772 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
774 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
775 GTK_EXPAND | GTK_FILL, 0, 0, 0);
776 gtk_widget_show(combo);
779 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
783 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
786 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
788 c_options->thumbnails.max_width = thumb_size_list[n].w;
789 c_options->thumbnails.max_height = thumb_size_list[n].h;
793 c_options->thumbnails.max_width = options->thumbnails.max_width;
794 c_options->thumbnails.max_height = options->thumbnails.max_height;
798 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
804 c_options->thumbnails.max_width = options->thumbnails.max_width;
805 c_options->thumbnails.max_height = options->thumbnails.max_height;
807 pref_table_label(table, column, row, text, 0.0);
809 combo = gtk_combo_box_text_new();
812 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
817 w = thumb_size_list[i].w;
818 h = thumb_size_list[i].h;
820 buf = g_strdup_printf("%d x %d", w, h);
821 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
824 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
831 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
832 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
838 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
839 g_signal_connect(G_OBJECT(combo), "changed",
840 G_CALLBACK(thumb_size_menu_cb), NULL);
842 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
843 GTK_EXPAND | GTK_FILL, 0, 0, 0);
844 gtk_widget_show(combo);
847 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
851 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
855 *option = PR_STEREO_NONE;
858 *option = PR_STEREO_ANAGLYPH_RC;
861 *option = PR_STEREO_ANAGLYPH_GM;
864 *option = PR_STEREO_ANAGLYPH_YB;
867 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
870 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
873 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
876 *option = PR_STEREO_ANAGLYPH_DB_RC;
879 *option = PR_STEREO_ANAGLYPH_DB_GM;
882 *option = PR_STEREO_ANAGLYPH_DB_YB;
885 *option = PR_STEREO_HORIZ;
888 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
891 *option = PR_STEREO_VERT;
894 *option = PR_STEREO_VERT | PR_STEREO_HALF;
897 *option = PR_STEREO_FIXED;
902 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
903 gint option, gint *option_c, gboolean add_fixed)
910 pref_table_label(table, column, row, text, 0.0);
912 combo = gtk_combo_box_text_new();
914 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
916 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
917 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
918 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
919 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
920 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
921 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
922 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
923 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
924 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
925 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
926 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
927 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
928 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
929 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
930 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
931 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
932 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
933 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
935 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
936 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
937 if (option & PR_STEREO_HORIZ)
940 if (option & PR_STEREO_HALF) current = 11;
943 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
944 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
945 if (option & PR_STEREO_VERT)
948 if (option & PR_STEREO_HALF) current = 13;
953 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
954 if (option & PR_STEREO_FIXED) current = 14;
957 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
959 g_signal_connect(G_OBJECT(combo), "changed",
960 G_CALLBACK(stereo_mode_menu_cb), option_c);
962 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
963 GTK_EXPAND | GTK_FILL, 0, 0, 0);
964 gtk_widget_show(combo);
967 static void video_menu_cb(GtkWidget *combo, gpointer data)
969 gchar **option = data;
971 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
975 static void video_menu_populate(gpointer data, gpointer user_data)
977 GtkWidget *combo = user_data;
978 EditorDescription *ed = data;
980 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
983 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
984 gchar *option, gchar **option_c)
988 /* use lists since they are sorted */
989 GList *eds = editor_list_get();
993 pref_table_label(table, column, row, text, 0.0);
995 combo = gtk_combo_box_text_new();
996 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
997 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
999 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1001 g_signal_connect(G_OBJECT(combo), "changed",
1002 G_CALLBACK(video_menu_cb), option_c);
1004 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
1005 GTK_EXPAND | GTK_FILL, 0, 0, 0);
1006 gtk_widget_show(combo);
1009 static void filter_store_populate(void)
1013 if (!filter_store) return;
1015 gtk_list_store_clear(filter_store);
1017 work = filter_get_list();
1026 gtk_list_store_append(filter_store, &iter);
1027 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1031 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1032 gchar *new_text, gpointer data)
1034 GtkWidget *model = data;
1035 FilterEntry *fe = data;
1039 if (!new_text || strlen(new_text) < 1) return;
1041 tpath = gtk_tree_path_new_from_string(path_str);
1042 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1043 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1045 g_free(fe->extensions);
1046 fe->extensions = g_strdup(new_text);
1048 gtk_tree_path_free(tpath);
1052 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1053 gchar *new_text, gpointer data)
1055 GtkWidget *model = data;
1056 FilterEntry *fe = data;
1061 if (!new_text || !new_text[0]) return;
1063 tpath = gtk_tree_path_new_from_string(path_str);
1064 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1065 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1067 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1069 if (strcmp(new_text, _(format_class_list[i])) == 0)
1076 gtk_tree_path_free(tpath);
1080 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1081 gchar *new_text, gpointer data)
1083 GtkWidget *model = data;
1088 if (!new_text || !new_text[0]) return;
1090 tpath = gtk_tree_path_new_from_string(path_str);
1091 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1092 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1094 g_free(fe->description);
1095 fe->description = g_strdup(new_text);
1097 gtk_tree_path_free(tpath);
1100 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1101 gchar *path_str, gpointer data)
1103 GtkWidget *model = data;
1108 tpath = gtk_tree_path_new_from_string(path_str);
1109 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1110 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1112 fe->enabled = !fe->enabled;
1114 gtk_tree_path_free(tpath);
1118 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1119 gchar *path_str, gpointer data)
1121 GtkWidget *model = data;
1126 tpath = gtk_tree_path_new_from_string(path_str);
1127 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1128 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1130 fe->writable = !fe->writable;
1131 if (fe->writable) fe->allow_sidecar = FALSE;
1133 gtk_tree_path_free(tpath);
1137 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1138 gchar *path_str, gpointer data)
1140 GtkWidget *model = data;
1145 tpath = gtk_tree_path_new_from_string(path_str);
1146 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1147 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1149 fe->allow_sidecar = !fe->allow_sidecar;
1150 if (fe->allow_sidecar) fe->writable = FALSE;
1152 gtk_tree_path_free(tpath);
1156 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1157 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1161 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1163 switch (GPOINTER_TO_INT(data))
1166 g_object_set(GTK_CELL_RENDERER(cell),
1167 "active", fe->enabled, NULL);
1170 g_object_set(GTK_CELL_RENDERER(cell),
1171 "text", fe->extensions, NULL);
1173 case FE_DESCRIPTION:
1174 g_object_set(GTK_CELL_RENDERER(cell),
1175 "text", fe->description, NULL);
1178 g_object_set(GTK_CELL_RENDERER(cell),
1179 "text", _(format_class_list[fe->file_class]), NULL);
1182 g_object_set(GTK_CELL_RENDERER(cell),
1183 "active", fe->writable, NULL);
1185 case FE_ALLOW_SIDECAR:
1186 g_object_set(GTK_CELL_RENDERER(cell),
1187 "active", fe->allow_sidecar, NULL);
1192 static gboolean filter_add_scroll(gpointer data)
1196 GtkCellRenderer *cell;
1197 GtkTreeViewColumn *column;
1202 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1203 path = gtk_tree_path_new_from_indices(rows-1, -1);
1205 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1207 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1208 cell = g_list_last(list_cells)->data;
1210 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1211 path, column, FALSE, 0.0, 0.0 );
1212 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1213 path, column, cell, TRUE);
1215 gtk_tree_path_free(path);
1216 g_list_free(list_cells);
1221 static void filter_add_cb(GtkWidget *widget, gpointer data)
1223 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1224 filter_store_populate();
1226 g_idle_add((GSourceFunc)filter_add_scroll, data);
1229 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1231 GtkWidget *filter_view = data;
1232 GtkTreeSelection *selection;
1236 if (!filter_store) return;
1237 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1238 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1239 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1242 filter_remove_entry(fe);
1244 filter_store_populate();
1247 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1251 GtkTreeViewColumn *column;
1253 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1254 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1255 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1257 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1261 gtk_tree_path_free(path);
1266 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1269 filter_add_defaults();
1271 filter_store_populate();
1273 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1276 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1278 /* no op, only so cancel button appears */
1281 static void filter_default_cb(GtkWidget *widget, gpointer data)
1285 gd = generic_dialog_new(_("Reset filters"),
1286 "reset_filter", widget, TRUE,
1287 dummy_cancel_cb, data);
1288 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1289 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1290 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1291 gtk_widget_show(gd->dialog);
1294 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1296 GtkWidget *frame = data;
1298 gtk_widget_set_sensitive(frame,
1299 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1302 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1304 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1307 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1309 file_util_trash_clear();
1312 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1316 gd = generic_dialog_new(_("Clear trash"),
1317 "clear_trash", widget, TRUE,
1318 dummy_cancel_cb, NULL);
1319 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1320 _("This will remove the trash contents."), FALSE);
1321 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1322 entry = gtk_entry_new();
1323 gtk_widget_set_can_focus(entry, FALSE);
1324 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1325 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1326 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1327 gtk_widget_show(entry);
1328 gtk_widget_show(gd->dialog);
1331 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1333 GtkWidget *pTextView;
1334 GtkTextBuffer *pTextBuffer;
1338 pTextView = GTK_WIDGET(data);
1340 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1341 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1342 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1344 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1345 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1348 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1350 GtkTextView *text_view = data;
1351 GtkTextBuffer *buffer;
1353 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1354 if (!configwindow) return;
1356 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1357 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1360 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1364 gd = generic_dialog_new(_("Reset image overlay template string"),
1365 "reset_image_overlay_template_string", widget, TRUE,
1366 dummy_cancel_cb, data);
1367 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1368 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1369 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1370 gtk_widget_show(gd->dialog);
1373 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1375 help_window_show("GuideOptionsOSD.html");
1378 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1380 #if GTK_CHECK_VERSION(3,4,0)
1383 PangoFontDescription *font_desc;
1385 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1386 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1388 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1390 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1391 font = pango_font_description_to_string(font_desc);
1392 g_free(c_options->image_overlay.font);
1393 c_options->image_overlay.font = g_strdup(font);
1397 gtk_widget_destroy(dialog);
1401 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1402 c_options->image_overlay.font = g_strdup(font);
1406 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1409 #if GTK_CHECK_VERSION(3,4,0)
1412 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1413 colour.red = options->image_overlay.text_red;
1414 colour.green = options->image_overlay.text_green;
1415 colour.blue = options->image_overlay.text_blue;
1416 colour.alpha = options->image_overlay.text_alpha;
1417 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1418 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1420 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1422 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1423 c_options->image_overlay.text_red = colour.red*255;
1424 c_options->image_overlay.text_green = colour.green*255;
1425 c_options->image_overlay.text_blue = colour.blue*255;
1426 c_options->image_overlay.text_alpha = colour.alpha*255;
1428 gtk_widget_destroy(dialog);
1431 GtkColorSelection *colorsel;
1433 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1434 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1435 colour.red = options->image_overlay.text_red*257;
1436 colour.green = options->image_overlay.text_green*257;
1437 colour.blue = options->image_overlay.text_blue*257;
1438 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1439 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1440 gtk_color_selection_set_current_color(colorsel, &colour);
1441 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1443 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1445 gtk_color_selection_get_current_color(colorsel, &colour);
1446 c_options->image_overlay.text_red = colour.red/257;
1447 c_options->image_overlay.text_green = colour.green/257;
1448 c_options->image_overlay.text_blue = colour.blue/257;
1449 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1451 gtk_widget_destroy (dialog);
1456 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1459 #if GTK_CHECK_VERSION(3,4,0)
1462 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1463 colour.red = options->image_overlay.background_red;
1464 colour.green = options->image_overlay.background_green;
1465 colour.blue = options->image_overlay.background_blue;
1466 colour.alpha = options->image_overlay.background_alpha;
1467 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1468 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1470 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1472 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1473 c_options->image_overlay.background_red = colour.red*255;
1474 c_options->image_overlay.background_green = colour.green*255;
1475 c_options->image_overlay.background_blue = colour.blue*255;
1476 c_options->image_overlay.background_alpha = colour.alpha*255;
1478 gtk_widget_destroy(dialog);
1481 GtkColorSelection *colorsel;
1483 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1484 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1485 colour.red = options->image_overlay.background_red*257;
1486 colour.green = options->image_overlay.background_green*257;
1487 colour.blue = options->image_overlay.background_blue*257;
1488 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1489 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1490 gtk_color_selection_set_current_color(colorsel, &colour);
1491 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1493 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1495 gtk_color_selection_get_current_color(colorsel, &colour);
1496 c_options->image_overlay.background_red = colour.red/257;
1497 c_options->image_overlay.background_green = colour.green/257;
1498 c_options->image_overlay.background_blue = colour.blue/257;
1499 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1501 gtk_widget_destroy(dialog);
1505 static void accel_store_populate(void)
1508 GList *groups, *actions;
1510 const gchar *accel_path;
1514 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1516 gtk_tree_store_clear(accel_store);
1517 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1519 g_assert(lw && lw->ui_manager);
1520 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1523 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1526 action = GTK_ACTION(actions->data);
1527 accel_path = gtk_action_get_accel_path(action);
1528 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1530 gchar *label, *label2, *tooltip, *accel;
1531 g_object_get(action,
1532 "tooltip", &tooltip,
1536 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1542 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1546 gtk_tree_store_append(accel_store, &iter, NULL);
1547 gtk_tree_store_set(accel_store, &iter,
1550 AE_TOOLTIP, tooltip ? tooltip : "",
1551 AE_ACCEL, accel_path,
1559 actions = actions->next;
1562 groups = groups->next;
1566 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1571 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1573 gchar *accel1 = data;
1578 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1580 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1581 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1583 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1585 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1586 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1595 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1597 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1601 GtkAccelKey old_key, key;
1602 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1604 gtk_tree_model_get_iter(model, &iter, path);
1605 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1607 /* test if the accelerator can be stored without conflicts*/
1608 gtk_accel_map_lookup_entry(accel_path, &old_key);
1610 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1611 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1612 gtk_accel_map_lookup_entry(accel_path, &key);
1614 /* restore the original for now, the key will be really changed when the changes are confirmed */
1615 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1617 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1618 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1620 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1621 gtk_tree_path_free(path);
1625 static gboolean accel_default_scroll(GtkTreeView *data)
1629 GtkTreeViewColumn *column;
1631 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1632 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1633 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1635 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1639 gtk_tree_path_free(path);
1644 static void accel_default_cb(GtkWidget *widget, gpointer data)
1646 accel_store_populate();
1648 g_idle_add((GSourceFunc)accel_default_scroll, data);
1651 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1653 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1656 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1659 gchar *accel_path, *accel;
1661 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1662 gtk_accel_map_lookup_entry(accel_path, &key);
1663 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1665 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1667 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1672 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1674 GtkTreeSelection *selection;
1676 if (!accel_store) return;
1677 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1678 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1683 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1687 GtkWidget *scrolled;
1688 GtkWidget *viewport;
1690 scrolled = gtk_scrolled_window_new(NULL, NULL);
1691 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1692 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1693 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1694 label = gtk_label_new(title);
1695 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1696 gtk_widget_show(scrolled);
1698 viewport = gtk_viewport_new(NULL, NULL);
1699 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1700 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1701 gtk_widget_show(viewport);
1703 vbox = gtk_vbox_new(FALSE, 0);
1704 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1705 gtk_widget_show(vbox);
1710 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1712 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1714 c_options->thumbnails.spec_standard =TRUE;
1715 c_options->thumbnails.cache_into_dirs = FALSE;
1719 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1721 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1723 c_options->thumbnails.spec_standard =FALSE;
1724 c_options->thumbnails.cache_into_dirs = FALSE;
1728 static void cache_local_cb(GtkWidget *widget, gpointer data)
1730 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1732 c_options->thumbnails.cache_into_dirs = TRUE;
1733 c_options->thumbnails.spec_standard =FALSE;
1737 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1738 GdkEvent *event, gpointer userdata)
1740 if (pos == GTK_ENTRY_ICON_PRIMARY)
1742 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1746 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1750 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1751 GdkEvent *event, gpointer userdata)
1753 gchar *rating_symbol;
1755 if (pos == GTK_ENTRY_ICON_PRIMARY)
1757 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1758 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1759 g_free(rating_symbol);
1763 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1764 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1765 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1769 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1770 GdkEvent *event, gpointer userdata)
1772 gchar *rating_symbol;
1774 if (pos == GTK_ENTRY_ICON_PRIMARY)
1776 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1777 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1778 g_free(rating_symbol);
1782 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1783 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1784 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1788 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1790 GtkContainer *hbox = data;
1791 GString *str = g_string_new(NULL);
1792 GtkEntry *hex_code_entry;
1793 gchar *hex_code_full;
1796 guint64 hex_value = 0;
1798 list = gtk_container_get_children(hbox);
1800 hex_code_entry = g_list_nth_data(list, 2);
1801 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1803 hex_code = g_strsplit(hex_code_full, "+", 2);
1804 if (hex_code[0] && hex_code[1])
1806 hex_value = strtoull(hex_code[1], NULL, 16);
1808 if (!hex_value || hex_value > 0x10FFFF)
1810 hex_value = 0x003F; // Unicode 'Question Mark'
1812 str = g_string_append_unichar(str, (gunichar)hex_value);
1813 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1815 g_strfreev(hex_code);
1816 g_string_free(str, TRUE);
1817 g_free(hex_code_full);
1822 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1824 guint64 star_symbol;
1826 star_symbol = star_rating_symbol_test(widget, data);
1827 c_options->star_rating.star = star_symbol;
1830 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1832 guint64 rejected_symbol;
1834 rejected_symbol = star_rating_symbol_test(widget, data);
1835 c_options->star_rating.rejected = rejected_symbol;
1838 /* general options tab */
1839 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1840 typedef struct _TZData TZData;
1844 GCancellable *cancellable;
1846 GtkWidget *progress;
1848 GFile *timezone_database_gq;
1849 gchar *timezone_database_user;
1852 static void config_tab_general(GtkWidget *notebook)
1857 GtkWidget *group_frame;
1858 GtkWidget *subgroup;
1860 GtkWidget *ct_button;
1863 gint hours, minutes, remainder;
1865 GtkWidget *star_rating_entry;
1867 gchar *rating_symbol;
1870 GNetworkMonitor *net_mon;
1871 GSocketConnectable *geeqie_org;
1872 gboolean internet_available;
1875 vbox = scrolled_notebook_page(notebook, _("General"));
1877 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1879 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1880 add_thumb_size_menu(table, 0, 0, _("Size:"));
1881 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1883 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1884 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1886 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1887 pref_checkbox_link_sensitivity(ct_button, subgroup);
1889 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1890 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1891 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1892 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1893 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1894 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1895 G_CALLBACK(cache_geeqie_cb), NULL);
1897 group_frame = pref_frame_new(subgroup, TRUE,
1898 _("Store thumbnails local to image folder (non-standard)"),
1899 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1900 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1901 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1902 G_CALLBACK(cache_local_cb), NULL);
1904 group_frame = pref_frame_new(subgroup, TRUE,
1905 _("Use standard thumbnail style and cache, shared with other applications"),
1906 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1907 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1908 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1909 G_CALLBACK(cache_standard_cb), NULL);
1911 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1912 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1914 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1916 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1917 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1919 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1920 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1921 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1923 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1924 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1927 pref_spacer(group, PREF_PAD_GROUP);
1929 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1931 c_options->star_rating.star = options->star_rating.star;
1932 c_options->star_rating.rejected = options->star_rating.rejected;
1934 str = g_string_new(NULL);
1935 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1936 pref_label_new(hbox, "Star character: ");
1937 str = g_string_append_unichar(str, options->star_rating.star);
1938 pref_label_new(hbox, g_strdup(str->str));
1939 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1940 star_rating_entry = gtk_entry_new();
1941 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1942 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1943 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1944 gtk_widget_show(star_rating_entry);
1945 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1946 G_CALLBACK(star_rating_star_test_cb), hbox);
1947 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1948 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1949 gtk_widget_show(button);
1950 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."));
1951 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1952 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1953 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1954 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1955 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1956 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1957 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1958 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1959 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1960 G_CALLBACK(star_rating_star_icon_cb),
1963 g_string_free(str, TRUE);
1964 g_free(rating_symbol);
1966 str = g_string_new(NULL);
1967 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1968 pref_label_new(hbox, "Rejected character: ");
1969 str = g_string_append_unichar(str, options->star_rating.rejected);
1970 pref_label_new(hbox, g_strdup(str->str));
1971 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
1972 star_rating_entry = gtk_entry_new();
1973 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1974 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1975 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1976 gtk_widget_show(star_rating_entry);
1977 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1978 G_CALLBACK(star_rating_rejected_test_cb), hbox);
1979 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1980 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1981 gtk_widget_show(button);
1982 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."));
1983 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1984 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1985 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1986 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1987 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1988 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1989 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1990 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1991 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1992 G_CALLBACK(star_rating_rejected_icon_cb),
1995 g_string_free(str, TRUE);
1996 g_free(rating_symbol);
1998 pref_spacer(group, PREF_PAD_GROUP);
2000 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2002 c_options->slideshow.delay = options->slideshow.delay;
2003 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2004 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2005 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2006 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2007 SLIDESHOW_SUBSECOND_PRECISION;
2009 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2011 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2013 options->slideshow.delay ? hours : 0.0,
2014 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2015 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2016 spin = pref_spin_new(hbox, ":" , NULL,
2018 options->slideshow.delay ? minutes: 0.0,
2019 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2020 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2021 spin = pref_spin_new(hbox, ":", NULL,
2022 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2023 options->slideshow.delay ? seconds : 10.0,
2024 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2025 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2027 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2028 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2030 pref_spacer(group, PREF_PAD_GROUP);
2032 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2034 pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
2035 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2036 pref_checkbox_new_int(group, _("Preload next image"),
2037 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2039 pref_checkbox_new_int(group, _("Refresh on file change"),
2040 options->update_on_time_change, &c_options->update_on_time_change);
2042 pref_spacer(group, PREF_PAD_GROUP);
2044 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2045 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2046 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2047 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2049 options->info_keywords.height, &c_options->info_keywords.height);
2050 pref_spin_new_int(hbox, _("Title:"), NULL,
2052 options->info_title.height, &c_options->info_title.height);
2053 pref_spin_new_int(hbox, _("Comment:"), NULL,
2055 options->info_comment.height, &c_options->info_comment.height);
2056 pref_spin_new_int(hbox, _("Rating:"), NULL,
2058 options->info_rating.height, &c_options->info_rating.height);
2060 pref_spacer(group, PREF_PAD_GROUP);
2062 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2064 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2065 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2067 pref_spacer(group, PREF_PAD_GROUP);
2069 net_mon = g_network_monitor_get_default();
2070 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2071 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2072 g_object_unref(geeqie_org);
2074 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2075 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2077 if (!internet_available)
2079 gtk_widget_set_sensitive(group, FALSE);
2082 tz = g_new0(TZData, 1);
2084 path = path_from_utf8(TIMEZONE_DATABASE);
2085 basename = g_path_get_basename(path);
2086 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2090 if (isfile(tz->timezone_database_user))
2092 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2096 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2099 if (!internet_available)
2101 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"));
2105 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"));
2107 gtk_widget_show(button);
2109 pref_spacer(group, PREF_PAD_GROUP);
2111 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2113 help_search_engine_entry = gtk_entry_new();
2114 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2115 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2116 gtk_widget_show(help_search_engine_entry);
2118 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"));
2120 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2121 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2122 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2123 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2124 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2125 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2126 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2127 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2128 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2129 G_CALLBACK(help_search_engine_entry_icon_cb),
2130 help_search_engine_entry);
2134 static void config_tab_image(GtkWidget *notebook)
2139 GtkWidget *ct_button;
2140 GtkWidget *enlargement_button;
2144 vbox = scrolled_notebook_page(notebook, _("Image"));
2146 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2148 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2149 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2152 pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
2153 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2156 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2157 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2159 c_options->image.zoom_increment = options->image.zoom_increment;
2160 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2161 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2162 G_CALLBACK(zoom_increment_cb), NULL);
2163 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2165 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2167 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2168 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2169 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2170 spin = pref_spin_new_int(hbox, NULL, NULL,
2172 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2173 pref_checkbox_link_sensitivity(enlargement_button, spin);
2174 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."));
2176 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2177 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2178 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2179 spin = pref_spin_new_int(hbox, NULL, NULL,
2181 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2182 pref_checkbox_link_sensitivity(ct_button, spin);
2183 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."));
2185 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2187 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2188 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2190 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2191 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2193 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2194 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2196 c_options->image.border_color = options->image.border_color;
2198 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2199 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2201 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2202 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2204 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2205 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2207 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2209 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2210 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2214 static void config_tab_windows(GtkWidget *notebook)
2220 GtkWidget *ct_button;
2223 vbox = scrolled_notebook_page(notebook, _("Windows"));
2225 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2227 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2228 options->save_window_positions, &c_options->save_window_positions);
2230 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2231 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2232 pref_checkbox_link_sensitivity(ct_button, button);
2234 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2235 options->tools_restore_state, &c_options->tools_restore_state);
2237 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2238 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2240 pref_checkbox_new_int(group, _("Show window IDs"),
2241 options->show_window_ids, &c_options->show_window_ids);
2243 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2245 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2246 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2248 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2249 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2250 options->image.limit_window_size, &c_options->image.limit_window_size);
2251 spin = pref_spin_new_int(hbox, NULL, NULL,
2253 options->image.max_window_size, &c_options->image.max_window_size);
2254 pref_checkbox_link_sensitivity(ct_button, spin);
2256 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2258 c_options->fullscreen.screen = options->fullscreen.screen;
2259 c_options->fullscreen.above = options->fullscreen.above;
2260 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2261 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2262 gtk_widget_show(hbox);
2264 pref_checkbox_new_int(group, _("Smooth image flip"),
2265 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2266 pref_checkbox_new_int(group, _("Disable screen saver"),
2267 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2270 #define PRE_FORMATTED_COLUMNS 5
2271 static void config_tab_osd(GtkWidget *notebook)
2275 GtkWidget *vbox_buttons;
2278 GtkWidget *image_overlay_template_view;
2279 GtkWidget *scrolled;
2280 GtkWidget *scrolled_pre_formatted;
2281 GtkTextBuffer *buffer;
2283 GtkWidget * subgroup;
2288 vbox = scrolled_notebook_page(notebook, _("OSD"));
2290 image_overlay_template_view = gtk_text_view_new();
2292 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2294 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2296 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2297 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2298 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2299 gtk_widget_show(scrolled_pre_formatted);
2300 gtk_widget_show(subgroup);
2302 pref_line(group, PREF_PAD_GAP);
2304 pref_label_new(group, _("Image overlay template"));
2306 scrolled = gtk_scrolled_window_new(NULL, NULL);
2307 gtk_widget_set_size_request(scrolled, 200, 150);
2308 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2309 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2310 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2311 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2312 gtk_widget_show(scrolled);
2314 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2315 _("Extensive formatting options are shown in the Help file"));
2317 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2318 gtk_widget_show(image_overlay_template_view);
2320 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2322 #if GTK_CHECK_VERSION(3,4,0)
2323 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2324 G_CALLBACK(image_overlay_set_font_cb), notebook);
2326 button = gtk_font_button_new();
2327 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2328 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2329 g_signal_connect(G_OBJECT(button), "font-set",
2330 G_CALLBACK(image_overlay_set_font_cb),NULL);
2332 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2333 gtk_widget_show(button);
2335 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2336 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2337 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2338 gtk_widget_show(button);
2340 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2341 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2342 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2343 gtk_widget_show(button);
2344 image_overlay_set_text_colours();
2346 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2347 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2348 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2349 gtk_widget_show(button);
2351 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2352 G_CALLBACK(image_overlay_help_cb), NULL);
2353 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2354 gtk_widget_show(button);
2356 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2357 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2358 g_signal_connect(G_OBJECT(buffer), "changed",
2359 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2361 pref_line(group, PREF_PAD_GAP);
2363 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2364 hbox = gtk_hbox_new(FALSE, 0);
2365 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2366 gtk_widget_show(hbox);
2367 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2368 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2369 gtk_widget_show(label);
2370 pref_spacer(group,TRUE);
2372 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2373 hbox = gtk_hbox_new(FALSE, 0);
2374 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2375 gtk_widget_show(hbox);
2376 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2377 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2378 gtk_widget_show(label);
2379 pref_spacer(group,TRUE);
2381 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2382 hbox = gtk_hbox_new(FALSE, 0);
2383 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2384 gtk_widget_show(hbox);
2385 label = gtk_label_new(_("%path:39%"));
2386 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2387 gtk_widget_show(label);
2388 pref_spacer(group,TRUE);
2390 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2391 hbox = gtk_hbox_new(FALSE, 0);
2392 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2393 gtk_widget_show(hbox);
2394 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%"));
2395 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2396 gtk_widget_show(label);
2397 pref_spacer(group,TRUE);
2399 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2400 hbox = gtk_hbox_new(FALSE, 0);
2401 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2402 gtk_widget_show(hbox);
2403 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2404 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2405 gtk_widget_show(label);
2408 static GtkTreeModel *create_class_model(void)
2410 GtkListStore *model;
2414 /* create list store */
2415 model = gtk_list_store_new(1, G_TYPE_STRING);
2416 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2418 gtk_list_store_append(model, &iter);
2419 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2421 return GTK_TREE_MODEL (model);
2426 static void config_tab_files(GtkWidget *notebook)
2433 GtkWidget *ct_button;
2434 GtkWidget *scrolled;
2435 GtkWidget *filter_view;
2436 GtkCellRenderer *renderer;
2437 GtkTreeSelection *selection;
2438 GtkTreeViewColumn *column;
2440 vbox = scrolled_notebook_page(notebook, _("Files"));
2442 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2444 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2445 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2446 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2447 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2448 pref_checkbox_new_int(group, _("Case sensitive sort"),
2449 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2450 pref_checkbox_new_int(group, _("Natural sort order"),
2451 options->file_sort.natural, &c_options->file_sort.natural);
2452 pref_checkbox_new_int(group, _("Disable file extension checks"),
2453 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2455 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2456 options->file_filter.disable, &c_options->file_filter.disable);
2459 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2461 sidecar_ext_entry = gtk_entry_new();
2462 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2463 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2464 gtk_widget_show(sidecar_ext_entry);
2466 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2468 frame = pref_group_parent(group);
2469 g_signal_connect(G_OBJECT(ct_button), "toggled",
2470 G_CALLBACK(filter_disable_cb), frame);
2471 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2473 scrolled = gtk_scrolled_window_new(NULL, NULL);
2474 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2475 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2476 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2477 gtk_widget_show(scrolled);
2479 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2480 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2481 g_object_unref(filter_store);
2482 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2483 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2485 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2487 column = gtk_tree_view_column_new();
2488 gtk_tree_view_column_set_title(column, _("Filter"));
2489 gtk_tree_view_column_set_resizable(column, TRUE);
2491 renderer = gtk_cell_renderer_toggle_new();
2492 g_signal_connect(G_OBJECT(renderer), "toggled",
2493 G_CALLBACK(filter_store_enable_cb), filter_store);
2494 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2495 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2496 GINT_TO_POINTER(FE_ENABLE), NULL);
2498 renderer = gtk_cell_renderer_text_new();
2499 g_signal_connect(G_OBJECT(renderer), "edited",
2500 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2501 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2502 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2503 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2504 GINT_TO_POINTER(FE_EXTENSION), NULL);
2505 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2507 column = gtk_tree_view_column_new();
2508 gtk_tree_view_column_set_title(column, _("Description"));
2509 gtk_tree_view_column_set_resizable(column, TRUE);
2510 gtk_tree_view_column_set_fixed_width(column, 200);
2511 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2513 renderer = gtk_cell_renderer_text_new();
2514 g_signal_connect(G_OBJECT(renderer), "edited",
2515 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2516 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2517 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2518 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2519 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2520 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2522 column = gtk_tree_view_column_new();
2523 gtk_tree_view_column_set_title(column, _("Class"));
2524 gtk_tree_view_column_set_resizable(column, TRUE);
2525 renderer = gtk_cell_renderer_combo_new();
2526 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2527 "model", create_class_model(),
2532 g_signal_connect(G_OBJECT(renderer), "edited",
2533 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2534 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2535 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2536 GINT_TO_POINTER(FE_CLASS), NULL);
2537 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2539 column = gtk_tree_view_column_new();
2540 gtk_tree_view_column_set_title(column, _("Writable"));
2541 gtk_tree_view_column_set_resizable(column, FALSE);
2542 renderer = gtk_cell_renderer_toggle_new();
2543 g_signal_connect(G_OBJECT(renderer), "toggled",
2544 G_CALLBACK(filter_store_writable_cb), filter_store);
2545 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2546 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2547 GINT_TO_POINTER(FE_WRITABLE), NULL);
2548 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2550 column = gtk_tree_view_column_new();
2551 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2552 gtk_tree_view_column_set_resizable(column, FALSE);
2553 renderer = gtk_cell_renderer_toggle_new();
2554 g_signal_connect(G_OBJECT(renderer), "toggled",
2555 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2556 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2557 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2558 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2559 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2562 filter_store_populate();
2563 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2564 gtk_widget_show(filter_view);
2566 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2568 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2569 G_CALLBACK(filter_default_cb), filter_view);
2570 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2571 gtk_widget_show(button);
2573 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2574 G_CALLBACK(filter_remove_cb), filter_view);
2575 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2576 gtk_widget_show(button);
2578 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2579 G_CALLBACK(filter_add_cb), filter_view);
2580 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2581 gtk_widget_show(button);
2585 static void config_tab_metadata(GtkWidget *notebook)
2590 GtkWidget *ct_button;
2594 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2597 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2599 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2601 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2602 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2604 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2605 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2607 gtk_widget_set_sensitive(ct_button, FALSE);
2610 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2611 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2613 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2614 label = pref_label_new(group, text);
2615 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2616 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2619 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2621 gtk_widget_set_sensitive(group, FALSE);
2624 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2625 pref_checkbox_link_sensitivity(ct_button, hbox);
2627 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2628 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2630 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2631 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2633 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2634 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2636 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2637 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2639 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2641 gtk_widget_set_sensitive(group, FALSE);
2644 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2645 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2648 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2649 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2650 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2652 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2653 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2655 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2656 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2658 gtk_widget_set_sensitive(ct_button, FALSE);
2661 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2663 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2664 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2666 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2667 pref_checkbox_link_sensitivity(ct_button, hbox);
2669 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2670 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2672 pref_checkbox_new_int(group, _("Write metadata on image change"),
2673 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2675 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2676 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2678 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2680 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2681 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2682 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");
2687 typedef struct _KeywordFindData KeywordFindData;
2688 struct _KeywordFindData
2695 GtkWidget *button_close;
2696 GtkWidget *button_stop;
2697 GtkWidget *button_start;
2698 GtkWidget *progress;
2706 guint idle_id; /* event source id */
2709 #define KEYWORD_DIALOG_WIDTH 400
2711 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2713 GList *list_d = NULL;
2714 GList *list_f = NULL;
2718 filelist_read(dir_fd, &list_f, &list_d);
2722 filelist_read(dir_fd, &list_f, NULL);
2725 list_f = filelist_filter(list_f, FALSE);
2726 list_d = filelist_filter(list_d, TRUE);
2728 kfd->list = g_list_concat(list_f, kfd->list);
2729 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2732 static void keywords_find_reset(KeywordFindData *kfd)
2734 filelist_free(kfd->list);
2737 filelist_free(kfd->list_dir);
2738 kfd->list_dir = NULL;
2741 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2743 KeywordFindData *kfd = data;
2745 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2747 keywords_find_reset(kfd);
2748 generic_dialog_close(kfd->gd);
2752 static void keywords_find_finish(KeywordFindData *kfd)
2754 keywords_find_reset(kfd);
2756 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2757 spinner_set_interval(kfd->spinner, -1);
2759 gtk_widget_set_sensitive(kfd->group, TRUE);
2760 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2761 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2762 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2765 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2767 KeywordFindData *kfd = data;
2769 g_idle_remove_by_data(kfd);
2771 keywords_find_finish(kfd);
2774 static gboolean keywords_find_file(gpointer data)
2776 KeywordFindData *kfd = data;
2778 GtkTextBuffer *buffer;
2786 fd = kfd->list->data;
2787 kfd->list = g_list_remove(kfd->list, fd);
2789 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2790 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2794 gtk_text_buffer_get_end_iter(buffer, &iter);
2795 tmp = g_strconcat(keywords->data, "\n", NULL);
2796 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2798 keywords = keywords->next;
2801 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2802 file_data_unref(fd);
2803 string_list_free(keywords);
2807 else if (kfd->list_dir)
2811 fd = kfd->list_dir->data;
2812 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2814 keywords_find_folder(kfd, fd);
2816 file_data_unref(fd);
2821 keywords_find_finish(kfd);
2826 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2828 KeywordFindData *kfd = data;
2831 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2833 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2834 parse_out_relatives(path);
2838 warning_dialog(_("Invalid folder"),
2839 _("The specified folder can not be found."),
2840 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2846 gtk_widget_set_sensitive(kfd->group, FALSE);
2847 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2848 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2849 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2850 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2852 dir_fd = file_data_new_dir(path);
2853 keywords_find_folder(kfd, dir_fd);
2854 file_data_unref(dir_fd);
2855 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2861 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2863 KeywordFindData *kfd;
2867 kfd = g_new0(KeywordFindData, 1);
2869 kfd->gd = generic_dialog_new(_("Search for keywords"),
2870 "search_for_keywords",
2873 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2874 kfd->gd->cancel_cb = keywords_find_close_cb;
2875 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2876 keywords_find_close_cb, FALSE);
2877 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2878 keywords_find_start_cb, FALSE);
2879 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2880 keywords_find_stop_cb, FALSE);
2881 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2883 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2885 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2886 pref_spacer(hbox, PREF_PAD_INDENT);
2887 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2889 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2890 pref_label_new(hbox, _("Folder:"));
2892 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2893 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2894 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2895 gtk_widget_show(label);
2897 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2899 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2900 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2902 kfd->progress = gtk_entry_new();
2903 gtk_widget_set_can_focus(kfd->progress, FALSE);
2904 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2905 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2906 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2907 gtk_widget_show(kfd->progress);
2909 kfd->spinner = spinner_new(NULL, -1);
2910 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2911 gtk_widget_show(kfd->spinner);
2915 gtk_widget_show(kfd->gd->dialog);
2918 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2920 const gchar *path = layout_get_path(NULL);
2922 if (!path || !*path) path = homedir();
2923 keywords_find_dialog(widget, path);
2926 static void config_tab_keywords_save()
2928 GtkTextIter start, end;
2929 GtkTextBuffer *buffer;
2930 GList *kw_list = NULL;
2936 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2937 gtk_text_buffer_get_bounds(buffer, &start, &end);
2939 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
2941 kw_split = strtok(buffer_text, "\n");
2942 while (kw_split != NULL)
2948 if (g_strcmp0(work->data, kw_split) == 0)
2957 kw_list = g_list_append(kw_list, g_strdup(kw_split));
2959 kw_split = strtok(NULL, "\n");
2962 keyword_list_set(kw_list);
2964 string_list_free(kw_list);
2965 g_free(buffer_text);
2968 static void config_tab_keywords(GtkWidget *notebook)
2974 GtkWidget *scrolled;
2976 GtkTextBuffer *buffer;
2979 vbox = scrolled_notebook_page(notebook, _("Keywords"));
2981 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
2983 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2985 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
2986 G_CALLBACK(keywords_find_cb), keyword_text);
2987 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
2990 keyword_text = gtk_text_view_new();
2991 gtk_widget_set_size_request(keyword_text, 20, 20);
2992 scrolled = gtk_scrolled_window_new(NULL, NULL);
2993 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2994 gtk_widget_show(scrolled);
2996 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
2997 gtk_widget_show(keyword_text);
2999 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3001 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3002 gtk_text_buffer_create_tag(buffer, "monospace",
3003 "family", "monospace", NULL);
3005 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3006 gtk_text_buffer_get_start_iter(buffer, &iter);
3007 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3010 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3012 GList *kwl = keyword_list_get();
3013 kwl = g_list_first(kwl);
3016 gtk_text_buffer_get_end_iter (buffer, &iter);
3017 tmp = g_strconcat(kwl->data, "\n", NULL);
3018 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3023 gtk_text_buffer_set_modified(buffer, FALSE);
3030 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3032 gint *option = data;
3034 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3038 *option = INTENT_PERCEPTUAL;
3041 *option = INTENT_RELATIVE_COLORIMETRIC;
3044 *option = INTENT_SATURATION;
3047 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3052 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3053 gint option, gint *option_c)
3060 pref_table_label(table, column, row, text, 0.0);
3062 combo = gtk_combo_box_text_new();
3064 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3065 if (option == INTENT_PERCEPTUAL) current = 0;
3066 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3067 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3068 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3069 if (option == INTENT_SATURATION) current = 2;
3070 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3071 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3073 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3075 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3077 g_signal_connect(G_OBJECT(combo), "changed",
3078 G_CALLBACK(intent_menu_cb), option_c);
3080 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
3081 GTK_EXPAND | GTK_FILL, 0, 0, 0);
3082 gtk_widget_show(combo);
3086 static void config_tab_color(GtkWidget *notebook)
3095 vbox = scrolled_notebook_page(notebook, _("Color management"));
3097 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3099 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3102 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3103 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3105 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3106 pref_label_bold(label, TRUE, FALSE);
3108 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3109 pref_label_bold(label, TRUE, FALSE);
3111 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3112 pref_label_bold(label, TRUE, FALSE);
3114 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3119 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3120 pref_table_label(table, 0, i + 1, buf, 1.0);
3123 entry = gtk_entry_new();
3124 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3125 if (options->color_profile.input_name[i])
3127 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3129 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3130 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3131 gtk_widget_show(entry);
3132 color_profile_input_name_entry[i] = entry;
3134 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3135 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3136 gtk_widget_set_size_request(entry, 160, -1);
3137 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3138 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3139 gtk_widget_show(tabcomp);
3140 color_profile_input_file_entry[i] = entry;
3143 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3145 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3147 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3148 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3150 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3152 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3153 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3154 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3155 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3156 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3158 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3160 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3162 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3164 gtk_widget_show(tabcomp);
3167 /* advanced entry tab */
3168 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3170 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3172 c_options->file_ops.use_system_trash = FALSE;
3173 c_options->file_ops.no_trash = FALSE;
3177 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3179 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3181 c_options->file_ops.use_system_trash = TRUE;
3182 c_options->file_ops.no_trash = FALSE;
3186 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3188 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3190 c_options->file_ops.no_trash = TRUE;
3194 static void config_tab_behavior(GtkWidget *notebook)
3201 GtkWidget *ct_button;
3205 GtkWidget *with_rename;
3206 GtkWidget *collections_on_top;
3208 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3210 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3212 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3213 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3214 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3215 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3216 pref_checkbox_new_int(group, _("Enable Delete key"),
3217 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3219 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3220 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3222 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3223 pref_checkbox_link_sensitivity(ct_button, hbox);
3225 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3226 pref_label_new(hbox, _("Folder:"));
3228 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3229 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3230 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3231 gtk_widget_show(tabcomp);
3233 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3234 pref_checkbox_link_sensitivity(ct_button, hbox);
3236 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3237 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3238 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3239 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3240 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3241 G_CALLBACK(safe_delete_view_cb), NULL);
3242 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3243 gtk_widget_show(button);
3245 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3246 G_CALLBACK(safe_delete_clear_cb), NULL);
3247 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3248 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3249 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3251 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3252 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3254 gtk_widget_show(button);
3256 pref_spacer(group, PREF_PAD_GROUP);
3259 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3261 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3262 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3264 pref_checkbox_new_int(group, _("In place renaming"),
3265 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3267 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3268 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3270 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3271 options->marks_save, &c_options->marks_save);
3272 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3274 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3275 options->with_rename, &c_options->with_rename);
3276 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3278 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3279 options->collections_on_top, &c_options->collections_on_top);
3280 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3282 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3283 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3285 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3286 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3288 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3289 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3291 pref_spacer(group, PREF_PAD_GROUP);
3293 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3295 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3296 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3297 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3298 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3299 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3300 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3301 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3302 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3303 pref_checkbox_new_int(group, _("Play video by left click on image"),
3304 options->image_l_click_video, &c_options->image_l_click_video);
3305 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3306 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3308 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3309 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3310 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3311 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3312 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3315 pref_spacer(group, PREF_PAD_GROUP);
3317 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3319 pref_spin_new_int(group, _("Debug level:"), NULL,
3320 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3322 pref_checkbox_new_int(group, _("Timer data"),
3323 options->log_window.timer_data, &c_options->log_window.timer_data);
3325 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3326 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3330 /* accelerators tab */
3331 static void config_tab_accelerators(GtkWidget *notebook)
3337 GtkWidget *scrolled;
3338 GtkWidget *accel_view;
3339 GtkCellRenderer *renderer;
3340 GtkTreeSelection *selection;
3341 GtkTreeViewColumn *column;
3343 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3345 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3347 scrolled = gtk_scrolled_window_new(NULL, NULL);
3348 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3349 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3350 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3351 gtk_widget_show(scrolled);
3353 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3355 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3356 g_object_unref(accel_store);
3357 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3358 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3360 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3362 renderer = gtk_cell_renderer_text_new();
3364 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3369 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3370 gtk_tree_view_column_set_resizable(column, TRUE);
3371 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3374 renderer = gtk_cell_renderer_accel_new();
3375 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3376 G_CALLBACK(accel_store_cleared_cb), accel_store);
3377 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3378 G_CALLBACK(accel_store_edited_cb), accel_store);
3381 g_object_set (renderer,
3383 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3386 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3391 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3392 gtk_tree_view_column_set_resizable(column, TRUE);
3393 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3395 renderer = gtk_cell_renderer_text_new();
3397 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3402 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3403 gtk_tree_view_column_set_resizable(column, TRUE);
3404 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3406 renderer = gtk_cell_renderer_text_new();
3408 column = gtk_tree_view_column_new_with_attributes("Accel",
3413 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3414 gtk_tree_view_column_set_resizable(column, TRUE);
3415 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3417 accel_store_populate();
3418 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3419 gtk_widget_show(accel_view);
3421 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3423 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3424 G_CALLBACK(accel_default_cb), accel_view);
3425 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3426 gtk_widget_show(button);
3428 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3429 G_CALLBACK(accel_reset_cb), accel_view);
3430 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3431 gtk_widget_show(button);
3434 /* toolbar main tab */
3435 static void config_tab_toolbar_main(GtkWidget *notebook)
3438 GtkWidget *toolbardata;
3441 lw = layout_window_list->data;
3443 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3445 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3446 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3447 gtk_widget_show(vbox);
3450 /* toolbar status tab */
3451 static void config_tab_toolbar_status(GtkWidget *notebook)
3454 GtkWidget *toolbardata;
3457 lw = layout_window_list->data;
3459 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3461 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3462 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3463 gtk_widget_show(vbox);
3467 static void config_tab_stereo(GtkWidget *notebook)
3475 GtkWidget *fs_button;
3476 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3478 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3480 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3481 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3483 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3484 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3485 pref_checkbox_new_int(box, _("Mirror left image"),
3486 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3487 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3488 pref_checkbox_new_int(box, _("Flip left image"),
3489 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3490 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3491 pref_checkbox_new_int(box, _("Mirror right image"),
3492 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3493 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3494 pref_checkbox_new_int(box, _("Flip right image"),
3495 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3496 pref_checkbox_new_int(group, _("Swap left and right images"),
3497 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3498 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3499 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3501 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3502 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3503 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3504 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3505 pref_checkbox_link_sensitivity(fs_button, box2);
3506 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3507 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3508 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3509 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3510 pref_checkbox_new_int(box, _("Mirror left image"),
3511 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3512 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3513 pref_checkbox_new_int(box, _("Flip left image"),
3514 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3515 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3516 pref_checkbox_new_int(box, _("Mirror right image"),
3517 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3518 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3519 pref_checkbox_new_int(box, _("Flip right image"),
3520 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3521 pref_checkbox_new_int(box2, _("Swap left and right images"),
3522 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3523 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3524 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3526 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3527 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3528 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3529 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3530 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3531 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3532 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3533 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3534 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3535 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3536 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3537 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3538 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3539 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3543 /* Main preferences window */
3544 static void config_window_create(void)
3546 GtkWidget *win_vbox;
3548 GtkWidget *notebook;
3550 GtkWidget *ct_button;
3552 if (!c_options) c_options = init_options(NULL);
3554 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3555 DEBUG_NAME(configwindow);
3556 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3557 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3558 G_CALLBACK(config_window_delete), NULL);
3559 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3560 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3561 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3563 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3564 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3565 gtk_widget_show(win_vbox);
3567 notebook = gtk_notebook_new();
3568 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3569 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3570 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3572 config_tab_general(notebook);
3573 config_tab_image(notebook);
3574 config_tab_osd(notebook);
3575 config_tab_windows(notebook);
3576 config_tab_accelerators(notebook);
3577 config_tab_files(notebook);
3578 config_tab_metadata(notebook);
3579 config_tab_keywords(notebook);
3580 config_tab_color(notebook);
3581 config_tab_stereo(notebook);
3582 config_tab_behavior(notebook);
3583 config_tab_toolbar_main(notebook);
3584 config_tab_toolbar_status(notebook);
3586 hbox = gtk_hbutton_box_new();
3587 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3588 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3589 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3590 gtk_widget_show(hbox);
3592 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3593 G_CALLBACK(config_window_help_cb), notebook);
3594 gtk_container_add(GTK_CONTAINER(hbox), button);
3595 gtk_widget_set_can_default(button, TRUE);
3596 gtk_widget_show(button);
3598 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3599 G_CALLBACK(config_window_ok_cb), NULL);
3600 gtk_container_add(GTK_CONTAINER(hbox), button);
3601 gtk_widget_set_can_default(button, TRUE);
3602 gtk_widget_grab_default(button);
3603 gtk_widget_show(button);
3607 button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
3608 G_CALLBACK(config_window_save_cb), NULL);
3609 gtk_container_add(GTK_CONTAINER(hbox), button);
3610 gtk_widget_set_can_default(button, TRUE);
3611 gtk_widget_show(button);
3613 button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
3614 G_CALLBACK(config_window_apply_cb), NULL);
3615 gtk_container_add(GTK_CONTAINER(hbox), button);
3616 gtk_widget_set_can_default(button, TRUE);
3617 gtk_widget_show(button);
3619 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3620 G_CALLBACK(config_window_close_cb), NULL);
3621 gtk_container_add(GTK_CONTAINER(hbox), button);
3622 gtk_widget_set_can_default(button, TRUE);
3623 gtk_widget_show(button);
3625 if (!generic_dialog_get_alternative_button_order(configwindow))
3627 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3630 gtk_widget_show(notebook);
3632 gtk_widget_show(configwindow);
3636 *-----------------------------------------------------------------------------
3637 * config window show (public)
3638 *-----------------------------------------------------------------------------
3641 void show_config_window(void)
3645 gtk_window_present(GTK_WINDOW(configwindow));
3649 config_window_create();
3658 void show_about_window(LayoutWindow *lw)
3660 GdkPixbuf *pixbuf_logo;
3661 GdkPixbuf *pixbuf_icon;
3662 gchar *authors[1000];
3667 gchar *timezone_path;
3671 #define LINE_LENGTH 1000
3672 gchar line[LINE_LENGTH];
3674 copyright = g_string_new(NULL);
3675 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");
3677 path = path_from_utf8(TIMEZONE_DATABASE);
3678 basename = g_path_get_basename(path);
3679 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3680 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3682 cd = ZDOpenDatabase(timezone_path);
3685 copyright = g_string_append(copyright, ZDGetNotice(cd));
3686 ZDCloseDatabase(cd);
3690 g_free(timezone_path);
3694 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3695 fp = fopen(path, "r");
3698 while(fgets(line, LINE_LENGTH, fp))
3700 /* get rid of ending \n from fgets */
3701 line[strlen(line) - 1] = '\0';
3702 authors[i_authors] = g_strdup(line);
3705 authors[i_authors] = NULL;
3710 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3711 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3713 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3714 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3715 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3716 "title", _("About Geeqie"),
3718 "program-name", GQ_APPNAME,
3720 "logo", pixbuf_logo,
3721 "icon", pixbuf_icon,
3722 "website", GQ_WEBSITE,
3723 "website-label", "Website",
3724 "comments", comment,
3726 "translator-credits", _("translator-credits"),
3727 "wrap-license", TRUE,
3728 "license", copyright->str,
3731 g_string_free(copyright, TRUE);
3734 while(n < i_authors)
3744 static void image_overlay_set_text_colours()
3746 c_options->image_overlay.text_red = options->image_overlay.text_red;
3747 c_options->image_overlay.text_green = options->image_overlay.text_green;
3748 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3749 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3750 c_options->image_overlay.background_red = options->image_overlay.background_red;
3751 c_options->image_overlay.background_green = options->image_overlay.background_green;
3752 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3753 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3757 *-----------------------------------------------------------------------------
3758 * timezone database routines
3759 *-----------------------------------------------------------------------------
3762 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3764 GError *error = NULL;
3766 gchar *tmp_filename;
3768 if (!g_cancellable_is_cancelled(tz->cancellable))
3770 generic_dialog_close(tz->gd);
3774 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3776 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3777 move_file(tmp_filename, tz->timezone_database_user);
3778 g_free(tmp_filename);
3782 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3785 g_file_delete(tz->tmp_g_file, NULL, &error);
3786 g_object_unref(tz->tmp_g_file);
3787 tz->tmp_g_file = NULL;
3788 g_object_unref(tz->cancellable);
3789 g_object_unref(tz->timezone_database_gq);
3792 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3796 if (!g_cancellable_is_cancelled(tz->cancellable))
3798 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3802 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3805 GError *error = NULL;
3807 g_cancellable_cancel(tz->cancellable);
3810 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3813 GError *error = NULL;
3814 GFileIOStream *io_stream;
3821 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3825 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3826 log_printf("Error: Download timezone database failed:\n%s", error->message);
3827 g_error_free(error);
3828 g_object_unref(tz->tmp_g_file);
3832 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3834 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3836 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3838 tz->progress = gtk_progress_bar_new();
3839 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3840 gtk_widget_show(tz->progress);
3842 gtk_widget_show(tz->gd->dialog);
3843 tz->cancellable = g_cancellable_new();
3844 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);
3846 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3849 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */