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