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