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[] = {
124 /* config memory values */
125 static ConfOptions *c_options = NULL;
132 static GtkWidget *configwindow = NULL;
133 static GtkListStore *filter_store = NULL;
134 static GtkTreeStore *accel_store = NULL;
136 static GtkWidget *safe_delete_path_entry;
138 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
139 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
140 static GtkWidget *color_profile_screen_file_entry;
142 static GtkWidget *sidecar_ext_entry;
143 static GtkWidget *help_search_engine_entry;
146 #define CONFIG_WINDOW_DEF_WIDTH 700
147 #define CONFIG_WINDOW_DEF_HEIGHT 600
150 *-----------------------------------------------------------------------------
151 * option widget callbacks (private)
152 *-----------------------------------------------------------------------------
155 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
157 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
160 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
162 gint mins_secs_tenths, delay;
164 mins_secs_tenths = c_options->slideshow.delay %
165 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
167 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
168 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
171 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
172 SLIDESHOW_SUBSECOND_PRECISION;
175 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
177 gint hours, secs_tenths, delay;
179 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
180 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
182 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
183 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
184 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
186 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
187 SLIDESHOW_SUBSECOND_PRECISION;
190 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
192 gint hours_mins, delay;
194 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
196 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
197 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
198 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
200 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
201 SLIDESHOW_SUBSECOND_PRECISION;
205 *-----------------------------------------------------------------------------
206 * sync progam to config window routine (private)
207 *-----------------------------------------------------------------------------
210 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
216 buf = gtk_entry_get_text(GTK_ENTRY(entry));
217 if (buf && strlen(buf) > 0)
222 *option = g_strdup(buf);
227 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
229 gchar *accel_path, *accel;
231 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
233 if (accel_path && accel_path[0])
236 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
237 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
247 static void config_window_apply(void)
250 gboolean refresh = FALSE;
252 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
254 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
255 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
256 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
257 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
258 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
259 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
260 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
262 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
263 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
264 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
265 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
266 options->file_ops.no_trash = c_options->file_ops.no_trash;
267 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
268 options->tools_restore_state = c_options->tools_restore_state;
269 options->save_window_positions = c_options->save_window_positions;
270 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
271 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
272 options->show_window_ids = c_options->show_window_ids;
273 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
274 options->image.zoom_2pass = c_options->image.zoom_2pass;
275 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
276 options->image.limit_window_size = c_options->image.limit_window_size;
277 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
278 options->image.max_window_size = c_options->image.max_window_size;
279 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
280 options->image.max_autofit_size = c_options->image.max_autofit_size;
281 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
282 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
283 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
284 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
286 if (options->thumbnails.max_width != c_options->thumbnails.max_width
287 || options->thumbnails.max_height != c_options->thumbnails.max_height
288 || options->thumbnails.quality != c_options->thumbnails.quality)
290 thumb_format_changed = TRUE;
292 options->thumbnails.max_width = c_options->thumbnails.max_width;
293 options->thumbnails.max_height = c_options->thumbnails.max_height;
294 options->thumbnails.quality = c_options->thumbnails.quality;
296 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
297 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
298 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
299 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
300 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
301 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
302 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
303 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
304 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
305 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
306 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
307 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
309 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
310 options->file_sort.natural = c_options->file_sort.natural;
311 options->file_filter.disable = c_options->file_filter.disable;
313 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
314 sidecar_ext_parse(options->sidecar.ext);
316 options->slideshow.random = c_options->slideshow.random;
317 options->slideshow.repeat = c_options->slideshow.repeat;
318 options->slideshow.delay = c_options->slideshow.delay;
320 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
321 options->image_lm_click_nav = c_options->image_lm_click_nav;
322 options->image_l_click_video = c_options->image_l_click_video;
323 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
325 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
327 options->image.tile_cache_max = c_options->image.tile_cache_max;
328 options->image.image_cache_max = c_options->image.image_cache_max;
330 options->image.zoom_quality = c_options->image.zoom_quality;
332 options->image.zoom_increment = c_options->image.zoom_increment;
334 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
337 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
338 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
339 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
341 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
342 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
343 options->image.border_color = c_options->image.border_color;
344 layout_colors_update();
345 view_window_colors_update();
348 options->image.alpha_color_1 = c_options->image.alpha_color_1;
349 options->image.alpha_color_2 = c_options->image.alpha_color_2;
351 options->fullscreen.screen = c_options->fullscreen.screen;
352 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
353 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
354 options->fullscreen.above = c_options->fullscreen.above;
355 if (c_options->image_overlay.template_string)
356 set_image_overlay_template_string(&options->image_overlay.template_string,
357 c_options->image_overlay.template_string);
358 if (c_options->image_overlay.font)
359 set_image_overlay_font_string(&options->image_overlay.font,
360 c_options->image_overlay.font);
361 options->image_overlay.text_red = c_options->image_overlay.text_red;
362 options->image_overlay.text_green = c_options->image_overlay.text_green;
363 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
364 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
365 options->image_overlay.background_red = c_options->image_overlay.background_red;
366 options->image_overlay.background_green = c_options->image_overlay.background_green;
367 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
368 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
369 options->update_on_time_change = c_options->update_on_time_change;
370 options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
372 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
373 options->rot_invariant_sim = c_options->rot_invariant_sim;
375 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
377 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
379 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
380 options->dnd_icon_size = c_options->dnd_icon_size;
381 options->clipboard_selection = c_options->clipboard_selection;
383 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
384 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
385 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
386 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
387 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
388 options->metadata.confirm_write = c_options->metadata.confirm_write;
389 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
390 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
391 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
392 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
393 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
394 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
395 options->metadata.write_orientation = c_options->metadata.write_orientation;
396 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
397 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
398 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
399 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
400 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
401 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
402 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
403 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
404 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
405 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
406 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
407 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
408 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
409 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
410 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
411 options->stereo.fixed_w = c_options->stereo.fixed_w;
412 options->stereo.fixed_h = c_options->stereo.fixed_h;
413 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
414 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
415 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
416 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
418 options->info_keywords.height = c_options->info_keywords.height;
419 options->info_title.height = c_options->info_title.height;
420 options->info_comment.height = c_options->info_comment.height;
421 options->info_rating.height = c_options->info_rating.height;
423 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
425 options->marks_save = c_options->marks_save;
426 options->with_rename = c_options->with_rename;
427 options->collections_on_top = c_options->collections_on_top;
428 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
430 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
432 options->star_rating.star = c_options->star_rating.star;
433 options->star_rating.rejected = c_options->star_rating.rejected;
435 set_debug_level(debug_c);
439 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
441 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
442 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
444 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
445 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
446 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
448 options->color_profile.render_intent = c_options->color_profile.render_intent;
453 options->mouse_button_8 = c_options->mouse_button_8;
454 options->mouse_button_9 = c_options->mouse_button_9;
456 config_tab_keywords_save();
458 image_options_sync();
463 layout_refresh(NULL);
466 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
468 toolbar_apply(TOOLBAR_MAIN);
469 toolbar_apply(TOOLBAR_STATUS);
473 *-----------------------------------------------------------------------------
474 * config window main button callbacks (private)
475 *-----------------------------------------------------------------------------
478 static void config_window_close_cb(GtkWidget *widget, gpointer data)
480 gtk_widget_destroy(configwindow);
485 static void config_window_help_cb(GtkWidget *widget, gpointer data)
487 GtkWidget *notebook = data;
490 static gchar *html_section[] =
492 "GuideOptionsGeneral.html",
493 "GuideOptionsImage.html",
494 "GuideOptionsOSD.html",
495 "GuideOptionsWindow.html",
496 "GuideOptionsKeyboard.html",
497 "GuideOptionsFiltering.html",
498 "GuideOptionsMetadata.html",
499 "GuideOptionsKeywords.html",
500 "GuideOptionsColor.html",
501 "GuideOptionsStereo.html",
502 "GuideOptionsBehavior.html",
503 "GuideOptionsToolbar.html"
506 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
507 help_window_show(html_section[i]);
510 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
512 config_window_close_cb(NULL, NULL);
516 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
518 config_window_apply();
519 config_window_close_cb(NULL, NULL);
522 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
525 lw = layout_window_list->data;
527 config_window_apply();
528 layout_util_sync(lw);
531 static void config_window_save_cb(GtkWidget *widget, gpointer data)
533 config_window_apply();
534 save_options(options);
538 *-----------------------------------------------------------------------------
539 * config window setup (private)
540 *-----------------------------------------------------------------------------
543 static void quality_menu_cb(GtkWidget *combo, gpointer data)
547 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
551 *option = GDK_INTERP_NEAREST;
554 *option = GDK_INTERP_TILES;
557 *option = GDK_INTERP_BILINEAR;
560 *option = GDK_INTERP_HYPER;
565 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
569 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
581 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
582 guint option, guint *option_c)
589 pref_table_label(table, column, row, text, 0.0);
591 combo = gtk_combo_box_text_new();
593 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
594 if (option == GDK_INTERP_NEAREST) current = 0;
595 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
596 if (option == GDK_INTERP_TILES) current = 1;
597 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
598 if (option == GDK_INTERP_BILINEAR) current = 2;
599 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
600 if (option == GDK_INTERP_HYPER) current = 3;
602 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
604 g_signal_connect(G_OBJECT(combo), "changed",
605 G_CALLBACK(quality_menu_cb), option_c);
607 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
608 GTK_EXPAND | GTK_FILL, 0, 0, 0);
609 gtk_widget_show(combo);
612 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
613 gint option, gint *option_c)
620 pref_table_label(table, column, row, text, 0.0);
622 combo = gtk_combo_box_text_new();
624 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
625 if (option == PRIMARY) current = 0;
626 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
627 if (option == CLIPBOARD) current = 1;
629 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
631 g_signal_connect(G_OBJECT(combo), "changed",
632 G_CALLBACK(clipboard_selection_menu_cb), option_c);
634 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
635 GTK_EXPAND | GTK_FILL, 0, 0, 0);
636 gtk_widget_show(combo);
639 typedef struct _UseableMouseItems UseableMouseItems;
640 struct _UseableMouseItems
642 gchar *name; /* GtkActionEntry terminology */
647 static const UseableMouseItems useable_mouse_items[] = {
649 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
650 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
651 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
652 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
653 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
654 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
655 {"Home", N_("Home"), GTK_STOCK_HOME},
656 {"Up", N_("Up"), GTK_STOCK_GO_UP},
657 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
658 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
659 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
660 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
661 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
662 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
663 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
664 {"Search", N_("Search"), GTK_STOCK_FIND},
665 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
666 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
667 {"Copy", N_("Copy"), GTK_STOCK_COPY},
668 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
669 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
670 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
671 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
672 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
673 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
674 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
675 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
676 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
677 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
678 {"Print", N_("Print"), GTK_STOCK_PRINT},
679 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
680 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
681 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
682 {"RotateCW", N_("Rotate clockwise"), PIXBUF_INLINE_ICON_CW},
683 {"RotateCCW", N_("Rotate counterclockwise"), PIXBUF_INLINE_ICON_CCW},
684 {"Rotate180", N_("Rotate 180"), PIXBUF_INLINE_ICON_180},
685 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
686 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
687 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
688 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
689 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
690 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
691 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
692 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
693 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
694 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
695 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
696 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
697 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
698 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
699 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
700 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
701 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
702 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
703 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
704 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
705 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
706 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
707 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
708 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
709 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
710 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
711 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
712 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
713 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
714 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
715 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
716 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
717 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
721 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
723 gchar **option = data;
726 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
728 const UseableMouseItems *list = useable_mouse_items;
732 if (g_strcmp0(list->label, label) == 0)
740 *option = g_strdup(list->name);
744 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
745 gchar *option, gchar **option_c)
753 pref_table_label(table, column, row, text, 0.0);
755 combo = gtk_combo_box_text_new();
757 const UseableMouseItems *list = useable_mouse_items;
761 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
762 if (g_strcmp0(list->name, option) == 0)
770 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
772 g_signal_connect(G_OBJECT(combo), "changed",
773 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
775 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
776 GTK_EXPAND | GTK_FILL, 0, 0, 0);
777 gtk_widget_show(combo);
780 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
784 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
787 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
789 c_options->thumbnails.max_width = thumb_size_list[n].w;
790 c_options->thumbnails.max_height = thumb_size_list[n].h;
794 c_options->thumbnails.max_width = options->thumbnails.max_width;
795 c_options->thumbnails.max_height = options->thumbnails.max_height;
799 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
805 c_options->thumbnails.max_width = options->thumbnails.max_width;
806 c_options->thumbnails.max_height = options->thumbnails.max_height;
808 pref_table_label(table, column, row, text, 0.0);
810 combo = gtk_combo_box_text_new();
813 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
818 w = thumb_size_list[i].w;
819 h = thumb_size_list[i].h;
821 buf = g_strdup_printf("%d x %d", w, h);
822 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
825 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
832 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
833 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
839 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
840 g_signal_connect(G_OBJECT(combo), "changed",
841 G_CALLBACK(thumb_size_menu_cb), NULL);
843 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
844 GTK_EXPAND | GTK_FILL, 0, 0, 0);
845 gtk_widget_show(combo);
848 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
852 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
856 *option = PR_STEREO_NONE;
859 *option = PR_STEREO_ANAGLYPH_RC;
862 *option = PR_STEREO_ANAGLYPH_GM;
865 *option = PR_STEREO_ANAGLYPH_YB;
868 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
871 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
874 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
877 *option = PR_STEREO_ANAGLYPH_DB_RC;
880 *option = PR_STEREO_ANAGLYPH_DB_GM;
883 *option = PR_STEREO_ANAGLYPH_DB_YB;
886 *option = PR_STEREO_HORIZ;
889 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
892 *option = PR_STEREO_VERT;
895 *option = PR_STEREO_VERT | PR_STEREO_HALF;
898 *option = PR_STEREO_FIXED;
903 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
904 gint option, gint *option_c, gboolean add_fixed)
911 pref_table_label(table, column, row, text, 0.0);
913 combo = gtk_combo_box_text_new();
915 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
917 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
918 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
919 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
920 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
921 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
922 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
923 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
924 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
925 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
926 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
927 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
928 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
929 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
930 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
931 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
932 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
933 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
934 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
936 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
937 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
938 if (option & PR_STEREO_HORIZ)
941 if (option & PR_STEREO_HALF) current = 11;
944 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
945 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
946 if (option & PR_STEREO_VERT)
949 if (option & PR_STEREO_HALF) current = 13;
954 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
955 if (option & PR_STEREO_FIXED) current = 14;
958 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
960 g_signal_connect(G_OBJECT(combo), "changed",
961 G_CALLBACK(stereo_mode_menu_cb), option_c);
963 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
964 GTK_EXPAND | GTK_FILL, 0, 0, 0);
965 gtk_widget_show(combo);
968 static void video_menu_cb(GtkWidget *combo, gpointer data)
970 gchar **option = data;
972 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
976 static void video_menu_populate(gpointer data, gpointer user_data)
978 GtkWidget *combo = user_data;
979 EditorDescription *ed = data;
981 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
984 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
985 gchar *option, gchar **option_c)
989 /* use lists since they are sorted */
990 GList *eds = editor_list_get();
994 pref_table_label(table, column, row, text, 0.0);
996 combo = gtk_combo_box_text_new();
997 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
998 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1000 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1002 g_signal_connect(G_OBJECT(combo), "changed",
1003 G_CALLBACK(video_menu_cb), option_c);
1005 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
1006 GTK_EXPAND | GTK_FILL, 0, 0, 0);
1007 gtk_widget_show(combo);
1010 static void filter_store_populate(void)
1014 if (!filter_store) return;
1016 gtk_list_store_clear(filter_store);
1018 work = filter_get_list();
1027 gtk_list_store_append(filter_store, &iter);
1028 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1032 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1033 gchar *new_text, gpointer data)
1035 GtkWidget *model = data;
1036 FilterEntry *fe = data;
1040 if (!new_text || strlen(new_text) < 1) return;
1042 tpath = gtk_tree_path_new_from_string(path_str);
1043 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1044 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1046 g_free(fe->extensions);
1047 fe->extensions = g_strdup(new_text);
1049 gtk_tree_path_free(tpath);
1053 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1054 gchar *new_text, gpointer data)
1056 GtkWidget *model = data;
1057 FilterEntry *fe = data;
1062 if (!new_text || !new_text[0]) return;
1064 tpath = gtk_tree_path_new_from_string(path_str);
1065 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1066 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1068 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1070 if (strcmp(new_text, _(format_class_list[i])) == 0)
1077 gtk_tree_path_free(tpath);
1081 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1082 gchar *new_text, gpointer data)
1084 GtkWidget *model = data;
1089 if (!new_text || !new_text[0]) return;
1091 tpath = gtk_tree_path_new_from_string(path_str);
1092 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1093 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1095 g_free(fe->description);
1096 fe->description = g_strdup(new_text);
1098 gtk_tree_path_free(tpath);
1101 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1102 gchar *path_str, gpointer data)
1104 GtkWidget *model = data;
1109 tpath = gtk_tree_path_new_from_string(path_str);
1110 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1111 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1113 fe->enabled = !fe->enabled;
1115 gtk_tree_path_free(tpath);
1119 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1120 gchar *path_str, gpointer data)
1122 GtkWidget *model = data;
1127 tpath = gtk_tree_path_new_from_string(path_str);
1128 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1129 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1131 fe->writable = !fe->writable;
1132 if (fe->writable) fe->allow_sidecar = FALSE;
1134 gtk_tree_path_free(tpath);
1138 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1139 gchar *path_str, gpointer data)
1141 GtkWidget *model = data;
1146 tpath = gtk_tree_path_new_from_string(path_str);
1147 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1148 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1150 fe->allow_sidecar = !fe->allow_sidecar;
1151 if (fe->allow_sidecar) fe->writable = FALSE;
1153 gtk_tree_path_free(tpath);
1157 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1158 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1162 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1164 switch (GPOINTER_TO_INT(data))
1167 g_object_set(GTK_CELL_RENDERER(cell),
1168 "active", fe->enabled, NULL);
1171 g_object_set(GTK_CELL_RENDERER(cell),
1172 "text", fe->extensions, NULL);
1174 case FE_DESCRIPTION:
1175 g_object_set(GTK_CELL_RENDERER(cell),
1176 "text", fe->description, NULL);
1179 g_object_set(GTK_CELL_RENDERER(cell),
1180 "text", _(format_class_list[fe->file_class]), NULL);
1183 g_object_set(GTK_CELL_RENDERER(cell),
1184 "active", fe->writable, NULL);
1186 case FE_ALLOW_SIDECAR:
1187 g_object_set(GTK_CELL_RENDERER(cell),
1188 "active", fe->allow_sidecar, NULL);
1193 static gboolean filter_add_scroll(gpointer data)
1197 GtkCellRenderer *cell;
1198 GtkTreeViewColumn *column;
1203 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1204 path = gtk_tree_path_new_from_indices(rows-1, -1);
1206 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1208 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1209 cell = g_list_last(list_cells)->data;
1211 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1212 path, column, FALSE, 0.0, 0.0 );
1213 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1214 path, column, cell, TRUE);
1216 gtk_tree_path_free(path);
1217 g_list_free(list_cells);
1222 static void filter_add_cb(GtkWidget *widget, gpointer data)
1224 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1225 filter_store_populate();
1227 g_idle_add((GSourceFunc)filter_add_scroll, data);
1230 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1232 GtkWidget *filter_view = data;
1233 GtkTreeSelection *selection;
1237 if (!filter_store) return;
1238 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1239 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1240 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1243 filter_remove_entry(fe);
1245 filter_store_populate();
1248 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1252 GtkTreeViewColumn *column;
1254 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1255 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1256 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1258 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1262 gtk_tree_path_free(path);
1267 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1270 filter_add_defaults();
1272 filter_store_populate();
1274 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1277 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1279 /* no op, only so cancel button appears */
1282 static void filter_default_cb(GtkWidget *widget, gpointer data)
1286 gd = generic_dialog_new(_("Reset filters"),
1287 "reset_filter", widget, TRUE,
1288 dummy_cancel_cb, data);
1289 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1290 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1291 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1292 gtk_widget_show(gd->dialog);
1295 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1297 GtkWidget *frame = data;
1299 gtk_widget_set_sensitive(frame,
1300 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1303 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1305 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1308 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1310 file_util_trash_clear();
1313 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1317 gd = generic_dialog_new(_("Clear trash"),
1318 "clear_trash", widget, TRUE,
1319 dummy_cancel_cb, NULL);
1320 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1321 _("This will remove the trash contents."), FALSE);
1322 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1323 entry = gtk_entry_new();
1324 gtk_widget_set_can_focus(entry, FALSE);
1325 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1326 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1327 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1328 gtk_widget_show(entry);
1329 gtk_widget_show(gd->dialog);
1332 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1334 GtkWidget *pTextView;
1335 GtkTextBuffer *pTextBuffer;
1339 pTextView = GTK_WIDGET(data);
1341 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1342 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1343 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1345 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1346 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1349 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1351 GtkTextView *text_view = data;
1352 GtkTextBuffer *buffer;
1354 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1355 if (!configwindow) return;
1357 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1358 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1361 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1365 gd = generic_dialog_new(_("Reset image overlay template string"),
1366 "reset_image_overlay_template_string", widget, TRUE,
1367 dummy_cancel_cb, data);
1368 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1369 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1370 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1371 gtk_widget_show(gd->dialog);
1374 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1376 help_window_show("GuideOptionsOSD.html");
1379 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1381 #if GTK_CHECK_VERSION(3,4,0)
1384 PangoFontDescription *font_desc;
1386 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1387 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1389 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1391 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1392 font = pango_font_description_to_string(font_desc);
1393 g_free(c_options->image_overlay.font);
1394 c_options->image_overlay.font = g_strdup(font);
1398 gtk_widget_destroy(dialog);
1402 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1403 c_options->image_overlay.font = g_strdup(font);
1407 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1410 #if GTK_CHECK_VERSION(3,4,0)
1413 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1414 colour.red = options->image_overlay.text_red;
1415 colour.green = options->image_overlay.text_green;
1416 colour.blue = options->image_overlay.text_blue;
1417 colour.alpha = options->image_overlay.text_alpha;
1418 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1419 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1421 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1423 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1424 c_options->image_overlay.text_red = colour.red*255;
1425 c_options->image_overlay.text_green = colour.green*255;
1426 c_options->image_overlay.text_blue = colour.blue*255;
1427 c_options->image_overlay.text_alpha = colour.alpha*255;
1429 gtk_widget_destroy(dialog);
1432 GtkColorSelection *colorsel;
1434 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1435 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1436 colour.red = options->image_overlay.text_red*257;
1437 colour.green = options->image_overlay.text_green*257;
1438 colour.blue = options->image_overlay.text_blue*257;
1439 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1440 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1441 gtk_color_selection_set_current_color(colorsel, &colour);
1442 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1444 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1446 gtk_color_selection_get_current_color(colorsel, &colour);
1447 c_options->image_overlay.text_red = colour.red/257;
1448 c_options->image_overlay.text_green = colour.green/257;
1449 c_options->image_overlay.text_blue = colour.blue/257;
1450 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1452 gtk_widget_destroy (dialog);
1457 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1460 #if GTK_CHECK_VERSION(3,4,0)
1463 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1464 colour.red = options->image_overlay.background_red;
1465 colour.green = options->image_overlay.background_green;
1466 colour.blue = options->image_overlay.background_blue;
1467 colour.alpha = options->image_overlay.background_alpha;
1468 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1469 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1471 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1473 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1474 c_options->image_overlay.background_red = colour.red*255;
1475 c_options->image_overlay.background_green = colour.green*255;
1476 c_options->image_overlay.background_blue = colour.blue*255;
1477 c_options->image_overlay.background_alpha = colour.alpha*255;
1479 gtk_widget_destroy(dialog);
1482 GtkColorSelection *colorsel;
1484 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1485 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1486 colour.red = options->image_overlay.background_red*257;
1487 colour.green = options->image_overlay.background_green*257;
1488 colour.blue = options->image_overlay.background_blue*257;
1489 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1490 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1491 gtk_color_selection_set_current_color(colorsel, &colour);
1492 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1494 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1496 gtk_color_selection_get_current_color(colorsel, &colour);
1497 c_options->image_overlay.background_red = colour.red/257;
1498 c_options->image_overlay.background_green = colour.green/257;
1499 c_options->image_overlay.background_blue = colour.blue/257;
1500 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1502 gtk_widget_destroy(dialog);
1506 static void accel_store_populate(void)
1509 GList *groups, *actions;
1511 const gchar *accel_path;
1515 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1517 gtk_tree_store_clear(accel_store);
1518 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1520 g_assert(lw && lw->ui_manager);
1521 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1524 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1527 action = GTK_ACTION(actions->data);
1528 accel_path = gtk_action_get_accel_path(action);
1529 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1531 gchar *label, *label2, *tooltip, *accel;
1532 g_object_get(action,
1533 "tooltip", &tooltip,
1537 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1543 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1547 gtk_tree_store_append(accel_store, &iter, NULL);
1548 gtk_tree_store_set(accel_store, &iter,
1551 AE_TOOLTIP, tooltip ? tooltip : "",
1552 AE_ACCEL, accel_path,
1560 actions = actions->next;
1563 groups = groups->next;
1567 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1572 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1574 gchar *accel1 = data;
1579 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1581 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1582 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1584 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1586 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1587 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1596 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1598 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1602 GtkAccelKey old_key, key;
1603 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1605 gtk_tree_model_get_iter(model, &iter, path);
1606 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1608 /* test if the accelerator can be stored without conflicts*/
1609 gtk_accel_map_lookup_entry(accel_path, &old_key);
1611 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1612 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1613 gtk_accel_map_lookup_entry(accel_path, &key);
1615 /* restore the original for now, the key will be really changed when the changes are confirmed */
1616 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1618 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1619 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1621 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1622 gtk_tree_path_free(path);
1626 static gboolean accel_default_scroll(GtkTreeView *data)
1630 GtkTreeViewColumn *column;
1632 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1633 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1634 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1636 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1640 gtk_tree_path_free(path);
1645 static void accel_default_cb(GtkWidget *widget, gpointer data)
1647 accel_store_populate();
1649 g_idle_add((GSourceFunc)accel_default_scroll, data);
1652 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1654 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1657 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1660 gchar *accel_path, *accel;
1662 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1663 gtk_accel_map_lookup_entry(accel_path, &key);
1664 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1666 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1668 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1673 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1675 GtkTreeSelection *selection;
1677 if (!accel_store) return;
1678 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1679 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1684 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1688 GtkWidget *scrolled;
1689 GtkWidget *viewport;
1691 scrolled = gtk_scrolled_window_new(NULL, NULL);
1692 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1693 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1694 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1695 label = gtk_label_new(title);
1696 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1697 gtk_widget_show(scrolled);
1699 viewport = gtk_viewport_new(NULL, NULL);
1700 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1701 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1702 gtk_widget_show(viewport);
1704 vbox = gtk_vbox_new(FALSE, 0);
1705 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1706 gtk_widget_show(vbox);
1711 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1713 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1715 c_options->thumbnails.spec_standard =TRUE;
1716 c_options->thumbnails.cache_into_dirs = FALSE;
1720 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1722 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1724 c_options->thumbnails.spec_standard =FALSE;
1725 c_options->thumbnails.cache_into_dirs = FALSE;
1729 static void cache_local_cb(GtkWidget *widget, gpointer data)
1731 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1733 c_options->thumbnails.cache_into_dirs = TRUE;
1734 c_options->thumbnails.spec_standard =FALSE;
1738 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1739 GdkEvent *event, gpointer userdata)
1741 if (pos == GTK_ENTRY_ICON_PRIMARY)
1743 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1747 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1751 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1752 GdkEvent *event, gpointer userdata)
1754 gchar *rating_symbol;
1756 if (pos == GTK_ENTRY_ICON_PRIMARY)
1758 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1759 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1760 g_free(rating_symbol);
1764 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1765 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1766 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1770 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1771 GdkEvent *event, gpointer userdata)
1773 gchar *rating_symbol;
1775 if (pos == GTK_ENTRY_ICON_PRIMARY)
1777 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1778 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1779 g_free(rating_symbol);
1783 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1784 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1785 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1789 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1791 GtkContainer *hbox = data;
1792 GString *str = g_string_new(NULL);
1793 GtkEntry *hex_code_entry;
1794 gchar *hex_code_full;
1797 guint64 hex_value = 0;
1799 list = gtk_container_get_children(hbox);
1801 hex_code_entry = g_list_nth_data(list, 2);
1802 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1804 hex_code = g_strsplit(hex_code_full, "+", 2);
1805 if (hex_code[0] && hex_code[1])
1807 hex_value = strtoull(hex_code[1], NULL, 16);
1809 if (!hex_value || hex_value > 0x10FFFF)
1811 hex_value = 0x003F; // Unicode 'Question Mark'
1813 str = g_string_append_unichar(str, (gunichar)hex_value);
1814 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1816 g_strfreev(hex_code);
1817 g_string_free(str, TRUE);
1818 g_free(hex_code_full);
1823 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1825 guint64 star_symbol;
1827 star_symbol = star_rating_symbol_test(widget, data);
1828 c_options->star_rating.star = star_symbol;
1831 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1833 guint64 rejected_symbol;
1835 rejected_symbol = star_rating_symbol_test(widget, data);
1836 c_options->star_rating.rejected = rejected_symbol;
1839 /* general options tab */
1840 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1841 typedef struct _TZData TZData;
1845 GCancellable *cancellable;
1847 GtkWidget *progress;
1849 GFile *timezone_database_gq;
1850 gchar *timezone_database_user;
1853 static void config_tab_general(GtkWidget *notebook)
1858 GtkWidget *group_frame;
1859 GtkWidget *subgroup;
1861 GtkWidget *ct_button;
1864 gint hours, minutes, remainder;
1866 GtkWidget *star_rating_entry;
1868 gchar *rating_symbol;
1871 GNetworkMonitor *net_mon;
1872 GSocketConnectable *geeqie_org;
1873 gboolean internet_available;
1876 vbox = scrolled_notebook_page(notebook, _("General"));
1878 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1880 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1881 add_thumb_size_menu(table, 0, 0, _("Size:"));
1882 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1884 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1885 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1887 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1888 pref_checkbox_link_sensitivity(ct_button, subgroup);
1890 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1891 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1892 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1893 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1894 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1895 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1896 G_CALLBACK(cache_geeqie_cb), NULL);
1898 group_frame = pref_frame_new(subgroup, TRUE,
1899 _("Store thumbnails local to image folder (non-standard)"),
1900 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1901 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1902 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1903 G_CALLBACK(cache_local_cb), NULL);
1905 group_frame = pref_frame_new(subgroup, TRUE,
1906 _("Use standard thumbnail style and cache, shared with other applications"),
1907 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1908 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1909 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1910 G_CALLBACK(cache_standard_cb), NULL);
1912 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1913 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1915 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1917 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1918 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1920 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1921 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1922 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1924 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1925 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1928 pref_spacer(group, PREF_PAD_GROUP);
1930 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1932 c_options->star_rating.star = options->star_rating.star;
1933 c_options->star_rating.rejected = options->star_rating.rejected;
1935 str = g_string_new(NULL);
1936 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1937 pref_label_new(hbox, "Star character: ");
1938 str = g_string_append_unichar(str, options->star_rating.star);
1939 pref_label_new(hbox, g_strdup(str->str));
1940 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1941 star_rating_entry = gtk_entry_new();
1942 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1943 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1944 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1945 gtk_widget_show(star_rating_entry);
1946 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1947 G_CALLBACK(star_rating_star_test_cb), hbox);
1948 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1949 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1950 gtk_widget_show(button);
1951 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."));
1952 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1953 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1954 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1955 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1956 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1957 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1958 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1959 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1960 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1961 G_CALLBACK(star_rating_star_icon_cb),
1964 g_string_free(str, TRUE);
1965 g_free(rating_symbol);
1967 str = g_string_new(NULL);
1968 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1969 pref_label_new(hbox, "Rejected character: ");
1970 str = g_string_append_unichar(str, options->star_rating.rejected);
1971 pref_label_new(hbox, g_strdup(str->str));
1972 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
1973 star_rating_entry = gtk_entry_new();
1974 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1975 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1976 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1977 gtk_widget_show(star_rating_entry);
1978 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1979 G_CALLBACK(star_rating_rejected_test_cb), hbox);
1980 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1981 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1982 gtk_widget_show(button);
1983 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."));
1984 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1985 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1986 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1987 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1988 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1989 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1990 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1991 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1992 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1993 G_CALLBACK(star_rating_rejected_icon_cb),
1996 g_string_free(str, TRUE);
1997 g_free(rating_symbol);
1999 pref_spacer(group, PREF_PAD_GROUP);
2001 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2003 c_options->slideshow.delay = options->slideshow.delay;
2004 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2005 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2006 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2007 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2008 SLIDESHOW_SUBSECOND_PRECISION;
2010 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2012 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2014 options->slideshow.delay ? hours : 0.0,
2015 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2016 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2017 spin = pref_spin_new(hbox, ":" , NULL,
2019 options->slideshow.delay ? minutes: 0.0,
2020 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2021 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2022 spin = pref_spin_new(hbox, ":", NULL,
2023 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2024 options->slideshow.delay ? seconds : 10.0,
2025 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2026 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2028 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2029 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2031 pref_spacer(group, PREF_PAD_GROUP);
2033 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2035 pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
2036 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2037 pref_checkbox_new_int(group, _("Preload next image"),
2038 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2040 pref_checkbox_new_int(group, _("Refresh on file change"),
2041 options->update_on_time_change, &c_options->update_on_time_change);
2043 pref_spacer(group, PREF_PAD_GROUP);
2045 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2046 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2047 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2048 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2050 options->info_keywords.height, &c_options->info_keywords.height);
2051 pref_spin_new_int(hbox, _("Title:"), NULL,
2053 options->info_title.height, &c_options->info_title.height);
2054 pref_spin_new_int(hbox, _("Comment:"), NULL,
2056 options->info_comment.height, &c_options->info_comment.height);
2057 pref_spin_new_int(hbox, _("Rating:"), NULL,
2059 options->info_rating.height, &c_options->info_rating.height);
2061 pref_spacer(group, PREF_PAD_GROUP);
2063 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2065 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2066 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2068 pref_spacer(group, PREF_PAD_GROUP);
2070 net_mon = g_network_monitor_get_default();
2071 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2072 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2073 g_object_unref(geeqie_org);
2075 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2076 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2078 if (!internet_available)
2080 gtk_widget_set_sensitive(group, FALSE);
2083 tz = g_new0(TZData, 1);
2085 path = path_from_utf8(TIMEZONE_DATABASE);
2086 basename = g_path_get_basename(path);
2087 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2091 if (isfile(tz->timezone_database_user))
2093 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2097 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2100 if (!internet_available)
2102 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"));
2106 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"));
2108 gtk_widget_show(button);
2110 pref_spacer(group, PREF_PAD_GROUP);
2112 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2114 help_search_engine_entry = gtk_entry_new();
2115 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2116 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2117 gtk_widget_show(help_search_engine_entry);
2119 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"));
2121 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2122 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2123 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2124 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2125 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2126 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2127 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2128 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2129 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2130 G_CALLBACK(help_search_engine_entry_icon_cb),
2131 help_search_engine_entry);
2135 static void config_tab_image(GtkWidget *notebook)
2140 GtkWidget *ct_button;
2141 GtkWidget *enlargement_button;
2145 vbox = scrolled_notebook_page(notebook, _("Image"));
2147 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2149 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2150 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2153 pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
2154 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2157 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2158 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2160 c_options->image.zoom_increment = options->image.zoom_increment;
2161 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2162 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2163 G_CALLBACK(zoom_increment_cb), NULL);
2164 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2166 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2168 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2169 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2170 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2171 spin = pref_spin_new_int(hbox, NULL, NULL,
2173 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2174 pref_checkbox_link_sensitivity(enlargement_button, spin);
2175 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."));
2177 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2178 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2179 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2180 spin = pref_spin_new_int(hbox, NULL, NULL,
2182 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2183 pref_checkbox_link_sensitivity(ct_button, spin);
2184 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."));
2186 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2188 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2189 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2191 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2192 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2194 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2195 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2197 c_options->image.border_color = options->image.border_color;
2199 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2200 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2202 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2203 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2205 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2206 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2208 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2210 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2211 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2215 static void config_tab_windows(GtkWidget *notebook)
2221 GtkWidget *ct_button;
2224 vbox = scrolled_notebook_page(notebook, _("Windows"));
2226 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2228 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2229 options->save_window_positions, &c_options->save_window_positions);
2231 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2232 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2233 pref_checkbox_link_sensitivity(ct_button, button);
2235 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2236 options->tools_restore_state, &c_options->tools_restore_state);
2238 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2239 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2241 pref_checkbox_new_int(group, _("Show window IDs"),
2242 options->show_window_ids, &c_options->show_window_ids);
2244 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2246 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2247 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2249 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2250 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2251 options->image.limit_window_size, &c_options->image.limit_window_size);
2252 spin = pref_spin_new_int(hbox, NULL, NULL,
2254 options->image.max_window_size, &c_options->image.max_window_size);
2255 pref_checkbox_link_sensitivity(ct_button, spin);
2257 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2259 c_options->fullscreen.screen = options->fullscreen.screen;
2260 c_options->fullscreen.above = options->fullscreen.above;
2261 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2262 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2263 gtk_widget_show(hbox);
2265 pref_checkbox_new_int(group, _("Smooth image flip"),
2266 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2267 pref_checkbox_new_int(group, _("Disable screen saver"),
2268 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2271 #define PRE_FORMATTED_COLUMNS 5
2272 static void config_tab_osd(GtkWidget *notebook)
2276 GtkWidget *vbox_buttons;
2279 GtkWidget *image_overlay_template_view;
2280 GtkWidget *scrolled;
2281 GtkWidget *scrolled_pre_formatted;
2282 GtkTextBuffer *buffer;
2284 GtkWidget * subgroup;
2289 vbox = scrolled_notebook_page(notebook, _("OSD"));
2291 image_overlay_template_view = gtk_text_view_new();
2293 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2295 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2297 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2298 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2299 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2300 gtk_widget_show(scrolled_pre_formatted);
2301 gtk_widget_show(subgroup);
2303 pref_line(group, PREF_PAD_GAP);
2305 pref_label_new(group, _("Image overlay template"));
2307 scrolled = gtk_scrolled_window_new(NULL, NULL);
2308 gtk_widget_set_size_request(scrolled, 200, 150);
2309 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2310 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2311 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2312 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2313 gtk_widget_show(scrolled);
2315 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2316 _("Extensive formatting options are shown in the Help file"));
2318 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2319 gtk_widget_show(image_overlay_template_view);
2321 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2323 #if GTK_CHECK_VERSION(3,4,0)
2324 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2325 G_CALLBACK(image_overlay_set_font_cb), notebook);
2327 button = gtk_font_button_new();
2328 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2329 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2330 g_signal_connect(G_OBJECT(button), "font-set",
2331 G_CALLBACK(image_overlay_set_font_cb),NULL);
2333 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2334 gtk_widget_show(button);
2336 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2337 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2338 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2339 gtk_widget_show(button);
2341 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2342 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2343 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2344 gtk_widget_show(button);
2345 image_overlay_set_text_colours();
2347 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2348 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2349 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2350 gtk_widget_show(button);
2352 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2353 G_CALLBACK(image_overlay_help_cb), NULL);
2354 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2355 gtk_widget_show(button);
2357 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2358 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2359 g_signal_connect(G_OBJECT(buffer), "changed",
2360 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2362 pref_line(group, PREF_PAD_GAP);
2364 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2365 hbox = gtk_hbox_new(FALSE, 0);
2366 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2367 gtk_widget_show(hbox);
2368 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2369 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2370 gtk_widget_show(label);
2371 pref_spacer(group,TRUE);
2373 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2374 hbox = gtk_hbox_new(FALSE, 0);
2375 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2376 gtk_widget_show(hbox);
2377 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2378 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2379 gtk_widget_show(label);
2380 pref_spacer(group,TRUE);
2382 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2383 hbox = gtk_hbox_new(FALSE, 0);
2384 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2385 gtk_widget_show(hbox);
2386 label = gtk_label_new(_("%path:39%"));
2387 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2388 gtk_widget_show(label);
2389 pref_spacer(group,TRUE);
2391 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2392 hbox = gtk_hbox_new(FALSE, 0);
2393 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2394 gtk_widget_show(hbox);
2395 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%"));
2396 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2397 gtk_widget_show(label);
2398 pref_spacer(group,TRUE);
2400 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2401 hbox = gtk_hbox_new(FALSE, 0);
2402 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2403 gtk_widget_show(hbox);
2404 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2405 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2406 gtk_widget_show(label);
2409 static GtkTreeModel *create_class_model(void)
2411 GtkListStore *model;
2415 /* create list store */
2416 model = gtk_list_store_new(1, G_TYPE_STRING);
2417 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2419 gtk_list_store_append(model, &iter);
2420 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2422 return GTK_TREE_MODEL (model);
2427 static void config_tab_files(GtkWidget *notebook)
2434 GtkWidget *ct_button;
2435 GtkWidget *scrolled;
2436 GtkWidget *filter_view;
2437 GtkCellRenderer *renderer;
2438 GtkTreeSelection *selection;
2439 GtkTreeViewColumn *column;
2441 vbox = scrolled_notebook_page(notebook, _("Files"));
2443 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2445 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2446 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2447 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2448 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2449 pref_checkbox_new_int(group, _("Case sensitive sort"),
2450 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2451 pref_checkbox_new_int(group, _("Natural sort order"),
2452 options->file_sort.natural, &c_options->file_sort.natural);
2453 pref_checkbox_new_int(group, _("Disable file extension checks"),
2454 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2456 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2457 options->file_filter.disable, &c_options->file_filter.disable);
2460 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2462 sidecar_ext_entry = gtk_entry_new();
2463 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2464 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2465 gtk_widget_show(sidecar_ext_entry);
2467 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2469 frame = pref_group_parent(group);
2470 g_signal_connect(G_OBJECT(ct_button), "toggled",
2471 G_CALLBACK(filter_disable_cb), frame);
2472 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2474 scrolled = gtk_scrolled_window_new(NULL, NULL);
2475 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2476 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2477 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2478 gtk_widget_show(scrolled);
2480 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2481 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2482 g_object_unref(filter_store);
2483 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2484 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2486 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2488 column = gtk_tree_view_column_new();
2489 gtk_tree_view_column_set_title(column, _("Filter"));
2490 gtk_tree_view_column_set_resizable(column, TRUE);
2492 renderer = gtk_cell_renderer_toggle_new();
2493 g_signal_connect(G_OBJECT(renderer), "toggled",
2494 G_CALLBACK(filter_store_enable_cb), filter_store);
2495 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2496 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2497 GINT_TO_POINTER(FE_ENABLE), NULL);
2499 renderer = gtk_cell_renderer_text_new();
2500 g_signal_connect(G_OBJECT(renderer), "edited",
2501 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2502 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2503 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2504 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2505 GINT_TO_POINTER(FE_EXTENSION), NULL);
2506 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2508 column = gtk_tree_view_column_new();
2509 gtk_tree_view_column_set_title(column, _("Description"));
2510 gtk_tree_view_column_set_resizable(column, TRUE);
2511 gtk_tree_view_column_set_fixed_width(column, 200);
2512 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2514 renderer = gtk_cell_renderer_text_new();
2515 g_signal_connect(G_OBJECT(renderer), "edited",
2516 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2517 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2518 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2519 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2520 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2521 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2523 column = gtk_tree_view_column_new();
2524 gtk_tree_view_column_set_title(column, _("Class"));
2525 gtk_tree_view_column_set_resizable(column, TRUE);
2526 renderer = gtk_cell_renderer_combo_new();
2527 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2528 "model", create_class_model(),
2533 g_signal_connect(G_OBJECT(renderer), "edited",
2534 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2535 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2536 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2537 GINT_TO_POINTER(FE_CLASS), 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, _("Writable"));
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_writable_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_WRITABLE), NULL);
2549 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2551 column = gtk_tree_view_column_new();
2552 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2553 gtk_tree_view_column_set_resizable(column, FALSE);
2554 renderer = gtk_cell_renderer_toggle_new();
2555 g_signal_connect(G_OBJECT(renderer), "toggled",
2556 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2557 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2558 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2559 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2560 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2563 filter_store_populate();
2564 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2565 gtk_widget_show(filter_view);
2567 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2569 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2570 G_CALLBACK(filter_default_cb), filter_view);
2571 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2572 gtk_widget_show(button);
2574 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2575 G_CALLBACK(filter_remove_cb), filter_view);
2576 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2577 gtk_widget_show(button);
2579 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2580 G_CALLBACK(filter_add_cb), filter_view);
2581 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2582 gtk_widget_show(button);
2586 static void config_tab_metadata(GtkWidget *notebook)
2591 GtkWidget *ct_button;
2595 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2598 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2600 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2602 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2603 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2605 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2606 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2608 gtk_widget_set_sensitive(ct_button, FALSE);
2611 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2612 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2614 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2615 label = pref_label_new(group, text);
2616 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2617 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2620 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2622 gtk_widget_set_sensitive(group, FALSE);
2625 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2626 pref_checkbox_link_sensitivity(ct_button, hbox);
2628 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2629 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2631 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2632 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2634 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2635 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2637 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2638 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2640 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2642 gtk_widget_set_sensitive(group, FALSE);
2645 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2646 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2649 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2650 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2651 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2653 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2654 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2656 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2657 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2659 gtk_widget_set_sensitive(ct_button, FALSE);
2662 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2664 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2665 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2667 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2668 pref_checkbox_link_sensitivity(ct_button, hbox);
2670 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2671 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2673 pref_checkbox_new_int(group, _("Write metadata on image change"),
2674 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2676 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2677 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2679 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2681 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2682 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2683 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");
2688 typedef struct _KeywordFindData KeywordFindData;
2689 struct _KeywordFindData
2696 GtkWidget *button_close;
2697 GtkWidget *button_stop;
2698 GtkWidget *button_start;
2699 GtkWidget *progress;
2707 guint idle_id; /* event source id */
2710 #define KEYWORD_DIALOG_WIDTH 400
2712 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2714 GList *list_d = NULL;
2715 GList *list_f = NULL;
2719 filelist_read(dir_fd, &list_f, &list_d);
2723 filelist_read(dir_fd, &list_f, NULL);
2726 list_f = filelist_filter(list_f, FALSE);
2727 list_d = filelist_filter(list_d, TRUE);
2729 kfd->list = g_list_concat(list_f, kfd->list);
2730 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2733 static void keywords_find_reset(KeywordFindData *kfd)
2735 filelist_free(kfd->list);
2738 filelist_free(kfd->list_dir);
2739 kfd->list_dir = NULL;
2742 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2744 KeywordFindData *kfd = data;
2746 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2748 keywords_find_reset(kfd);
2749 generic_dialog_close(kfd->gd);
2753 static void keywords_find_finish(KeywordFindData *kfd)
2755 keywords_find_reset(kfd);
2757 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2758 spinner_set_interval(kfd->spinner, -1);
2760 gtk_widget_set_sensitive(kfd->group, TRUE);
2761 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2762 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2763 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2766 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2768 KeywordFindData *kfd = data;
2770 g_idle_remove_by_data(kfd);
2772 keywords_find_finish(kfd);
2775 static gboolean keywords_find_file(gpointer data)
2777 KeywordFindData *kfd = data;
2779 GtkTextBuffer *buffer;
2787 fd = kfd->list->data;
2788 kfd->list = g_list_remove(kfd->list, fd);
2790 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2791 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2795 gtk_text_buffer_get_end_iter(buffer, &iter);
2796 tmp = g_strconcat(keywords->data, "\n", NULL);
2797 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2799 keywords = keywords->next;
2802 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2803 file_data_unref(fd);
2804 string_list_free(keywords);
2808 else if (kfd->list_dir)
2812 fd = kfd->list_dir->data;
2813 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2815 keywords_find_folder(kfd, fd);
2817 file_data_unref(fd);
2822 keywords_find_finish(kfd);
2827 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2829 KeywordFindData *kfd = data;
2832 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2834 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2835 parse_out_relatives(path);
2839 warning_dialog(_("Invalid folder"),
2840 _("The specified folder can not be found."),
2841 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2847 gtk_widget_set_sensitive(kfd->group, FALSE);
2848 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2849 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2850 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2851 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2853 dir_fd = file_data_new_dir(path);
2854 keywords_find_folder(kfd, dir_fd);
2855 file_data_unref(dir_fd);
2856 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2862 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2864 KeywordFindData *kfd;
2868 kfd = g_new0(KeywordFindData, 1);
2870 kfd->gd = generic_dialog_new(_("Search for keywords"),
2871 "search_for_keywords",
2874 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2875 kfd->gd->cancel_cb = keywords_find_close_cb;
2876 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2877 keywords_find_close_cb, FALSE);
2878 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2879 keywords_find_start_cb, FALSE);
2880 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2881 keywords_find_stop_cb, FALSE);
2882 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2884 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2886 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2887 pref_spacer(hbox, PREF_PAD_INDENT);
2888 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2890 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2891 pref_label_new(hbox, _("Folder:"));
2893 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2894 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2895 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2896 gtk_widget_show(label);
2898 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2900 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2901 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2903 kfd->progress = gtk_entry_new();
2904 gtk_widget_set_can_focus(kfd->progress, FALSE);
2905 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2906 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2907 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2908 gtk_widget_show(kfd->progress);
2910 kfd->spinner = spinner_new(NULL, -1);
2911 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2912 gtk_widget_show(kfd->spinner);
2916 gtk_widget_show(kfd->gd->dialog);
2919 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2921 const gchar *path = layout_get_path(NULL);
2923 if (!path || !*path) path = homedir();
2924 keywords_find_dialog(widget, path);
2927 static void config_tab_keywords_save()
2929 GtkTextIter start, end;
2930 GtkTextBuffer *buffer;
2931 GList *kw_list = NULL;
2937 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2938 gtk_text_buffer_get_bounds(buffer, &start, &end);
2940 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
2942 kw_split = strtok(buffer_text, "\n");
2943 while (kw_split != NULL)
2949 if (g_strcmp0(work->data, kw_split) == 0)
2958 kw_list = g_list_append(kw_list, g_strdup(kw_split));
2960 kw_split = strtok(NULL, "\n");
2963 keyword_list_set(kw_list);
2965 string_list_free(kw_list);
2966 g_free(buffer_text);
2969 static void config_tab_keywords(GtkWidget *notebook)
2975 GtkWidget *scrolled;
2977 GtkTextBuffer *buffer;
2980 vbox = scrolled_notebook_page(notebook, _("Keywords"));
2982 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
2984 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2986 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
2987 G_CALLBACK(keywords_find_cb), keyword_text);
2988 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
2991 keyword_text = gtk_text_view_new();
2992 gtk_widget_set_size_request(keyword_text, 20, 20);
2993 scrolled = gtk_scrolled_window_new(NULL, NULL);
2994 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2995 gtk_widget_show(scrolled);
2997 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
2998 gtk_widget_show(keyword_text);
3000 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3002 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3003 gtk_text_buffer_create_tag(buffer, "monospace",
3004 "family", "monospace", NULL);
3006 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3007 gtk_text_buffer_get_start_iter(buffer, &iter);
3008 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3011 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3013 GList *kwl = keyword_list_get();
3014 kwl = g_list_first(kwl);
3017 gtk_text_buffer_get_end_iter (buffer, &iter);
3018 tmp = g_strconcat(kwl->data, "\n", NULL);
3019 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3024 gtk_text_buffer_set_modified(buffer, FALSE);
3031 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3033 gint *option = data;
3035 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3039 *option = INTENT_PERCEPTUAL;
3042 *option = INTENT_RELATIVE_COLORIMETRIC;
3045 *option = INTENT_SATURATION;
3048 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3053 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3054 gint option, gint *option_c)
3061 pref_table_label(table, column, row, text, 0.0);
3063 combo = gtk_combo_box_text_new();
3065 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3066 if (option == INTENT_PERCEPTUAL) current = 0;
3067 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3068 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3069 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3070 if (option == INTENT_SATURATION) current = 2;
3071 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3072 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3074 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3076 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3078 g_signal_connect(G_OBJECT(combo), "changed",
3079 G_CALLBACK(intent_menu_cb), option_c);
3081 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
3082 GTK_EXPAND | GTK_FILL, 0, 0, 0);
3083 gtk_widget_show(combo);
3087 static void config_tab_color(GtkWidget *notebook)
3096 vbox = scrolled_notebook_page(notebook, _("Color management"));
3098 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3100 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3103 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3104 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3106 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3107 pref_label_bold(label, TRUE, FALSE);
3109 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3110 pref_label_bold(label, TRUE, FALSE);
3112 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3113 pref_label_bold(label, TRUE, FALSE);
3115 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3120 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3121 pref_table_label(table, 0, i + 1, buf, 1.0);
3124 entry = gtk_entry_new();
3125 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3126 if (options->color_profile.input_name[i])
3128 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3130 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3131 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3132 gtk_widget_show(entry);
3133 color_profile_input_name_entry[i] = entry;
3135 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3136 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3137 gtk_widget_set_size_request(entry, 160, -1);
3138 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3139 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3140 gtk_widget_show(tabcomp);
3141 color_profile_input_file_entry[i] = entry;
3144 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3146 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3148 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3149 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3151 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3153 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3154 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3155 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3156 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3157 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3159 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3161 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3163 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3165 gtk_widget_show(tabcomp);
3168 /* advanced entry tab */
3169 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3171 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3173 c_options->file_ops.use_system_trash = FALSE;
3174 c_options->file_ops.no_trash = FALSE;
3178 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3180 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3182 c_options->file_ops.use_system_trash = TRUE;
3183 c_options->file_ops.no_trash = FALSE;
3187 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3189 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3191 c_options->file_ops.no_trash = TRUE;
3195 static void config_tab_behavior(GtkWidget *notebook)
3202 GtkWidget *ct_button;
3206 GtkWidget *with_rename;
3207 GtkWidget *collections_on_top;
3209 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3211 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3213 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3214 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3215 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3216 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3217 pref_checkbox_new_int(group, _("Enable Delete key"),
3218 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3220 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3221 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3223 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3224 pref_checkbox_link_sensitivity(ct_button, hbox);
3226 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3227 pref_label_new(hbox, _("Folder:"));
3229 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3230 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3231 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3232 gtk_widget_show(tabcomp);
3234 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3235 pref_checkbox_link_sensitivity(ct_button, hbox);
3237 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3238 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3239 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3240 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3241 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3242 G_CALLBACK(safe_delete_view_cb), NULL);
3243 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3244 gtk_widget_show(button);
3246 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3247 G_CALLBACK(safe_delete_clear_cb), NULL);
3248 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3249 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3250 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3252 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3253 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3255 gtk_widget_show(button);
3257 pref_spacer(group, PREF_PAD_GROUP);
3260 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3262 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3263 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3265 pref_checkbox_new_int(group, _("In place renaming"),
3266 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3268 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3269 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3271 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3272 options->marks_save, &c_options->marks_save);
3273 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3275 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3276 options->with_rename, &c_options->with_rename);
3277 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3279 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3280 options->collections_on_top, &c_options->collections_on_top);
3281 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3283 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3284 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3286 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3287 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3289 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3290 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3292 pref_spacer(group, PREF_PAD_GROUP);
3294 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3296 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3297 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3298 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3299 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3300 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3301 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3302 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3303 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3304 pref_checkbox_new_int(group, _("Play video by left click on image"),
3305 options->image_l_click_video, &c_options->image_l_click_video);
3306 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3307 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3309 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3310 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3311 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3312 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3313 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3316 pref_spacer(group, PREF_PAD_GROUP);
3318 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3320 pref_spin_new_int(group, _("Debug level:"), NULL,
3321 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3323 pref_checkbox_new_int(group, _("Timer data"),
3324 options->log_window.timer_data, &c_options->log_window.timer_data);
3326 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3327 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3331 /* accelerators tab */
3332 static void config_tab_accelerators(GtkWidget *notebook)
3338 GtkWidget *scrolled;
3339 GtkWidget *accel_view;
3340 GtkCellRenderer *renderer;
3341 GtkTreeSelection *selection;
3342 GtkTreeViewColumn *column;
3344 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3346 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3348 scrolled = gtk_scrolled_window_new(NULL, NULL);
3349 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3350 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3351 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3352 gtk_widget_show(scrolled);
3354 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3356 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3357 g_object_unref(accel_store);
3358 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3359 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3361 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3363 renderer = gtk_cell_renderer_text_new();
3365 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3370 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3371 gtk_tree_view_column_set_resizable(column, TRUE);
3372 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3375 renderer = gtk_cell_renderer_accel_new();
3376 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3377 G_CALLBACK(accel_store_cleared_cb), accel_store);
3378 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3379 G_CALLBACK(accel_store_edited_cb), accel_store);
3382 g_object_set (renderer,
3384 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3387 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3392 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
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(_("Tooltip"),
3403 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3404 gtk_tree_view_column_set_resizable(column, TRUE);
3405 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3407 renderer = gtk_cell_renderer_text_new();
3409 column = gtk_tree_view_column_new_with_attributes("Accel",
3414 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3415 gtk_tree_view_column_set_resizable(column, TRUE);
3416 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3418 accel_store_populate();
3419 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3420 gtk_widget_show(accel_view);
3422 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3424 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3425 G_CALLBACK(accel_default_cb), accel_view);
3426 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3427 gtk_widget_show(button);
3429 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3430 G_CALLBACK(accel_reset_cb), accel_view);
3431 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3432 gtk_widget_show(button);
3435 /* toolbar main tab */
3436 static void config_tab_toolbar_main(GtkWidget *notebook)
3439 GtkWidget *toolbardata;
3442 lw = layout_window_list->data;
3444 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3446 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3447 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3448 gtk_widget_show(vbox);
3451 /* toolbar status tab */
3452 static void config_tab_toolbar_status(GtkWidget *notebook)
3455 GtkWidget *toolbardata;
3458 lw = layout_window_list->data;
3460 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3462 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3463 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3464 gtk_widget_show(vbox);
3468 static void config_tab_stereo(GtkWidget *notebook)
3476 GtkWidget *fs_button;
3477 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3479 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3481 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3482 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3484 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3485 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3486 pref_checkbox_new_int(box, _("Mirror left image"),
3487 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3488 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3489 pref_checkbox_new_int(box, _("Flip left image"),
3490 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3491 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3492 pref_checkbox_new_int(box, _("Mirror right image"),
3493 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3494 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3495 pref_checkbox_new_int(box, _("Flip right image"),
3496 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3497 pref_checkbox_new_int(group, _("Swap left and right images"),
3498 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3499 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3500 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3502 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3503 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3504 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3505 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3506 pref_checkbox_link_sensitivity(fs_button, box2);
3507 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3508 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3509 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3510 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3511 pref_checkbox_new_int(box, _("Mirror left image"),
3512 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3513 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3514 pref_checkbox_new_int(box, _("Flip left image"),
3515 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3516 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3517 pref_checkbox_new_int(box, _("Mirror right image"),
3518 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3519 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3520 pref_checkbox_new_int(box, _("Flip right image"),
3521 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3522 pref_checkbox_new_int(box2, _("Swap left and right images"),
3523 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3524 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3525 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3527 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3528 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3529 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3530 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3531 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3532 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3533 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3534 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3535 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3536 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3537 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3538 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3539 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3540 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3544 /* Main preferences window */
3545 static void config_window_create(void)
3547 GtkWidget *win_vbox;
3549 GtkWidget *notebook;
3551 GtkWidget *ct_button;
3553 if (!c_options) c_options = init_options(NULL);
3555 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3556 DEBUG_NAME(configwindow);
3557 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3558 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3559 G_CALLBACK(config_window_delete), NULL);
3560 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3561 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3562 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3564 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3565 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3566 gtk_widget_show(win_vbox);
3568 notebook = gtk_notebook_new();
3569 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3570 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3571 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3573 config_tab_general(notebook);
3574 config_tab_image(notebook);
3575 config_tab_osd(notebook);
3576 config_tab_windows(notebook);
3577 config_tab_accelerators(notebook);
3578 config_tab_files(notebook);
3579 config_tab_metadata(notebook);
3580 config_tab_keywords(notebook);
3581 config_tab_color(notebook);
3582 config_tab_stereo(notebook);
3583 config_tab_behavior(notebook);
3584 config_tab_toolbar_main(notebook);
3585 config_tab_toolbar_status(notebook);
3587 hbox = gtk_hbutton_box_new();
3588 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3589 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3590 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3591 gtk_widget_show(hbox);
3593 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3594 G_CALLBACK(config_window_help_cb), notebook);
3595 gtk_container_add(GTK_CONTAINER(hbox), button);
3596 gtk_widget_set_can_default(button, TRUE);
3597 gtk_widget_show(button);
3599 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3600 G_CALLBACK(config_window_ok_cb), NULL);
3601 gtk_container_add(GTK_CONTAINER(hbox), button);
3602 gtk_widget_set_can_default(button, TRUE);
3603 gtk_widget_grab_default(button);
3604 gtk_widget_show(button);
3608 button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
3609 G_CALLBACK(config_window_save_cb), NULL);
3610 gtk_container_add(GTK_CONTAINER(hbox), button);
3611 gtk_widget_set_can_default(button, TRUE);
3612 gtk_widget_show(button);
3614 button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
3615 G_CALLBACK(config_window_apply_cb), NULL);
3616 gtk_container_add(GTK_CONTAINER(hbox), button);
3617 gtk_widget_set_can_default(button, TRUE);
3618 gtk_widget_show(button);
3620 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3621 G_CALLBACK(config_window_close_cb), NULL);
3622 gtk_container_add(GTK_CONTAINER(hbox), button);
3623 gtk_widget_set_can_default(button, TRUE);
3624 gtk_widget_show(button);
3626 if (!generic_dialog_get_alternative_button_order(configwindow))
3628 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3631 gtk_widget_show(notebook);
3633 gtk_widget_show(configwindow);
3637 *-----------------------------------------------------------------------------
3638 * config window show (public)
3639 *-----------------------------------------------------------------------------
3642 void show_config_window(void)
3646 gtk_window_present(GTK_WINDOW(configwindow));
3650 config_window_create();
3659 void show_about_window(LayoutWindow *lw)
3661 GdkPixbuf *pixbuf_logo;
3662 GdkPixbuf *pixbuf_icon;
3663 gchar *authors[1000];
3671 #define LINE_LENGTH 1000
3672 gchar line[LINE_LENGTH];
3674 copyright = g_string_new(NULL);
3675 copyright = g_string_append(copyright, "This program comes with absolutely no warranty.\nGNU General Public License, version 2 or later.\nSee https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n\n");
3677 zd_path = g_build_filename(GQ_BIN_DIR, TIMEZONE_DATABASE, NULL);
3678 cd = ZDOpenDatabase(zd_path);
3681 copyright = g_string_append(copyright, ZDGetNotice(cd));
3683 ZDCloseDatabase(cd);
3687 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3688 fp = fopen(path, "r");
3691 while(fgets(line, LINE_LENGTH, fp))
3693 /* get rid of ending \n from fgets */
3694 line[strlen(line) - 1] = '\0';
3695 authors[i_authors] = g_strdup(line);
3698 authors[i_authors] = NULL;
3703 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3704 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3706 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3707 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3708 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3709 "title", _("About Geeqie"),
3711 "program-name", GQ_APPNAME,
3713 "logo", pixbuf_logo,
3714 "icon", pixbuf_icon,
3715 "website", GQ_WEBSITE,
3716 "website-label", "Website",
3717 "comments", comment,
3719 "translator-credits", _("translator-credits"),
3720 "wrap-license", TRUE,
3721 "license", copyright->str,
3724 g_string_free(copyright, TRUE);
3727 while(n < i_authors)
3737 static void image_overlay_set_text_colours()
3739 c_options->image_overlay.text_red = options->image_overlay.text_red;
3740 c_options->image_overlay.text_green = options->image_overlay.text_green;
3741 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3742 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3743 c_options->image_overlay.background_red = options->image_overlay.background_red;
3744 c_options->image_overlay.background_green = options->image_overlay.background_green;
3745 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3746 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3750 *-----------------------------------------------------------------------------
3751 * timezone database routines
3752 *-----------------------------------------------------------------------------
3755 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3757 GError *error = NULL;
3759 gchar *tmp_filename;
3761 if (!g_cancellable_is_cancelled(tz->cancellable))
3763 generic_dialog_close(tz->gd);
3767 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3769 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3770 move_file(tmp_filename, tz->timezone_database_user);
3771 g_free(tmp_filename);
3775 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3778 g_file_delete(tz->tmp_g_file, NULL, &error);
3779 g_object_unref(tz->tmp_g_file);
3780 tz->tmp_g_file = NULL;
3781 g_object_unref(tz->cancellable);
3782 g_object_unref(tz->timezone_database_gq);
3785 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3789 if (!g_cancellable_is_cancelled(tz->cancellable))
3791 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3795 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3798 GError *error = NULL;
3800 g_cancellable_cancel(tz->cancellable);
3803 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3806 GError *error = NULL;
3807 GFileIOStream *io_stream;
3814 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3818 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3819 log_printf("Error: Download timezone database failed:\n%s", error->message);
3820 g_error_free(error);
3821 g_object_unref(tz->tmp_g_file);
3825 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3827 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3829 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3831 tz->progress = gtk_progress_bar_new();
3832 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3833 gtk_widget_show(tz->progress);
3835 gtk_widget_show(tz->gd->dialog);
3836 tz->cancellable = g_cancellable_new();
3837 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);
3839 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3842 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */