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"
25 #include "bar-keywords.h"
29 #include "filefilter.h"
30 #include "fullscreen.h"
32 #include "image-overlay.h"
33 #include "color-man.h"
35 #include "layout-util.h"
39 #include "pixbuf-util.h"
41 #include "slideshow.h"
45 #include "ui-fileops.h"
47 #include "ui-spinner.h"
48 #include "ui-tabcomp.h"
50 #include "zonedetect.h"
61 #include <gspell/gspell.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[] =
114 FILETYPES_COLUMN_ENABLED = 0,
115 FILETYPES_COLUMN_FILTER,
116 FILETYPES_COLUMN_DESCRIPTION,
117 FILETYPES_COLUMN_CLASS,
118 FILETYPES_COLUMN_WRITABLE,
119 FILETYPES_COLUMN_SIDECAR,
120 FILETYPES_COLUMN_COUNT
123 const gchar *format_class_list[] = {
134 /* config memory values */
135 static ConfOptions *c_options = NULL;
142 static GtkWidget *configwindow = NULL;
143 static GtkListStore *filter_store = NULL;
144 static GtkTreeStore *accel_store = NULL;
146 static GtkWidget *safe_delete_path_entry;
148 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
149 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
150 static GtkWidget *color_profile_screen_file_entry;
151 static GtkWidget *external_preview_select_entry;
152 static GtkWidget *external_preview_extract_entry;
154 static GtkWidget *sidecar_ext_entry;
155 static GtkWidget *help_search_engine_entry;
158 #define CONFIG_WINDOW_DEF_WIDTH 700
159 #define CONFIG_WINDOW_DEF_HEIGHT 600
162 *-----------------------------------------------------------------------------
163 * option widget callbacks (private)
164 *-----------------------------------------------------------------------------
167 static void zoom_increment_cb(GtkWidget *spin, gpointer UNUSED(data))
169 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
172 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer UNUSED(data))
174 gint mins_secs_tenths, delay;
176 mins_secs_tenths = c_options->slideshow.delay %
177 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
179 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
180 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
183 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
184 SLIDESHOW_SUBSECOND_PRECISION;
187 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer UNUSED(data))
189 gint hours, secs_tenths, delay;
191 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
192 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
194 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
195 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
196 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
198 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
199 SLIDESHOW_SUBSECOND_PRECISION;
202 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer UNUSED(data))
204 gint hours_mins, delay;
206 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
208 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
209 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
210 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
212 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
213 SLIDESHOW_SUBSECOND_PRECISION;
217 *-----------------------------------------------------------------------------
218 * sync program to config window routine (private)
219 *-----------------------------------------------------------------------------
222 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
228 buf = gtk_entry_get_text(GTK_ENTRY(entry));
229 if (buf && strlen(buf) > 0)
234 *option = g_strdup(buf);
239 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
241 gchar *accel_path, *accel;
243 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
245 if (accel_path && accel_path[0])
248 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
249 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
259 static void config_window_apply(void)
261 gboolean refresh = FALSE;
266 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
268 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
269 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
270 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
271 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
272 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
273 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
274 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
276 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
277 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
278 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
279 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
280 options->file_ops.no_trash = c_options->file_ops.no_trash;
281 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
282 options->tools_restore_state = c_options->tools_restore_state;
283 options->save_window_positions = c_options->save_window_positions;
284 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
285 options->save_window_workspace = c_options->save_window_workspace;
286 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
287 options->show_window_ids = c_options->show_window_ids;
288 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
289 options->image.zoom_2pass = c_options->image.zoom_2pass;
290 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
291 options->image.limit_window_size = c_options->image.limit_window_size;
292 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
293 options->image.max_window_size = c_options->image.max_window_size;
294 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
295 options->image.max_autofit_size = c_options->image.max_autofit_size;
296 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
297 //~ options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
298 options->image.tile_size = c_options->image.tile_size;
299 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
300 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
302 if (options->thumbnails.max_width != c_options->thumbnails.max_width
303 || options->thumbnails.max_height != c_options->thumbnails.max_height
304 || options->thumbnails.quality != c_options->thumbnails.quality)
306 thumb_format_changed = TRUE;
308 options->thumbnails.max_width = c_options->thumbnails.max_width;
309 options->thumbnails.max_height = c_options->thumbnails.max_height;
310 options->thumbnails.quality = c_options->thumbnails.quality;
312 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
313 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
314 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
315 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
316 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
317 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
318 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
319 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
320 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
321 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
322 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
323 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
324 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
326 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
327 options->file_sort.natural = c_options->file_sort.natural;
328 options->file_filter.disable = c_options->file_filter.disable;
330 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
331 sidecar_ext_parse(options->sidecar.ext);
333 options->slideshow.random = c_options->slideshow.random;
334 options->slideshow.repeat = c_options->slideshow.repeat;
335 options->slideshow.delay = c_options->slideshow.delay;
337 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
338 options->image_lm_click_nav = c_options->image_lm_click_nav;
339 options->image_l_click_archive = c_options->image_l_click_archive;
340 options->image_l_click_video = c_options->image_l_click_video;
341 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
343 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
345 options->image.tile_cache_max = c_options->image.tile_cache_max;
346 options->image.image_cache_max = c_options->image.image_cache_max;
348 options->image.zoom_quality = c_options->image.zoom_quality;
350 options->image.zoom_increment = c_options->image.zoom_increment;
352 options->image.zoom_style = c_options->image.zoom_style;
354 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
356 options->appimage_notifications = c_options->appimage_notifications;
359 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
360 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
361 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
363 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
364 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
365 options->image.border_color = c_options->image.border_color;
366 layout_colors_update();
367 view_window_colors_update();
370 options->image.alpha_color_1 = c_options->image.alpha_color_1;
371 options->image.alpha_color_2 = c_options->image.alpha_color_2;
373 options->fullscreen.screen = c_options->fullscreen.screen;
374 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
375 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
376 options->fullscreen.above = c_options->fullscreen.above;
377 if (c_options->image_overlay.template_string)
378 set_image_overlay_template_string(&options->image_overlay.template_string,
379 c_options->image_overlay.template_string);
380 if (c_options->image_overlay.font)
381 set_image_overlay_font_string(&options->image_overlay.font,
382 c_options->image_overlay.font);
383 options->image_overlay.text_red = c_options->image_overlay.text_red;
384 options->image_overlay.text_green = c_options->image_overlay.text_green;
385 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
386 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
387 options->image_overlay.background_red = c_options->image_overlay.background_red;
388 options->image_overlay.background_green = c_options->image_overlay.background_green;
389 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
390 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
391 options->update_on_time_change = c_options->update_on_time_change;
393 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
394 options->rot_invariant_sim = c_options->rot_invariant_sim;
396 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
398 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
399 options->circular_selection_lists = c_options->circular_selection_lists;
401 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
402 options->recent_folder_image_list_maxsize = c_options->recent_folder_image_list_maxsize;
403 options->dnd_icon_size = c_options->dnd_icon_size;
404 options->clipboard_selection = c_options->clipboard_selection;
405 options->dnd_default_action = c_options->dnd_default_action;
407 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
408 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
409 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
410 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
411 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
412 options->metadata.confirm_write = c_options->metadata.confirm_write;
413 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
414 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
415 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
416 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
417 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
418 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
419 options->metadata.write_orientation = c_options->metadata.write_orientation;
420 options->metadata.check_spelling = c_options->metadata.check_spelling;
421 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
422 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
423 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
424 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
425 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
426 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
427 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
428 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
429 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
430 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
431 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
432 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
433 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
434 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
435 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
436 options->stereo.fixed_w = c_options->stereo.fixed_w;
437 options->stereo.fixed_h = c_options->stereo.fixed_h;
438 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
439 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
440 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
441 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
443 options->info_keywords.height = c_options->info_keywords.height;
444 options->info_title.height = c_options->info_title.height;
445 options->info_comment.height = c_options->info_comment.height;
446 options->info_rating.height = c_options->info_rating.height;
448 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
449 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
451 options->marks_save = c_options->marks_save;
452 options->with_rename = c_options->with_rename;
453 options->collections_on_top = c_options->collections_on_top;
454 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
455 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
457 options->external_preview.enable = c_options->external_preview.enable;
458 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
459 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
461 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
463 options->star_rating.star = c_options->star_rating.star;
464 options->star_rating.rejected = c_options->star_rating.rejected;
466 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
469 set_debug_level(debug_c);
473 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
475 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
476 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
478 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
479 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
480 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
482 options->color_profile.render_intent = c_options->color_profile.render_intent;
487 options->mouse_button_8 = c_options->mouse_button_8;
488 options->mouse_button_9 = c_options->mouse_button_9;
490 options->override_disable_gpu = c_options->override_disable_gpu;
492 config_tab_keywords_save();
494 image_options_sync();
499 layout_refresh(NULL);
502 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
504 toolbar_apply(TOOLBAR_MAIN);
505 toolbar_apply(TOOLBAR_STATUS);
509 *-----------------------------------------------------------------------------
510 * config window main button callbacks (private)
511 *-----------------------------------------------------------------------------
514 static void config_window_close_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
516 gtk_widget_destroy(configwindow);
521 static void config_window_help_cb(GtkWidget *UNUSED(widget), gpointer data)
523 GtkWidget *notebook = static_cast<GtkWidget *>(data);
526 static const gchar *html_section[] =
528 "GuideOptionsGeneral.html",
529 "GuideOptionsImage.html",
530 "GuideOptionsOSD.html",
531 "GuideOptionsWindow.html",
532 "GuideOptionsKeyboard.html",
533 "GuideOptionsFiltering.html",
534 "GuideOptionsMetadata.html",
535 "GuideOptionsKeywords.html",
536 "GuideOptionsColor.html",
537 "GuideOptionsStereo.html",
538 "GuideOptionsBehavior.html",
539 "GuideOptionsToolbar.html",
540 "GuideOptionsToolbar.html",
541 "GuideOptionsAdvanced.html"
544 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
545 help_window_show(html_section[i]);
548 static gboolean config_window_delete(GtkWidget *UNUSED(widget), GdkEventAny *UNUSED(event), gpointer UNUSED(data))
550 config_window_close_cb(NULL, NULL);
554 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
557 GtkNotebook *notebook = static_cast<GtkNotebook *>(data);
565 lw = static_cast<LayoutWindow *>(layout_window_list->data);
567 window = gtk_widget_get_window(widget);
568 gdk_window_get_root_origin(window, &x, &y);
569 w = gdk_window_get_width(window);
570 h = gdk_window_get_height(window);
571 page_number = gtk_notebook_get_current_page(notebook);
573 lw->options.preferences_window.x = x;
574 lw->options.preferences_window.y = y;
575 lw->options.preferences_window.w = w;
576 lw->options.preferences_window.h = h;
577 lw->options.preferences_window.page_number = page_number;
579 config_window_apply();
580 layout_util_sync(lw);
581 save_options(options);
582 config_window_close_cb(NULL, NULL);
586 *-----------------------------------------------------------------------------
587 * config window setup (private)
588 *-----------------------------------------------------------------------------
591 static void quality_menu_cb(GtkWidget *combo, gpointer data)
593 gint *option = static_cast<gint *>(data);
595 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
599 *option = GDK_INTERP_NEAREST;
602 *option = GDK_INTERP_TILES;
605 *option = GDK_INTERP_BILINEAR;
610 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
612 gint *option = static_cast<gint *>(data);
614 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
618 *option = DND_ACTION_ASK;
621 *option = DND_ACTION_COPY;
624 *option = DND_ACTION_MOVE;
628 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
630 gint *option = static_cast<gint *>(data);
632 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
635 *option = CLIPBOARD_PRIMARY;
638 *option = CLIPBOARD_CLIPBOARD;
641 *option = CLIPBOARD_BOTH;
644 *option = CLIPBOARD_BOTH;
648 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
649 guint option, guint *option_c)
656 pref_table_label(table, column, row, text, 0.0);
658 combo = gtk_combo_box_text_new();
660 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
661 if (option == GDK_INTERP_NEAREST) current = 0;
662 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
663 if (option == GDK_INTERP_TILES) current = 1;
664 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
665 if (option == GDK_INTERP_BILINEAR) current = 2;
667 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
669 g_signal_connect(G_OBJECT(combo), "changed",
670 G_CALLBACK(quality_menu_cb), option_c);
672 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
673 gtk_widget_show(combo);
676 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
683 pref_table_label(table, column, row, text, 0.0);
685 combo = gtk_combo_box_text_new();
687 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
688 if (option == DND_ACTION_ASK) current = 0;
689 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
690 if (option == DND_ACTION_COPY) current = 1;
691 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
692 if (option == DND_ACTION_MOVE) current = 2;
694 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
696 g_signal_connect(G_OBJECT(combo), "changed",
697 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
699 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
700 gtk_widget_show(combo);
703 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
704 gint option, gint *option_c)
711 pref_table_label(table, column, row, text, 0.0);
713 combo = gtk_combo_box_text_new();
715 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
716 if (option == CLIPBOARD_PRIMARY) current = 0;
717 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
718 if (option == CLIPBOARD_CLIPBOARD) current = 1;
719 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
720 if (option == CLIPBOARD_BOTH) current = 2;
722 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
724 g_signal_connect(G_OBJECT(combo), "changed",
725 G_CALLBACK(clipboard_selection_menu_cb), option_c);
727 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
728 gtk_widget_show(combo);
731 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
733 gint *option = static_cast<gint *>(data);
735 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
738 *option = ZOOM_GEOMETRIC;
741 *option = ZOOM_ARITHMETIC;
744 *option = ZOOM_GEOMETRIC;
748 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
755 pref_table_label(table, column, row, text, 0.0);
757 combo = gtk_combo_box_text_new();
759 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
760 if (option == ZOOM_GEOMETRIC) current = 0;
761 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
762 if (option == ZOOM_ARITHMETIC) current = 1;
764 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
766 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
768 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
769 gtk_widget_show(combo);
772 typedef struct _UseableMouseItems UseableMouseItems;
773 struct _UseableMouseItems
775 const gchar *name; /* GtkActionEntry terminology */
777 const gchar *stock_id;
780 static const UseableMouseItems useable_mouse_items[] = {
782 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
783 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
784 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
785 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
786 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
787 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
788 {"Home", N_("Home"), GTK_STOCK_HOME},
789 {"Up", N_("Up"), GTK_STOCK_GO_UP},
790 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
791 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
792 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
793 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
794 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
795 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
796 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
797 {"Search", N_("Search"), GTK_STOCK_FIND},
798 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
799 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
800 {"Copy", N_("Copy"), GTK_STOCK_COPY},
801 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
802 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
803 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
804 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
805 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
806 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
807 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
808 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
809 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
810 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
811 {"Print", N_("Print"), GTK_STOCK_PRINT},
812 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
813 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
814 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
815 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
816 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
817 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
818 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
819 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
820 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
821 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
822 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
823 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
824 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
825 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
826 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
827 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
828 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
829 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
830 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
831 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
832 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
833 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
834 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
835 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
836 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
837 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
838 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
839 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
840 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
841 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
842 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
843 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
844 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
845 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
846 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
847 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
848 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
849 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
850 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
854 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
856 gchar **option = static_cast<gchar **>(data);
859 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
861 const UseableMouseItems *list = useable_mouse_items;
865 if (g_strcmp0(list->label, label) == 0)
873 *option = g_strdup(list->name);
877 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
878 gchar *option, gchar **option_c)
886 pref_table_label(table, column, row, text, 0.0);
888 combo = gtk_combo_box_text_new();
890 const UseableMouseItems *list = useable_mouse_items;
894 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
895 if (g_strcmp0(list->name, option) == 0)
903 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
905 g_signal_connect(G_OBJECT(combo), "changed",
906 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
908 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
909 gtk_widget_show(combo);
912 static void thumb_size_menu_cb(GtkWidget *combo, gpointer UNUSED(data))
916 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
919 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
921 c_options->thumbnails.max_width = thumb_size_list[n].w;
922 c_options->thumbnails.max_height = thumb_size_list[n].h;
926 c_options->thumbnails.max_width = options->thumbnails.max_width;
927 c_options->thumbnails.max_height = options->thumbnails.max_height;
931 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
937 c_options->thumbnails.max_width = options->thumbnails.max_width;
938 c_options->thumbnails.max_height = options->thumbnails.max_height;
940 pref_table_label(table, column, row, text, 0.0);
942 combo = gtk_combo_box_text_new();
945 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
950 w = thumb_size_list[i].w;
951 h = thumb_size_list[i].h;
953 buf = g_strdup_printf("%d x %d", w, h);
954 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
957 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
964 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
965 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
971 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
972 g_signal_connect(G_OBJECT(combo), "changed",
973 G_CALLBACK(thumb_size_menu_cb), NULL);
975 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
976 gtk_widget_show(combo);
979 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
981 gint *option = static_cast<gint *>(data);
983 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
987 *option = PR_STEREO_NONE;
990 *option = PR_STEREO_ANAGLYPH_RC;
993 *option = PR_STEREO_ANAGLYPH_GM;
996 *option = PR_STEREO_ANAGLYPH_YB;
999 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
1002 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
1005 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
1008 *option = PR_STEREO_ANAGLYPH_DB_RC;
1011 *option = PR_STEREO_ANAGLYPH_DB_GM;
1014 *option = PR_STEREO_ANAGLYPH_DB_YB;
1017 *option = PR_STEREO_HORIZ;
1020 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1023 *option = PR_STEREO_VERT;
1026 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1029 *option = PR_STEREO_FIXED;
1034 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1035 gint option, gint *option_c, gboolean add_fixed)
1042 pref_table_label(table, column, row, text, 0.0);
1044 combo = gtk_combo_box_text_new();
1046 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1048 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1049 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1050 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1051 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1052 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1053 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1054 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1055 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1057 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1058 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1059 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1061 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1062 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1063 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1064 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1065 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1067 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1068 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1069 if (option & PR_STEREO_HORIZ)
1072 if (option & PR_STEREO_HALF) current = 11;
1075 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1076 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1077 if (option & PR_STEREO_VERT)
1080 if (option & PR_STEREO_HALF) current = 13;
1085 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1086 if (option & PR_STEREO_FIXED) current = 14;
1089 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1091 g_signal_connect(G_OBJECT(combo), "changed",
1092 G_CALLBACK(stereo_mode_menu_cb), option_c);
1094 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1095 gtk_widget_show(combo);
1098 static void video_menu_cb(GtkWidget *combo, gpointer data)
1100 gchar **option = static_cast<gchar **>(data);
1102 EditorDescription *ed = static_cast<EditorDescription *>(g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo))));
1106 static void video_menu_populate(gpointer data, gpointer user_data)
1108 GtkWidget *combo = static_cast<GtkWidget *>(user_data);
1109 EditorDescription *ed = static_cast<EditorDescription *>(data);
1111 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1114 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1115 gchar *option, gchar **option_c)
1119 /* use lists since they are sorted */
1120 GList *eds = editor_list_get();
1124 pref_table_label(table, column, row, text, 0.0);
1126 combo = gtk_combo_box_text_new();
1127 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1128 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1130 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1132 g_signal_connect(G_OBJECT(combo), "changed",
1133 G_CALLBACK(video_menu_cb), option_c);
1135 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1136 gtk_widget_show(combo);
1139 static void filter_store_populate(void)
1143 if (!filter_store) return;
1145 gtk_list_store_clear(filter_store);
1147 work = filter_get_list();
1153 fe = static_cast<FilterEntry *>(work->data);
1156 gtk_list_store_append(filter_store, &iter);
1157 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1161 static void filter_store_ext_edit_cb(GtkCellRendererText *UNUSED(cell), gchar *path_str,
1162 gchar *new_text, gpointer data)
1164 GtkWidget *model = static_cast<GtkWidget *>(data);
1165 FilterEntry *fe = static_cast<FilterEntry *>(data);
1169 if (!new_text || strlen(new_text) < 1) return;
1171 tpath = gtk_tree_path_new_from_string(path_str);
1172 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1173 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1175 g_free(fe->extensions);
1176 fe->extensions = g_strdup(new_text);
1178 gtk_tree_path_free(tpath);
1182 static void filter_store_class_edit_cb(GtkCellRendererText *UNUSED(cell), gchar *path_str,
1183 gchar *new_text, gpointer data)
1185 GtkWidget *model = static_cast<GtkWidget *>(data);
1186 FilterEntry *fe = static_cast<FilterEntry *>(data);
1191 if (!new_text || !new_text[0]) return;
1193 tpath = gtk_tree_path_new_from_string(path_str);
1194 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1195 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1197 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1199 if (strcmp(new_text, _(format_class_list[i])) == 0)
1201 fe->file_class = static_cast<FileFormatClass>(i);
1206 gtk_tree_path_free(tpath);
1210 static void filter_store_desc_edit_cb(GtkCellRendererText *UNUSED(cell), gchar *path_str,
1211 gchar *new_text, gpointer data)
1213 GtkWidget *model = static_cast<GtkWidget *>(data);
1218 if (!new_text || !new_text[0]) return;
1220 tpath = gtk_tree_path_new_from_string(path_str);
1221 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1222 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1224 g_free(fe->description);
1225 fe->description = g_strdup(new_text);
1227 gtk_tree_path_free(tpath);
1230 static void filter_store_enable_cb(GtkCellRendererToggle *UNUSED(renderer),
1231 gchar *path_str, gpointer data)
1233 GtkWidget *model = static_cast<GtkWidget *>(data);
1238 tpath = gtk_tree_path_new_from_string(path_str);
1239 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1240 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1242 fe->enabled = !fe->enabled;
1244 gtk_tree_path_free(tpath);
1248 static void filter_store_writable_cb(GtkCellRendererToggle *UNUSED(renderer),
1249 gchar *path_str, gpointer data)
1251 GtkWidget *model = static_cast<GtkWidget *>(data);
1256 tpath = gtk_tree_path_new_from_string(path_str);
1257 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1258 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1260 fe->writable = !fe->writable;
1261 if (fe->writable) fe->allow_sidecar = FALSE;
1263 gtk_tree_path_free(tpath);
1267 static void filter_store_sidecar_cb(GtkCellRendererToggle *UNUSED(renderer),
1268 gchar *path_str, gpointer data)
1270 GtkWidget *model = static_cast<GtkWidget *>(data);
1275 tpath = gtk_tree_path_new_from_string(path_str);
1276 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1277 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1279 fe->allow_sidecar = !fe->allow_sidecar;
1280 if (fe->allow_sidecar) fe->writable = FALSE;
1282 gtk_tree_path_free(tpath);
1286 static void filter_set_func(GtkTreeViewColumn *UNUSED(tree_column), GtkCellRenderer *cell,
1287 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1291 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1293 switch (GPOINTER_TO_INT(data))
1296 g_object_set(GTK_CELL_RENDERER(cell),
1297 "active", fe->enabled, NULL);
1300 g_object_set(GTK_CELL_RENDERER(cell),
1301 "text", fe->extensions, NULL);
1303 case FE_DESCRIPTION:
1304 g_object_set(GTK_CELL_RENDERER(cell),
1305 "text", fe->description, NULL);
1308 g_object_set(GTK_CELL_RENDERER(cell),
1309 "text", _(format_class_list[fe->file_class]), NULL);
1312 g_object_set(GTK_CELL_RENDERER(cell),
1313 "active", fe->writable, NULL);
1315 case FE_ALLOW_SIDECAR:
1316 g_object_set(GTK_CELL_RENDERER(cell),
1317 "active", fe->allow_sidecar, NULL);
1322 static gboolean filter_add_scroll(gpointer data)
1326 GtkCellRenderer *cell;
1327 GtkTreeViewColumn *column;
1330 GtkTreeModel *store;
1332 FilterEntry *filter;
1334 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1335 path = gtk_tree_path_new_from_indices(rows-1, -1);
1337 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1339 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1340 cell = static_cast<GtkCellRenderer *>(g_list_last(list_cells)->data);
1342 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1343 valid = gtk_tree_model_get_iter_first(store, &iter);
1347 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1349 if (g_strcmp0(filter->extensions, ".new") == 0)
1351 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1355 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1358 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1359 path, column, FALSE, 0.0, 0.0 );
1360 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1361 path, column, cell, TRUE);
1363 gtk_tree_path_free(path);
1364 g_list_free(list_cells);
1369 static void filter_add_cb(GtkWidget *UNUSED(widget), gpointer data)
1371 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1372 filter_store_populate();
1374 g_idle_add((GSourceFunc)filter_add_scroll, data);
1377 static void filter_remove_cb(GtkWidget *UNUSED(widget), gpointer data)
1379 GtkWidget *filter_view = static_cast<GtkWidget *>(data);
1380 GtkTreeSelection *selection;
1384 if (!filter_store) return;
1385 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1386 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1387 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1390 filter_remove_entry(fe);
1392 filter_store_populate();
1395 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1399 GtkTreeViewColumn *column;
1401 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1402 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1403 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1405 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1409 gtk_tree_path_free(path);
1414 static void filter_default_ok_cb(GenericDialog *gd, gpointer UNUSED(data))
1417 filter_add_defaults();
1419 filter_store_populate();
1421 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1424 static void dummy_cancel_cb(GenericDialog *UNUSED(gd), gpointer UNUSED(data))
1426 /* no op, only so cancel button appears */
1429 static void filter_default_cb(GtkWidget *widget, gpointer data)
1433 gd = generic_dialog_new(_("Reset filters"),
1434 "reset_filter", widget, TRUE,
1435 dummy_cancel_cb, data);
1436 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1437 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1438 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1439 gtk_widget_show(gd->dialog);
1442 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1444 GtkWidget *frame = static_cast<GtkWidget *>(data);
1446 gtk_widget_set_sensitive(frame,
1447 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1450 static void safe_delete_view_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
1452 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1455 static void safe_delete_clear_ok_cb(GenericDialog *UNUSED(gd), gpointer UNUSED(data))
1457 file_util_trash_clear();
1460 static void safe_delete_clear_cb(GtkWidget *widget, gpointer UNUSED(data))
1464 gd = generic_dialog_new(_("Clear trash"),
1465 "clear_trash", widget, TRUE,
1466 dummy_cancel_cb, NULL);
1467 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1468 _("This will remove the trash contents."), FALSE);
1469 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1470 entry = gtk_entry_new();
1471 gtk_widget_set_can_focus(entry, FALSE);
1472 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1473 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1474 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1475 gtk_widget_show(entry);
1476 gtk_widget_show(gd->dialog);
1479 static void image_overlay_template_view_changed_cb(GtkWidget *UNUSED(widget), gpointer data)
1481 GtkWidget *pTextView;
1482 GtkTextBuffer *pTextBuffer;
1486 pTextView = GTK_WIDGET(data);
1488 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1489 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1490 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1492 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1493 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1496 static void image_overlay_default_template_ok_cb(GenericDialog *UNUSED(gd), gpointer data)
1498 GtkTextView *text_view = static_cast<GtkTextView *>(data);
1499 GtkTextBuffer *buffer;
1501 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1502 if (!configwindow) return;
1504 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1505 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1508 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1512 gd = generic_dialog_new(_("Reset image overlay template string"),
1513 "reset_image_overlay_template_string", widget, TRUE,
1514 dummy_cancel_cb, data);
1515 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1516 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1517 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1518 gtk_widget_show(gd->dialog);
1521 static void image_overlay_help_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
1523 help_window_show("GuideOptionsOSD.html");
1526 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer UNUSED(data))
1530 PangoFontDescription *font_desc;
1532 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1533 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1535 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1537 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1538 font = pango_font_description_to_string(font_desc);
1539 g_free(c_options->image_overlay.font);
1540 c_options->image_overlay.font = g_strdup(font);
1544 gtk_widget_destroy(dialog);
1547 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer UNUSED(data))
1552 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1553 colour.red = options->image_overlay.text_red;
1554 colour.green = options->image_overlay.text_green;
1555 colour.blue = options->image_overlay.text_blue;
1556 colour.alpha = options->image_overlay.text_alpha;
1557 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1558 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1560 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1562 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1563 c_options->image_overlay.text_red = colour.red*255;
1564 c_options->image_overlay.text_green = colour.green*255;
1565 c_options->image_overlay.text_blue = colour.blue*255;
1566 c_options->image_overlay.text_alpha = colour.alpha*255;
1568 gtk_widget_destroy(dialog);
1572 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer UNUSED(data))
1577 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1578 colour.red = options->image_overlay.background_red;
1579 colour.green = options->image_overlay.background_green;
1580 colour.blue = options->image_overlay.background_blue;
1581 colour.alpha = options->image_overlay.background_alpha;
1582 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1583 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1585 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1587 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1588 c_options->image_overlay.background_red = colour.red*255;
1589 c_options->image_overlay.background_green = colour.green*255;
1590 c_options->image_overlay.background_blue = colour.blue*255;
1591 c_options->image_overlay.background_alpha = colour.alpha*255;
1593 gtk_widget_destroy(dialog);
1596 static void accel_store_populate(void)
1599 GList *groups, *actions;
1601 const gchar *accel_path;
1605 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1607 gtk_tree_store_clear(accel_store);
1608 lw = static_cast<LayoutWindow *>(layout_window_list->data); /* get the actions from the first window, it should not matter, they should be the same in all windows */
1610 g_assert(lw && lw->ui_manager);
1611 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1614 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1617 action = GTK_ACTION(actions->data);
1618 accel_path = gtk_action_get_accel_path(action);
1619 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1621 gchar *label, *label2, *tooltip, *accel;
1622 g_object_get(action,
1623 "tooltip", &tooltip,
1627 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1633 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1637 gtk_tree_store_append(accel_store, &iter, NULL);
1638 gtk_tree_store_set(accel_store, &iter,
1641 AE_TOOLTIP, tooltip ? tooltip : "",
1642 AE_ACCEL, accel_path,
1650 actions = actions->next;
1653 groups = groups->next;
1657 static void accel_store_cleared_cb(GtkCellRendererAccel *UNUSED(accel), gchar *UNUSED(path_string), gpointer UNUSED(user_data))
1662 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer data)
1664 gchar *accel1 = static_cast<gchar *>(data);
1669 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1671 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1672 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1674 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1676 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1677 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1686 static void accel_store_edited_cb(GtkCellRendererAccel *UNUSED(accel), gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint UNUSED(hardware_keycode), gpointer UNUSED(user_data))
1688 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1692 GtkAccelKey old_key, key;
1693 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1695 gtk_tree_model_get_iter(model, &iter, path);
1696 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1698 /* test if the accelerator can be stored without conflicts*/
1699 gtk_accel_map_lookup_entry(accel_path, &old_key);
1701 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1702 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1703 gtk_accel_map_lookup_entry(accel_path, &key);
1705 /* restore the original for now, the key will be really changed when the changes are confirmed */
1706 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1708 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1709 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1711 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1712 gtk_tree_path_free(path);
1716 static gboolean accel_default_scroll(GtkTreeView *data)
1720 GtkTreeViewColumn *column;
1722 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1723 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1724 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1726 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1730 gtk_tree_path_free(path);
1735 static void accel_default_cb(GtkWidget *UNUSED(widget), gpointer data)
1737 accel_store_populate();
1739 g_idle_add((GSourceFunc)accel_default_scroll, data);
1742 //void accel_remove_selection(GtkTreeModel *UNUSED(model), GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
1744 //gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1747 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
1750 gchar *accel_path, *accel;
1752 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1753 gtk_accel_map_lookup_entry(accel_path, &key);
1754 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1756 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1758 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1763 static void accel_reset_cb(GtkWidget *UNUSED(widget), gpointer data)
1765 GtkTreeSelection *selection;
1767 if (!accel_store) return;
1768 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1769 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1774 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1778 GtkWidget *scrolled;
1779 GtkWidget *viewport;
1781 scrolled = gtk_scrolled_window_new(NULL, NULL);
1782 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1783 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1784 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1785 label = gtk_label_new(title);
1786 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1787 gtk_widget_show(scrolled);
1789 viewport = gtk_viewport_new(NULL, NULL);
1790 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1791 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1792 gtk_widget_show(viewport);
1794 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1795 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1796 gtk_widget_show(vbox);
1801 static void cache_standard_cb(GtkWidget *widget, gpointer UNUSED(data))
1803 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1805 c_options->thumbnails.spec_standard =TRUE;
1806 c_options->thumbnails.cache_into_dirs = FALSE;
1810 static void cache_geeqie_cb(GtkWidget *widget, gpointer UNUSED(data))
1812 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1814 c_options->thumbnails.spec_standard =FALSE;
1815 c_options->thumbnails.cache_into_dirs = FALSE;
1819 static void cache_local_cb(GtkWidget *widget, gpointer UNUSED(data))
1821 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1823 c_options->thumbnails.cache_into_dirs = TRUE;
1824 c_options->thumbnails.spec_standard =FALSE;
1828 static void help_search_engine_entry_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1829 GdkEvent *UNUSED(event), gpointer userdata)
1831 if (pos == GTK_ENTRY_ICON_PRIMARY)
1833 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1837 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1841 static void star_rating_star_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1842 GdkEvent *UNUSED(event), gpointer userdata)
1844 gchar *rating_symbol;
1846 if (pos == GTK_ENTRY_ICON_PRIMARY)
1848 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1849 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1850 g_free(rating_symbol);
1854 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1855 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1856 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1860 static void star_rating_rejected_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1861 GdkEvent *UNUSED(event), gpointer userdata)
1863 gchar *rating_symbol;
1865 if (pos == GTK_ENTRY_ICON_PRIMARY)
1867 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1868 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1869 g_free(rating_symbol);
1873 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1874 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1875 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1879 static guint star_rating_symbol_test(GtkWidget *UNUSED(widget), gpointer data)
1881 GtkContainer *hbox = static_cast<GtkContainer *>(data);
1882 GString *str = g_string_new(NULL);
1883 GtkEntry *hex_code_entry;
1884 gchar *hex_code_full;
1887 guint64 hex_value = 0;
1889 list = gtk_container_get_children(hbox);
1891 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1892 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1894 hex_code = g_strsplit(hex_code_full, "+", 2);
1895 if (hex_code[0] && hex_code[1])
1897 hex_value = strtoull(hex_code[1], NULL, 16);
1899 if (!hex_value || hex_value > 0x10FFFF)
1901 hex_value = 0x003F; // Unicode 'Question Mark'
1903 str = g_string_append_unichar(str, (gunichar)hex_value);
1904 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1906 g_strfreev(hex_code);
1907 g_string_free(str, TRUE);
1908 g_free(hex_code_full);
1913 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1915 guint64 star_symbol;
1917 star_symbol = star_rating_symbol_test(widget, data);
1918 c_options->star_rating.star = star_symbol;
1921 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1923 guint64 rejected_symbol;
1925 rejected_symbol = star_rating_symbol_test(widget, data);
1926 c_options->star_rating.rejected = rejected_symbol;
1929 /* general options tab */
1930 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1931 typedef struct _TZData TZData;
1935 GCancellable *cancellable;
1937 GtkWidget *progress;
1939 GFile *timezone_database_gq;
1940 gchar *timezone_database_user;
1943 static void config_tab_general(GtkWidget *notebook)
1948 GtkWidget *group_frame;
1949 GtkWidget *subgroup;
1951 GtkWidget *ct_button;
1954 gint hours, minutes, remainder;
1956 GtkWidget *star_rating_entry;
1958 gchar *rating_symbol;
1961 gchar *download_locn;
1962 GNetworkMonitor *net_mon;
1963 GSocketConnectable *tz_org;
1964 gboolean internet_available = FALSE;
1967 vbox = scrolled_notebook_page(notebook, _("General"));
1969 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1971 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1972 add_thumb_size_menu(table, 0, 0, _("Size:"));
1973 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1975 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1976 pref_label_new(hbox, _("Custom size: "));
1977 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1978 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1980 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1981 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1983 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1984 pref_checkbox_link_sensitivity(ct_button, subgroup);
1986 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1987 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1988 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1989 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1990 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1991 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1992 G_CALLBACK(cache_geeqie_cb), NULL);
1994 group_frame = pref_frame_new(subgroup, TRUE,
1995 _("Store thumbnails local to image folder (non-standard)"),
1996 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1997 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1998 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1999 G_CALLBACK(cache_local_cb), NULL);
2001 group_frame = pref_frame_new(subgroup, TRUE,
2002 _("Use standard thumbnail style and cache, shared with other applications"),
2003 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2004 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2005 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2006 G_CALLBACK(cache_standard_cb), NULL);
2008 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2009 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2011 pref_checkbox_new_int(group, _("Thumbnail color management"),
2012 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2014 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2016 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2017 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2019 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2020 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2021 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2023 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2024 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2027 pref_spacer(group, PREF_PAD_GROUP);
2029 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2031 c_options->star_rating.star = options->star_rating.star;
2032 c_options->star_rating.rejected = options->star_rating.rejected;
2034 str = g_string_new(NULL);
2035 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2036 pref_label_new(hbox, _("Star character: "));
2037 str = g_string_append_unichar(str, options->star_rating.star);
2038 pref_label_new(hbox, g_strdup(str->str));
2039 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2040 star_rating_entry = gtk_entry_new();
2041 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2042 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2043 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2044 gtk_widget_show(star_rating_entry);
2045 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2046 G_CALLBACK(star_rating_star_test_cb), hbox);
2047 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2048 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2049 gtk_widget_show(button);
2050 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."));
2051 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2052 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2053 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2054 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2055 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2056 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2057 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2058 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2059 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2060 G_CALLBACK(star_rating_star_icon_cb),
2063 g_string_free(str, TRUE);
2064 g_free(rating_symbol);
2066 str = g_string_new(NULL);
2067 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2068 pref_label_new(hbox, _("Rejected character: "));
2069 str = g_string_append_unichar(str, options->star_rating.rejected);
2070 pref_label_new(hbox, g_strdup(str->str));
2071 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2072 star_rating_entry = gtk_entry_new();
2073 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2074 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2075 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2076 gtk_widget_show(star_rating_entry);
2077 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2078 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2079 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2080 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2081 gtk_widget_show(button);
2082 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."));
2083 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2084 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2085 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2086 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2087 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2088 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2089 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2090 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2091 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2092 G_CALLBACK(star_rating_rejected_icon_cb),
2095 g_string_free(str, TRUE);
2096 g_free(rating_symbol);
2098 pref_spacer(group, PREF_PAD_GROUP);
2100 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2102 c_options->slideshow.delay = options->slideshow.delay;
2103 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2104 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2105 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2106 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2107 SLIDESHOW_SUBSECOND_PRECISION;
2109 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2111 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2113 options->slideshow.delay ? hours : 0.0,
2114 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2115 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2116 spin = pref_spin_new(hbox, ":" , NULL,
2118 options->slideshow.delay ? minutes: 0.0,
2119 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2120 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2121 spin = pref_spin_new(hbox, ":", NULL,
2122 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2123 options->slideshow.delay ? seconds : 10.0,
2124 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2125 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2127 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2128 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2130 pref_spacer(group, PREF_PAD_GROUP);
2132 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2134 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2135 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2136 pref_checkbox_new_int(group, _("Preload next image"),
2137 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2139 pref_checkbox_new_int(group, _("Refresh on file change"),
2140 options->update_on_time_change, &c_options->update_on_time_change);
2143 pref_spacer(group, PREF_PAD_GROUP);
2145 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2147 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2148 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2149 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2151 pref_spacer(group, PREF_PAD_GROUP);
2153 if (g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
2155 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2156 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2157 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2158 gtk_widget_set_tooltip_text(group, _("Show a notification on start-up if the server has a newer version than the current. Requires an Internet connection"));
2160 pref_spacer(group, PREF_PAD_GROUP);
2164 net_mon = g_network_monitor_get_default();
2165 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, NULL);
2168 internet_available = g_network_monitor_can_reach(net_mon, tz_org, NULL, NULL);
2169 g_object_unref(tz_org);
2172 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2173 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2175 if (!internet_available)
2177 gtk_widget_set_sensitive(group, FALSE);
2180 tz = g_new0(TZData, 1);
2182 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2183 basename = g_path_get_basename(path);
2184 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2188 if (isfile(tz->timezone_database_user))
2190 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2194 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2197 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2198 pref_label_new(GTK_WIDGET(hbox), download_locn);
2199 g_free(download_locn);
2201 if (!internet_available)
2203 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"));
2207 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"));
2209 gtk_widget_show(button);
2211 pref_spacer(group, PREF_PAD_GROUP);
2213 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2215 help_search_engine_entry = gtk_entry_new();
2216 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2217 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2218 gtk_widget_show(help_search_engine_entry);
2220 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"));
2222 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2223 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2224 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2225 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2226 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2227 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2228 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2229 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2230 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2231 G_CALLBACK(help_search_engine_entry_icon_cb),
2232 help_search_engine_entry);
2236 static void config_tab_image(GtkWidget *notebook)
2241 GtkWidget *ct_button;
2242 GtkWidget *enlargement_button;
2245 //~ #ifdef HAVE_CLUTTER
2246 //~ GtkWidget *gpu_accel;
2249 vbox = scrolled_notebook_page(notebook, _("Image"));
2251 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2253 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2254 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2255 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2257 //~ gtk_widget_set_sensitive(table, FALSE);
2260 //~ #ifdef HAVE_CLUTTER
2261 //~ gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2262 //~ options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2263 //~ if (options->disable_gpu && !options->override_disable_gpu)
2265 //~ gtk_widget_set_sensitive(gpu_accel, FALSE);
2269 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2270 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2271 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2273 //~ gtk_widget_set_sensitive(two_pass, FALSE);
2276 c_options->image.zoom_increment = options->image.zoom_increment;
2277 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2278 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2279 G_CALLBACK(zoom_increment_cb), NULL);
2280 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2282 c_options->image.zoom_style = options->image.zoom_style;
2283 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2284 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2286 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2288 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2289 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2290 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2291 spin = pref_spin_new_int(hbox, NULL, NULL,
2293 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2294 pref_checkbox_link_sensitivity(enlargement_button, spin);
2295 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."));
2297 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2298 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2299 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2300 spin = pref_spin_new_int(hbox, NULL, NULL,
2302 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2303 pref_checkbox_link_sensitivity(ct_button, spin);
2304 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."));
2306 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2307 //~ gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2309 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2310 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2312 options->image.tile_size, &c_options->image.tile_size);
2313 gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value changes the size of the tiles large images are split into. Increasing the size of the tiles will reduce the tiling effect seen on image changes, but will also slightly increase the delay before the first part of a large image is seen."));
2315 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2317 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2318 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2320 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2321 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2323 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2324 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2326 c_options->image.border_color = options->image.border_color;
2328 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2329 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2331 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2332 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2334 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2335 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2340 static void save_default_window_layout_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
2342 LayoutWindow *lw = NULL;
2343 gchar *default_path;
2346 /* Get current lw */
2349 tmp_id = lw->options.id;
2350 lw->options.id = g_strdup("lw_default");
2352 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2353 save_default_layout_options_to_file(default_path, options, lw);
2354 g_free(lw->options.id);
2355 lw->options.id = tmp_id;
2356 g_free(default_path);
2359 static gboolean popover_cb(gpointer data)
2361 GtkPopover *popover = static_cast<GtkPopover *>(data);
2363 gtk_popover_popdown(popover);
2368 static void default_layout_changed_cb(GtkWidget *UNUSED(button), GtkPopover *popover)
2370 gtk_popover_popup(popover);
2372 g_timeout_add(2000, popover_cb, popover);
2375 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2379 popover = gtk_popover_new(parent);
2380 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2381 gtk_container_add (GTK_CONTAINER(popover), child);
2382 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2383 gtk_widget_show (child);
2388 static void config_tab_windows(GtkWidget *notebook)
2393 GtkWidget *subgroup;
2395 GtkWidget *ct_button;
2398 vbox = scrolled_notebook_page(notebook, _("Windows"));
2400 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2402 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2403 options->save_window_positions, &c_options->save_window_positions);
2405 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2406 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2407 pref_checkbox_link_sensitivity(ct_button, button);
2409 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2410 options->save_window_workspace, &c_options->save_window_workspace);
2411 pref_checkbox_link_sensitivity(ct_button, button);
2413 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2414 options->tools_restore_state, &c_options->tools_restore_state);
2416 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2417 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2419 pref_checkbox_new_int(group, _("Show window IDs"),
2420 options->show_window_ids, &c_options->show_window_ids);
2422 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2423 pref_label_new(subgroup, _("Use current layout for default: "));
2424 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2428 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2429 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2430 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2432 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2434 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2435 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2437 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2438 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2439 options->image.limit_window_size, &c_options->image.limit_window_size);
2440 spin = pref_spin_new_int(hbox, NULL, NULL,
2442 options->image.max_window_size, &c_options->image.max_window_size);
2443 pref_checkbox_link_sensitivity(ct_button, spin);
2445 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2447 c_options->fullscreen.screen = options->fullscreen.screen;
2448 c_options->fullscreen.above = options->fullscreen.above;
2449 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2450 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2451 gtk_widget_show(hbox);
2453 pref_checkbox_new_int(group, _("Smooth image flip"),
2454 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2455 pref_checkbox_new_int(group, _("Disable screen saver"),
2456 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2459 #define PRE_FORMATTED_COLUMNS 5
2460 static void config_tab_osd(GtkWidget *notebook)
2466 GtkWidget *image_overlay_template_view;
2467 GtkWidget *scrolled;
2468 GtkWidget *scrolled_pre_formatted;
2469 GtkTextBuffer *buffer;
2471 GtkWidget *subgroup;
2473 vbox = scrolled_notebook_page(notebook, _("OSD"));
2475 image_overlay_template_view = gtk_text_view_new();
2477 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2479 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2481 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2482 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2483 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2484 gtk_widget_show(scrolled_pre_formatted);
2485 gtk_widget_show(subgroup);
2487 pref_line(group, PREF_PAD_GAP);
2489 pref_label_new(group, _("Image overlay template"));
2491 scrolled = gtk_scrolled_window_new(NULL, NULL);
2492 gtk_widget_set_size_request(scrolled, 200, 150);
2493 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2494 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2495 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2496 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2497 gtk_widget_show(scrolled);
2499 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2500 _("Extensive formatting options are shown in the Help file"));
2502 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2503 gtk_widget_show(image_overlay_template_view);
2505 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2507 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2508 G_CALLBACK(image_overlay_set_font_cb), notebook);
2510 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2511 gtk_widget_show(button);
2513 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2514 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2515 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2516 gtk_widget_show(button);
2518 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2519 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2520 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2521 gtk_widget_show(button);
2522 image_overlay_set_text_colours();
2524 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2525 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2526 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2527 gtk_widget_show(button);
2529 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2530 G_CALLBACK(image_overlay_help_cb), NULL);
2531 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2532 gtk_widget_show(button);
2534 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2535 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2536 g_signal_connect(G_OBJECT(buffer), "changed",
2537 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2539 pref_line(group, PREF_PAD_GAP);
2541 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2542 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2543 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2544 gtk_widget_show(hbox);
2545 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2546 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2547 gtk_widget_show(label);
2548 pref_spacer(group,TRUE);
2550 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2551 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2552 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2553 gtk_widget_show(hbox);
2554 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2555 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2556 gtk_widget_show(label);
2557 pref_spacer(group,TRUE);
2559 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2560 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2561 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2562 gtk_widget_show(hbox);
2563 label = gtk_label_new(_("%path:39%"));
2564 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2565 gtk_widget_show(label);
2566 pref_spacer(group,TRUE);
2568 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2569 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2570 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2571 gtk_widget_show(hbox);
2572 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%"));
2573 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2574 gtk_widget_show(label);
2575 pref_spacer(group,TRUE);
2577 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2578 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2579 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2580 gtk_widget_show(hbox);
2581 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2582 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2583 gtk_widget_show(label);
2586 static GtkTreeModel *create_class_model(void)
2588 GtkListStore *model;
2592 /* create list store */
2593 model = gtk_list_store_new(1, G_TYPE_STRING);
2594 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2596 gtk_list_store_append(model, &iter);
2597 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2599 return GTK_TREE_MODEL (model);
2604 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2606 gint n = GPOINTER_TO_INT(data);
2608 FilterEntry *filter_a;
2609 FilterEntry *filter_b;
2611 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2612 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2616 case FILETYPES_COLUMN_ENABLED:
2618 ret = filter_a->enabled - filter_b->enabled;
2621 case FILETYPES_COLUMN_FILTER:
2623 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2626 case FILETYPES_COLUMN_DESCRIPTION:
2628 ret = g_utf8_collate(filter_a->description, filter_b->description);
2631 case FILETYPES_COLUMN_CLASS:
2633 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2636 case FILETYPES_COLUMN_WRITABLE:
2638 ret = filter_a->writable - filter_b->writable;
2641 case FILETYPES_COLUMN_SIDECAR:
2643 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2647 g_return_val_if_reached(0);
2653 static gboolean search_function_cb(GtkTreeModel *model, gint UNUSED(column), const gchar *key, GtkTreeIter *iter, gpointer UNUSED(search_data))
2656 gboolean ret = TRUE;
2658 gtk_tree_model_get(model, iter, 0, &fe, -1);
2660 if (g_strstr_len(fe->extensions, -1, key))
2668 static void config_tab_files(GtkWidget *notebook)
2675 GtkWidget *ct_button;
2676 GtkWidget *scrolled;
2677 GtkWidget *filter_view;
2678 GtkCellRenderer *renderer;
2679 GtkTreeSelection *selection;
2680 GtkTreeViewColumn *column;
2682 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2684 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2686 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2687 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2688 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2689 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2690 pref_checkbox_new_int(group, _("Case sensitive sort"),
2691 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2692 pref_checkbox_new_int(group, _("Natural sort order - Requires restart"),
2693 options->file_sort.natural, &c_options->file_sort.natural);
2694 pref_checkbox_new_int(group, _("Disable file extension checks"),
2695 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2697 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2698 options->file_filter.disable, &c_options->file_filter.disable);
2701 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2703 sidecar_ext_entry = gtk_entry_new();
2704 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2705 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2706 gtk_widget_show(sidecar_ext_entry);
2708 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2710 frame = pref_group_parent(group);
2711 g_signal_connect(G_OBJECT(ct_button), "toggled",
2712 G_CALLBACK(filter_disable_cb), frame);
2713 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2715 scrolled = gtk_scrolled_window_new(NULL, NULL);
2716 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2717 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2718 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2719 gtk_widget_show(scrolled);
2721 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2722 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2723 g_object_unref(filter_store);
2724 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2725 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2727 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2729 column = gtk_tree_view_column_new();
2730 gtk_tree_view_column_set_title(column, _("Enabled"));
2731 gtk_tree_view_column_set_resizable(column, TRUE);
2733 renderer = gtk_cell_renderer_toggle_new();
2734 g_signal_connect(G_OBJECT(renderer), "toggled",
2735 G_CALLBACK(filter_store_enable_cb), filter_store);
2736 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2737 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2738 GINT_TO_POINTER(FE_ENABLE), NULL);
2739 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_ENABLED, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_ENABLED), NULL);
2740 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2741 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2743 column = gtk_tree_view_column_new();
2744 gtk_tree_view_column_set_title(column, _("Filter"));
2745 gtk_tree_view_column_set_resizable(column, TRUE);
2746 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_FILTER, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_FILTER), NULL);
2747 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2749 renderer = gtk_cell_renderer_text_new();
2750 g_signal_connect(G_OBJECT(renderer), "edited",
2751 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2752 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2753 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2754 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2755 GINT_TO_POINTER(FE_EXTENSION), NULL);
2756 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2758 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2759 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2760 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, NULL, NULL);
2762 column = gtk_tree_view_column_new();
2763 gtk_tree_view_column_set_title(column, _("Description"));
2764 gtk_tree_view_column_set_resizable(column, TRUE);
2765 gtk_tree_view_column_set_fixed_width(column, 200);
2766 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2768 renderer = gtk_cell_renderer_text_new();
2769 g_signal_connect(G_OBJECT(renderer), "edited",
2770 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2771 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2772 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2773 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2774 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2775 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2776 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_DESCRIPTION, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_DESCRIPTION), NULL);
2777 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2779 column = gtk_tree_view_column_new();
2780 gtk_tree_view_column_set_title(column, _("Class"));
2781 gtk_tree_view_column_set_resizable(column, TRUE);
2782 renderer = gtk_cell_renderer_combo_new();
2783 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2784 "model", create_class_model(),
2789 g_signal_connect(G_OBJECT(renderer), "edited",
2790 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2791 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2792 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2793 GINT_TO_POINTER(FE_CLASS), NULL);
2794 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2795 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_CLASS, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_CLASS), NULL);
2796 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2798 column = gtk_tree_view_column_new();
2799 gtk_tree_view_column_set_title(column, _("Writable"));
2800 gtk_tree_view_column_set_resizable(column, FALSE);
2801 renderer = gtk_cell_renderer_toggle_new();
2802 g_signal_connect(G_OBJECT(renderer), "toggled",
2803 G_CALLBACK(filter_store_writable_cb), filter_store);
2804 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2805 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2806 GINT_TO_POINTER(FE_WRITABLE), NULL);
2807 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2808 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_WRITABLE, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_WRITABLE), NULL);
2809 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2811 column = gtk_tree_view_column_new();
2812 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2813 gtk_tree_view_column_set_resizable(column, FALSE);
2814 renderer = gtk_cell_renderer_toggle_new();
2815 g_signal_connect(G_OBJECT(renderer), "toggled",
2816 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2817 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2818 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2819 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2820 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2821 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_SIDECAR, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_SIDECAR), NULL);
2822 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2824 filter_store_populate();
2825 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2826 gtk_widget_show(filter_view);
2828 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2830 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2831 G_CALLBACK(filter_default_cb), filter_view);
2832 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2833 gtk_widget_show(button);
2835 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2836 G_CALLBACK(filter_remove_cb), filter_view);
2837 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2838 gtk_widget_show(button);
2840 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2841 G_CALLBACK(filter_add_cb), filter_view);
2842 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2843 gtk_widget_show(button);
2847 static void config_tab_metadata(GtkWidget *notebook)
2852 GtkWidget *ct_button;
2854 GtkWidget *tmp_widget;
2856 GtkWidget *text_label;
2858 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2861 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2863 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2865 label = pref_label_new(group, _("When writing metadata, Geeqie will follow these steps, if selected. This process will stop when the first successful write occurs."));
2866 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2867 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2869 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2871 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2872 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2873 markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>%s", _("Step 1"), _(") Save metadata in either the image file or the sidecar file, according to the XMP standard"));
2874 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2876 markup = g_markup_printf_escaped ("%s<span style=\"italic\">%s</span>%s<span style=\"italic\">%s</span>%s", _("The destination is dependent on the settings in the "), _("Writable"), _(" and "), _("Sidecar Is Allowed"), _(" columns of the File Filters tab)"));
2877 gtk_widget_set_tooltip_markup(ct_button, markup);
2881 gtk_widget_set_sensitive(ct_button, FALSE);
2884 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2885 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2886 markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>%s<span style=\"italic\">%s</span>%s", _("Step 2"), _(") Save metadata in the folder "),".metadata,", _(" local to the image folder (non-standard)"));
2887 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2890 label = pref_label_new(group, "");
2891 markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>%s<span style=\"italic\">%s</span>%s", _("Step 3"), _(") Save metadata in Geeqie private directory "), get_metadata_cache_dir(), "/");
2892 gtk_label_set_markup (GTK_LABEL(label), markup);
2895 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2896 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2897 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2898 pref_spacer(group, PREF_PAD_GROUP);
2900 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2902 gtk_widget_set_sensitive(group, FALSE);
2905 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2906 pref_checkbox_link_sensitivity(ct_button, hbox);
2908 tmp_widget= pref_checkbox_new_int(hbox, _("Store metadata also in IPTC tags (converted according to the IPTC4XMP standard)"), options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2909 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2911 pref_checkbox_new_int(hbox, _("Warn if the image or sidecar file is not writable"), options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2913 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2915 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2916 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2917 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2918 markup = g_markup_printf_escaped ("%s<span style=\"italic\">%s</span>%s<span style=\"italic\">%s</span>%s", _("Create sidecar files named "), "image.ext.xmp", _(" (as opposed to the normal "), "image.xmp", ")");
2919 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2922 pref_spacer(group, PREF_PAD_GROUP);
2924 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2926 gtk_widget_set_sensitive(group, FALSE);
2929 pref_checkbox_new_int(group, _("Use GQview legacy metadata format instead of XMP (supports only Keywords and Comments)"), options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2931 pref_spacer(group, PREF_PAD_GROUP);
2933 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2934 tmp_widget = pref_checkbox_new_int(group, _("Write the same description tags to all grouped sidecars"), options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2935 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2937 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2938 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2940 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2941 gtk_widget_set_tooltip_text(ct_button, _("If checked, the results of orientation commands (Rotate, Mirror and Flip) issued on an image will be written to metadata\nNote: If this option is not checked, the results of orientation commands will be lost when Geeqie closes"));
2944 gtk_widget_set_sensitive(ct_button, FALSE);
2947 pref_spacer(group, PREF_PAD_GROUP);
2949 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2951 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2953 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2954 pref_checkbox_link_sensitivity(ct_button, hbox);
2956 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2958 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2960 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2962 pref_spacer(group, PREF_PAD_GROUP);
2965 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2967 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
2968 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
2971 pref_spacer(group, PREF_PAD_GROUP);
2973 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2975 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2976 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");
2981 typedef struct _KeywordFindData KeywordFindData;
2982 struct _KeywordFindData
2989 GtkWidget *button_close;
2990 GtkWidget *button_stop;
2991 GtkWidget *button_start;
2992 GtkWidget *progress;
3000 guint idle_id; /* event source id */
3003 #define KEYWORD_DIALOG_WIDTH 400
3005 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3007 GList *list_d = NULL;
3008 GList *list_f = NULL;
3012 filelist_read(dir_fd, &list_f, &list_d);
3016 filelist_read(dir_fd, &list_f, NULL);
3019 list_f = filelist_filter(list_f, FALSE);
3020 list_d = filelist_filter(list_d, TRUE);
3022 kfd->list = g_list_concat(list_f, kfd->list);
3023 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3026 static void keywords_find_reset(KeywordFindData *kfd)
3028 filelist_free(kfd->list);
3031 filelist_free(kfd->list_dir);
3032 kfd->list_dir = NULL;
3035 static void keywords_find_close_cb(GenericDialog *UNUSED(fd), gpointer data)
3037 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3039 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3041 keywords_find_reset(kfd);
3042 generic_dialog_close(kfd->gd);
3046 static void keywords_find_finish(KeywordFindData *kfd)
3048 keywords_find_reset(kfd);
3050 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3051 spinner_set_interval(kfd->spinner, -1);
3053 gtk_widget_set_sensitive(kfd->group, TRUE);
3054 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3055 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3056 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3059 static void keywords_find_stop_cb(GenericDialog *UNUSED(fd), gpointer data)
3061 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3063 g_idle_remove_by_data(kfd);
3065 keywords_find_finish(kfd);
3068 static gboolean keywords_find_file(gpointer data)
3070 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3072 GtkTextBuffer *buffer;
3080 fd = static_cast<FileData *>(kfd->list->data);
3081 kfd->list = g_list_remove(kfd->list, fd);
3083 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3084 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3088 gtk_text_buffer_get_end_iter(buffer, &iter);
3089 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3090 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3092 keywords = keywords->next;
3095 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3096 file_data_unref(fd);
3097 string_list_free(keywords);
3101 else if (kfd->list_dir)
3105 fd = static_cast<FileData *>(kfd->list_dir->data);
3106 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3108 keywords_find_folder(kfd, fd);
3110 file_data_unref(fd);
3115 keywords_find_finish(kfd);
3120 static void keywords_find_start_cb(GenericDialog *UNUSED(fd), gpointer data)
3122 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3125 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3127 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3128 parse_out_relatives(path);
3132 warning_dialog(_("Invalid folder"),
3133 _("The specified folder can not be found."),
3134 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3140 gtk_widget_set_sensitive(kfd->group, FALSE);
3141 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3142 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3143 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3144 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3146 dir_fd = file_data_new_dir(path);
3147 keywords_find_folder(kfd, dir_fd);
3148 file_data_unref(dir_fd);
3149 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3155 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3157 KeywordFindData *kfd;
3161 kfd = g_new0(KeywordFindData, 1);
3163 kfd->gd = generic_dialog_new(_("Search for keywords"),
3164 "search_for_keywords",
3167 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3168 kfd->gd->cancel_cb = keywords_find_close_cb;
3169 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3170 keywords_find_close_cb, FALSE);
3171 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3172 keywords_find_start_cb, FALSE);
3173 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3174 keywords_find_stop_cb, FALSE);
3175 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3177 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3179 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3180 pref_spacer(hbox, PREF_PAD_INDENT);
3181 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3183 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3184 pref_label_new(hbox, _("Folder:"));
3186 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3187 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3188 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3189 gtk_widget_show(label);
3191 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3193 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3194 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3196 kfd->progress = gtk_entry_new();
3197 gtk_widget_set_can_focus(kfd->progress, FALSE);
3198 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3199 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3200 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3201 gtk_widget_show(kfd->progress);
3203 kfd->spinner = spinner_new(NULL, -1);
3204 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3205 gtk_widget_show(kfd->spinner);
3209 gtk_widget_show(kfd->gd->dialog);
3212 static void keywords_find_cb(GtkWidget *widget, gpointer UNUSED(data))
3214 const gchar *path = layout_get_path(NULL);
3216 if (!path || !*path) path = homedir();
3217 keywords_find_dialog(widget, path);
3220 static void config_tab_keywords_save()
3222 GtkTextIter start, end;
3223 GtkTextBuffer *buffer;
3224 GList *kw_list = NULL;
3230 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3231 gtk_text_buffer_get_bounds(buffer, &start, &end);
3233 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3235 kw_split = strtok(buffer_text, "\n");
3236 while (kw_split != NULL)
3242 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3251 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3253 kw_split = strtok(NULL, "\n");
3256 keyword_list_set(kw_list);
3258 string_list_free(kw_list);
3259 g_free(buffer_text);
3262 static void config_tab_keywords(GtkWidget *notebook)
3268 GtkWidget *scrolled;
3270 GtkTextBuffer *buffer;
3273 GspellTextView *gspell_view;
3276 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3278 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3280 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3282 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3283 G_CALLBACK(keywords_find_cb), keyword_text);
3284 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3287 keyword_text = gtk_text_view_new();
3288 gtk_widget_set_size_request(keyword_text, 20, 20);
3289 scrolled = gtk_scrolled_window_new(NULL, NULL);
3290 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3291 gtk_widget_show(scrolled);
3294 if (options->metadata.check_spelling)
3296 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3297 gspell_text_view_basic_setup(gspell_view);
3301 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3302 gtk_widget_show(keyword_text);
3304 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3306 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3307 gtk_text_buffer_create_tag(buffer, "monospace",
3308 "family", "monospace", NULL);
3310 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3311 gtk_text_buffer_get_start_iter(buffer, &iter);
3312 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3315 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3317 GList *kwl = keyword_list_get();
3318 kwl = g_list_first(kwl);
3321 gtk_text_buffer_get_end_iter (buffer, &iter);
3322 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3323 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3328 gtk_text_buffer_set_modified(buffer, FALSE);
3335 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3337 gint *option = static_cast<gint *>(data);
3339 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3343 *option = INTENT_PERCEPTUAL;
3346 *option = INTENT_RELATIVE_COLORIMETRIC;
3349 *option = INTENT_SATURATION;
3352 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3357 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3358 gint option, gint *option_c)
3365 pref_table_label(table, column, row, text, 0.0);
3367 combo = gtk_combo_box_text_new();
3369 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3370 if (option == INTENT_PERCEPTUAL) current = 0;
3371 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3372 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3373 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3374 if (option == INTENT_SATURATION) current = 2;
3375 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3376 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3378 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3380 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3382 g_signal_connect(G_OBJECT(combo), "changed",
3383 G_CALLBACK(intent_menu_cb), option_c);
3385 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3386 gtk_widget_show(combo);
3390 static void config_tab_color(GtkWidget *notebook)
3399 vbox = scrolled_notebook_page(notebook, _("Color management"));
3401 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3403 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3406 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3407 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3409 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3410 pref_label_bold(label, TRUE, FALSE);
3412 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3413 pref_label_bold(label, TRUE, FALSE);
3415 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3416 pref_label_bold(label, TRUE, FALSE);
3418 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3423 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3424 pref_table_label(table, 0, i + 1, buf, 1.0);
3427 entry = gtk_entry_new();
3428 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3429 if (options->color_profile.input_name[i])
3431 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3433 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3434 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3435 gtk_widget_show(entry);
3436 color_profile_input_name_entry[i] = entry;
3438 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3439 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3440 gtk_widget_set_size_request(entry, 160, -1);
3441 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3442 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3443 gtk_widget_show(tabcomp);
3444 color_profile_input_file_entry[i] = entry;
3447 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3449 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3451 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3452 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3454 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3456 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3457 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3458 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3459 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3460 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3462 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3464 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3466 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3468 gtk_widget_show(tabcomp);
3471 /* advanced entry tab */
3472 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer UNUSED(data))
3474 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3476 c_options->file_ops.use_system_trash = FALSE;
3477 c_options->file_ops.no_trash = FALSE;
3481 static void use_system_trash_cb(GtkWidget *widget, gpointer UNUSED(data))
3483 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3485 c_options->file_ops.use_system_trash = TRUE;
3486 c_options->file_ops.no_trash = FALSE;
3490 static void use_no_cache_cb(GtkWidget *widget, gpointer UNUSED(data))
3492 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3494 c_options->file_ops.no_trash = TRUE;
3498 static void config_tab_behavior(GtkWidget *notebook)
3505 GtkWidget *ct_button;
3509 GtkWidget *with_rename;
3510 GtkWidget *collections_on_top;
3511 GtkWidget *hide_window_in_fullscreen;
3512 GtkWidget *checkbox;
3515 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3517 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3519 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3520 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3521 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3522 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3523 pref_checkbox_new_int(group, _("Enable Delete key"),
3524 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3526 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3527 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3529 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3530 pref_checkbox_link_sensitivity(ct_button, hbox);
3532 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3533 pref_label_new(hbox, _("Folder:"));
3535 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3536 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3537 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3538 gtk_widget_show(tabcomp);
3540 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3541 pref_checkbox_link_sensitivity(ct_button, hbox);
3543 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3544 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3545 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3546 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3547 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3548 G_CALLBACK(safe_delete_view_cb), NULL);
3549 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3550 gtk_widget_show(button);
3552 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3553 G_CALLBACK(safe_delete_clear_cb), NULL);
3554 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3556 c_options->file_ops.no_trash = options->file_ops.no_trash;
3557 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3559 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3560 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3562 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3563 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3565 gtk_widget_show(button);
3567 pref_spacer(group, PREF_PAD_GROUP);
3570 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3572 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3573 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3575 pref_checkbox_new_int(group, _("In place renaming"),
3576 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3578 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3579 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3581 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3582 options->circular_selection_lists, &c_options->circular_selection_lists);
3583 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3585 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3586 options->marks_save, &c_options->marks_save);
3587 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3589 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3590 options->with_rename, &c_options->with_rename);
3591 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3593 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3594 options->collections_on_top, &c_options->collections_on_top);
3595 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3597 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3598 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3599 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3601 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3602 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3604 tmp = pref_spin_new_int(group, _("Recent folder-image list maximum size"), NULL, 0, 50, 1, options->recent_folder_image_list_maxsize, &c_options->recent_folder_image_list_maxsize);
3605 gtk_widget_set_tooltip_text(tmp, _("List of the last image viewed in each recent folder.\nRe-opening a folder will set focus to the last image viewed."));
3607 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3608 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3610 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3611 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3613 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3614 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3616 pref_spacer(group, PREF_PAD_GROUP);
3618 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3620 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3621 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3622 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3623 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3624 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3625 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3626 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3627 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3628 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3629 options->image_l_click_archive, &c_options->image_l_click_archive);
3630 pref_checkbox_new_int(group, _("Play video by left click on image"),
3631 options->image_l_click_video, &c_options->image_l_click_video);
3632 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3633 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3635 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3636 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3637 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3638 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3639 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3641 pref_spacer(group, PREF_PAD_GROUP);
3643 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3645 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3646 options->override_disable_gpu, &c_options->override_disable_gpu);
3647 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3650 pref_spacer(group, PREF_PAD_GROUP);
3652 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3654 pref_spin_new_int(group, _("Debug level:"), NULL,
3655 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3657 pref_checkbox_new_int(group, _("Timer data"),
3658 options->log_window.timer_data, &c_options->log_window.timer_data);
3660 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3661 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3665 /* accelerators tab */
3666 static void config_tab_accelerators(GtkWidget *notebook)
3672 GtkWidget *scrolled;
3673 GtkWidget *accel_view;
3674 GtkCellRenderer *renderer;
3675 GtkTreeSelection *selection;
3676 GtkTreeViewColumn *column;
3678 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3680 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3682 scrolled = gtk_scrolled_window_new(NULL, NULL);
3683 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3684 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3685 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3686 gtk_widget_show(scrolled);
3688 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3690 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3691 g_object_unref(accel_store);
3692 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3693 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3695 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3697 renderer = gtk_cell_renderer_text_new();
3699 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3704 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3705 gtk_tree_view_column_set_resizable(column, TRUE);
3706 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3709 renderer = gtk_cell_renderer_accel_new();
3710 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3711 G_CALLBACK(accel_store_cleared_cb), accel_store);
3712 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3713 G_CALLBACK(accel_store_edited_cb), accel_store);
3716 g_object_set (renderer,
3718 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3721 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3726 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3727 gtk_tree_view_column_set_resizable(column, TRUE);
3728 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3730 renderer = gtk_cell_renderer_text_new();
3732 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3737 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3738 gtk_tree_view_column_set_resizable(column, TRUE);
3739 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3741 renderer = gtk_cell_renderer_text_new();
3743 column = gtk_tree_view_column_new_with_attributes("Accel",
3748 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3749 gtk_tree_view_column_set_resizable(column, TRUE);
3750 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3752 accel_store_populate();
3753 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3754 gtk_widget_show(accel_view);
3756 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3758 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3759 G_CALLBACK(accel_default_cb), accel_view);
3760 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3761 gtk_widget_show(button);
3763 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3764 G_CALLBACK(accel_reset_cb), accel_view);
3765 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3766 gtk_widget_show(button);
3769 /* toolbar main tab */
3770 static void config_tab_toolbar_main(GtkWidget *notebook)
3773 GtkWidget *toolbardata;
3776 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3778 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3780 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3781 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3782 gtk_widget_show(vbox);
3785 /* toolbar status tab */
3786 static void config_tab_toolbar_status(GtkWidget *notebook)
3789 GtkWidget *toolbardata;
3792 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3794 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3796 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3797 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3798 gtk_widget_show(vbox);
3802 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3804 return g_strcmp0((gchar *)a, (gchar *)b);
3807 static void config_tab_advanced(GtkWidget *notebook)
3811 GSList *formats_list;
3812 GList *extensions_list = NULL;
3815 GdkPixbufFormat *fm;
3817 GString *types_string = g_string_new(NULL);
3818 GtkWidget *types_string_label;
3819 GtkWidget *threads_string_label;
3820 GtkWidget *dupes_threads_spin;
3822 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3823 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3825 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3827 pref_spacer(group, PREF_PAD_GROUP);
3829 formats_list = gdk_pixbuf_get_formats();
3831 while (formats_list)
3833 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3834 extensions = gdk_pixbuf_format_get_extensions(fm);
3837 while (extensions[i])
3839 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3843 g_strfreev(extensions);
3844 formats_list = formats_list->next;
3847 while (extensions_list)
3849 if (types_string->len == 0)
3851 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3855 types_string = g_string_append(types_string, ", ");
3856 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3859 extensions_list = extensions_list->next;
3862 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3863 types_string_label = pref_label_new(group, types_string->str);
3864 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3866 pref_spacer(group, PREF_PAD_GROUP);
3868 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3869 external_preview_select_entry = gtk_entry_new();
3870 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3871 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3872 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3873 gtk_widget_show(tabcomp);
3875 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3876 external_preview_extract_entry = gtk_entry_new();
3877 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3878 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3879 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3880 gtk_widget_show(tabcomp);
3882 gtk_widget_show(vbox);
3884 g_slist_free(formats_list);
3885 string_list_free(extensions_list);
3886 g_string_free(types_string, TRUE);
3888 pref_spacer(group, PREF_PAD_GROUP);
3890 pref_line(vbox, PREF_PAD_SPACE);
3891 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3893 threads_string_label = pref_label_new(group, "This option limits the number of threads (or cpu cores)\nthat Geeqie will use when running duplicate checks. The default value is 0, which means all available cores will be used.");
3894 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3896 pref_spacer(vbox, PREF_PAD_GROUP);
3898 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3899 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3903 static void config_tab_stereo(GtkWidget *notebook)
3911 GtkWidget *fs_button;
3912 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3914 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3916 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3917 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3919 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3920 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3921 pref_checkbox_new_int(box, _("Mirror left image"),
3922 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3923 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3924 pref_checkbox_new_int(box, _("Flip left image"),
3925 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3926 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3927 pref_checkbox_new_int(box, _("Mirror right image"),
3928 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3929 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3930 pref_checkbox_new_int(box, _("Flip right image"),
3931 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3932 pref_checkbox_new_int(group, _("Swap left and right images"),
3933 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3934 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3935 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3937 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3938 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3939 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3940 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3941 pref_checkbox_link_sensitivity(fs_button, box2);
3942 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3943 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3944 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3945 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3946 pref_checkbox_new_int(box, _("Mirror left image"),
3947 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3948 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3949 pref_checkbox_new_int(box, _("Flip left image"),
3950 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3951 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3952 pref_checkbox_new_int(box, _("Mirror right image"),
3953 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3954 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3955 pref_checkbox_new_int(box, _("Flip right image"),
3956 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3957 pref_checkbox_new_int(box2, _("Swap left and right images"),
3958 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3959 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3960 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3962 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3963 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3964 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3965 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3966 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3967 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3968 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3969 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3970 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3971 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3972 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3973 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3974 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3975 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3979 /* Main preferences window */
3980 static void config_window_create(LayoutWindow *lw)
3982 GtkWidget *win_vbox;
3984 GtkWidget *notebook;
3986 GtkWidget *ct_button;
3988 if (!c_options) c_options = init_options(NULL);
3990 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3991 DEBUG_NAME(configwindow);
3992 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3993 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3994 G_CALLBACK(config_window_delete), NULL);
3995 if (options->save_dialog_window_positions)
3997 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
3998 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4002 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4004 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4005 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4007 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4008 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
4009 gtk_widget_show(win_vbox);
4011 notebook = gtk_notebook_new();
4012 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4013 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4014 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4016 config_tab_general(notebook);
4017 config_tab_image(notebook);
4018 config_tab_osd(notebook);
4019 config_tab_windows(notebook);
4020 config_tab_accelerators(notebook);
4021 config_tab_files(notebook);
4022 config_tab_metadata(notebook);
4023 config_tab_keywords(notebook);
4024 config_tab_color(notebook);
4025 config_tab_stereo(notebook);
4026 config_tab_behavior(notebook);
4027 config_tab_toolbar_main(notebook);
4028 config_tab_toolbar_status(notebook);
4029 config_tab_advanced(notebook);
4031 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4033 hbox = gtk_hbutton_box_new();
4034 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4035 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4036 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4037 gtk_widget_show(hbox);
4039 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
4040 G_CALLBACK(config_window_help_cb), notebook);
4041 gtk_container_add(GTK_CONTAINER(hbox), button);
4042 gtk_widget_set_can_default(button, TRUE);
4043 gtk_widget_show(button);
4045 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
4046 G_CALLBACK(config_window_ok_cb), notebook);
4047 gtk_container_add(GTK_CONTAINER(hbox), button);
4048 gtk_widget_set_can_default(button, TRUE);
4049 gtk_widget_grab_default(button);
4050 gtk_widget_show(button);
4054 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
4055 G_CALLBACK(config_window_close_cb), NULL);
4056 gtk_container_add(GTK_CONTAINER(hbox), button);
4057 gtk_widget_set_can_default(button, TRUE);
4058 gtk_widget_show(button);
4060 if (!generic_dialog_get_alternative_button_order(configwindow))
4062 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4065 gtk_widget_show(notebook);
4067 gtk_widget_show(configwindow);
4071 *-----------------------------------------------------------------------------
4072 * config window show (public)
4073 *-----------------------------------------------------------------------------
4076 void show_config_window(LayoutWindow *lw)
4080 gtk_window_present(GTK_WINDOW(configwindow));
4084 config_window_create(lw);
4093 void show_about_window(LayoutWindow *lw)
4095 GdkPixbuf *pixbuf_logo;
4096 GdkPixbuf *pixbuf_icon;
4097 gchar *authors[1000];
4102 gchar *timezone_path;
4105 #define LINE_LENGTH 1000
4106 gchar line[LINE_LENGTH];
4108 copyright = g_string_new(NULL);
4109 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");
4111 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4112 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4114 cd = ZDOpenDatabase(timezone_path);
4117 copyright = g_string_append(copyright, ZDGetNotice(cd));
4121 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4123 ZDCloseDatabase(cd);
4125 g_free(timezone_path);
4128 path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
4129 fp = fopen(path, "r");
4132 while(fgets(line, LINE_LENGTH, fp))
4134 /* get rid of ending \n from fgets */
4135 line[strlen(line) - 1] = '\0';
4136 authors[i_authors] = g_strdup(line);
4139 authors[i_authors] = NULL;
4144 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
4145 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4147 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4148 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4149 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4150 "title", _("About Geeqie"),
4152 "program-name", GQ_APPNAME,
4154 "logo", pixbuf_logo,
4155 "icon", pixbuf_icon,
4156 "website", GQ_WEBSITE,
4157 "website-label", "Website",
4158 "comments", comment,
4160 "translator-credits", _("translator-credits"),
4161 "wrap-license", TRUE,
4162 "license", copyright->str,
4165 g_string_free(copyright, TRUE);
4168 while(n < i_authors)
4178 static void image_overlay_set_text_colours()
4180 c_options->image_overlay.text_red = options->image_overlay.text_red;
4181 c_options->image_overlay.text_green = options->image_overlay.text_green;
4182 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4183 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4184 c_options->image_overlay.background_red = options->image_overlay.background_red;
4185 c_options->image_overlay.background_green = options->image_overlay.background_green;
4186 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4187 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4191 *-----------------------------------------------------------------------------
4192 * timezone database routines
4193 *-----------------------------------------------------------------------------
4196 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4198 GError *error = NULL;
4199 TZData *tz = static_cast<TZData *>(data);
4200 gchar *tmp_filename;
4201 gchar *timezone_bin;
4202 gchar *tmp_dir = NULL;
4205 if (!g_cancellable_is_cancelled(tz->cancellable))
4207 generic_dialog_close(tz->gd);
4211 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4213 tmp_filename = g_file_get_path(tz->tmp_g_file);
4214 fd = file_data_new_simple(tmp_filename);
4215 tmp_dir = open_archive(fd);
4219 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4220 if (isfile(timezone_bin))
4222 move_file(timezone_bin, tz->timezone_database_user);
4226 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4229 g_free(timezone_bin);
4230 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4234 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4236 g_free(tmp_filename);
4237 file_data_unref(fd);
4241 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4244 g_file_delete(tz->tmp_g_file, NULL, &error);
4245 g_object_unref(tz->tmp_g_file);
4246 tz->tmp_g_file = NULL;
4247 g_object_unref(tz->cancellable);
4248 g_object_unref(tz->timezone_database_gq);
4251 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4253 TZData *tz = static_cast<TZData *>(data);
4255 if (!g_cancellable_is_cancelled(tz->cancellable))
4257 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4261 static void timezone_cancel_button_cb(GenericDialog *UNUSED(gd), gpointer data)
4263 TZData *tz = static_cast<TZData *>(data);
4265 g_cancellable_cancel(tz->cancellable);
4268 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4270 TZData *tz = static_cast<TZData *>(data);
4271 GError *error = NULL;
4272 GFileIOStream *io_stream;
4279 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4283 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4284 log_printf("Error: Download timezone database failed:\n%s", error->message);
4285 g_error_free(error);
4286 g_object_unref(tz->tmp_g_file);
4290 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4292 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4294 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4296 tz->progress = gtk_progress_bar_new();
4297 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4298 gtk_widget_show(tz->progress);
4300 gtk_widget_show(tz->gd->dialog);
4301 tz->cancellable = g_cancellable_new();
4302 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);
4304 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4307 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */