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