The Battle for Wesnoth  1.17.23+dev
preferences_dialog.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2023
3  by Charles Dang <exodia339gmail.com>
4  Copyright (C) 2011, 2015 by Iris Morelle <shadowm2006@gmail.com>
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
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.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 #define GETTEXT_DOMAIN "wesnoth-lib"
18 
20 
21 #include "display.hpp"
22 #include "events.hpp"
23 #include "filesystem.hpp"
24 #include "formatter.hpp"
25 #include "formula/string_utils.hpp"
26 #include "game_data.hpp"
27 #include "gettext.hpp"
28 #include "hotkey/hotkey_item.hpp"
29 #include "lexical_cast.hpp"
31 #include "preferences/display.hpp"
32 #include "preferences/game.hpp"
33 #include "preferences/general.hpp"
34 #include "preferences/lobby.hpp"
35 #include "resources.hpp"
36 #include "theme.hpp"
37 #include "video.hpp"
38 
39 // Sub-dialog includes
45 
48 #include "gui/dialogs/message.hpp"
50 #include "gui/widgets/button.hpp"
53 #include "gui/widgets/grid.hpp"
54 #include "gui/widgets/image.hpp"
55 #include "gui/widgets/label.hpp"
56 #include "gui/widgets/listbox.hpp"
58 #include "gui/widgets/settings.hpp"
59 #include "gui/widgets/slider.hpp"
62 #include "gui/widgets/text_box.hpp"
64 #include "gui/widgets/window.hpp"
65 
66 #include <functional>
67 #include <numeric>
68 
69 namespace gui2::dialogs
70 {
71 namespace
72 {
73 template<typename W>
74 void disable_widget_on_toggle(window& window, widget& w, const std::string& id)
75 {
76  find_widget<W>(&window, id, false).set_active(dynamic_cast<selectable_item&>(w).get_value_bool());
77 }
78 
79 template<typename W>
80 void disable_widget_on_toggle_inverted(window& window, widget& w, const std::string& id)
81 {
82  find_widget<W>(&window, id, false).set_active(!dynamic_cast<selectable_item&>(w).get_value_bool());
83 }
84 
85 // Ensure the specified index is between 0 and one less than the max
86 // number of pager layers (since get_layer_count returns one-past-end).
87 int index_in_pager_range(const int first, const stacked_widget& pager)
88 {
89  return std::clamp<int>(first, 0, pager.get_layer_count() - 1);
90 }
91 
92 // Helper to make it easier to immediately apply sound toggles immediately.
93 template<bool(*fptr)(bool)>
94 void sound_toggle_on_change(window& window, const std::string& id_to_toggle, widget& w)
95 {
96  std::invoke(fptr, dynamic_cast<selectable_item&>(w).get_value_bool());
97 
98  // Toggle the corresponding slider.
99  disable_widget_on_toggle<slider>(window, w, id_to_toggle);
100 }
101 
102 // Helper to make it easier to immediately apply volume (music, etc) setings on change.
103 template<void(*fptr)(int)>
104 void volume_setter_on_change(widget& w)
105 {
106  std::invoke(fptr, dynamic_cast<integer_selector&>(w).get_value());
107 }
108 
109 } // end anon namespace
110 
111 using namespace preferences;
113 
115 
117  : modal_dialog(window_id())
118  , adv_preferences_(preferences::get_advanced_preferences())
119  , resolutions_() // should be populated by set_resolution_list before use
120  , themes_() // populated by set_theme_list
121  , last_selected_item_(0)
122  , accl_speeds_({0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 3, 4, 8, 16})
123  , visible_hotkeys_()
124  , visible_categories_()
125  , initial_index_(pef_view_map[initial_view])
126 {
127  initialize_callbacks();
128 }
129 
130 // Helper function to refresh resolution list
132 {
133  resolutions_ = video::get_available_resolutions(true);
134 
135  std::vector<config> options;
136  for(const point& res : resolutions_) {
137  config option;
138  option["label"] = formatter() << res.x << font::unicode_multiplication_sign << res.y;
139 
140  const int div = std::gcd(res.x, res.y);
141  const int x_ratio = res.x / div;
142  const int y_ratio = res.y / div;
143 
144  if(x_ratio <= 10 || y_ratio <= 10) {
145  option["details"] = formatter() << "<span color='#777777'>(" << x_ratio << ':' << y_ratio << ")</span>";
146  }
147 
148  options.push_back(std::move(option));
149  }
150 
151  const unsigned current_res = std::distance(resolutions_.begin(), std::find(
152  resolutions_.begin(), resolutions_.end(), video::current_resolution()));
153 
154  res_list.set_values(options, current_res);
155 }
156 
158 {
159  themes_ = theme::get_basic_theme_info();
160 
161  std::vector<config> options;
162  for(const auto& theme : themes_) {
163  options.emplace_back("label", theme.name, "tooltip", theme.description);
164  }
165 
166  const unsigned current_theme = std::distance(themes_.begin(),
167  std::find_if(themes_.begin(), themes_.end(), [](const auto& theme) {
168  return theme.id == preferences::theme();
169  }));
170 
171  theme_list.set_values(options, current_theme);
172 }
173 
175 {
178 
179  std::string image = "friend.png";
180  std::string descriptor = _("friend");
181  std::string notes;
182 
183  if(entry.get_status() == "ignore") {
184  image = "ignore.png";
185  descriptor = _("ignored");
186  }
187 
188  if(!entry.get_notes().empty()) {
189  notes = " <small>(" + entry.get_notes() + ")</small>";
190  }
191 
192  item["use_markup"] = "true";
193 
194  item["label"] = "misc/status-" + image;
195  data.emplace("friend_icon", item);
196 
197  item["label"] = entry.get_nick() + notes;
198  data.emplace("friend_name", item);
199 
200  item["label"] = "<small>" + descriptor + "</small>";
201  data.emplace("friend_status", item);
202 
203  return data;
204 }
205 
207 {
208  const int num_friends = get_acquaintances().size();
209  const int sel = list.get_selected_row();
210 
211  if(sel < 0 || sel >= num_friends) {
212  return;
213  }
214 
215  std::map<std::string, acquaintance>::const_iterator who = get_acquaintances().begin();
216  std::advance(who, sel);
217 
218  textbox.set_value(who->second.get_nick() + " " + who->second.get_notes());
219 }
220 
222 {
223  const bool list_empty = list.get_item_count() == 0;
224 
225  if(!list_empty) {
226  list.select_row(std::min(static_cast<int>(list.get_item_count()) - 1, list.get_selected_row()));
227  }
228 
229  find_widget<button>(this, "remove", false).set_active(!list_empty);
230 
231  find_widget<label>(this, "no_friends_notice", false).set_visible(
233 }
234 
236 {
237  std::string username = textbox.text();
238  if(username.empty()) {
239  gui2::show_transient_message("", _("No username specified"));
240  return;
241  }
242 
243  std::string reason;
244 
245  std::size_t pos = username.find_first_of(' ');
246  if(pos != std::string::npos) {
247  reason = username.substr(pos + 1);
248  username = username.substr(0, pos);
249  }
250 
251  auto [entry, added_new] = add_acquaintance(username, (is_friend ? "friend": "ignore"), reason);
252 
253  if(!entry) {
254  gui2::show_transient_message(_("Error"), _("Invalid username"));
255  return;
256  }
257 
258  textbox.clear();
259 
260  listbox& list = find_widget<listbox>(this, "friends_list", false);
261 
262  //
263  // If this is a new entry, just add a new row. If it's not, we find the relevant
264  // row, remove it, and add a new row with the updated data. Should probably come
265  // up with a more elegant way to do this... the only reason I'm using the remove
266  // -and-replace method is to prevent any issues with the widgets' layout sizes.
267  //
268  if(added_new) {
269  list.add_row(get_friends_list_row_data(*entry));
270  } else {
271  for(unsigned i = 0; i < list.get_item_count(); ++i) {
272  grid* row_grid = list.get_row_grid(i);
273 
274  if(find_widget<label>(row_grid, "friend_name", false).get_label() == entry->get_nick()) {
275  list.remove_row(i);
276  list.add_row(get_friends_list_row_data(*entry), i);
277 
278  break;
279  }
280  }
281  }
282 
283  update_friends_list_controls(list);
284 }
285 
287 {
288  const int selected_row = std::max(0, friends_list.get_selected_row());
289 
290  std::map<std::string, acquaintance>::const_iterator who = get_acquaintances().begin();
291  std::advance(who, selected_row);
292 
293  const std::string to_remove = !textbox.text().empty() ? textbox.text() : who->second.get_nick();
294 
295  if(to_remove.empty()) {
296  gui2::show_transient_message("", _("No username specified"));
297  return;
298  }
299 
300  if(!remove_acquaintance(to_remove)) {
301  gui2::show_transient_error_message(_("Not on friends or ignore lists"));
302  return;
303  }
304 
305  textbox.clear();
306 
307  listbox& list = find_widget<listbox>(this, "friends_list", false);
308  list.remove_row(selected_row);
309 
310  update_friends_list_controls(list);
311 }
312 
313 template<bool(*toggle_getter)(), bool(*toggle_setter)(bool), int(*vol_getter)(), void(*vol_setter)(int)>
314 void preferences_dialog::initialize_sound_option_group(const std::string& id_suffix)
315 {
316  const std::string toggle_widget_id = "sound_toggle_" + id_suffix;
317  const std::string volume_widget_id = "sound_volume_" + id_suffix;
318 
319  // Set up the toggle. We utilize field_bool's callback-on-changed mechanism instead
320  // of manually registering the callback. Since we want the effects to apply immediately,
321  // the callback the setter callback is duplicated in the on-change callback. The field
322  // class could possibly use some reworking to make this less redundant, but for now it
323  // works well enough.
324  register_bool(toggle_widget_id, true, toggle_getter, std::bind(toggle_setter, std::placeholders::_1),
325  std::bind(sound_toggle_on_change<toggle_setter>, std::ref(*this), volume_widget_id, std::placeholders::_1), true);
326 
327  // Set up the volume slider. integer_field doesn't have a callback-on-changed mechanism.
328  // To add one would either mean adding it to the base field class or make it a proper
329  // class of is own.
330  register_integer(volume_widget_id, true, vol_getter, vol_setter);
331 
332  // Callback to actually immediately apply the volume effect.
333  connect_signal_notify_modified(find_widget<slider>(this, volume_widget_id, false),
334  std::bind(volume_setter_on_change<vol_setter>, std::placeholders::_1));
335 }
336 
338 {
339  // Update pixel scale preference.
340  slider& ps_slider = find_widget<slider>(this, "pixel_scale_slider", false);
341  set_pixel_scale(ps_slider.get_value());
342 
343  // Update auto pixel scale preference.
344  toggle_button& auto_ps_toggle =
345  find_widget<toggle_button>(this, "auto_pixel_scale", false);
346  set_auto_pixel_scale(auto_ps_toggle.get_value_bool());
347 
348  // Update draw buffers, taking these into account.
350 
351  // Update game display, if active
352  if(::display* disp = display::get_singleton()) {
353  disp->queue_rerender();
354  }
355 
356  // Raise a window resize event so we can react to the change
358 }
359 
360 
361 /**
362  * Sets up states and callbacks for each of the widgets
363  */
365 {
366  //
367  // GENERAL PANEL
368  //
369 
370  /* SCROLL SPEED */
371  register_integer("scroll_speed", true,
373 
374  /* ACCELERATED SPEED */
375  register_bool("turbo_toggle", true, turbo, set_turbo);
376 
377  const auto accl_load = [this]()->int {
378  return std::distance(accl_speeds_.begin(), std::find(accl_speeds_.begin(), accl_speeds_.end(), turbo_speed()));
379  };
380 
381  const auto accl_save = [this](int i) {
382  set_turbo_speed(accl_speeds_[i]);
383  };
384 
385  register_integer("turbo_slider", true,
386  accl_load, accl_save);
387 
388  // Set the value label transform function.
389  find_widget<slider>(this, "turbo_slider", false).set_value_labels(
390  [this](int pos, int /*max*/)->t_string { return lexical_cast<std::string>(accl_speeds_[pos]); }
391  );
392 
393  /* SKIP AI MOVES */
394  register_bool("skip_ai_moves", true,
396 
397  /* DISABLE AUTO MOVES */
398  register_bool("disable_auto_moves", true,
400 
401  /* TURN DIALOG */
402  register_bool("show_turn_dialog", true,
404 
405  /* ENABLE PLANNING MODE */
406  register_bool("whiteboard_on_start", true,
408 
409  /* HIDE ALLY PLANS */
410  register_bool("whiteboard_hide_allies", true,
412 
413  /* INTERRUPT ON SIGHTING */
414  register_bool("interrupt_move_when_ally_sighted", true,
416 
417  /* SAVE REPLAYS */
418  register_bool("save_replays", true,
420 
421  /* DELETE AUTOSAVES */
422  register_bool("delete_saves", true,
424 
425  /* MAX AUTO SAVES */
426  register_integer("max_saves_slider", true,
428 
429  /* CACHE MANAGE */
430  connect_signal_mouse_left_click(find_widget<button>(this, "cachemg", false),
431  std::bind(&gui2::dialogs::game_cache_options::display<>));
432 
433  //
434  // DISPLAY PANEL
435  //
436 
437  /* FULLSCREEN TOGGLE */
439  find_widget<toggle_button>(this, "fullscreen", false);
440 
441  toggle_fullscreen.set_value(fullscreen());
442 
443  // We bind a special callback function, so setup_single_toggle() is not used
446 
447  /* SET RESOLUTION */
448  menu_button& res_list = find_widget<menu_button>(this, "resolution_set", false);
449 
450  res_list.set_use_markup(true);
451  res_list.set_active(!fullscreen());
452 
453  set_resolution_list(res_list);
454 
456  std::bind(&preferences_dialog::handle_res_select, this));
457 
458  connect_signal<event::SDL_VIDEO_RESIZE>(std::bind(&preferences_dialog::set_resolution_list, this, std::ref(res_list)));
459 
460  /* PIXEL SCALE */
461  register_integer("pixel_scale_slider", true,
463 
464  slider& ps_slider =
465  find_widget<slider>(this, "pixel_scale_slider", false);
467  std::bind(&preferences_dialog::apply_pixel_scale, this));
468 
469  /* AUTOMATIC PIXEL SCALE */
470  register_bool("auto_pixel_scale", true,
472  [&](widget& w) { disable_widget_on_toggle_inverted<slider>(*this, w, "pixel_scale_slider"); }, true);
473 
474  toggle_button& auto_ps_toggle =
475  find_widget<toggle_button>(this, "auto_pixel_scale", false);
476  connect_signal_mouse_left_click(auto_ps_toggle,
477  std::bind(&preferences_dialog::apply_pixel_scale, this));
478 
479  /* SHOW FLOATING LABELS */
480  register_bool("show_floating_labels", true,
482 
483  /* SHOW TEAM COLORS */
484  register_bool("show_ellipses", true,
486 
487  /* SHOW GRID */
488  register_bool("show_grid", true,
490 
491  /* ANIMATE MAP */
492  register_bool("animate_terrains", true, animate_map, set_animate_map,
493  [&](widget& w) { disable_widget_on_toggle<toggle_button>(*this, w, "animate_water"); }, true);
494 
495  /* ANIMATE WATER */
496  register_bool("animate_water", true,
498 
499  /* SHOW UNIT STANDING ANIMS */
500  register_bool("animate_units_standing", true,
502 
503  /* SHOW UNIT IDLE ANIMS */
504  register_bool("animate_units_idle", true, idle_anim, set_idle_anim,
505  [&](widget& w) { disable_widget_on_toggle<slider>(*this, w, "idle_anim_frequency"); });
506 
507  register_integer("idle_anim_frequency", true,
509 
510  /* FONT SCALING */
511  //register_integer("scaling_slider", true,
512  // font_scaling, set_font_scaling);
513 
514  /* FPS LIMITER */
515  register_bool("fps_limiter", true,
516  []() { return draw_delay() != 0; }, [](bool v) { set_draw_delay(v ? -1 : 0); });
517 
518  /* VSYNC */
519  register_bool("vsync", true, vsync, set_vsync);
520 
521  /* SELECT THEME */
522  menu_button& theme_list = find_widget<menu_button>(this, "choose_theme", false);
523  set_theme_list(theme_list);
525  std::bind(&preferences_dialog::handle_theme_select, this));
526  //connect_signal_mouse_left_click(
527  // find_widget<button>(this, "choose_theme", false),
528  // std::bind(&show_theme_dialog));
529 
530  //
531  // SOUND PANEL
532  //
533 
534  /* SOUND FX */
535  initialize_sound_option_group<sound_on, set_sound, sound_volume, set_sound_volume>("sfx");
536 
537  /* MUSIC */
538  initialize_sound_option_group<music_on, set_music, music_volume, set_music_volume>("music");
539 
540  register_bool("sound_toggle_stop_music_in_background", true,
542 
543  /* TURN BELL */
544  initialize_sound_option_group<turn_bell, set_turn_bell, bell_volume, set_bell_volume>("bell");
545 
546  /* UI FX */
547  initialize_sound_option_group<UI_sound_on, set_UI_sound, UI_volume, set_UI_volume>("uisfx");
548 
549  //
550  // MULTIPLAYER PANEL
551  //
552 
553  /* CHAT LINES */
554  register_integer("chat_lines", true,
556 
557  /* CHAT TIMESTAMPPING */
558  register_bool("chat_timestamps", true,
560 
561  /* SAVE PASSWORD */
562  register_bool("remember_password", true,
564 
565  /* WHISPERS FROM FRIENDS ONLY */
566  register_bool("lobby_whisper_friends_only", true,
568 
569  /* LOBBY JOIN NOTIFICATIONS */
570  lobby_joins_group.add_member(find_widget<toggle_button>(this, "lobby_joins_none", false, true), lobby_joins::show_none);
571  lobby_joins_group.add_member(find_widget<toggle_button>(this, "lobby_joins_friends", false, true), lobby_joins::show_friends);
572  lobby_joins_group.add_member(find_widget<toggle_button>(this, "lobby_joins_all", false, true), lobby_joins::show_all);
573 
574  lobby_joins_group.set_member_states(get_lobby_joins());
575 
576  lobby_joins_group.set_callback_on_value_change([&](widget&, const lobby_joins val) {
577  _set_lobby_joins(val);
578  });
579 
580  /* FRIENDS LIST */
581  listbox& friends_list = find_widget<listbox>(this, "friends_list", false);
582 
583  friends_list.clear();
584 
585  for(const auto& entry : get_acquaintances()) {
586  friends_list.add_row(get_friends_list_row_data(entry.second));
587  }
588 
589  update_friends_list_controls(friends_list);
590 
591  text_box& textbox = find_widget<text_box>(this, "friend_name_box", false);
592 
594  find_widget<button>(this, "add_friend", false), std::bind(
596  this, true,
597  std::ref(textbox)));
598 
600  find_widget<button>(this, "add_ignored", false), std::bind(
602  this, false,
603  std::ref(textbox)));
604 
606  find_widget<button>(this, "remove", false), std::bind(
608  this,
609  std::ref(friends_list),
610  std::ref(textbox)));
611 
612  connect_signal_notify_modified(friends_list, std::bind(
614  this,
615  std::ref(friends_list),
616  std::ref(textbox)));
617 
618  /* ALERTS */
620  find_widget<button>(this, "mp_alerts", false),
621  std::bind(&gui2::dialogs::mp_alerts_options::display<>));
622 
623  /* SET WESNOTHD PATH */
625  find_widget<button>(this, "mp_wesnothd", false), std::bind(
627 
628 
629  //
630  // ADVANCED PANEL
631  //
632 
633  listbox& advanced = find_widget<listbox>(this, "advanced_prefs", false);
634 
635  widget_data row_data;
636 
637  for(const auto& option : adv_preferences_) {
638  const std::string& pref_name = option.field;
639 
640  row_data["pref_name"]["label"] = option.name;
641  grid* main_grid = &advanced.add_row(row_data);
642 
643  grid& details_grid = find_widget<grid>(main_grid, "prefs_setter_grid", false);
645 
646  // The toggle widget for toggle-type options (hidden for other types)
647  toggle_button& toggle_box = find_widget<toggle_button>(main_grid, "value_toggle", false);
649 
650  if(!option.description.empty()) {
651  find_widget<styled_widget>(main_grid, "description", false).set_label(option.description);
652  }
653 
654  switch(option.type) {
655  case avp::avd_type::TOGGLE: {
656  //main_grid->remove_child("setter");
657 
659  toggle_box.set_value(get(pref_name, option.cfg["default"].to_bool()));
660 
661  // We need to bind a lambda here since preferences::set is overloaded.
662  // A lambda alone would be more verbose because it'd need to specify all the parameters.
663  connect_signal_mouse_left_click(toggle_box, std::bind(
664  [&, pref_name]() { set(pref_name, toggle_box.get_value_bool()); }
665  ));
666 
667  gui2::bind_status_label<toggle_button>(
668  main_grid, "value_toggle", default_status_value_getter<toggle_button>, "value");
669 
670  break;
671  }
672 
673  case avp::avd_type::SLIDER: {
674  auto setter_widget = build_single_widget_instance<slider>(config {"definition", "minimal"});
675  setter_widget->set_id("setter");
676  // Maximum must be set first or this will assert
677  setter_widget->set_value_range(option.cfg["min"].to_int(), option.cfg["max"].to_int());
678  setter_widget->set_step_size(option.cfg["step"].to_int(1));
679 
680  details_grid.swap_child("setter", std::move(setter_widget), true);
681 
682  slider& slide = find_widget<slider>(&details_grid, "setter", false);
683 
684  slide.set_value(lexical_cast_default<int>(get(pref_name), option.cfg["default"].to_int()));
685 
686  // We need to bind a lambda here since preferences::set is overloaded.
687  // A lambda alone would be more verbose because it'd need to specify all the parameters.
688  connect_signal_notify_modified(slide, std::bind(
689  [&, pref_name]() { set(pref_name, slide.get_value()); }
690  ));
691 
692  gui2::bind_status_label<slider>(main_grid, "setter", default_status_value_getter<slider>, "value");
693 
694  break;
695  }
696 
697  case avp::avd_type::COMBO: {
698  std::vector<config> menu_data;
699  std::vector<std::string> option_ids;
700 
701  for(const config& choice : option.cfg.child_range("option")) {
702  config menu_item;
703  menu_item["label"] = choice["name"];
704  if(choice.has_attribute("description")) {
705  menu_item["details"] = std::string("<span color='#777'>") + choice["description"] + "</span>";
706  }
707  menu_data.push_back(menu_item);
708  option_ids.push_back(choice["id"]);
709  }
710 
711  // Attempt to find an initial selection
712  int selected = std::distance(option_ids.begin(), std::find(option_ids.begin(), option_ids.end(),
713  get(pref_name, option.cfg["default"].str())
714  ));
715 
716  // If the saved option value was invalid, reset selection to 0.
717  if(selected < 0 || selected >= static_cast<int>(option_ids.size())) {
718  selected = 0;
719  }
720 
721  auto setter_widget = build_single_widget_instance<menu_button>();
722  setter_widget->set_id("setter");
723 
724  details_grid.swap_child("setter", std::move(setter_widget), true);
725 
726  menu_button& menu = find_widget<menu_button>(&details_grid, "setter", false);
727 
728  menu.set_use_markup(true);
729  menu.set_values(menu_data, selected);
730 
731  // We need to bind a lambda here since preferences::set is overloaded.
732  // A lambda alone would be more verbose because it'd need to specify all the parameters.
734  std::bind([=](widget& w) { set(pref_name, option_ids[dynamic_cast<menu_button&>(w).get_value()]); }, std::placeholders::_1));
735 
736  gui2::bind_status_label<menu_button>(main_grid, "setter", default_status_value_getter<menu_button>, "value");
737 
738  break;
739  }
740 
741  case avp::avd_type::SPECIAL: {
742  //main_grid->remove_child("setter");
743 
744  auto value_widget = build_single_widget_instance<image>();
745  value_widget->set_label("icons/arrows/arrows_blank_right_25.png~CROP(3,3,18,18)");
746 
747  main_grid->swap_child("value", std::move(value_widget), true);
748 
749  break;
750  }
751  }
752  }
753 
754  connect_signal_notify_modified(advanced, std::bind(
756  this,
757  std::ref(advanced)));
758 
759  on_advanced_prefs_list_select(advanced);
760 
761  //
762  // HOTKEYS PANEL
763  //
764 
765  multimenu_button& hotkey_menu = find_widget<multimenu_button>(this, "hotkey_category_menu", false);
766  connect_signal_notify_modified(hotkey_menu,
768 
769  listbox& hotkey_list = setup_hotkey_list();
770 
771  text_box& filter = find_widget<text_box>(this, "filter", false);
773 
774  // Action column
775  hotkey_list.register_translatable_sorting_option(0, [this](const int i) { return visible_hotkeys_[i]->description.str(); });
776 
777  // Hotkey column
778  hotkey_list.register_sorting_option(1, [this](const int i) { return hotkey::get_names(visible_hotkeys_[i]->id); });
779 
780  // Scope columns
781  hotkey_list.register_sorting_option(2, [this](const int i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_GAME]; });
782  hotkey_list.register_sorting_option(3, [this](const int i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_EDITOR]; });
783  hotkey_list.register_sorting_option(4, [this](const int i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_MAIN_MENU]; });
784 
785  hotkey_list.set_active_sorting_option({0, sort_order::type::ascending}, true);
786 
788  find_widget<button>(this, "btn_add_hotkey", false), std::bind(
790  this,
791  std::ref(hotkey_list)));
792 
794  find_widget<button>(this, "btn_clear_hotkey", false), std::bind(
796  this,
797  std::ref(hotkey_list)));
798 
800  find_widget<button>(this, "btn_reset_hotkeys", false), std::bind(
802  this));
803 }
804 
806 {
807  widget_data row_data;
808 
809  t_string& row_icon = row_data["img_icon"]["label"];
810  t_string& row_action = row_data["lbl_desc"]["label"];
811  t_string& row_hotkey = row_data["lbl_hotkey"]["label"];
812 
813  t_string& row_is_g = row_data["lbl_is_game"]["label"];
814  t_string& row_is_e = row_data["lbl_is_editor"]["label"];
815  t_string& row_is_m = row_data["lbl_is_mainmenu"]["label"];
816 
817  listbox& hotkey_list = find_widget<listbox>(this, "list_hotkeys", false);
818 
819  hotkey_list.clear();
820  visible_hotkeys_.clear();
821  visible_categories_.clear();
822 
823  //
824  // Main hotkeys list
825  //
826 
827  // These translated initials should match those used in data/gui/window/preferences/02_hotkeys.cfg
828  const std::string gh = "<span color='#0f0'>" + _("game_hotkeys^G") + "</span>";
829  const std::string eh = "<span color='#0f0'>" + _("editor_hotkeys^E") + "</span>";
830  const std::string mh = "<span color='#0f0'>" + _("mainmenu_hotkeys^M") + "</span>";
831 
832  for(const auto& [id, hotkey_item] : hotkey::get_hotkey_commands()) {
833  if(hotkey_item.hidden) {
834  continue;
835  }
836 
837  visible_hotkeys_.push_back(&hotkey_item);
838  visible_categories_.insert(hotkey_item.category);
839 
840  if(filesystem::file_exists(game_config::path + "/images/icons/action/" + hotkey_item.id + "_25.png")) {
841  row_icon = "icons/action/" + hotkey_item.id + "_25.png~CROP(3,3,18,18)";
842  } else {
843  row_icon = "";
844  }
845 
846  row_action = hotkey_item.description;
847  row_hotkey = hotkey::get_names(hotkey_item.id);
848 
849  row_is_g = hotkey_item.scope[hotkey::SCOPE_GAME] ? gh : "";
850  row_is_e = hotkey_item.scope[hotkey::SCOPE_EDITOR] ? eh : "";
851  row_is_m = hotkey_item.scope[hotkey::SCOPE_MAIN_MENU] ? mh : "";
852 
853  hotkey_list.add_row(row_data);
854  }
855 
856  //
857  // Filter options
858  //
859 
860  std::vector<config> filter_ops;
861  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
862  filter_ops.emplace_back("label", hotkey::get_translatable_category_name(cat), "checkbox", false);
863  }
864 
865  find_widget<multimenu_button>(this, "hotkey_category_menu", false).set_values(filter_ops);
866 
867  return hotkey_list;
868 }
869 
871 {
872  int row_number = hotkeys.get_selected_row();
873  if(row_number < 0) {
874  gui2::show_transient_message("", _("No hotkey selected"));
875  return;
876  }
877 
878  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
879 
880  gui2::dialogs::hotkey_bind bind_dlg(hotkey_item.id);
881  bind_dlg.show();
882 
883  hotkey::hotkey_ptr newhk = bind_dlg.get_new_binding();
884  hotkey::hotkey_ptr oldhk;
885 
886  // only if not cancelled.
887  if(newhk.get() == nullptr) {
888  return;
889  }
890 
891  for(const hotkey::hotkey_ptr& hk : hotkey::get_hotkeys()) {
892  if(!hk->is_disabled() && newhk->bindings_equal(hk)) {
893  oldhk = hk;
894  }
895  }
896 
897  if(oldhk && oldhk->get_command() == hotkey_item.id) {
898  return;
899  }
900 
901  if(oldhk && oldhk->get_command() != "null") {
902  const std::string text = VGETTEXT("“<b>$hotkey_sequence|</b>” is in use by “<b>$old_hotkey_action|</b>”.\nDo you wish to reassign it to “<b>$new_hotkey_action|</b>”?", {
903  {"hotkey_sequence", oldhk->get_name()},
904  {"old_hotkey_action", hotkey::get_hotkey_command(oldhk->get_command()).description},
905  {"new_hotkey_action", hotkey::get_hotkey_command(newhk->get_command()).description}
906  });
907 
908  const int res = gui2::show_message(_("Reassign Hotkey"), text, gui2::dialogs::message::yes_no_buttons, true);
909  if(res != gui2::retval::OK) {
910  return;
911  }
912  }
913 
914  hotkey::add_hotkey(newhk);
915 
916  // We need to recalculate all hotkey names in because we might have removed a hotkey from another command.
917  for(std::size_t i = 0; i < hotkeys.get_item_count(); ++i) {
918  const hotkey::hotkey_command& hotkey_item_row = *visible_hotkeys_[i];
919  find_widget<label>(hotkeys.get_row_grid(i), "lbl_hotkey", false).set_label(hotkey::get_names(hotkey_item_row.id));
920  }
921 }
922 
924 {
925  gui2::show_transient_message(_("Hotkeys Reset"), _("All hotkeys have been reset to their default values."));
926 
927  clear_hotkeys();
928 
929  // Set up the list again and reselect the default sorting option.
930  listbox& hotkey_list = setup_hotkey_list();
931  hotkey_list.set_active_sorting_option({0, sort_order::type::ascending}, true);
932 }
933 
935 {
936  int row_number = hotkeys.get_selected_row();
937  if(row_number < 0) {
938  gui2::show_transient_message("", _("No hotkey selected"));
939  return;
940  }
941 
942  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
943  hotkey::clear_hotkeys(hotkey_item.id);
944  find_widget<label>(hotkeys.get_row_grid(row_number), "lbl_hotkey", false).set_label(hotkey::get_names(hotkey_item.id));
945 }
946 
948 {
949  const multimenu_button& hotkey_menu = find_widget<const multimenu_button>(this, "hotkey_category_menu", false);
950  const text_box& name_filter = find_widget<const text_box>(this, "filter", false);
951 
952  boost::dynamic_bitset<> toggle_states = hotkey_menu.get_toggle_states();
953  boost::dynamic_bitset<> res(visible_hotkeys_.size());
954 
955  std::string text = name_filter.get_value();
956 
957  // Nothing selected. It means that *all* categories are shown.
958  if(toggle_states.none()) {
959  toggle_states = ~toggle_states;
960  }
961 
962  for(std::size_t h = 0; h < visible_hotkeys_.size(); ++h) {
963  // Default to true if there is no filter text
964  bool found = true;
965 
966  if(!text.empty()) {
967  const std::string description = visible_hotkeys_[h]->description.str();
968 
969  for(const auto& word : utils::split(text, ' ')) {
970  found = translation::ci_search(description, word);
971 
972  // No match, we're excluding this hotkey
973  if(!found) {
974  break;
975  }
976  }
977  }
978 
979  unsigned cat_index = 0;
980 
981  // Filter categories
982  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
983  if(visible_hotkeys_[h]->category == cat) {
984  break;
985  } else {
986  ++cat_index;
987  }
988  }
989 
990  if(cat_index < toggle_states.size() && found) {
991  res[h] = toggle_states[cat_index];
992  } else {
993  res[h] = false;
994  }
995  }
996 
997  find_widget<listbox>(this, "list_hotkeys", false).set_row_shown(res);
998 }
999 
1001 {
1002  const int selected_row = list.get_selected_row();
1003  const auto& pref = adv_preferences_[selected_row];
1004 
1005  if(pref.type == avp::avd_type::SPECIAL) {
1006  if(pref.field == "logging") {
1007  gui2::dialogs::log_settings::display();
1008  } else if(pref.field == "orb_color") {
1009  gui2::dialogs::select_orb_colors::display();
1010  } else {
1011  WRN_GUI_L << "Invalid or unimplemented custom advanced prefs option: " << pref.field;
1012  }
1013 
1014  // Add more options here as needed
1015  }
1016 
1017  const bool has_description = !pref.description.empty();
1018 
1019  if(has_description || (pref.type != avp::avd_type::SPECIAL && pref.type != avp::avd_type::TOGGLE)) {
1020  find_widget<widget>(list.get_row_grid(selected_row), "prefs_setter_grid", false)
1021  .set_visible(widget::visibility::visible);
1022  }
1023 
1024  if(last_selected_item_ != selected_row) {
1025  find_widget<widget>(list.get_row_grid(last_selected_item_), "prefs_setter_grid", false)
1026  .set_visible(widget::visibility::invisible);
1027 
1028  last_selected_item_ = selected_row;
1029  }
1030 }
1031 
1033 {
1034  //
1035  // MULTIPLAYER TABS
1036  //
1038  std::bind(&preferences_dialog::on_tab_select, this));
1039 }
1040 
1042 {
1043  set_always_save_fields(true);
1044 
1045  connect_signal_mouse_left_click(find_widget<button>(&window, "about", false), std::bind(&game_version::display<>));
1046 
1047  //
1048  // Status labels
1049  // These need to be set here in pre_show, once the fields are initialized. For some reason, this
1050  // is not the case for those in Advanced
1051  //
1052 
1053  gui2::bind_status_label<slider>(&window, "max_saves_slider");
1054  gui2::bind_status_label<slider>(&window, "turbo_slider");
1055  gui2::bind_status_label<slider>(&window, "pixel_scale_slider");
1056 
1057  //gui2::bind_status_label<slider>(&window, "scaling_slider", [](slider& s)->std::string {
1058  // return s.get_value_label() + "%";
1059  //});
1060 
1061  listbox& selector = find_widget<listbox>(&window, "selector", false);
1062  stacked_widget& pager = find_widget<stacked_widget>(&window, "pager", false);
1063 
1064  pager.set_find_in_all_layers(true);
1065 
1067  std::bind(&preferences_dialog::on_page_select, this));
1068 
1069  window.keyboard_capture(&selector);
1070 
1071  VALIDATE(selector.get_item_count() == pager.get_layer_count(),
1072  "The preferences pager and its selector listbox do not have the same number of items.");
1073 
1074  const int main_index = index_in_pager_range(initial_index_.first, pager);
1075 
1076  // Loops through each pager layer and checks if it has both a tab bar
1077  // and stack. If so, it initializes the options for the former and
1078  // selects the specified layer of the latter.
1079  for(unsigned int i = 0; i < pager.get_layer_count(); ++i) {
1080  listbox* tab_selector = find_widget<listbox>(
1081  pager.get_layer_grid(i), "tab_selector", false, false);
1082 
1083  stacked_widget* tab_pager = find_widget<stacked_widget>(
1084  pager.get_layer_grid(i), "tab_pager", false, false);
1085 
1086  if(tab_pager && tab_selector) {
1087  const int ii = static_cast<int>(i);
1088  const int tab_index = index_in_pager_range(initial_index_.second, *tab_pager);
1089  const int to_select = (ii == main_index ? tab_index : 0);
1090 
1091  // Initialize tabs for this page
1092  initialize_tabs(*tab_selector);
1093 
1094  tab_selector->select_row(to_select);
1095  tab_pager->select_layer(to_select);
1096  }
1097  }
1098 
1099  // Finally, select the initial main page
1100  selector.select_row(main_index);
1101  pager.select_layer(main_index);
1102 }
1103 
1104 void preferences_dialog::set_visible_page(unsigned int page, const std::string& pager_id)
1105 {
1106  find_widget<stacked_widget>(this, pager_id, false).select_layer(page);
1107 }
1108 
1109 // Special fullsceen callback
1111 {
1112  const bool ison = find_widget<toggle_button>(this, "fullscreen", false).get_value_bool();
1113  video::set_fullscreen(ison);
1114 
1115  menu_button& res_list = find_widget<menu_button>(this, "resolution_set", false);
1116 
1117  set_resolution_list(res_list);
1118  res_list.set_active(!ison);
1119 }
1120 
1122 {
1123  menu_button& res_list = find_widget<menu_button>(this, "resolution_set", false);
1124 
1125  if(video::set_resolution(resolutions_[res_list.get_value()])) {
1126  set_resolution_list(res_list);
1127  }
1128 }
1129 
1131 {
1132  menu_button& theme_list = find_widget<menu_button>(this, "choose_theme", false);
1133 
1134  const auto selection = theme_list.get_value();
1135  const auto& theme = themes_.at(selection);
1136  auto* display = display::get_singleton();
1137 
1139  if(display && resources::gamedata && resources::gamedata->get_theme().empty()) {
1140  display->set_theme(theme.id);
1141  }
1142 
1143 }
1144 
1146 {
1147  const int selected_row =
1148  std::max(0, find_widget<listbox>(this, "selector", false).get_selected_row());
1149  set_visible_page(static_cast<unsigned int>(selected_row), "pager");
1150 }
1151 
1153 {
1154  const int selected_row =
1155  std::max(0, find_widget<listbox>(this, "tab_selector", false).get_selected_row());
1156  set_visible_page(static_cast<unsigned int>(selected_row), "tab_pager");
1157 }
1158 
1160 {
1161  save_hotkeys();
1162 
1163  // Save new prefs to disk. This also happens on app close, but doing
1164  // it here too ensures nothing is lost in case of, say, a crash.
1166 }
1167 
1168 } // namespace dialogs
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
child_itors child_range(config_key_type key)
Definition: config.cpp:277
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:87
void set_theme(const std::string &new_theme)
Definition: display.cpp:253
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:101
std::ostringstream wrapper.
Definition: formatter.hpp:40
hotkey::hotkey_ptr get_new_binding() const
Definition: hotkey_bind.hpp:32
@ yes_no_buttons
Shows a yes and no button.
Definition: message.hpp:81
Abstract base class for all modal dialogs.
bool show(const unsigned auto_close_time=0)
Shows the window.
void set_visible_page(unsigned int page, const std::string &pager_id)
void set_theme_list(menu_button &theme_list)
void remove_hotkey_callback(listbox &hotkeys)
virtual void post_show(window &) override
Actions to be taken after the window has been shown.
void set_resolution_list(menu_button &res_list)
void on_advanced_prefs_list_select(listbox &tree)
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
void on_page_select()
Callback for selection changes.
void on_friends_list_select(listbox &list, text_box &textbox)
void add_friend_list_entry(const bool is_friend, text_box &textbox)
widget_data get_friends_list_row_data(const preferences::acquaintance &entry)
void update_friends_list_controls(listbox &list)
void handle_res_select()
Special callback functions.
void remove_friend_list_entry(listbox &friends_list, text_box &textbox)
void initialize_sound_option_group(const std::string &id_suffix)
void add_hotkey_callback(listbox &hotkeys)
Dialog for selecting a GUI theme.
Definition: theme_list.hpp:36
Base container class.
Definition: grid.hpp:32
std::unique_ptr< widget > swap_child(const std::string &id, std::unique_ptr< widget > w, const bool recurse, widget *new_parent=nullptr)
Exchanges a child in the grid.
Definition: grid.cpp:101
The listbox class.
Definition: listbox.hpp:46
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:62
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:233
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:246
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:82
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:121
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:271
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:127
A menu_button is a styled_widget to choose an element from a list of elements.
Definition: menu_button.hpp:62
void set_values(const std::vector<::config > &values, unsigned selected=0)
virtual unsigned get_value() const override
Inherited from selectable_item.
Definition: menu_button.hpp:84
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: menu_button.cpp:77
A multimenu_button is a styled_widget to choose an element from a list of elements.
boost::dynamic_bitset get_toggle_states() const
Get the current state of the menu options.
A slider is a control that can select a value by moving a grip on a groove.
Definition: slider.hpp:60
virtual void set_value(int value) override
Inherited from integer_selector.
Definition: slider.cpp:82
virtual int get_value() const override
Inherited from integer_selector.
Definition: slider.hpp:79
A stacked widget holds several widgets on top of each other.
grid * get_layer_grid(unsigned int i)
Gets the grid for a specified layer.
unsigned int get_layer_count() const
Gets the total number of layers.
void set_find_in_all_layers(const bool do_find)
void select_layer(const int layer)
Selects and displays a particular layer.
virtual void set_use_markup(bool use_markup)
std::string get_value() const
const std::string & text() const
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
void set_text_changed_callback(std::function< void(text_box_base *textbox, const std::string text)> cb)
Set the text_changed callback.
Class for a single line text area.
Definition: text_box.hpp:142
Class for a toggle button.
virtual void set_value(unsigned selected, bool fire_event=false) override
Inherited from selectable_item.
Base class for all widgets.
Definition: widget.hpp:54
void set_visible(const visibility visible)
Definition: widget.cpp:471
@ visible
The user sets the widget visible, that means:
@ invisible
The user set the widget invisible, that means:
@ hidden
The user sets the widget hidden, that means:
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:67
void keyboard_capture(widget *widget)
Definition: window.cpp:1224
const std::string & get_status() const
Definition: game.hpp:62
const std::string & get_nick() const
Definition: game.hpp:61
const std::string & get_notes() const
Definition: game.hpp:63
Definition: theme.hpp:43
static std::vector< theme_info > get_basic_theme_info(bool include_hidden=false)
Returns minimal info about saved themes, optionally including hidden ones.
Definition: theme.cpp:988
Declarations for File-IO.
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
std::size_t i
Definition: function.cpp:968
int w
static std::string _(const char *str)
Definition: gettext.hpp:93
#define WRN_GUI_L
Definition: log.hpp:57
This file contains the window object, this object is a top level container which has the event manage...
New lexcical_cast header.
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
CURSOR_TYPE get()
Definition: cursor.cpp:216
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:176
void raise_resize_event()
Definition: events.cpp:759
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:321
const std::string unicode_multiplication_sign
Definition: constants.cpp:46
std::string selected
std::string path
Definition: filesystem.cpp:86
void connect_signal_mouse_left_release(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button release.
Definition: dispatcher.cpp:189
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:205
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:179
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:35
void show_transient_error_message(const std::string &message, const std::string &image, const bool message_use_markup)
Shows a transient error message to the user.
std::map< std::string, t_string > widget_item
Definition: widget.hpp:32
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:151
@ OK
Dialog was closed with the OK button.
Definition: retval.hpp:35
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414
const hotkey_list & get_hotkeys()
Returns the list of hotkeys.
std::string get_names(const std::string &id)
Returns a comma-separated string of hotkey names.
void save_hotkeys(config &cfg)
Save the non-default hotkeys to the config.
std::shared_ptr< class hotkey_base > hotkey_ptr
Definition: hotkey_item.hpp:27
void clear_hotkeys(const std::string &command)
Unset the command bindings for all hotkeys matching the command.
const std::map< std::string_view, hotkey::hotkey_command > & get_hotkey_commands()
returns a container that contains all currently active hotkey_commands.
std::vector< hotkey::hotkey_ptr > hotkey_list
Definition: hotkey_item.hpp:31
void add_hotkey(hotkey_ptr item)
Add a hotkey to the list of hotkeys.
t_string get_translatable_category_name(HOTKEY_CATEGORY category)
Gets the display name for a given hotkey category.
const hotkey_command & get_hotkey_command(const std::string &command)
returns the hotkey_command with the given name
Functions to load and save images from/to disk.
Modify, read and display user preferences.
void set_show_side_colors(bool value)
Definition: game.cpp:741
void set_scroll_speed(const int new_speed)
Definition: general.cpp:799
void set_skip_ai_moves(bool value)
Definition: game.cpp:736
bool stop_music_in_background()
Definition: general.cpp:777
bool show_floating_labels()
Definition: game.cpp:823
void set_turbo(bool ison)
Definition: general.cpp:474
lobby_joins get_lobby_joins()
Definition: game.cpp:331
void set_idle_anim(const bool ison)
Definition: general.cpp:520
void set_remember_password(bool remember)
void _set_lobby_joins(lobby_joins show)
Definition: game.cpp:345
bool chat_timestamping()
Definition: game.cpp:876
bool vsync()
Definition: general.cpp:439
void set_hide_whiteboard(bool value)
Definition: game.cpp:441
bool delete_saves()
Definition: game.cpp:766
bool auto_pixel_scale()
Definition: general.cpp:419
void set_turbo_speed(const double speed)
Definition: general.cpp:484
void set_grid(bool ison)
Definition: general.cpp:570
void set_draw_delay(int value)
Definition: general.cpp:910
bool interrupt_when_ally_sighted()
Definition: game.cpp:786
double idle_anim_rate()
Definition: general.cpp:525
bool whisper_friends_only()
Definition: lobby.cpp:21
bool turbo()
Definition: general.cpp:465
void set_idle_anim_rate(const int rate)
Definition: general.cpp:530
void write_preferences()
Definition: general.cpp:141
static std::map< PREFERENCE_VIEW, std::pair< int, int > > pef_view_map
Map containing page mappings that can be used to set the initially displayed page of the dialog.
bool idle_anim()
Definition: general.cpp:515
double turbo_speed()
Definition: general.cpp:479
void set_stop_music_in_background(bool ison)
Definition: general.cpp:782
int autosavemax()
Definition: game.cpp:791
void set_animate_water(bool value)
Definition: general.cpp:890
void set_vsync(bool ison)
Definition: general.cpp:460
bool show_standing_animations()
Definition: display.cpp:51
bool fullscreen()
Definition: general.cpp:434
void set_chat_lines(int lines)
Definition: game.cpp:891
bool save_replays()
Definition: game.cpp:756
void set_pixel_scale(const int scale)
Definition: general.cpp:414
void set_delete_saves(bool value)
Definition: game.cpp:761
void set_interrupt_when_ally_sighted(bool value)
Definition: game.cpp:781
void set_chat_timestamping(bool value)
Definition: game.cpp:881
void set_disable_auto_moves(bool value)
Definition: general.cpp:984
bool turn_dialog()
Definition: game.cpp:416
bool disable_auto_moves()
Definition: general.cpp:979
bool hide_whiteboard()
Definition: game.cpp:436
bool animate_water()
Definition: general.cpp:830
int pixel_scale()
Definition: general.cpp:408
void set_auto_pixel_scale(bool choice)
Definition: general.cpp:424
void set_turn_dialog(bool ison)
Definition: game.cpp:421
void set_theme(const std::string &theme)
Definition: game.cpp:816
int draw_delay()
Definition: general.cpp:905
bool remove_acquaintance(const std::string &nick)
Definition: game.cpp:241
int chat_lines()
Definition: game.cpp:886
bool show_side_colors()
Definition: game.cpp:746
void set_show_floating_labels(bool value)
Definition: game.cpp:828
bool remember_password()
std::pair< preferences::acquaintance *, bool > add_acquaintance(const std::string &nick, const std::string &mode, const std::string &notes)
Definition: game.cpp:227
void set_save_replays(bool value)
Definition: game.cpp:751
void set_autosavemax(int value)
Definition: game.cpp:796
void set_show_standing_animations(bool value)
Definition: display.cpp:56
void set_animate_map(bool value)
Definition: general.cpp:885
bool skip_ai_moves()
Definition: game.cpp:731
bool grid()
Definition: general.cpp:565
bool animate_map()
Definition: general.cpp:825
bool enable_whiteboard_mode_on_start()
Definition: game.cpp:426
void set_enable_whiteboard_mode_on_start(bool value)
Definition: game.cpp:431
void set_whisper_friends_only(bool v)
Definition: lobby.cpp:26
const config & options()
Definition: game.cpp:555
const advanced_pref_list & get_advanced_preferences()
Gets a list of the available advanced preferences.
Definition: advanced.cpp:87
int scroll_speed()
Definition: general.cpp:791
const std::map< std::string, acquaintance > & get_acquaintances()
Definition: game.cpp:192
bool is_friend(const std::string &nick)
Definition: game.cpp:264
void show_wesnothd_server_search()
Definition: display.cpp:99
game_data * gamedata
Definition: resources.cpp:23
bool ci_search(const std::string &s1, const std::string &s2)
Definition: gettext.cpp:567
std::vector< std::string > split(const config_attribute_value &val)
std::vector< point > get_available_resolutions(const bool include_current)
Returns the list of available screen resolutions.
Definition: video.cpp:708
point current_resolution()
The current window size in desktop coordinates.
Definition: video.cpp:760
void set_fullscreen(bool fullscreen)
Set the fullscreen state.
Definition: video.cpp:776
bool set_resolution(const point &resolution)
Set the window resolution.
Definition: video.cpp:805
void toggle_fullscreen()
Toggle fullscreen mode.
Definition: video.cpp:800
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
Definition: video.cpp:835
std::string_view data
Definition: picture.cpp:199
This file contains the settings handling of the widget library.
Stores all information related to functions that can be bound to hotkeys.
std::string id
The unique ID.
Holds a 2D point.
Definition: point.hpp:25
Definitions related to theme-support.
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
#define h