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)
518 lw = layout_window_list->data;
520 config_window_apply();
521 layout_util_sync(lw);
522 save_options(options);
523 config_window_close_cb(NULL, NULL);
527 *-----------------------------------------------------------------------------
528 * config window setup (private)
529 *-----------------------------------------------------------------------------
532 static void quality_menu_cb(GtkWidget *combo, gpointer data)
536 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
540 *option = GDK_INTERP_NEAREST;
543 *option = GDK_INTERP_TILES;
546 *option = GDK_INTERP_BILINEAR;
549 *option = GDK_INTERP_HYPER;
554 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
558 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
570 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
571 guint option, guint *option_c)
578 pref_table_label(table, column, row, text, 0.0);
580 combo = gtk_combo_box_text_new();
582 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
583 if (option == GDK_INTERP_NEAREST) current = 0;
584 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
585 if (option == GDK_INTERP_TILES) current = 1;
586 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
587 if (option == GDK_INTERP_BILINEAR) current = 2;
588 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
589 if (option == GDK_INTERP_HYPER) current = 3;
591 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
593 g_signal_connect(G_OBJECT(combo), "changed",
594 G_CALLBACK(quality_menu_cb), option_c);
596 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
597 GTK_EXPAND | GTK_FILL, 0, 0, 0);
598 gtk_widget_show(combo);
601 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
602 gint option, gint *option_c)
609 pref_table_label(table, column, row, text, 0.0);
611 combo = gtk_combo_box_text_new();
613 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
614 if (option == PRIMARY) current = 0;
615 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
616 if (option == CLIPBOARD) current = 1;
618 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
620 g_signal_connect(G_OBJECT(combo), "changed",
621 G_CALLBACK(clipboard_selection_menu_cb), option_c);
623 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
624 GTK_EXPAND | GTK_FILL, 0, 0, 0);
625 gtk_widget_show(combo);
628 typedef struct _UseableMouseItems UseableMouseItems;
629 struct _UseableMouseItems
631 gchar *name; /* GtkActionEntry terminology */
636 static const UseableMouseItems useable_mouse_items[] = {
638 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
639 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
640 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
641 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
642 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
643 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
644 {"Home", N_("Home"), GTK_STOCK_HOME},
645 {"Up", N_("Up"), GTK_STOCK_GO_UP},
646 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
647 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
648 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
649 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
650 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
651 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
652 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
653 {"Search", N_("Search"), GTK_STOCK_FIND},
654 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
655 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
656 {"Copy", N_("Copy"), GTK_STOCK_COPY},
657 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
658 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
659 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
660 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
661 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
662 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
663 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
664 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
665 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
666 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
667 {"Print", N_("Print"), GTK_STOCK_PRINT},
668 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
669 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
670 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
671 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
672 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
673 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
674 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
675 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
676 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
677 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
678 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
679 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
680 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
681 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
682 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
683 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
684 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
685 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
686 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
687 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
688 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
689 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
690 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
691 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
692 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
693 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
694 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
695 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
696 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
697 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
698 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
699 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
700 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
701 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
702 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
703 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
704 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
705 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
706 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
710 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
712 gchar **option = data;
715 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
717 const UseableMouseItems *list = useable_mouse_items;
721 if (g_strcmp0(list->label, label) == 0)
729 *option = g_strdup(list->name);
733 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
734 gchar *option, gchar **option_c)
742 pref_table_label(table, column, row, text, 0.0);
744 combo = gtk_combo_box_text_new();
746 const UseableMouseItems *list = useable_mouse_items;
750 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
751 if (g_strcmp0(list->name, option) == 0)
759 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
761 g_signal_connect(G_OBJECT(combo), "changed",
762 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
764 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
765 GTK_EXPAND | GTK_FILL, 0, 0, 0);
766 gtk_widget_show(combo);
769 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
773 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
776 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
778 c_options->thumbnails.max_width = thumb_size_list[n].w;
779 c_options->thumbnails.max_height = thumb_size_list[n].h;
783 c_options->thumbnails.max_width = options->thumbnails.max_width;
784 c_options->thumbnails.max_height = options->thumbnails.max_height;
788 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
794 c_options->thumbnails.max_width = options->thumbnails.max_width;
795 c_options->thumbnails.max_height = options->thumbnails.max_height;
797 pref_table_label(table, column, row, text, 0.0);
799 combo = gtk_combo_box_text_new();
802 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
807 w = thumb_size_list[i].w;
808 h = thumb_size_list[i].h;
810 buf = g_strdup_printf("%d x %d", w, h);
811 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
814 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
821 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
822 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
828 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
829 g_signal_connect(G_OBJECT(combo), "changed",
830 G_CALLBACK(thumb_size_menu_cb), NULL);
832 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
833 GTK_EXPAND | GTK_FILL, 0, 0, 0);
834 gtk_widget_show(combo);
837 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
841 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
845 *option = PR_STEREO_NONE;
848 *option = PR_STEREO_ANAGLYPH_RC;
851 *option = PR_STEREO_ANAGLYPH_GM;
854 *option = PR_STEREO_ANAGLYPH_YB;
857 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
860 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
863 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
866 *option = PR_STEREO_ANAGLYPH_DB_RC;
869 *option = PR_STEREO_ANAGLYPH_DB_GM;
872 *option = PR_STEREO_ANAGLYPH_DB_YB;
875 *option = PR_STEREO_HORIZ;
878 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
881 *option = PR_STEREO_VERT;
884 *option = PR_STEREO_VERT | PR_STEREO_HALF;
887 *option = PR_STEREO_FIXED;
892 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
893 gint option, gint *option_c, gboolean add_fixed)
900 pref_table_label(table, column, row, text, 0.0);
902 combo = gtk_combo_box_text_new();
904 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
906 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
907 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
908 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
909 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
910 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
911 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
912 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
913 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
914 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
915 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
916 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
917 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
918 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
919 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
920 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
921 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
922 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
923 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
925 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
926 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
927 if (option & PR_STEREO_HORIZ)
930 if (option & PR_STEREO_HALF) current = 11;
933 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
934 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
935 if (option & PR_STEREO_VERT)
938 if (option & PR_STEREO_HALF) current = 13;
943 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
944 if (option & PR_STEREO_FIXED) current = 14;
947 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
949 g_signal_connect(G_OBJECT(combo), "changed",
950 G_CALLBACK(stereo_mode_menu_cb), option_c);
952 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
953 GTK_EXPAND | GTK_FILL, 0, 0, 0);
954 gtk_widget_show(combo);
957 static void video_menu_cb(GtkWidget *combo, gpointer data)
959 gchar **option = data;
961 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
965 static void video_menu_populate(gpointer data, gpointer user_data)
967 GtkWidget *combo = user_data;
968 EditorDescription *ed = data;
970 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
973 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
974 gchar *option, gchar **option_c)
978 /* use lists since they are sorted */
979 GList *eds = editor_list_get();
983 pref_table_label(table, column, row, text, 0.0);
985 combo = gtk_combo_box_text_new();
986 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
987 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
989 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
991 g_signal_connect(G_OBJECT(combo), "changed",
992 G_CALLBACK(video_menu_cb), option_c);
994 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
995 GTK_EXPAND | GTK_FILL, 0, 0, 0);
996 gtk_widget_show(combo);
999 static void filter_store_populate(void)
1003 if (!filter_store) return;
1005 gtk_list_store_clear(filter_store);
1007 work = filter_get_list();
1016 gtk_list_store_append(filter_store, &iter);
1017 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1021 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1022 gchar *new_text, gpointer data)
1024 GtkWidget *model = data;
1025 FilterEntry *fe = data;
1029 if (!new_text || strlen(new_text) < 1) return;
1031 tpath = gtk_tree_path_new_from_string(path_str);
1032 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1033 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1035 g_free(fe->extensions);
1036 fe->extensions = g_strdup(new_text);
1038 gtk_tree_path_free(tpath);
1042 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1043 gchar *new_text, gpointer data)
1045 GtkWidget *model = data;
1046 FilterEntry *fe = data;
1051 if (!new_text || !new_text[0]) return;
1053 tpath = gtk_tree_path_new_from_string(path_str);
1054 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1055 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1057 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1059 if (strcmp(new_text, _(format_class_list[i])) == 0)
1066 gtk_tree_path_free(tpath);
1070 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1071 gchar *new_text, gpointer data)
1073 GtkWidget *model = data;
1078 if (!new_text || !new_text[0]) return;
1080 tpath = gtk_tree_path_new_from_string(path_str);
1081 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1082 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1084 g_free(fe->description);
1085 fe->description = g_strdup(new_text);
1087 gtk_tree_path_free(tpath);
1090 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1091 gchar *path_str, gpointer data)
1093 GtkWidget *model = data;
1098 tpath = gtk_tree_path_new_from_string(path_str);
1099 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1100 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1102 fe->enabled = !fe->enabled;
1104 gtk_tree_path_free(tpath);
1108 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1109 gchar *path_str, gpointer data)
1111 GtkWidget *model = data;
1116 tpath = gtk_tree_path_new_from_string(path_str);
1117 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1118 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1120 fe->writable = !fe->writable;
1121 if (fe->writable) fe->allow_sidecar = FALSE;
1123 gtk_tree_path_free(tpath);
1127 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1128 gchar *path_str, gpointer data)
1130 GtkWidget *model = data;
1135 tpath = gtk_tree_path_new_from_string(path_str);
1136 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1137 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1139 fe->allow_sidecar = !fe->allow_sidecar;
1140 if (fe->allow_sidecar) fe->writable = FALSE;
1142 gtk_tree_path_free(tpath);
1146 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1147 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1151 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1153 switch (GPOINTER_TO_INT(data))
1156 g_object_set(GTK_CELL_RENDERER(cell),
1157 "active", fe->enabled, NULL);
1160 g_object_set(GTK_CELL_RENDERER(cell),
1161 "text", fe->extensions, NULL);
1163 case FE_DESCRIPTION:
1164 g_object_set(GTK_CELL_RENDERER(cell),
1165 "text", fe->description, NULL);
1168 g_object_set(GTK_CELL_RENDERER(cell),
1169 "text", _(format_class_list[fe->file_class]), NULL);
1172 g_object_set(GTK_CELL_RENDERER(cell),
1173 "active", fe->writable, NULL);
1175 case FE_ALLOW_SIDECAR:
1176 g_object_set(GTK_CELL_RENDERER(cell),
1177 "active", fe->allow_sidecar, NULL);
1182 static gboolean filter_add_scroll(gpointer data)
1186 GtkCellRenderer *cell;
1187 GtkTreeViewColumn *column;
1192 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1193 path = gtk_tree_path_new_from_indices(rows-1, -1);
1195 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1197 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1198 cell = g_list_last(list_cells)->data;
1200 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1201 path, column, FALSE, 0.0, 0.0 );
1202 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1203 path, column, cell, TRUE);
1205 gtk_tree_path_free(path);
1206 g_list_free(list_cells);
1211 static void filter_add_cb(GtkWidget *widget, gpointer data)
1213 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1214 filter_store_populate();
1216 g_idle_add((GSourceFunc)filter_add_scroll, data);
1219 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1221 GtkWidget *filter_view = data;
1222 GtkTreeSelection *selection;
1226 if (!filter_store) return;
1227 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1228 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1229 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1232 filter_remove_entry(fe);
1234 filter_store_populate();
1237 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1241 GtkTreeViewColumn *column;
1243 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1244 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1245 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1247 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1251 gtk_tree_path_free(path);
1256 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1259 filter_add_defaults();
1261 filter_store_populate();
1263 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1266 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1268 /* no op, only so cancel button appears */
1271 static void filter_default_cb(GtkWidget *widget, gpointer data)
1275 gd = generic_dialog_new(_("Reset filters"),
1276 "reset_filter", widget, TRUE,
1277 dummy_cancel_cb, data);
1278 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1279 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1280 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1281 gtk_widget_show(gd->dialog);
1284 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1286 GtkWidget *frame = data;
1288 gtk_widget_set_sensitive(frame,
1289 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1292 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1294 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1297 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1299 file_util_trash_clear();
1302 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1306 gd = generic_dialog_new(_("Clear trash"),
1307 "clear_trash", widget, TRUE,
1308 dummy_cancel_cb, NULL);
1309 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1310 _("This will remove the trash contents."), FALSE);
1311 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1312 entry = gtk_entry_new();
1313 gtk_widget_set_can_focus(entry, FALSE);
1314 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1315 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1316 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1317 gtk_widget_show(entry);
1318 gtk_widget_show(gd->dialog);
1321 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1323 GtkWidget *pTextView;
1324 GtkTextBuffer *pTextBuffer;
1328 pTextView = GTK_WIDGET(data);
1330 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1331 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1332 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1334 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1335 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1338 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1340 GtkTextView *text_view = data;
1341 GtkTextBuffer *buffer;
1343 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1344 if (!configwindow) return;
1346 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1347 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1350 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1354 gd = generic_dialog_new(_("Reset image overlay template string"),
1355 "reset_image_overlay_template_string", widget, TRUE,
1356 dummy_cancel_cb, data);
1357 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1358 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1359 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1360 gtk_widget_show(gd->dialog);
1363 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1365 help_window_show("GuideOptionsOSD.html");
1368 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1370 #if GTK_CHECK_VERSION(3,4,0)
1373 PangoFontDescription *font_desc;
1375 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1376 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1378 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1380 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1381 font = pango_font_description_to_string(font_desc);
1382 g_free(c_options->image_overlay.font);
1383 c_options->image_overlay.font = g_strdup(font);
1387 gtk_widget_destroy(dialog);
1391 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1392 c_options->image_overlay.font = g_strdup(font);
1396 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1399 #if GTK_CHECK_VERSION(3,4,0)
1402 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1403 colour.red = options->image_overlay.text_red;
1404 colour.green = options->image_overlay.text_green;
1405 colour.blue = options->image_overlay.text_blue;
1406 colour.alpha = options->image_overlay.text_alpha;
1407 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1408 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1410 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1412 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1413 c_options->image_overlay.text_red = colour.red*255;
1414 c_options->image_overlay.text_green = colour.green*255;
1415 c_options->image_overlay.text_blue = colour.blue*255;
1416 c_options->image_overlay.text_alpha = colour.alpha*255;
1418 gtk_widget_destroy(dialog);
1421 GtkColorSelection *colorsel;
1423 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1424 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1425 colour.red = options->image_overlay.text_red*257;
1426 colour.green = options->image_overlay.text_green*257;
1427 colour.blue = options->image_overlay.text_blue*257;
1428 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1429 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1430 gtk_color_selection_set_current_color(colorsel, &colour);
1431 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1433 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1435 gtk_color_selection_get_current_color(colorsel, &colour);
1436 c_options->image_overlay.text_red = colour.red/257;
1437 c_options->image_overlay.text_green = colour.green/257;
1438 c_options->image_overlay.text_blue = colour.blue/257;
1439 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1441 gtk_widget_destroy (dialog);
1446 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1449 #if GTK_CHECK_VERSION(3,4,0)
1452 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1453 colour.red = options->image_overlay.background_red;
1454 colour.green = options->image_overlay.background_green;
1455 colour.blue = options->image_overlay.background_blue;
1456 colour.alpha = options->image_overlay.background_alpha;
1457 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1458 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1460 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1462 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1463 c_options->image_overlay.background_red = colour.red*255;
1464 c_options->image_overlay.background_green = colour.green*255;
1465 c_options->image_overlay.background_blue = colour.blue*255;
1466 c_options->image_overlay.background_alpha = colour.alpha*255;
1468 gtk_widget_destroy(dialog);
1471 GtkColorSelection *colorsel;
1473 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1474 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1475 colour.red = options->image_overlay.background_red*257;
1476 colour.green = options->image_overlay.background_green*257;
1477 colour.blue = options->image_overlay.background_blue*257;
1478 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1479 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1480 gtk_color_selection_set_current_color(colorsel, &colour);
1481 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1483 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1485 gtk_color_selection_get_current_color(colorsel, &colour);
1486 c_options->image_overlay.background_red = colour.red/257;
1487 c_options->image_overlay.background_green = colour.green/257;
1488 c_options->image_overlay.background_blue = colour.blue/257;
1489 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1491 gtk_widget_destroy(dialog);
1495 static void accel_store_populate(void)
1498 GList *groups, *actions;
1500 const gchar *accel_path;
1504 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1506 gtk_tree_store_clear(accel_store);
1507 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1509 g_assert(lw && lw->ui_manager);
1510 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1513 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1516 action = GTK_ACTION(actions->data);
1517 accel_path = gtk_action_get_accel_path(action);
1518 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1520 gchar *label, *label2, *tooltip, *accel;
1521 g_object_get(action,
1522 "tooltip", &tooltip,
1526 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1532 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1536 gtk_tree_store_append(accel_store, &iter, NULL);
1537 gtk_tree_store_set(accel_store, &iter,
1540 AE_TOOLTIP, tooltip ? tooltip : "",
1541 AE_ACCEL, accel_path,
1549 actions = actions->next;
1552 groups = groups->next;
1556 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1561 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1563 gchar *accel1 = data;
1568 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1570 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1571 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1573 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1575 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1576 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1585 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1587 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1591 GtkAccelKey old_key, key;
1592 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1594 gtk_tree_model_get_iter(model, &iter, path);
1595 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1597 /* test if the accelerator can be stored without conflicts*/
1598 gtk_accel_map_lookup_entry(accel_path, &old_key);
1600 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1601 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1602 gtk_accel_map_lookup_entry(accel_path, &key);
1604 /* restore the original for now, the key will be really changed when the changes are confirmed */
1605 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1607 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1608 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1610 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1611 gtk_tree_path_free(path);
1615 static gboolean accel_default_scroll(GtkTreeView *data)
1619 GtkTreeViewColumn *column;
1621 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1622 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1623 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1625 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1629 gtk_tree_path_free(path);
1634 static void accel_default_cb(GtkWidget *widget, gpointer data)
1636 accel_store_populate();
1638 g_idle_add((GSourceFunc)accel_default_scroll, data);
1641 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1643 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1646 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1649 gchar *accel_path, *accel;
1651 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1652 gtk_accel_map_lookup_entry(accel_path, &key);
1653 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1655 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1657 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1662 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1664 GtkTreeSelection *selection;
1666 if (!accel_store) return;
1667 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1668 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1673 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1677 GtkWidget *scrolled;
1678 GtkWidget *viewport;
1680 scrolled = gtk_scrolled_window_new(NULL, NULL);
1681 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1682 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1683 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1684 label = gtk_label_new(title);
1685 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1686 gtk_widget_show(scrolled);
1688 viewport = gtk_viewport_new(NULL, NULL);
1689 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1690 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1691 gtk_widget_show(viewport);
1693 vbox = gtk_vbox_new(FALSE, 0);
1694 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1695 gtk_widget_show(vbox);
1700 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1702 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1704 c_options->thumbnails.spec_standard =TRUE;
1705 c_options->thumbnails.cache_into_dirs = FALSE;
1709 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1711 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1713 c_options->thumbnails.spec_standard =FALSE;
1714 c_options->thumbnails.cache_into_dirs = FALSE;
1718 static void cache_local_cb(GtkWidget *widget, gpointer data)
1720 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1722 c_options->thumbnails.cache_into_dirs = TRUE;
1723 c_options->thumbnails.spec_standard =FALSE;
1727 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1728 GdkEvent *event, gpointer userdata)
1730 if (pos == GTK_ENTRY_ICON_PRIMARY)
1732 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1736 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1740 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1741 GdkEvent *event, gpointer userdata)
1743 gchar *rating_symbol;
1745 if (pos == GTK_ENTRY_ICON_PRIMARY)
1747 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1748 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1749 g_free(rating_symbol);
1753 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1754 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1755 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1759 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1760 GdkEvent *event, gpointer userdata)
1762 gchar *rating_symbol;
1764 if (pos == GTK_ENTRY_ICON_PRIMARY)
1766 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1767 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1768 g_free(rating_symbol);
1772 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1773 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1774 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1778 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1780 GtkContainer *hbox = data;
1781 GString *str = g_string_new(NULL);
1782 GtkEntry *hex_code_entry;
1783 gchar *hex_code_full;
1786 guint64 hex_value = 0;
1788 list = gtk_container_get_children(hbox);
1790 hex_code_entry = g_list_nth_data(list, 2);
1791 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1793 hex_code = g_strsplit(hex_code_full, "+", 2);
1794 if (hex_code[0] && hex_code[1])
1796 hex_value = strtoull(hex_code[1], NULL, 16);
1798 if (!hex_value || hex_value > 0x10FFFF)
1800 hex_value = 0x003F; // Unicode 'Question Mark'
1802 str = g_string_append_unichar(str, (gunichar)hex_value);
1803 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1805 g_strfreev(hex_code);
1806 g_string_free(str, TRUE);
1807 g_free(hex_code_full);
1812 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1814 guint64 star_symbol;
1816 star_symbol = star_rating_symbol_test(widget, data);
1817 c_options->star_rating.star = star_symbol;
1820 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1822 guint64 rejected_symbol;
1824 rejected_symbol = star_rating_symbol_test(widget, data);
1825 c_options->star_rating.rejected = rejected_symbol;
1828 /* general options tab */
1829 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1830 typedef struct _TZData TZData;
1834 GCancellable *cancellable;
1836 GtkWidget *progress;
1838 GFile *timezone_database_gq;
1839 gchar *timezone_database_user;
1842 static void config_tab_general(GtkWidget *notebook)
1847 GtkWidget *group_frame;
1848 GtkWidget *subgroup;
1850 GtkWidget *ct_button;
1853 gint hours, minutes, remainder;
1855 GtkWidget *star_rating_entry;
1857 gchar *rating_symbol;
1860 GNetworkMonitor *net_mon;
1861 GSocketConnectable *geeqie_org;
1862 gboolean internet_available;
1865 vbox = scrolled_notebook_page(notebook, _("General"));
1867 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1869 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1870 add_thumb_size_menu(table, 0, 0, _("Size:"));
1871 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1873 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1874 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1876 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1877 pref_checkbox_link_sensitivity(ct_button, subgroup);
1879 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1880 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1881 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1882 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1883 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1884 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1885 G_CALLBACK(cache_geeqie_cb), NULL);
1887 group_frame = pref_frame_new(subgroup, TRUE,
1888 _("Store thumbnails local to image folder (non-standard)"),
1889 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1890 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1891 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1892 G_CALLBACK(cache_local_cb), NULL);
1894 group_frame = pref_frame_new(subgroup, TRUE,
1895 _("Use standard thumbnail style and cache, shared with other applications"),
1896 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1897 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1898 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1899 G_CALLBACK(cache_standard_cb), NULL);
1901 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1902 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1904 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1906 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1907 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1909 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1910 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1911 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1913 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1914 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1917 pref_spacer(group, PREF_PAD_GROUP);
1919 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1921 c_options->star_rating.star = options->star_rating.star;
1922 c_options->star_rating.rejected = options->star_rating.rejected;
1924 str = g_string_new(NULL);
1925 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1926 pref_label_new(hbox, "Star character: ");
1927 str = g_string_append_unichar(str, options->star_rating.star);
1928 pref_label_new(hbox, g_strdup(str->str));
1929 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1930 star_rating_entry = gtk_entry_new();
1931 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1932 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1933 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1934 gtk_widget_show(star_rating_entry);
1935 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1936 G_CALLBACK(star_rating_star_test_cb), hbox);
1937 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1938 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1939 gtk_widget_show(button);
1940 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."));
1941 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1942 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1943 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1944 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1945 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1946 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1947 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1948 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1949 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1950 G_CALLBACK(star_rating_star_icon_cb),
1953 g_string_free(str, TRUE);
1954 g_free(rating_symbol);
1956 str = g_string_new(NULL);
1957 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1958 pref_label_new(hbox, "Rejected character: ");
1959 str = g_string_append_unichar(str, options->star_rating.rejected);
1960 pref_label_new(hbox, g_strdup(str->str));
1961 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
1962 star_rating_entry = gtk_entry_new();
1963 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1964 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1965 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1966 gtk_widget_show(star_rating_entry);
1967 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1968 G_CALLBACK(star_rating_rejected_test_cb), hbox);
1969 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1970 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1971 gtk_widget_show(button);
1972 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."));
1973 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1974 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1975 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1976 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1977 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1978 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1979 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1980 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1981 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1982 G_CALLBACK(star_rating_rejected_icon_cb),
1985 g_string_free(str, TRUE);
1986 g_free(rating_symbol);
1988 pref_spacer(group, PREF_PAD_GROUP);
1990 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
1992 c_options->slideshow.delay = options->slideshow.delay;
1993 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1994 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1995 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
1996 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
1997 SLIDESHOW_SUBSECOND_PRECISION;
1999 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2001 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2003 options->slideshow.delay ? hours : 0.0,
2004 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2005 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2006 spin = pref_spin_new(hbox, ":" , NULL,
2008 options->slideshow.delay ? minutes: 0.0,
2009 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2010 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2011 spin = pref_spin_new(hbox, ":", NULL,
2012 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2013 options->slideshow.delay ? seconds : 10.0,
2014 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2015 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2017 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2018 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2020 pref_spacer(group, PREF_PAD_GROUP);
2022 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2024 pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
2025 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2026 pref_checkbox_new_int(group, _("Preload next image"),
2027 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2029 pref_checkbox_new_int(group, _("Refresh on file change"),
2030 options->update_on_time_change, &c_options->update_on_time_change);
2032 pref_spacer(group, PREF_PAD_GROUP);
2034 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2035 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2036 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2037 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2039 options->info_keywords.height, &c_options->info_keywords.height);
2040 pref_spin_new_int(hbox, _("Title:"), NULL,
2042 options->info_title.height, &c_options->info_title.height);
2043 pref_spin_new_int(hbox, _("Comment:"), NULL,
2045 options->info_comment.height, &c_options->info_comment.height);
2046 pref_spin_new_int(hbox, _("Rating:"), NULL,
2048 options->info_rating.height, &c_options->info_rating.height);
2050 pref_spacer(group, PREF_PAD_GROUP);
2052 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2054 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2055 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2057 pref_spacer(group, PREF_PAD_GROUP);
2059 net_mon = g_network_monitor_get_default();
2060 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2061 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2062 g_object_unref(geeqie_org);
2064 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2065 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2067 if (!internet_available)
2069 gtk_widget_set_sensitive(group, FALSE);
2072 tz = g_new0(TZData, 1);
2074 path = path_from_utf8(TIMEZONE_DATABASE);
2075 basename = g_path_get_basename(path);
2076 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2080 if (isfile(tz->timezone_database_user))
2082 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2086 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2089 if (!internet_available)
2091 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"));
2095 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"));
2097 gtk_widget_show(button);
2099 pref_spacer(group, PREF_PAD_GROUP);
2101 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2103 help_search_engine_entry = gtk_entry_new();
2104 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2105 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2106 gtk_widget_show(help_search_engine_entry);
2108 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"));
2110 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2111 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2112 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2113 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2114 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2115 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2116 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2117 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2118 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2119 G_CALLBACK(help_search_engine_entry_icon_cb),
2120 help_search_engine_entry);
2124 static void config_tab_image(GtkWidget *notebook)
2129 GtkWidget *ct_button;
2130 GtkWidget *enlargement_button;
2134 vbox = scrolled_notebook_page(notebook, _("Image"));
2136 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2138 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2139 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2142 pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
2143 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2146 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2147 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2149 c_options->image.zoom_increment = options->image.zoom_increment;
2150 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2151 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2152 G_CALLBACK(zoom_increment_cb), NULL);
2153 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2155 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2157 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2158 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2159 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2160 spin = pref_spin_new_int(hbox, NULL, NULL,
2162 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2163 pref_checkbox_link_sensitivity(enlargement_button, spin);
2164 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."));
2166 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2167 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2168 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2169 spin = pref_spin_new_int(hbox, NULL, NULL,
2171 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2172 pref_checkbox_link_sensitivity(ct_button, spin);
2173 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."));
2175 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2177 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2178 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2180 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2181 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2183 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2184 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2186 c_options->image.border_color = options->image.border_color;
2188 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2189 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2191 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2192 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2194 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2195 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2197 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2199 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2200 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2204 static void config_tab_windows(GtkWidget *notebook)
2210 GtkWidget *ct_button;
2213 vbox = scrolled_notebook_page(notebook, _("Windows"));
2215 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2217 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2218 options->save_window_positions, &c_options->save_window_positions);
2220 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2221 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2222 pref_checkbox_link_sensitivity(ct_button, button);
2224 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2225 options->tools_restore_state, &c_options->tools_restore_state);
2227 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2228 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2230 pref_checkbox_new_int(group, _("Show window IDs"),
2231 options->show_window_ids, &c_options->show_window_ids);
2233 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2235 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2236 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2238 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2239 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2240 options->image.limit_window_size, &c_options->image.limit_window_size);
2241 spin = pref_spin_new_int(hbox, NULL, NULL,
2243 options->image.max_window_size, &c_options->image.max_window_size);
2244 pref_checkbox_link_sensitivity(ct_button, spin);
2246 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2248 c_options->fullscreen.screen = options->fullscreen.screen;
2249 c_options->fullscreen.above = options->fullscreen.above;
2250 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2251 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2252 gtk_widget_show(hbox);
2254 pref_checkbox_new_int(group, _("Smooth image flip"),
2255 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2256 pref_checkbox_new_int(group, _("Disable screen saver"),
2257 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2260 #define PRE_FORMATTED_COLUMNS 5
2261 static void config_tab_osd(GtkWidget *notebook)
2265 GtkWidget *vbox_buttons;
2268 GtkWidget *image_overlay_template_view;
2269 GtkWidget *scrolled;
2270 GtkWidget *scrolled_pre_formatted;
2271 GtkTextBuffer *buffer;
2273 GtkWidget * subgroup;
2278 vbox = scrolled_notebook_page(notebook, _("OSD"));
2280 image_overlay_template_view = gtk_text_view_new();
2282 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2284 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2286 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2287 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2288 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2289 gtk_widget_show(scrolled_pre_formatted);
2290 gtk_widget_show(subgroup);
2292 pref_line(group, PREF_PAD_GAP);
2294 pref_label_new(group, _("Image overlay template"));
2296 scrolled = gtk_scrolled_window_new(NULL, NULL);
2297 gtk_widget_set_size_request(scrolled, 200, 150);
2298 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2299 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2300 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2301 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2302 gtk_widget_show(scrolled);
2304 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2305 _("Extensive formatting options are shown in the Help file"));
2307 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2308 gtk_widget_show(image_overlay_template_view);
2310 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2312 #if GTK_CHECK_VERSION(3,4,0)
2313 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2314 G_CALLBACK(image_overlay_set_font_cb), notebook);
2316 button = gtk_font_button_new();
2317 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2318 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2319 g_signal_connect(G_OBJECT(button), "font-set",
2320 G_CALLBACK(image_overlay_set_font_cb),NULL);
2322 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2323 gtk_widget_show(button);
2325 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2326 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2327 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2328 gtk_widget_show(button);
2330 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2331 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2332 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2333 gtk_widget_show(button);
2334 image_overlay_set_text_colours();
2336 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2337 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2338 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2339 gtk_widget_show(button);
2341 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2342 G_CALLBACK(image_overlay_help_cb), NULL);
2343 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2344 gtk_widget_show(button);
2346 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2347 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2348 g_signal_connect(G_OBJECT(buffer), "changed",
2349 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2351 pref_line(group, PREF_PAD_GAP);
2353 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2354 hbox = gtk_hbox_new(FALSE, 0);
2355 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2356 gtk_widget_show(hbox);
2357 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2358 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2359 gtk_widget_show(label);
2360 pref_spacer(group,TRUE);
2362 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2363 hbox = gtk_hbox_new(FALSE, 0);
2364 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2365 gtk_widget_show(hbox);
2366 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2367 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2368 gtk_widget_show(label);
2369 pref_spacer(group,TRUE);
2371 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2372 hbox = gtk_hbox_new(FALSE, 0);
2373 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2374 gtk_widget_show(hbox);
2375 label = gtk_label_new(_("%path:39%"));
2376 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2377 gtk_widget_show(label);
2378 pref_spacer(group,TRUE);
2380 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2381 hbox = gtk_hbox_new(FALSE, 0);
2382 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2383 gtk_widget_show(hbox);
2384 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%"));
2385 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2386 gtk_widget_show(label);
2387 pref_spacer(group,TRUE);
2389 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2390 hbox = gtk_hbox_new(FALSE, 0);
2391 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2392 gtk_widget_show(hbox);
2393 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2394 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2395 gtk_widget_show(label);
2398 static GtkTreeModel *create_class_model(void)
2400 GtkListStore *model;
2404 /* create list store */
2405 model = gtk_list_store_new(1, G_TYPE_STRING);
2406 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2408 gtk_list_store_append(model, &iter);
2409 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2411 return GTK_TREE_MODEL (model);
2416 static void config_tab_files(GtkWidget *notebook)
2423 GtkWidget *ct_button;
2424 GtkWidget *scrolled;
2425 GtkWidget *filter_view;
2426 GtkCellRenderer *renderer;
2427 GtkTreeSelection *selection;
2428 GtkTreeViewColumn *column;
2430 vbox = scrolled_notebook_page(notebook, _("Files"));
2432 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2434 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2435 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2436 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2437 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2438 pref_checkbox_new_int(group, _("Case sensitive sort"),
2439 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2440 pref_checkbox_new_int(group, _("Natural sort order"),
2441 options->file_sort.natural, &c_options->file_sort.natural);
2442 pref_checkbox_new_int(group, _("Disable file extension checks"),
2443 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2445 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2446 options->file_filter.disable, &c_options->file_filter.disable);
2449 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2451 sidecar_ext_entry = gtk_entry_new();
2452 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2453 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2454 gtk_widget_show(sidecar_ext_entry);
2456 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2458 frame = pref_group_parent(group);
2459 g_signal_connect(G_OBJECT(ct_button), "toggled",
2460 G_CALLBACK(filter_disable_cb), frame);
2461 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2463 scrolled = gtk_scrolled_window_new(NULL, NULL);
2464 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2465 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2466 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2467 gtk_widget_show(scrolled);
2469 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2470 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2471 g_object_unref(filter_store);
2472 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2473 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2475 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2477 column = gtk_tree_view_column_new();
2478 gtk_tree_view_column_set_title(column, _("Filter"));
2479 gtk_tree_view_column_set_resizable(column, TRUE);
2481 renderer = gtk_cell_renderer_toggle_new();
2482 g_signal_connect(G_OBJECT(renderer), "toggled",
2483 G_CALLBACK(filter_store_enable_cb), filter_store);
2484 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2485 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2486 GINT_TO_POINTER(FE_ENABLE), NULL);
2488 renderer = gtk_cell_renderer_text_new();
2489 g_signal_connect(G_OBJECT(renderer), "edited",
2490 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2491 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2492 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2493 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2494 GINT_TO_POINTER(FE_EXTENSION), NULL);
2495 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2497 column = gtk_tree_view_column_new();
2498 gtk_tree_view_column_set_title(column, _("Description"));
2499 gtk_tree_view_column_set_resizable(column, TRUE);
2500 gtk_tree_view_column_set_fixed_width(column, 200);
2501 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2503 renderer = gtk_cell_renderer_text_new();
2504 g_signal_connect(G_OBJECT(renderer), "edited",
2505 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2506 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2507 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2508 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2509 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2510 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2512 column = gtk_tree_view_column_new();
2513 gtk_tree_view_column_set_title(column, _("Class"));
2514 gtk_tree_view_column_set_resizable(column, TRUE);
2515 renderer = gtk_cell_renderer_combo_new();
2516 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2517 "model", create_class_model(),
2522 g_signal_connect(G_OBJECT(renderer), "edited",
2523 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2524 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2525 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2526 GINT_TO_POINTER(FE_CLASS), NULL);
2527 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2529 column = gtk_tree_view_column_new();
2530 gtk_tree_view_column_set_title(column, _("Writable"));
2531 gtk_tree_view_column_set_resizable(column, FALSE);
2532 renderer = gtk_cell_renderer_toggle_new();
2533 g_signal_connect(G_OBJECT(renderer), "toggled",
2534 G_CALLBACK(filter_store_writable_cb), filter_store);
2535 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2536 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2537 GINT_TO_POINTER(FE_WRITABLE), NULL);
2538 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2540 column = gtk_tree_view_column_new();
2541 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2542 gtk_tree_view_column_set_resizable(column, FALSE);
2543 renderer = gtk_cell_renderer_toggle_new();
2544 g_signal_connect(G_OBJECT(renderer), "toggled",
2545 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2546 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2547 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2548 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2549 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2552 filter_store_populate();
2553 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2554 gtk_widget_show(filter_view);
2556 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2558 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2559 G_CALLBACK(filter_default_cb), filter_view);
2560 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2561 gtk_widget_show(button);
2563 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2564 G_CALLBACK(filter_remove_cb), filter_view);
2565 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2566 gtk_widget_show(button);
2568 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2569 G_CALLBACK(filter_add_cb), filter_view);
2570 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2571 gtk_widget_show(button);
2575 static void config_tab_metadata(GtkWidget *notebook)
2580 GtkWidget *ct_button;
2584 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2587 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2589 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2591 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2592 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2594 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2595 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2597 gtk_widget_set_sensitive(ct_button, FALSE);
2600 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2601 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2603 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2604 label = pref_label_new(group, text);
2605 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2606 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2609 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2611 gtk_widget_set_sensitive(group, FALSE);
2614 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2615 pref_checkbox_link_sensitivity(ct_button, hbox);
2617 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2618 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2620 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2621 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2623 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2624 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2626 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2627 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2629 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2631 gtk_widget_set_sensitive(group, FALSE);
2634 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2635 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2638 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2639 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2640 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2642 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2643 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2645 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2646 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2648 gtk_widget_set_sensitive(ct_button, FALSE);
2651 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2653 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2654 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2656 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2657 pref_checkbox_link_sensitivity(ct_button, hbox);
2659 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2660 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2662 pref_checkbox_new_int(group, _("Write metadata on image change"),
2663 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2665 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2666 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2668 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2670 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2671 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2672 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");
2677 typedef struct _KeywordFindData KeywordFindData;
2678 struct _KeywordFindData
2685 GtkWidget *button_close;
2686 GtkWidget *button_stop;
2687 GtkWidget *button_start;
2688 GtkWidget *progress;
2696 guint idle_id; /* event source id */
2699 #define KEYWORD_DIALOG_WIDTH 400
2701 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2703 GList *list_d = NULL;
2704 GList *list_f = NULL;
2708 filelist_read(dir_fd, &list_f, &list_d);
2712 filelist_read(dir_fd, &list_f, NULL);
2715 list_f = filelist_filter(list_f, FALSE);
2716 list_d = filelist_filter(list_d, TRUE);
2718 kfd->list = g_list_concat(list_f, kfd->list);
2719 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2722 static void keywords_find_reset(KeywordFindData *kfd)
2724 filelist_free(kfd->list);
2727 filelist_free(kfd->list_dir);
2728 kfd->list_dir = NULL;
2731 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2733 KeywordFindData *kfd = data;
2735 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2737 keywords_find_reset(kfd);
2738 generic_dialog_close(kfd->gd);
2742 static void keywords_find_finish(KeywordFindData *kfd)
2744 keywords_find_reset(kfd);
2746 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2747 spinner_set_interval(kfd->spinner, -1);
2749 gtk_widget_set_sensitive(kfd->group, TRUE);
2750 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2751 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2752 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2755 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2757 KeywordFindData *kfd = data;
2759 g_idle_remove_by_data(kfd);
2761 keywords_find_finish(kfd);
2764 static gboolean keywords_find_file(gpointer data)
2766 KeywordFindData *kfd = data;
2768 GtkTextBuffer *buffer;
2776 fd = kfd->list->data;
2777 kfd->list = g_list_remove(kfd->list, fd);
2779 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2780 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2784 gtk_text_buffer_get_end_iter(buffer, &iter);
2785 tmp = g_strconcat(keywords->data, "\n", NULL);
2786 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2788 keywords = keywords->next;
2791 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2792 file_data_unref(fd);
2793 string_list_free(keywords);
2797 else if (kfd->list_dir)
2801 fd = kfd->list_dir->data;
2802 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2804 keywords_find_folder(kfd, fd);
2806 file_data_unref(fd);
2811 keywords_find_finish(kfd);
2816 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2818 KeywordFindData *kfd = data;
2821 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2823 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2824 parse_out_relatives(path);
2828 warning_dialog(_("Invalid folder"),
2829 _("The specified folder can not be found."),
2830 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2836 gtk_widget_set_sensitive(kfd->group, FALSE);
2837 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2838 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2839 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2840 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2842 dir_fd = file_data_new_dir(path);
2843 keywords_find_folder(kfd, dir_fd);
2844 file_data_unref(dir_fd);
2845 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2851 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2853 KeywordFindData *kfd;
2857 kfd = g_new0(KeywordFindData, 1);
2859 kfd->gd = generic_dialog_new(_("Search for keywords"),
2860 "search_for_keywords",
2863 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2864 kfd->gd->cancel_cb = keywords_find_close_cb;
2865 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2866 keywords_find_close_cb, FALSE);
2867 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2868 keywords_find_start_cb, FALSE);
2869 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2870 keywords_find_stop_cb, FALSE);
2871 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2873 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2875 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2876 pref_spacer(hbox, PREF_PAD_INDENT);
2877 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2879 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2880 pref_label_new(hbox, _("Folder:"));
2882 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2883 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2884 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2885 gtk_widget_show(label);
2887 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2889 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2890 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2892 kfd->progress = gtk_entry_new();
2893 gtk_widget_set_can_focus(kfd->progress, FALSE);
2894 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2895 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2896 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2897 gtk_widget_show(kfd->progress);
2899 kfd->spinner = spinner_new(NULL, -1);
2900 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2901 gtk_widget_show(kfd->spinner);
2905 gtk_widget_show(kfd->gd->dialog);
2908 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2910 const gchar *path = layout_get_path(NULL);
2912 if (!path || !*path) path = homedir();
2913 keywords_find_dialog(widget, path);
2916 static void config_tab_keywords_save()
2918 GtkTextIter start, end;
2919 GtkTextBuffer *buffer;
2920 GList *kw_list = NULL;
2926 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2927 gtk_text_buffer_get_bounds(buffer, &start, &end);
2929 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
2931 kw_split = strtok(buffer_text, "\n");
2932 while (kw_split != NULL)
2938 if (g_strcmp0(work->data, kw_split) == 0)
2947 kw_list = g_list_append(kw_list, g_strdup(kw_split));
2949 kw_split = strtok(NULL, "\n");
2952 keyword_list_set(kw_list);
2954 string_list_free(kw_list);
2955 g_free(buffer_text);
2958 static void config_tab_keywords(GtkWidget *notebook)
2964 GtkWidget *scrolled;
2966 GtkTextBuffer *buffer;
2969 vbox = scrolled_notebook_page(notebook, _("Keywords"));
2971 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
2973 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2975 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
2976 G_CALLBACK(keywords_find_cb), keyword_text);
2977 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
2980 keyword_text = gtk_text_view_new();
2981 gtk_widget_set_size_request(keyword_text, 20, 20);
2982 scrolled = gtk_scrolled_window_new(NULL, NULL);
2983 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2984 gtk_widget_show(scrolled);
2986 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
2987 gtk_widget_show(keyword_text);
2989 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
2991 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2992 gtk_text_buffer_create_tag(buffer, "monospace",
2993 "family", "monospace", NULL);
2995 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
2996 gtk_text_buffer_get_start_iter(buffer, &iter);
2997 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3000 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3002 GList *kwl = keyword_list_get();
3003 kwl = g_list_first(kwl);
3006 gtk_text_buffer_get_end_iter (buffer, &iter);
3007 tmp = g_strconcat(kwl->data, "\n", NULL);
3008 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3013 gtk_text_buffer_set_modified(buffer, FALSE);
3020 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3022 gint *option = data;
3024 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3028 *option = INTENT_PERCEPTUAL;
3031 *option = INTENT_RELATIVE_COLORIMETRIC;
3034 *option = INTENT_SATURATION;
3037 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3042 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3043 gint option, gint *option_c)
3050 pref_table_label(table, column, row, text, 0.0);
3052 combo = gtk_combo_box_text_new();
3054 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3055 if (option == INTENT_PERCEPTUAL) current = 0;
3056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3057 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3058 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3059 if (option == INTENT_SATURATION) current = 2;
3060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3061 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3063 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3065 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3067 g_signal_connect(G_OBJECT(combo), "changed",
3068 G_CALLBACK(intent_menu_cb), option_c);
3070 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
3071 GTK_EXPAND | GTK_FILL, 0, 0, 0);
3072 gtk_widget_show(combo);
3076 static void config_tab_color(GtkWidget *notebook)
3085 vbox = scrolled_notebook_page(notebook, _("Color management"));
3087 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3089 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3092 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3093 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3095 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3096 pref_label_bold(label, TRUE, FALSE);
3098 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3099 pref_label_bold(label, TRUE, FALSE);
3101 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3102 pref_label_bold(label, TRUE, FALSE);
3104 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3109 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3110 pref_table_label(table, 0, i + 1, buf, 1.0);
3113 entry = gtk_entry_new();
3114 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3115 if (options->color_profile.input_name[i])
3117 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3119 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3120 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3121 gtk_widget_show(entry);
3122 color_profile_input_name_entry[i] = entry;
3124 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3125 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3126 gtk_widget_set_size_request(entry, 160, -1);
3127 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3128 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3129 gtk_widget_show(tabcomp);
3130 color_profile_input_file_entry[i] = entry;
3133 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3135 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3137 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3138 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3140 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3142 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3143 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3144 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3145 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3146 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3148 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3150 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3152 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3154 gtk_widget_show(tabcomp);
3157 /* advanced entry tab */
3158 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3160 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3162 c_options->file_ops.use_system_trash = FALSE;
3163 c_options->file_ops.no_trash = FALSE;
3167 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3169 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3171 c_options->file_ops.use_system_trash = TRUE;
3172 c_options->file_ops.no_trash = FALSE;
3176 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3178 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3180 c_options->file_ops.no_trash = TRUE;
3184 static void config_tab_behavior(GtkWidget *notebook)
3191 GtkWidget *ct_button;
3195 GtkWidget *with_rename;
3196 GtkWidget *collections_on_top;
3198 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3200 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3202 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3203 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3204 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3205 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3206 pref_checkbox_new_int(group, _("Enable Delete key"),
3207 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3209 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3210 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3212 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3213 pref_checkbox_link_sensitivity(ct_button, hbox);
3215 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3216 pref_label_new(hbox, _("Folder:"));
3218 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3219 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3220 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3221 gtk_widget_show(tabcomp);
3223 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3224 pref_checkbox_link_sensitivity(ct_button, hbox);
3226 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3227 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3228 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3229 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3230 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3231 G_CALLBACK(safe_delete_view_cb), NULL);
3232 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3233 gtk_widget_show(button);
3235 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3236 G_CALLBACK(safe_delete_clear_cb), NULL);
3237 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3238 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3239 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3241 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3242 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3244 gtk_widget_show(button);
3246 pref_spacer(group, PREF_PAD_GROUP);
3249 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3251 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3252 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3254 pref_checkbox_new_int(group, _("In place renaming"),
3255 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3257 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3258 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3260 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3261 options->marks_save, &c_options->marks_save);
3262 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3264 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3265 options->with_rename, &c_options->with_rename);
3266 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3268 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3269 options->collections_on_top, &c_options->collections_on_top);
3270 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3272 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3273 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3275 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3276 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3278 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3279 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3281 pref_spacer(group, PREF_PAD_GROUP);
3283 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3285 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3286 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3287 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3288 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3289 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3290 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3291 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3292 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3293 pref_checkbox_new_int(group, _("Play video by left click on image"),
3294 options->image_l_click_video, &c_options->image_l_click_video);
3295 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3296 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3298 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3299 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3300 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3301 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3302 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3305 pref_spacer(group, PREF_PAD_GROUP);
3307 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3309 pref_spin_new_int(group, _("Debug level:"), NULL,
3310 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3312 pref_checkbox_new_int(group, _("Timer data"),
3313 options->log_window.timer_data, &c_options->log_window.timer_data);
3315 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3316 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3320 /* accelerators tab */
3321 static void config_tab_accelerators(GtkWidget *notebook)
3327 GtkWidget *scrolled;
3328 GtkWidget *accel_view;
3329 GtkCellRenderer *renderer;
3330 GtkTreeSelection *selection;
3331 GtkTreeViewColumn *column;
3333 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3335 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3337 scrolled = gtk_scrolled_window_new(NULL, NULL);
3338 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3339 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3340 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3341 gtk_widget_show(scrolled);
3343 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3345 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3346 g_object_unref(accel_store);
3347 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3348 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3350 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3352 renderer = gtk_cell_renderer_text_new();
3354 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3359 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3360 gtk_tree_view_column_set_resizable(column, TRUE);
3361 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3364 renderer = gtk_cell_renderer_accel_new();
3365 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3366 G_CALLBACK(accel_store_cleared_cb), accel_store);
3367 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3368 G_CALLBACK(accel_store_edited_cb), accel_store);
3371 g_object_set (renderer,
3373 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3376 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3381 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3382 gtk_tree_view_column_set_resizable(column, TRUE);
3383 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3385 renderer = gtk_cell_renderer_text_new();
3387 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3392 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3393 gtk_tree_view_column_set_resizable(column, TRUE);
3394 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3396 renderer = gtk_cell_renderer_text_new();
3398 column = gtk_tree_view_column_new_with_attributes("Accel",
3403 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3404 gtk_tree_view_column_set_resizable(column, TRUE);
3405 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3407 accel_store_populate();
3408 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3409 gtk_widget_show(accel_view);
3411 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3413 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3414 G_CALLBACK(accel_default_cb), accel_view);
3415 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3416 gtk_widget_show(button);
3418 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3419 G_CALLBACK(accel_reset_cb), accel_view);
3420 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3421 gtk_widget_show(button);
3424 /* toolbar main tab */
3425 static void config_tab_toolbar_main(GtkWidget *notebook)
3428 GtkWidget *toolbardata;
3431 lw = layout_window_list->data;
3433 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3435 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3436 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3437 gtk_widget_show(vbox);
3440 /* toolbar status tab */
3441 static void config_tab_toolbar_status(GtkWidget *notebook)
3444 GtkWidget *toolbardata;
3447 lw = layout_window_list->data;
3449 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3451 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3452 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3453 gtk_widget_show(vbox);
3457 static void config_tab_stereo(GtkWidget *notebook)
3465 GtkWidget *fs_button;
3466 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3468 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3470 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3471 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3473 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3474 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3475 pref_checkbox_new_int(box, _("Mirror left image"),
3476 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3477 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3478 pref_checkbox_new_int(box, _("Flip left image"),
3479 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3480 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3481 pref_checkbox_new_int(box, _("Mirror right image"),
3482 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3483 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3484 pref_checkbox_new_int(box, _("Flip right image"),
3485 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3486 pref_checkbox_new_int(group, _("Swap left and right images"),
3487 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3488 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3489 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3491 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3492 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3493 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3494 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3495 pref_checkbox_link_sensitivity(fs_button, box2);
3496 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3497 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3498 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3499 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3500 pref_checkbox_new_int(box, _("Mirror left image"),
3501 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3502 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3503 pref_checkbox_new_int(box, _("Flip left image"),
3504 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3505 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3506 pref_checkbox_new_int(box, _("Mirror right image"),
3507 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3508 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3509 pref_checkbox_new_int(box, _("Flip right image"),
3510 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3511 pref_checkbox_new_int(box2, _("Swap left and right images"),
3512 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3513 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3514 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3516 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3517 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3518 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3519 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3520 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3521 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3522 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3523 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3524 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3525 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3526 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3527 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3528 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3529 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3533 /* Main preferences window */
3534 static void config_window_create(void)
3536 GtkWidget *win_vbox;
3538 GtkWidget *notebook;
3540 GtkWidget *ct_button;
3542 if (!c_options) c_options = init_options(NULL);
3544 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3545 DEBUG_NAME(configwindow);
3546 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3547 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3548 G_CALLBACK(config_window_delete), NULL);
3549 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3550 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3551 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3553 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3554 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3555 gtk_widget_show(win_vbox);
3557 notebook = gtk_notebook_new();
3558 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3559 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3560 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3562 config_tab_general(notebook);
3563 config_tab_image(notebook);
3564 config_tab_osd(notebook);
3565 config_tab_windows(notebook);
3566 config_tab_accelerators(notebook);
3567 config_tab_files(notebook);
3568 config_tab_metadata(notebook);
3569 config_tab_keywords(notebook);
3570 config_tab_color(notebook);
3571 config_tab_stereo(notebook);
3572 config_tab_behavior(notebook);
3573 config_tab_toolbar_main(notebook);
3574 config_tab_toolbar_status(notebook);
3576 hbox = gtk_hbutton_box_new();
3577 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3578 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3579 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3580 gtk_widget_show(hbox);
3582 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3583 G_CALLBACK(config_window_help_cb), notebook);
3584 gtk_container_add(GTK_CONTAINER(hbox), button);
3585 gtk_widget_set_can_default(button, TRUE);
3586 gtk_widget_show(button);
3588 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3589 G_CALLBACK(config_window_ok_cb), NULL);
3590 gtk_container_add(GTK_CONTAINER(hbox), button);
3591 gtk_widget_set_can_default(button, TRUE);
3592 gtk_widget_grab_default(button);
3593 gtk_widget_show(button);
3597 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3598 G_CALLBACK(config_window_close_cb), NULL);
3599 gtk_container_add(GTK_CONTAINER(hbox), button);
3600 gtk_widget_set_can_default(button, TRUE);
3601 gtk_widget_show(button);
3603 if (!generic_dialog_get_alternative_button_order(configwindow))
3605 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3608 gtk_widget_show(notebook);
3610 gtk_widget_show(configwindow);
3614 *-----------------------------------------------------------------------------
3615 * config window show (public)
3616 *-----------------------------------------------------------------------------
3619 void show_config_window(void)
3623 gtk_window_present(GTK_WINDOW(configwindow));
3627 config_window_create();
3636 void show_about_window(LayoutWindow *lw)
3638 GdkPixbuf *pixbuf_logo;
3639 GdkPixbuf *pixbuf_icon;
3640 gchar *authors[1000];
3645 gchar *timezone_path;
3649 #define LINE_LENGTH 1000
3650 gchar line[LINE_LENGTH];
3652 copyright = g_string_new(NULL);
3653 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");
3655 path = path_from_utf8(TIMEZONE_DATABASE);
3656 basename = g_path_get_basename(path);
3657 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3658 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3660 cd = ZDOpenDatabase(timezone_path);
3663 copyright = g_string_append(copyright, ZDGetNotice(cd));
3664 ZDCloseDatabase(cd);
3668 g_free(timezone_path);
3672 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3673 fp = fopen(path, "r");
3676 while(fgets(line, LINE_LENGTH, fp))
3678 /* get rid of ending \n from fgets */
3679 line[strlen(line) - 1] = '\0';
3680 authors[i_authors] = g_strdup(line);
3683 authors[i_authors] = NULL;
3688 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3689 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3691 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3692 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3693 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3694 "title", _("About Geeqie"),
3696 "program-name", GQ_APPNAME,
3698 "logo", pixbuf_logo,
3699 "icon", pixbuf_icon,
3700 "website", GQ_WEBSITE,
3701 "website-label", "Website",
3702 "comments", comment,
3704 "translator-credits", _("translator-credits"),
3705 "wrap-license", TRUE,
3706 "license", copyright->str,
3709 g_string_free(copyright, TRUE);
3712 while(n < i_authors)
3722 static void image_overlay_set_text_colours()
3724 c_options->image_overlay.text_red = options->image_overlay.text_red;
3725 c_options->image_overlay.text_green = options->image_overlay.text_green;
3726 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3727 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3728 c_options->image_overlay.background_red = options->image_overlay.background_red;
3729 c_options->image_overlay.background_green = options->image_overlay.background_green;
3730 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3731 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3735 *-----------------------------------------------------------------------------
3736 * timezone database routines
3737 *-----------------------------------------------------------------------------
3740 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3742 GError *error = NULL;
3744 gchar *tmp_filename;
3746 if (!g_cancellable_is_cancelled(tz->cancellable))
3748 generic_dialog_close(tz->gd);
3752 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3754 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3755 move_file(tmp_filename, tz->timezone_database_user);
3756 g_free(tmp_filename);
3760 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3763 g_file_delete(tz->tmp_g_file, NULL, &error);
3764 g_object_unref(tz->tmp_g_file);
3765 tz->tmp_g_file = NULL;
3766 g_object_unref(tz->cancellable);
3767 g_object_unref(tz->timezone_database_gq);
3770 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3774 if (!g_cancellable_is_cancelled(tz->cancellable))
3776 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3780 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3783 GError *error = NULL;
3785 g_cancellable_cancel(tz->cancellable);
3788 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3791 GError *error = NULL;
3792 GFileIOStream *io_stream;
3799 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3803 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3804 log_printf("Error: Download timezone database failed:\n%s", error->message);
3805 g_error_free(error);
3806 g_object_unref(tz->tmp_g_file);
3810 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3812 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3814 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3816 tz->progress = gtk_progress_bar_new();
3817 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3818 gtk_widget_show(tz->progress);
3820 gtk_widget_show(tz->gd->dialog);
3821 tz->cancellable = g_cancellable_new();
3822 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);
3824 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3827 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */