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