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);
472 *-----------------------------------------------------------------------------
473 * config window main button callbacks (private)
474 *-----------------------------------------------------------------------------
477 static void config_window_close_cb(GtkWidget *widget, gpointer data)
479 gtk_widget_destroy(configwindow);
484 static void config_window_help_cb(GtkWidget *widget, gpointer data)
486 GtkWidget *notebook = data;
489 static gchar *html_section[] =
491 "GuideOptionsGeneral.html",
492 "GuideOptionsImage.html",
493 "GuideOptionsOSD.html",
494 "GuideOptionsWindow.html",
495 "GuideOptionsKeyboard.html",
496 "GuideOptionsFiltering.html",
497 "GuideOptionsMetadata.html",
498 "GuideOptionsKeywords.html",
499 "GuideOptionsColor.html",
500 "GuideOptionsStereo.html",
501 "GuideOptionsBehavior.html",
502 "GuideOptionsToolbar.html"
505 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
506 help_window_show(html_section[i]);
509 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
511 config_window_close_cb(NULL, NULL);
515 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
517 config_window_apply();
518 config_window_close_cb(NULL, NULL);
521 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
524 lw = layout_window_list->data;
526 config_window_apply();
527 layout_util_sync(lw);
530 static void config_window_save_cb(GtkWidget *widget, gpointer data)
532 config_window_apply();
533 save_options(options);
537 *-----------------------------------------------------------------------------
538 * config window setup (private)
539 *-----------------------------------------------------------------------------
542 static void quality_menu_cb(GtkWidget *combo, gpointer data)
546 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
550 *option = GDK_INTERP_NEAREST;
553 *option = GDK_INTERP_TILES;
556 *option = GDK_INTERP_BILINEAR;
559 *option = GDK_INTERP_HYPER;
564 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
568 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
580 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
581 guint option, guint *option_c)
588 pref_table_label(table, column, row, text, 0.0);
590 combo = gtk_combo_box_text_new();
592 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
593 if (option == GDK_INTERP_NEAREST) current = 0;
594 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
595 if (option == GDK_INTERP_TILES) current = 1;
596 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
597 if (option == GDK_INTERP_BILINEAR) current = 2;
598 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
599 if (option == GDK_INTERP_HYPER) current = 3;
601 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
603 g_signal_connect(G_OBJECT(combo), "changed",
604 G_CALLBACK(quality_menu_cb), option_c);
606 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
607 GTK_EXPAND | GTK_FILL, 0, 0, 0);
608 gtk_widget_show(combo);
611 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
612 gint option, gint *option_c)
619 pref_table_label(table, column, row, text, 0.0);
621 combo = gtk_combo_box_text_new();
623 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
624 if (option == PRIMARY) current = 0;
625 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
626 if (option == CLIPBOARD) current = 1;
628 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
630 g_signal_connect(G_OBJECT(combo), "changed",
631 G_CALLBACK(clipboard_selection_menu_cb), option_c);
633 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
634 GTK_EXPAND | GTK_FILL, 0, 0, 0);
635 gtk_widget_show(combo);
638 typedef struct _UseableMouseItems UseableMouseItems;
639 struct _UseableMouseItems
641 gchar *name; /* GtkActionEntry terminology */
646 static const UseableMouseItems useable_mouse_items[] = {
648 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
649 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
650 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
651 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
652 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
653 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
654 {"Home", N_("Home"), GTK_STOCK_HOME},
655 {"Up", N_("Up"), GTK_STOCK_GO_UP},
656 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
657 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
658 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
659 {"Search", N_("Search"), GTK_STOCK_FIND},
660 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
661 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
662 {"Copy", N_("Copy"), GTK_STOCK_COPY},
663 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
664 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
665 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
666 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
667 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
668 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
669 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
670 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
671 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
672 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
673 {"Print", N_("Print"), GTK_STOCK_PRINT},
674 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
675 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
676 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
677 {"RotateCW", N_("Rotate clockwise"), PIXBUF_INLINE_ICON_CW},
678 {"RotateCCW", N_("Rotate counterclockwise"), PIXBUF_INLINE_ICON_CCW},
679 {"Rotate180", N_("Rotate 180"), PIXBUF_INLINE_ICON_180},
680 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
681 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
682 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
683 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
684 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
685 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
686 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
687 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
688 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
689 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
690 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
691 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
692 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
693 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
694 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
695 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
696 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
697 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
698 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
699 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
700 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
701 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
702 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
703 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
704 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
705 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
706 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
707 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
708 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
709 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
710 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
711 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
712 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
716 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
718 gchar **option = data;
721 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
723 const UseableMouseItems *list = useable_mouse_items;
727 if (g_strcmp0(list->label, label) == 0)
735 *option = g_strdup(list->name);
739 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
740 gchar *option, gchar **option_c)
748 pref_table_label(table, column, row, text, 0.0);
750 combo = gtk_combo_box_text_new();
752 const UseableMouseItems *list = useable_mouse_items;
756 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
757 if (g_strcmp0(list->name, option) == 0)
765 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
767 g_signal_connect(G_OBJECT(combo), "changed",
768 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
770 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
771 GTK_EXPAND | GTK_FILL, 0, 0, 0);
772 gtk_widget_show(combo);
775 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
779 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
782 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
784 c_options->thumbnails.max_width = thumb_size_list[n].w;
785 c_options->thumbnails.max_height = thumb_size_list[n].h;
789 c_options->thumbnails.max_width = options->thumbnails.max_width;
790 c_options->thumbnails.max_height = options->thumbnails.max_height;
794 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
800 c_options->thumbnails.max_width = options->thumbnails.max_width;
801 c_options->thumbnails.max_height = options->thumbnails.max_height;
803 pref_table_label(table, column, row, text, 0.0);
805 combo = gtk_combo_box_text_new();
808 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
813 w = thumb_size_list[i].w;
814 h = thumb_size_list[i].h;
816 buf = g_strdup_printf("%d x %d", w, h);
817 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
820 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
827 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
828 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
834 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
835 g_signal_connect(G_OBJECT(combo), "changed",
836 G_CALLBACK(thumb_size_menu_cb), NULL);
838 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
839 GTK_EXPAND | GTK_FILL, 0, 0, 0);
840 gtk_widget_show(combo);
843 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
847 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
851 *option = PR_STEREO_NONE;
854 *option = PR_STEREO_ANAGLYPH_RC;
857 *option = PR_STEREO_ANAGLYPH_GM;
860 *option = PR_STEREO_ANAGLYPH_YB;
863 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
866 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
869 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
872 *option = PR_STEREO_ANAGLYPH_DB_RC;
875 *option = PR_STEREO_ANAGLYPH_DB_GM;
878 *option = PR_STEREO_ANAGLYPH_DB_YB;
881 *option = PR_STEREO_HORIZ;
884 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
887 *option = PR_STEREO_VERT;
890 *option = PR_STEREO_VERT | PR_STEREO_HALF;
893 *option = PR_STEREO_FIXED;
898 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
899 gint option, gint *option_c, gboolean add_fixed)
906 pref_table_label(table, column, row, text, 0.0);
908 combo = gtk_combo_box_text_new();
910 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
912 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
913 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
914 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
915 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
916 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
917 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
918 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
919 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
920 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
921 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
922 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
923 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
924 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
925 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
926 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
927 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
928 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
929 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
931 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
932 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
933 if (option & PR_STEREO_HORIZ)
936 if (option & PR_STEREO_HALF) current = 11;
939 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
940 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
941 if (option & PR_STEREO_VERT)
944 if (option & PR_STEREO_HALF) current = 13;
949 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
950 if (option & PR_STEREO_FIXED) current = 14;
953 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
955 g_signal_connect(G_OBJECT(combo), "changed",
956 G_CALLBACK(stereo_mode_menu_cb), option_c);
958 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
959 GTK_EXPAND | GTK_FILL, 0, 0, 0);
960 gtk_widget_show(combo);
963 static void video_menu_cb(GtkWidget *combo, gpointer data)
965 gchar **option = data;
967 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
971 static void video_menu_populate(gpointer data, gpointer user_data)
973 GtkWidget *combo = user_data;
974 EditorDescription *ed = data;
976 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
979 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
980 gchar *option, gchar **option_c)
984 /* use lists since they are sorted */
985 GList *eds = editor_list_get();
989 pref_table_label(table, column, row, text, 0.0);
991 combo = gtk_combo_box_text_new();
992 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
993 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
995 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
997 g_signal_connect(G_OBJECT(combo), "changed",
998 G_CALLBACK(video_menu_cb), option_c);
1000 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
1001 GTK_EXPAND | GTK_FILL, 0, 0, 0);
1002 gtk_widget_show(combo);
1005 static void filter_store_populate(void)
1009 if (!filter_store) return;
1011 gtk_list_store_clear(filter_store);
1013 work = filter_get_list();
1022 gtk_list_store_append(filter_store, &iter);
1023 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1027 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1028 gchar *new_text, gpointer data)
1030 GtkWidget *model = data;
1031 FilterEntry *fe = data;
1035 if (!new_text || strlen(new_text) < 1) return;
1037 tpath = gtk_tree_path_new_from_string(path_str);
1038 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1039 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1041 g_free(fe->extensions);
1042 fe->extensions = g_strdup(new_text);
1044 gtk_tree_path_free(tpath);
1048 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1049 gchar *new_text, gpointer data)
1051 GtkWidget *model = data;
1052 FilterEntry *fe = data;
1057 if (!new_text || !new_text[0]) return;
1059 tpath = gtk_tree_path_new_from_string(path_str);
1060 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1061 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1063 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1065 if (strcmp(new_text, _(format_class_list[i])) == 0)
1072 gtk_tree_path_free(tpath);
1076 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1077 gchar *new_text, gpointer data)
1079 GtkWidget *model = data;
1084 if (!new_text || !new_text[0]) return;
1086 tpath = gtk_tree_path_new_from_string(path_str);
1087 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1088 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1090 g_free(fe->description);
1091 fe->description = g_strdup(new_text);
1093 gtk_tree_path_free(tpath);
1096 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1097 gchar *path_str, gpointer data)
1099 GtkWidget *model = data;
1104 tpath = gtk_tree_path_new_from_string(path_str);
1105 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1106 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1108 fe->enabled = !fe->enabled;
1110 gtk_tree_path_free(tpath);
1114 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1115 gchar *path_str, gpointer data)
1117 GtkWidget *model = data;
1122 tpath = gtk_tree_path_new_from_string(path_str);
1123 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1124 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1126 fe->writable = !fe->writable;
1127 if (fe->writable) fe->allow_sidecar = FALSE;
1129 gtk_tree_path_free(tpath);
1133 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1134 gchar *path_str, gpointer data)
1136 GtkWidget *model = data;
1141 tpath = gtk_tree_path_new_from_string(path_str);
1142 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1143 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1145 fe->allow_sidecar = !fe->allow_sidecar;
1146 if (fe->allow_sidecar) fe->writable = FALSE;
1148 gtk_tree_path_free(tpath);
1152 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1153 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1157 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1159 switch (GPOINTER_TO_INT(data))
1162 g_object_set(GTK_CELL_RENDERER(cell),
1163 "active", fe->enabled, NULL);
1166 g_object_set(GTK_CELL_RENDERER(cell),
1167 "text", fe->extensions, NULL);
1169 case FE_DESCRIPTION:
1170 g_object_set(GTK_CELL_RENDERER(cell),
1171 "text", fe->description, NULL);
1174 g_object_set(GTK_CELL_RENDERER(cell),
1175 "text", _(format_class_list[fe->file_class]), NULL);
1178 g_object_set(GTK_CELL_RENDERER(cell),
1179 "active", fe->writable, NULL);
1181 case FE_ALLOW_SIDECAR:
1182 g_object_set(GTK_CELL_RENDERER(cell),
1183 "active", fe->allow_sidecar, NULL);
1188 static gboolean filter_add_scroll(gpointer data)
1192 GtkCellRenderer *cell;
1193 GtkTreeViewColumn *column;
1198 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1199 path = gtk_tree_path_new_from_indices(rows-1, -1);
1201 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1203 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1204 cell = g_list_last(list_cells)->data;
1206 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1207 path, column, FALSE, 0.0, 0.0 );
1208 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1209 path, column, cell, TRUE);
1211 gtk_tree_path_free(path);
1212 g_list_free(list_cells);
1217 static void filter_add_cb(GtkWidget *widget, gpointer data)
1219 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1220 filter_store_populate();
1222 g_idle_add((GSourceFunc)filter_add_scroll, data);
1225 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1227 GtkWidget *filter_view = data;
1228 GtkTreeSelection *selection;
1232 if (!filter_store) return;
1233 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1234 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1235 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1238 filter_remove_entry(fe);
1240 filter_store_populate();
1243 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1247 GtkTreeViewColumn *column;
1249 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1250 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1251 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1253 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1257 gtk_tree_path_free(path);
1262 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1265 filter_add_defaults();
1267 filter_store_populate();
1269 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1272 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1274 /* no op, only so cancel button appears */
1277 static void filter_default_cb(GtkWidget *widget, gpointer data)
1281 gd = generic_dialog_new(_("Reset filters"),
1282 "reset_filter", widget, TRUE,
1283 dummy_cancel_cb, data);
1284 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1285 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1286 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1287 gtk_widget_show(gd->dialog);
1290 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1292 GtkWidget *frame = data;
1294 gtk_widget_set_sensitive(frame,
1295 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1298 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1300 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1303 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1305 file_util_trash_clear();
1308 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1312 gd = generic_dialog_new(_("Clear trash"),
1313 "clear_trash", widget, TRUE,
1314 dummy_cancel_cb, NULL);
1315 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1316 _("This will remove the trash contents."), FALSE);
1317 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1318 entry = gtk_entry_new();
1319 gtk_widget_set_can_focus(entry, FALSE);
1320 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1321 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1322 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1323 gtk_widget_show(entry);
1324 gtk_widget_show(gd->dialog);
1327 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1329 GtkWidget *pTextView;
1330 GtkTextBuffer *pTextBuffer;
1334 pTextView = GTK_WIDGET(data);
1336 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1337 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1338 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1340 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1341 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1344 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1346 GtkTextView *text_view = data;
1347 GtkTextBuffer *buffer;
1349 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1350 if (!configwindow) return;
1352 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1353 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1356 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1360 gd = generic_dialog_new(_("Reset image overlay template string"),
1361 "reset_image_overlay_template_string", widget, TRUE,
1362 dummy_cancel_cb, data);
1363 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1364 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1365 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1366 gtk_widget_show(gd->dialog);
1369 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1371 help_window_show("GuideOptionsOSD.html");
1374 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1376 #if GTK_CHECK_VERSION(3,4,0)
1379 PangoFontDescription *font_desc;
1381 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1382 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1384 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1386 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1387 font = pango_font_description_to_string(font_desc);
1388 g_free(c_options->image_overlay.font);
1389 c_options->image_overlay.font = g_strdup(font);
1393 gtk_widget_destroy(dialog);
1397 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1398 c_options->image_overlay.font = g_strdup(font);
1402 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1405 #if GTK_CHECK_VERSION(3,4,0)
1408 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1409 colour.red = options->image_overlay.text_red;
1410 colour.green = options->image_overlay.text_green;
1411 colour.blue = options->image_overlay.text_blue;
1412 colour.alpha = options->image_overlay.text_alpha;
1413 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1414 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1416 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1418 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1419 c_options->image_overlay.text_red = colour.red*255;
1420 c_options->image_overlay.text_green = colour.green*255;
1421 c_options->image_overlay.text_blue = colour.blue*255;
1422 c_options->image_overlay.text_alpha = colour.alpha*255;
1424 gtk_widget_destroy(dialog);
1427 GtkColorSelection *colorsel;
1429 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1430 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1431 colour.red = options->image_overlay.text_red*257;
1432 colour.green = options->image_overlay.text_green*257;
1433 colour.blue = options->image_overlay.text_blue*257;
1434 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1435 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1436 gtk_color_selection_set_current_color(colorsel, &colour);
1437 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1439 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1441 gtk_color_selection_get_current_color(colorsel, &colour);
1442 c_options->image_overlay.text_red = colour.red/257;
1443 c_options->image_overlay.text_green = colour.green/257;
1444 c_options->image_overlay.text_blue = colour.blue/257;
1445 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1447 gtk_widget_destroy (dialog);
1452 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1455 #if GTK_CHECK_VERSION(3,4,0)
1458 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1459 colour.red = options->image_overlay.background_red;
1460 colour.green = options->image_overlay.background_green;
1461 colour.blue = options->image_overlay.background_blue;
1462 colour.alpha = options->image_overlay.background_alpha;
1463 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1464 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1466 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1468 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1469 c_options->image_overlay.background_red = colour.red*255;
1470 c_options->image_overlay.background_green = colour.green*255;
1471 c_options->image_overlay.background_blue = colour.blue*255;
1472 c_options->image_overlay.background_alpha = colour.alpha*255;
1474 gtk_widget_destroy(dialog);
1477 GtkColorSelection *colorsel;
1479 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1480 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1481 colour.red = options->image_overlay.background_red*257;
1482 colour.green = options->image_overlay.background_green*257;
1483 colour.blue = options->image_overlay.background_blue*257;
1484 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1485 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1486 gtk_color_selection_set_current_color(colorsel, &colour);
1487 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1489 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1491 gtk_color_selection_get_current_color(colorsel, &colour);
1492 c_options->image_overlay.background_red = colour.red/257;
1493 c_options->image_overlay.background_green = colour.green/257;
1494 c_options->image_overlay.background_blue = colour.blue/257;
1495 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1497 gtk_widget_destroy(dialog);
1501 static void accel_store_populate(void)
1504 GList *groups, *actions;
1506 const gchar *accel_path;
1510 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1512 gtk_tree_store_clear(accel_store);
1513 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1515 g_assert(lw && lw->ui_manager);
1516 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1519 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1522 action = GTK_ACTION(actions->data);
1523 accel_path = gtk_action_get_accel_path(action);
1524 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1526 gchar *label, *label2, *tooltip, *accel;
1527 g_object_get(action,
1528 "tooltip", &tooltip,
1532 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1538 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1542 gtk_tree_store_append(accel_store, &iter, NULL);
1543 gtk_tree_store_set(accel_store, &iter,
1546 AE_TOOLTIP, tooltip ? tooltip : "",
1547 AE_ACCEL, accel_path,
1555 actions = actions->next;
1558 groups = groups->next;
1562 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1567 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1569 gchar *accel1 = data;
1574 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1576 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1577 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1579 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1581 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1582 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1591 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1593 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1597 GtkAccelKey old_key, key;
1598 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1600 gtk_tree_model_get_iter(model, &iter, path);
1601 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1603 /* test if the accelerator can be stored without conflicts*/
1604 gtk_accel_map_lookup_entry(accel_path, &old_key);
1606 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1607 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1608 gtk_accel_map_lookup_entry(accel_path, &key);
1610 /* restore the original for now, the key will be really changed when the changes are confirmed */
1611 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1613 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1614 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1616 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1617 gtk_tree_path_free(path);
1621 static gboolean accel_default_scroll(GtkTreeView *data)
1625 GtkTreeViewColumn *column;
1627 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1628 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1629 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1631 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1635 gtk_tree_path_free(path);
1640 static void accel_default_cb(GtkWidget *widget, gpointer data)
1642 accel_store_populate();
1644 g_idle_add((GSourceFunc)accel_default_scroll, data);
1647 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1649 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1652 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1655 gchar *accel_path, *accel;
1657 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1658 gtk_accel_map_lookup_entry(accel_path, &key);
1659 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1661 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1663 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1668 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1670 GtkTreeSelection *selection;
1672 if (!accel_store) return;
1673 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1674 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1679 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1683 GtkWidget *scrolled;
1684 GtkWidget *viewport;
1686 scrolled = gtk_scrolled_window_new(NULL, NULL);
1687 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1688 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1689 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1690 label = gtk_label_new(title);
1691 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1692 gtk_widget_show(scrolled);
1694 viewport = gtk_viewport_new(NULL, NULL);
1695 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1696 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1697 gtk_widget_show(viewport);
1699 vbox = gtk_vbox_new(FALSE, 0);
1700 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1701 gtk_widget_show(vbox);
1706 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1708 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1710 c_options->thumbnails.spec_standard =TRUE;
1711 c_options->thumbnails.cache_into_dirs = FALSE;
1715 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1717 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1719 c_options->thumbnails.spec_standard =FALSE;
1720 c_options->thumbnails.cache_into_dirs = FALSE;
1724 static void cache_local_cb(GtkWidget *widget, gpointer data)
1726 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1728 c_options->thumbnails.cache_into_dirs = TRUE;
1729 c_options->thumbnails.spec_standard =FALSE;
1733 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1734 GdkEvent *event, gpointer userdata)
1736 if (pos == GTK_ENTRY_ICON_PRIMARY)
1738 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1742 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1746 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1747 GdkEvent *event, gpointer userdata)
1749 gchar *rating_symbol;
1751 if (pos == GTK_ENTRY_ICON_PRIMARY)
1753 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1754 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1755 g_free(rating_symbol);
1759 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1760 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1761 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1765 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1766 GdkEvent *event, gpointer userdata)
1768 gchar *rating_symbol;
1770 if (pos == GTK_ENTRY_ICON_PRIMARY)
1772 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1773 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1774 g_free(rating_symbol);
1778 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1779 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1780 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1784 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1786 GtkContainer *hbox = data;
1787 GString *str = g_string_new(NULL);
1788 GtkEntry *hex_code_entry;
1789 gchar *hex_code_full;
1792 guint64 hex_value = 0;
1794 list = gtk_container_get_children(hbox);
1796 hex_code_entry = g_list_nth_data(list, 2);
1797 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1799 hex_code = g_strsplit(hex_code_full, "+", 2);
1800 if (hex_code[0] && hex_code[1])
1802 hex_value = strtoull(hex_code[1], NULL, 16);
1804 if (!hex_value || hex_value > 0x10FFFF)
1806 hex_value = 0x003F; // Unicode 'Question Mark'
1808 str = g_string_append_unichar(str, (gunichar)hex_value);
1809 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1811 g_strfreev(hex_code);
1812 g_string_free(str, TRUE);
1813 g_free(hex_code_full);
1818 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1820 guint64 star_symbol;
1822 star_symbol = star_rating_symbol_test(widget, data);
1823 c_options->star_rating.star = star_symbol;
1826 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1828 guint64 rejected_symbol;
1830 rejected_symbol = star_rating_symbol_test(widget, data);
1831 c_options->star_rating.rejected = rejected_symbol;
1834 /* general options tab */
1835 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1836 typedef struct _TZData TZData;
1840 GCancellable *cancellable;
1842 GtkWidget *progress;
1844 GFile *timezone_database_gq;
1845 gchar *timezone_database_user;
1848 static void config_tab_general(GtkWidget *notebook)
1853 GtkWidget *group_frame;
1854 GtkWidget *subgroup;
1856 GtkWidget *ct_button;
1859 gint hours, minutes, remainder;
1861 GtkWidget *star_rating_entry;
1863 gchar *rating_symbol;
1866 GNetworkMonitor *net_mon;
1867 GSocketConnectable *geeqie_org;
1868 gboolean internet_available;
1871 vbox = scrolled_notebook_page(notebook, _("General"));
1873 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1875 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1876 add_thumb_size_menu(table, 0, 0, _("Size:"));
1877 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1879 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1880 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1882 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1883 pref_checkbox_link_sensitivity(ct_button, subgroup);
1885 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1886 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1887 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1888 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1889 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1890 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1891 G_CALLBACK(cache_geeqie_cb), NULL);
1893 group_frame = pref_frame_new(subgroup, TRUE,
1894 _("Store thumbnails local to image folder (non-standard)"),
1895 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1896 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1897 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1898 G_CALLBACK(cache_local_cb), NULL);
1900 group_frame = pref_frame_new(subgroup, TRUE,
1901 _("Use standard thumbnail style and cache, shared with other applications"),
1902 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1903 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1904 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1905 G_CALLBACK(cache_standard_cb), NULL);
1907 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1908 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1910 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1912 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1913 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1915 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1916 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1917 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1919 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1920 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1923 pref_spacer(group, PREF_PAD_GROUP);
1925 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1927 c_options->star_rating.star = options->star_rating.star;
1928 c_options->star_rating.rejected = options->star_rating.rejected;
1930 str = g_string_new(NULL);
1931 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1932 pref_label_new(hbox, "Star character: ");
1933 str = g_string_append_unichar(str, options->star_rating.star);
1934 pref_label_new(hbox, g_strdup(str->str));
1935 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1936 star_rating_entry = gtk_entry_new();
1937 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1938 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1939 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1940 gtk_widget_show(star_rating_entry);
1941 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1942 G_CALLBACK(star_rating_star_test_cb), hbox);
1943 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1944 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1945 gtk_widget_show(button);
1946 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."));
1947 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1948 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1949 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1950 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1951 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1952 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1953 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1954 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1955 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1956 G_CALLBACK(star_rating_star_icon_cb),
1959 g_string_free(str, TRUE);
1960 g_free(rating_symbol);
1962 str = g_string_new(NULL);
1963 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1964 pref_label_new(hbox, "Rejected character: ");
1965 str = g_string_append_unichar(str, options->star_rating.rejected);
1966 pref_label_new(hbox, g_strdup(str->str));
1967 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
1968 star_rating_entry = gtk_entry_new();
1969 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1970 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1971 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1972 gtk_widget_show(star_rating_entry);
1973 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1974 G_CALLBACK(star_rating_rejected_test_cb), hbox);
1975 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1976 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1977 gtk_widget_show(button);
1978 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."));
1979 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1980 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1981 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1982 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1983 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1984 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
1985 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1986 GTK_ENTRY_ICON_PRIMARY, _("Default"));
1987 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
1988 G_CALLBACK(star_rating_rejected_icon_cb),
1991 g_string_free(str, TRUE);
1992 g_free(rating_symbol);
1994 pref_spacer(group, PREF_PAD_GROUP);
1996 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
1998 c_options->slideshow.delay = options->slideshow.delay;
1999 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2000 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2001 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2002 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2003 SLIDESHOW_SUBSECOND_PRECISION;
2005 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2007 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2009 options->slideshow.delay ? hours : 0.0,
2010 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2011 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2012 spin = pref_spin_new(hbox, ":" , NULL,
2014 options->slideshow.delay ? minutes: 0.0,
2015 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2016 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2017 spin = pref_spin_new(hbox, ":", NULL,
2018 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2019 options->slideshow.delay ? seconds : 10.0,
2020 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2021 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2023 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2024 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2026 pref_spacer(group, PREF_PAD_GROUP);
2028 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2030 pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
2031 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2032 pref_checkbox_new_int(group, _("Preload next image"),
2033 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2035 pref_checkbox_new_int(group, _("Refresh on file change"),
2036 options->update_on_time_change, &c_options->update_on_time_change);
2038 pref_spacer(group, PREF_PAD_GROUP);
2040 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2041 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2042 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2043 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2045 options->info_keywords.height, &c_options->info_keywords.height);
2046 pref_spin_new_int(hbox, _("Title:"), NULL,
2048 options->info_title.height, &c_options->info_title.height);
2049 pref_spin_new_int(hbox, _("Comment:"), NULL,
2051 options->info_comment.height, &c_options->info_comment.height);
2052 pref_spin_new_int(hbox, _("Rating:"), NULL,
2054 options->info_rating.height, &c_options->info_rating.height);
2056 pref_spacer(group, PREF_PAD_GROUP);
2058 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2060 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2061 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2063 pref_spacer(group, PREF_PAD_GROUP);
2065 net_mon = g_network_monitor_get_default();
2066 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2067 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2068 g_object_unref(geeqie_org);
2070 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2071 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2073 if (!internet_available)
2075 gtk_widget_set_sensitive(group, FALSE);
2078 tz = g_new0(TZData, 1);
2080 path = path_from_utf8(TIMEZONE_DATABASE);
2081 basename = g_path_get_basename(path);
2082 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2086 if (isfile(tz->timezone_database_user))
2088 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2092 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2095 if (!internet_available)
2097 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"));
2101 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"));
2103 gtk_widget_show(button);
2105 pref_spacer(group, PREF_PAD_GROUP);
2107 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2109 help_search_engine_entry = gtk_entry_new();
2110 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2111 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2112 gtk_widget_show(help_search_engine_entry);
2114 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"));
2116 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2117 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2118 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2119 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2120 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2121 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2122 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2123 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2124 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2125 G_CALLBACK(help_search_engine_entry_icon_cb),
2126 help_search_engine_entry);
2130 static void config_tab_image(GtkWidget *notebook)
2135 GtkWidget *ct_button;
2136 GtkWidget *enlargement_button;
2140 vbox = scrolled_notebook_page(notebook, _("Image"));
2142 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2144 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2145 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2148 pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
2149 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2152 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2153 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2155 c_options->image.zoom_increment = options->image.zoom_increment;
2156 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2157 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2158 G_CALLBACK(zoom_increment_cb), NULL);
2159 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2161 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2163 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2164 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2165 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2166 spin = pref_spin_new_int(hbox, NULL, NULL,
2168 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2169 pref_checkbox_link_sensitivity(enlargement_button, spin);
2170 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."));
2172 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2173 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2174 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2175 spin = pref_spin_new_int(hbox, NULL, NULL,
2177 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2178 pref_checkbox_link_sensitivity(ct_button, spin);
2179 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."));
2181 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2183 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2184 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2186 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2187 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2189 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2190 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2192 c_options->image.border_color = options->image.border_color;
2194 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2195 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2197 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2198 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2200 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2201 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2203 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2205 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2206 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2210 static void config_tab_windows(GtkWidget *notebook)
2216 GtkWidget *ct_button;
2219 vbox = scrolled_notebook_page(notebook, _("Windows"));
2221 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2223 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2224 options->save_window_positions, &c_options->save_window_positions);
2226 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2227 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2228 pref_checkbox_link_sensitivity(ct_button, button);
2230 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2231 options->tools_restore_state, &c_options->tools_restore_state);
2233 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2234 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2236 pref_checkbox_new_int(group, _("Show window IDs"),
2237 options->show_window_ids, &c_options->show_window_ids);
2239 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2241 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2242 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2244 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2245 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2246 options->image.limit_window_size, &c_options->image.limit_window_size);
2247 spin = pref_spin_new_int(hbox, NULL, NULL,
2249 options->image.max_window_size, &c_options->image.max_window_size);
2250 pref_checkbox_link_sensitivity(ct_button, spin);
2252 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2254 c_options->fullscreen.screen = options->fullscreen.screen;
2255 c_options->fullscreen.above = options->fullscreen.above;
2256 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2257 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2258 gtk_widget_show(hbox);
2260 pref_checkbox_new_int(group, _("Smooth image flip"),
2261 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2262 pref_checkbox_new_int(group, _("Disable screen saver"),
2263 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2266 #define PRE_FORMATTED_COLUMNS 5
2267 static void config_tab_osd(GtkWidget *notebook)
2271 GtkWidget *vbox_buttons;
2274 GtkWidget *image_overlay_template_view;
2275 GtkWidget *scrolled;
2276 GtkWidget *scrolled_pre_formatted;
2277 GtkTextBuffer *buffer;
2279 GtkWidget * subgroup;
2284 vbox = scrolled_notebook_page(notebook, _("OSD"));
2286 image_overlay_template_view = gtk_text_view_new();
2288 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2290 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2292 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2293 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2294 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2295 gtk_widget_show(scrolled_pre_formatted);
2296 gtk_widget_show(subgroup);
2298 pref_line(group, PREF_PAD_GAP);
2300 pref_label_new(group, _("Image overlay template"));
2302 scrolled = gtk_scrolled_window_new(NULL, NULL);
2303 gtk_widget_set_size_request(scrolled, 200, 150);
2304 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2305 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2306 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2307 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2308 gtk_widget_show(scrolled);
2310 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2311 _("Extensive formatting options are shown in the Help file"));
2313 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2314 gtk_widget_show(image_overlay_template_view);
2316 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2318 #if GTK_CHECK_VERSION(3,4,0)
2319 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2320 G_CALLBACK(image_overlay_set_font_cb), notebook);
2322 button = gtk_font_button_new();
2323 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2324 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2325 g_signal_connect(G_OBJECT(button), "font-set",
2326 G_CALLBACK(image_overlay_set_font_cb),NULL);
2328 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2329 gtk_widget_show(button);
2331 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2332 G_CALLBACK(image_overlay_set_text_colour_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, _("Background"), FALSE,
2337 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2338 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2339 gtk_widget_show(button);
2340 image_overlay_set_text_colours();
2342 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2343 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2344 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2345 gtk_widget_show(button);
2347 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2348 G_CALLBACK(image_overlay_help_cb), NULL);
2349 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2350 gtk_widget_show(button);
2352 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2353 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2354 g_signal_connect(G_OBJECT(buffer), "changed",
2355 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2357 pref_line(group, PREF_PAD_GAP);
2359 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2360 hbox = gtk_hbox_new(FALSE, 0);
2361 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2362 gtk_widget_show(hbox);
2363 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2364 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2365 gtk_widget_show(label);
2366 pref_spacer(group,TRUE);
2368 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2369 hbox = gtk_hbox_new(FALSE, 0);
2370 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2371 gtk_widget_show(hbox);
2372 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2373 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2374 gtk_widget_show(label);
2375 pref_spacer(group,TRUE);
2377 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2378 hbox = gtk_hbox_new(FALSE, 0);
2379 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2380 gtk_widget_show(hbox);
2381 label = gtk_label_new(_("%path:39%"));
2382 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2383 gtk_widget_show(label);
2384 pref_spacer(group,TRUE);
2386 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2387 hbox = gtk_hbox_new(FALSE, 0);
2388 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2389 gtk_widget_show(hbox);
2390 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%"));
2391 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2392 gtk_widget_show(label);
2393 pref_spacer(group,TRUE);
2395 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2396 hbox = gtk_hbox_new(FALSE, 0);
2397 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2398 gtk_widget_show(hbox);
2399 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2400 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2401 gtk_widget_show(label);
2404 static GtkTreeModel *create_class_model(void)
2406 GtkListStore *model;
2410 /* create list store */
2411 model = gtk_list_store_new(1, G_TYPE_STRING);
2412 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2414 gtk_list_store_append(model, &iter);
2415 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2417 return GTK_TREE_MODEL (model);
2422 static void config_tab_files(GtkWidget *notebook)
2429 GtkWidget *ct_button;
2430 GtkWidget *scrolled;
2431 GtkWidget *filter_view;
2432 GtkCellRenderer *renderer;
2433 GtkTreeSelection *selection;
2434 GtkTreeViewColumn *column;
2436 vbox = scrolled_notebook_page(notebook, _("Files"));
2438 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2440 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2441 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2442 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2443 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2444 pref_checkbox_new_int(group, _("Case sensitive sort"),
2445 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2446 pref_checkbox_new_int(group, _("Natural sort order"),
2447 options->file_sort.natural, &c_options->file_sort.natural);
2448 pref_checkbox_new_int(group, _("Disable file extension checks"),
2449 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2451 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2452 options->file_filter.disable, &c_options->file_filter.disable);
2455 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2457 sidecar_ext_entry = gtk_entry_new();
2458 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2459 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2460 gtk_widget_show(sidecar_ext_entry);
2462 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2464 frame = pref_group_parent(group);
2465 g_signal_connect(G_OBJECT(ct_button), "toggled",
2466 G_CALLBACK(filter_disable_cb), frame);
2467 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2469 scrolled = gtk_scrolled_window_new(NULL, NULL);
2470 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2471 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2472 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2473 gtk_widget_show(scrolled);
2475 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2476 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2477 g_object_unref(filter_store);
2478 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2479 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2481 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2483 column = gtk_tree_view_column_new();
2484 gtk_tree_view_column_set_title(column, _("Filter"));
2485 gtk_tree_view_column_set_resizable(column, TRUE);
2487 renderer = gtk_cell_renderer_toggle_new();
2488 g_signal_connect(G_OBJECT(renderer), "toggled",
2489 G_CALLBACK(filter_store_enable_cb), filter_store);
2490 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2491 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2492 GINT_TO_POINTER(FE_ENABLE), NULL);
2494 renderer = gtk_cell_renderer_text_new();
2495 g_signal_connect(G_OBJECT(renderer), "edited",
2496 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2497 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2498 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2499 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2500 GINT_TO_POINTER(FE_EXTENSION), NULL);
2501 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2503 column = gtk_tree_view_column_new();
2504 gtk_tree_view_column_set_title(column, _("Description"));
2505 gtk_tree_view_column_set_resizable(column, TRUE);
2506 gtk_tree_view_column_set_fixed_width(column, 200);
2507 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2509 renderer = gtk_cell_renderer_text_new();
2510 g_signal_connect(G_OBJECT(renderer), "edited",
2511 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2512 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2513 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2514 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2515 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2516 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2518 column = gtk_tree_view_column_new();
2519 gtk_tree_view_column_set_title(column, _("Class"));
2520 gtk_tree_view_column_set_resizable(column, TRUE);
2521 renderer = gtk_cell_renderer_combo_new();
2522 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2523 "model", create_class_model(),
2528 g_signal_connect(G_OBJECT(renderer), "edited",
2529 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2530 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2531 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2532 GINT_TO_POINTER(FE_CLASS), NULL);
2533 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2535 column = gtk_tree_view_column_new();
2536 gtk_tree_view_column_set_title(column, _("Writable"));
2537 gtk_tree_view_column_set_resizable(column, FALSE);
2538 renderer = gtk_cell_renderer_toggle_new();
2539 g_signal_connect(G_OBJECT(renderer), "toggled",
2540 G_CALLBACK(filter_store_writable_cb), filter_store);
2541 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2542 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2543 GINT_TO_POINTER(FE_WRITABLE), NULL);
2544 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2546 column = gtk_tree_view_column_new();
2547 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2548 gtk_tree_view_column_set_resizable(column, FALSE);
2549 renderer = gtk_cell_renderer_toggle_new();
2550 g_signal_connect(G_OBJECT(renderer), "toggled",
2551 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2552 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2553 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2554 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2555 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2558 filter_store_populate();
2559 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2560 gtk_widget_show(filter_view);
2562 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2564 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2565 G_CALLBACK(filter_default_cb), filter_view);
2566 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2567 gtk_widget_show(button);
2569 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2570 G_CALLBACK(filter_remove_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_ADD, NULL, FALSE,
2575 G_CALLBACK(filter_add_cb), filter_view);
2576 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2577 gtk_widget_show(button);
2581 static void config_tab_metadata(GtkWidget *notebook)
2586 GtkWidget *ct_button;
2590 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2593 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2595 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2597 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2598 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2600 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2601 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2603 gtk_widget_set_sensitive(ct_button, FALSE);
2606 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2607 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2609 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2610 label = pref_label_new(group, text);
2611 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2612 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2615 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2617 gtk_widget_set_sensitive(group, FALSE);
2620 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2621 pref_checkbox_link_sensitivity(ct_button, hbox);
2623 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2624 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2626 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2627 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2629 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2630 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2632 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2633 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2635 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2637 gtk_widget_set_sensitive(group, FALSE);
2640 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2641 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2644 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2645 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2646 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2648 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2649 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2651 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2652 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2654 gtk_widget_set_sensitive(ct_button, FALSE);
2657 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2659 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2660 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2662 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2663 pref_checkbox_link_sensitivity(ct_button, hbox);
2665 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2666 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2668 pref_checkbox_new_int(group, _("Write metadata on image change"),
2669 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2671 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2672 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2674 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2676 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2677 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2678 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");
2683 typedef struct _KeywordFindData KeywordFindData;
2684 struct _KeywordFindData
2691 GtkWidget *button_close;
2692 GtkWidget *button_stop;
2693 GtkWidget *button_start;
2694 GtkWidget *progress;
2702 guint idle_id; /* event source id */
2705 #define KEYWORD_DIALOG_WIDTH 400
2707 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2709 GList *list_d = NULL;
2710 GList *list_f = NULL;
2714 filelist_read(dir_fd, &list_f, &list_d);
2718 filelist_read(dir_fd, &list_f, NULL);
2721 list_f = filelist_filter(list_f, FALSE);
2722 list_d = filelist_filter(list_d, TRUE);
2724 kfd->list = g_list_concat(list_f, kfd->list);
2725 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2728 static void keywords_find_reset(KeywordFindData *kfd)
2730 filelist_free(kfd->list);
2733 filelist_free(kfd->list_dir);
2734 kfd->list_dir = NULL;
2737 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2739 KeywordFindData *kfd = data;
2741 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2743 keywords_find_reset(kfd);
2744 generic_dialog_close(kfd->gd);
2748 static void keywords_find_finish(KeywordFindData *kfd)
2750 keywords_find_reset(kfd);
2752 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2753 spinner_set_interval(kfd->spinner, -1);
2755 gtk_widget_set_sensitive(kfd->group, TRUE);
2756 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2757 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2758 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2761 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2763 KeywordFindData *kfd = data;
2765 g_idle_remove_by_data(kfd);
2767 keywords_find_finish(kfd);
2770 static gboolean keywords_find_file(gpointer data)
2772 KeywordFindData *kfd = data;
2774 GtkTextBuffer *buffer;
2782 fd = kfd->list->data;
2783 kfd->list = g_list_remove(kfd->list, fd);
2785 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2786 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2790 gtk_text_buffer_get_end_iter(buffer, &iter);
2791 tmp = g_strconcat(keywords->data, "\n", NULL);
2792 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2794 keywords = keywords->next;
2797 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2798 file_data_unref(fd);
2799 string_list_free(keywords);
2803 else if (kfd->list_dir)
2807 fd = kfd->list_dir->data;
2808 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2810 keywords_find_folder(kfd, fd);
2812 file_data_unref(fd);
2817 keywords_find_finish(kfd);
2822 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2824 KeywordFindData *kfd = data;
2827 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2829 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2830 parse_out_relatives(path);
2834 warning_dialog(_("Invalid folder"),
2835 _("The specified folder can not be found."),
2836 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2842 gtk_widget_set_sensitive(kfd->group, FALSE);
2843 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2844 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2845 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2846 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2848 dir_fd = file_data_new_dir(path);
2849 keywords_find_folder(kfd, dir_fd);
2850 file_data_unref(dir_fd);
2851 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2857 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2859 KeywordFindData *kfd;
2863 kfd = g_new0(KeywordFindData, 1);
2865 kfd->gd = generic_dialog_new(_("Search for keywords"),
2866 "search_for_keywords",
2869 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2870 kfd->gd->cancel_cb = keywords_find_close_cb;
2871 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2872 keywords_find_close_cb, FALSE);
2873 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2874 keywords_find_start_cb, FALSE);
2875 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2876 keywords_find_stop_cb, FALSE);
2877 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2879 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2881 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2882 pref_spacer(hbox, PREF_PAD_INDENT);
2883 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2885 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2886 pref_label_new(hbox, _("Folder:"));
2888 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2889 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2890 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2891 gtk_widget_show(label);
2893 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2895 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2896 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2898 kfd->progress = gtk_entry_new();
2899 gtk_widget_set_can_focus(kfd->progress, FALSE);
2900 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2901 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2902 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2903 gtk_widget_show(kfd->progress);
2905 kfd->spinner = spinner_new(NULL, -1);
2906 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2907 gtk_widget_show(kfd->spinner);
2911 gtk_widget_show(kfd->gd->dialog);
2914 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2916 const gchar *path = layout_get_path(NULL);
2918 if (!path || !*path) path = homedir();
2919 keywords_find_dialog(widget, path);
2922 static void config_tab_keywords_save()
2924 GtkTextIter start, end;
2925 GtkTextBuffer *buffer;
2926 GList *kw_list = NULL;
2932 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2933 gtk_text_buffer_get_bounds(buffer, &start, &end);
2935 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
2937 kw_split = strtok(buffer_text, "\n");
2938 while (kw_split != NULL)
2944 if (g_strcmp0(work->data, kw_split) == 0)
2953 kw_list = g_list_append(kw_list, g_strdup(kw_split));
2955 kw_split = strtok(NULL, "\n");
2958 keyword_list_set(kw_list);
2960 string_list_free(kw_list);
2961 g_free(buffer_text);
2964 static void config_tab_keywords(GtkWidget *notebook)
2970 GtkWidget *scrolled;
2972 GtkTextBuffer *buffer;
2975 vbox = scrolled_notebook_page(notebook, _("Keywords"));
2977 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
2979 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2981 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
2982 G_CALLBACK(keywords_find_cb), keyword_text);
2983 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
2986 keyword_text = gtk_text_view_new();
2987 gtk_widget_set_size_request(keyword_text, 20, 20);
2988 scrolled = gtk_scrolled_window_new(NULL, NULL);
2989 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2990 gtk_widget_show(scrolled);
2992 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
2993 gtk_widget_show(keyword_text);
2995 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
2997 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2998 gtk_text_buffer_create_tag(buffer, "monospace",
2999 "family", "monospace", NULL);
3001 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3002 gtk_text_buffer_get_start_iter(buffer, &iter);
3003 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3006 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3008 GList *kwl = keyword_list_get();
3009 kwl = g_list_first(kwl);
3012 gtk_text_buffer_get_end_iter (buffer, &iter);
3013 tmp = g_strconcat(kwl->data, "\n", NULL);
3014 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3019 gtk_text_buffer_set_modified(buffer, FALSE);
3026 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3028 gint *option = data;
3030 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3034 *option = INTENT_PERCEPTUAL;
3037 *option = INTENT_RELATIVE_COLORIMETRIC;
3040 *option = INTENT_SATURATION;
3043 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3048 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3049 gint option, gint *option_c)
3056 pref_table_label(table, column, row, text, 0.0);
3058 combo = gtk_combo_box_text_new();
3060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3061 if (option == INTENT_PERCEPTUAL) current = 0;
3062 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3063 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3064 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3065 if (option == INTENT_SATURATION) current = 2;
3066 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3067 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3069 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3071 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3073 g_signal_connect(G_OBJECT(combo), "changed",
3074 G_CALLBACK(intent_menu_cb), option_c);
3076 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
3077 GTK_EXPAND | GTK_FILL, 0, 0, 0);
3078 gtk_widget_show(combo);
3082 static void config_tab_color(GtkWidget *notebook)
3091 vbox = scrolled_notebook_page(notebook, _("Color management"));
3093 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3095 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3098 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3099 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3101 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3102 pref_label_bold(label, TRUE, FALSE);
3104 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3105 pref_label_bold(label, TRUE, FALSE);
3107 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3108 pref_label_bold(label, TRUE, FALSE);
3110 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3115 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3116 pref_table_label(table, 0, i + 1, buf, 1.0);
3119 entry = gtk_entry_new();
3120 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3121 if (options->color_profile.input_name[i])
3123 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3125 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3126 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3127 gtk_widget_show(entry);
3128 color_profile_input_name_entry[i] = entry;
3130 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3131 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3132 gtk_widget_set_size_request(entry, 160, -1);
3133 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3134 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3135 gtk_widget_show(tabcomp);
3136 color_profile_input_file_entry[i] = entry;
3139 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3141 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3143 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3144 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3146 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3148 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3149 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3150 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3151 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3152 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3154 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3156 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3158 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3160 gtk_widget_show(tabcomp);
3163 /* advanced entry tab */
3164 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3166 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3168 c_options->file_ops.use_system_trash = FALSE;
3169 c_options->file_ops.no_trash = FALSE;
3173 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3175 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3177 c_options->file_ops.use_system_trash = TRUE;
3178 c_options->file_ops.no_trash = FALSE;
3182 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3184 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3186 c_options->file_ops.no_trash = TRUE;
3190 static void config_tab_behavior(GtkWidget *notebook)
3197 GtkWidget *ct_button;
3201 GtkWidget *with_rename;
3202 GtkWidget *collections_on_top;
3204 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3206 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3208 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3209 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3210 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3211 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3212 pref_checkbox_new_int(group, _("Enable Delete key"),
3213 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3215 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3216 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3218 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3219 pref_checkbox_link_sensitivity(ct_button, hbox);
3221 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3222 pref_label_new(hbox, _("Folder:"));
3224 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3225 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3226 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3227 gtk_widget_show(tabcomp);
3229 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3230 pref_checkbox_link_sensitivity(ct_button, hbox);
3232 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3233 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3234 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3235 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3236 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3237 G_CALLBACK(safe_delete_view_cb), NULL);
3238 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3239 gtk_widget_show(button);
3241 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3242 G_CALLBACK(safe_delete_clear_cb), NULL);
3243 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3244 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3245 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3247 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3248 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3250 gtk_widget_show(button);
3252 pref_spacer(group, PREF_PAD_GROUP);
3255 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3257 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3258 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3260 pref_checkbox_new_int(group, _("In place renaming"),
3261 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3263 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3264 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3266 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3267 options->marks_save, &c_options->marks_save);
3268 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3270 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3271 options->with_rename, &c_options->with_rename);
3272 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3274 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3275 options->collections_on_top, &c_options->collections_on_top);
3276 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3278 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3279 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3281 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3282 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3284 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3285 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3287 pref_spacer(group, PREF_PAD_GROUP);
3289 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3291 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3292 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3293 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3294 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3295 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3296 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3297 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3298 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3299 pref_checkbox_new_int(group, _("Play video by left click on image"),
3300 options->image_l_click_video, &c_options->image_l_click_video);
3301 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3302 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3304 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3305 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3306 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3307 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3308 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3311 pref_spacer(group, PREF_PAD_GROUP);
3313 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3315 pref_spin_new_int(group, _("Debug level:"), NULL,
3316 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3318 pref_checkbox_new_int(group, _("Timer data"),
3319 options->log_window.timer_data, &c_options->log_window.timer_data);
3321 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3322 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3326 /* accelerators tab */
3327 static void config_tab_accelerators(GtkWidget *notebook)
3333 GtkWidget *scrolled;
3334 GtkWidget *accel_view;
3335 GtkCellRenderer *renderer;
3336 GtkTreeSelection *selection;
3337 GtkTreeViewColumn *column;
3339 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3341 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3343 scrolled = gtk_scrolled_window_new(NULL, NULL);
3344 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3345 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3346 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3347 gtk_widget_show(scrolled);
3349 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3351 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3352 g_object_unref(accel_store);
3353 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3354 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3356 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3358 renderer = gtk_cell_renderer_text_new();
3360 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3365 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3366 gtk_tree_view_column_set_resizable(column, TRUE);
3367 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3370 renderer = gtk_cell_renderer_accel_new();
3371 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3372 G_CALLBACK(accel_store_cleared_cb), accel_store);
3373 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3374 G_CALLBACK(accel_store_edited_cb), accel_store);
3377 g_object_set (renderer,
3379 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3382 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3387 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3388 gtk_tree_view_column_set_resizable(column, TRUE);
3389 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3391 renderer = gtk_cell_renderer_text_new();
3393 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3398 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3399 gtk_tree_view_column_set_resizable(column, TRUE);
3400 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3402 renderer = gtk_cell_renderer_text_new();
3404 column = gtk_tree_view_column_new_with_attributes("Accel",
3409 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3410 gtk_tree_view_column_set_resizable(column, TRUE);
3411 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3413 accel_store_populate();
3414 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3415 gtk_widget_show(accel_view);
3417 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3419 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3420 G_CALLBACK(accel_default_cb), accel_view);
3421 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3422 gtk_widget_show(button);
3424 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3425 G_CALLBACK(accel_reset_cb), accel_view);
3426 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3427 gtk_widget_show(button);
3431 static void config_tab_toolbar(GtkWidget *notebook)
3434 GtkWidget *toolbardata;
3437 lw = layout_window_list->data;
3439 vbox = scrolled_notebook_page(notebook, _("Toolbar"));
3441 toolbardata = toolbar_select_new(lw);
3442 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3443 gtk_widget_show(vbox);
3447 static void config_tab_stereo(GtkWidget *notebook)
3455 GtkWidget *fs_button;
3456 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3458 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3460 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3461 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3463 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3464 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3465 pref_checkbox_new_int(box, _("Mirror left image"),
3466 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3467 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3468 pref_checkbox_new_int(box, _("Flip left image"),
3469 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3470 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3471 pref_checkbox_new_int(box, _("Mirror right image"),
3472 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3473 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3474 pref_checkbox_new_int(box, _("Flip right image"),
3475 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3476 pref_checkbox_new_int(group, _("Swap left and right images"),
3477 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3478 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3479 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3481 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3482 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3483 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3484 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3485 pref_checkbox_link_sensitivity(fs_button, box2);
3486 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3487 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3488 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3489 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3490 pref_checkbox_new_int(box, _("Mirror left image"),
3491 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3492 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3493 pref_checkbox_new_int(box, _("Flip left image"),
3494 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3495 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3496 pref_checkbox_new_int(box, _("Mirror right image"),
3497 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3498 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3499 pref_checkbox_new_int(box, _("Flip right image"),
3500 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3501 pref_checkbox_new_int(box2, _("Swap left and right images"),
3502 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3503 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3504 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3506 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3507 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3508 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3509 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3510 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3511 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3512 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3513 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3514 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3515 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3516 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3517 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3518 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3519 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3523 /* Main preferences window */
3524 static void config_window_create(void)
3526 GtkWidget *win_vbox;
3528 GtkWidget *notebook;
3530 GtkWidget *ct_button;
3532 if (!c_options) c_options = init_options(NULL);
3534 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3535 DEBUG_NAME(configwindow);
3536 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3537 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3538 G_CALLBACK(config_window_delete), NULL);
3539 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3540 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3541 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3543 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3544 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3545 gtk_widget_show(win_vbox);
3547 notebook = gtk_notebook_new();
3548 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3549 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3550 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3552 config_tab_general(notebook);
3553 config_tab_image(notebook);
3554 config_tab_osd(notebook);
3555 config_tab_windows(notebook);
3556 config_tab_accelerators(notebook);
3557 config_tab_files(notebook);
3558 config_tab_metadata(notebook);
3559 config_tab_keywords(notebook);
3560 config_tab_color(notebook);
3561 config_tab_stereo(notebook);
3562 config_tab_behavior(notebook);
3563 config_tab_toolbar(notebook);
3565 hbox = gtk_hbutton_box_new();
3566 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3567 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3568 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3569 gtk_widget_show(hbox);
3571 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3572 G_CALLBACK(config_window_help_cb), notebook);
3573 gtk_container_add(GTK_CONTAINER(hbox), button);
3574 gtk_widget_set_can_default(button, TRUE);
3575 gtk_widget_show(button);
3577 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3578 G_CALLBACK(config_window_ok_cb), NULL);
3579 gtk_container_add(GTK_CONTAINER(hbox), button);
3580 gtk_widget_set_can_default(button, TRUE);
3581 gtk_widget_grab_default(button);
3582 gtk_widget_show(button);
3586 button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
3587 G_CALLBACK(config_window_save_cb), NULL);
3588 gtk_container_add(GTK_CONTAINER(hbox), button);
3589 gtk_widget_set_can_default(button, TRUE);
3590 gtk_widget_show(button);
3592 button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
3593 G_CALLBACK(config_window_apply_cb), NULL);
3594 gtk_container_add(GTK_CONTAINER(hbox), button);
3595 gtk_widget_set_can_default(button, TRUE);
3596 gtk_widget_show(button);
3598 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3599 G_CALLBACK(config_window_close_cb), NULL);
3600 gtk_container_add(GTK_CONTAINER(hbox), button);
3601 gtk_widget_set_can_default(button, TRUE);
3602 gtk_widget_show(button);
3604 if (!generic_dialog_get_alternative_button_order(configwindow))
3606 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3609 gtk_widget_show(notebook);
3611 gtk_widget_show(configwindow);
3615 *-----------------------------------------------------------------------------
3616 * config window show (public)
3617 *-----------------------------------------------------------------------------
3620 void show_config_window(void)
3624 gtk_window_present(GTK_WINDOW(configwindow));
3628 config_window_create();
3637 void show_about_window(LayoutWindow *lw)
3639 GdkPixbuf *pixbuf_logo;
3640 GdkPixbuf *pixbuf_icon;
3641 gchar *authors[1000];
3649 #define LINE_LENGTH 1000
3650 gchar line[LINE_LENGTH];
3652 copyright = g_string_new(NULL);
3653 copyright = g_string_append(copyright, "This program comes with absolutely no warranty.\nGNU General Public License, version 2 or later.\nSee https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n\n");
3655 zd_path = g_build_filename(GQ_BIN_DIR, TIMEZONE_DATABASE, NULL);
3656 cd = ZDOpenDatabase(zd_path);
3659 copyright = g_string_append(copyright, ZDGetNotice(cd));
3661 ZDCloseDatabase(cd);
3665 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3666 fp = fopen(path, "r");
3669 while(fgets(line, LINE_LENGTH, fp))
3671 /* get rid of ending \n from fgets */
3672 line[strlen(line) - 1] = '\0';
3673 authors[i_authors] = g_strdup(line);
3676 authors[i_authors] = NULL;
3681 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3682 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3684 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3685 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3686 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3687 "title", _("About Geeqie"),
3689 "program-name", GQ_APPNAME,
3691 "logo", pixbuf_logo,
3692 "icon", pixbuf_icon,
3693 "website", GQ_WEBSITE,
3694 "website-label", "Website",
3695 "comments", comment,
3697 "translator-credits", _("translator-credits"),
3698 "wrap-license", TRUE,
3699 "license", copyright->str,
3702 g_string_free(copyright, TRUE);
3705 while(n < i_authors)
3715 static void image_overlay_set_text_colours()
3717 c_options->image_overlay.text_red = options->image_overlay.text_red;
3718 c_options->image_overlay.text_green = options->image_overlay.text_green;
3719 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3720 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3721 c_options->image_overlay.background_red = options->image_overlay.background_red;
3722 c_options->image_overlay.background_green = options->image_overlay.background_green;
3723 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3724 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3728 *-----------------------------------------------------------------------------
3729 * timezone database routines
3730 *-----------------------------------------------------------------------------
3733 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3735 GError *error = NULL;
3737 gchar *tmp_filename;
3739 if (!g_cancellable_is_cancelled(tz->cancellable))
3741 generic_dialog_close(tz->gd);
3745 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3747 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3748 move_file(tmp_filename, tz->timezone_database_user);
3749 g_free(tmp_filename);
3753 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3756 g_file_delete(tz->tmp_g_file, NULL, &error);
3757 g_object_unref(tz->tmp_g_file);
3758 tz->tmp_g_file = NULL;
3759 g_object_unref(tz->cancellable);
3760 g_object_unref(tz->timezone_database_gq);
3763 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3767 if (!g_cancellable_is_cancelled(tz->cancellable))
3769 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3773 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3776 GError *error = NULL;
3778 g_cancellable_cancel(tz->cancellable);
3781 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3784 GError *error = NULL;
3785 GFileIOStream *io_stream;
3792 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3796 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3797 log_printf("Error: Download timezone database failed:\n%s", error->message);
3798 g_error_free(error);
3799 g_object_unref(tz->tmp_g_file);
3803 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3805 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3807 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3809 tz->progress = gtk_progress_bar_new();
3810 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3811 gtk_widget_show(tz->progress);
3813 gtk_widget_show(tz->gd->dialog);
3814 tz->cancellable = g_cancellable_new();
3815 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);
3817 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3820 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */