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