The Battle for Wesnoth  1.19.14+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  // TODO: this should probably be a locale dependent string (use comma/dot depending on language)
438  [this](int pos, int /*max*/)->t_string { return lexical_cast<std::string>(accl_speeds_[pos]); }
439  );
440 
441  /* SKIP AI MOVES */
442  register_bool("skip_ai_moves", true,
443  []() {return prefs::get().skip_ai_moves();},
444  [](bool v) {prefs::get().set_skip_ai_moves(v);});
445 
446  /* DISABLE AUTO MOVES */
447  register_bool("disable_auto_moves", true,
448  []() {return prefs::get().disable_auto_moves();},
449  [](bool v) {prefs::get().set_disable_auto_moves(v);});
450 
451  /* TURN DIALOG */
452  register_bool("show_turn_dialog", true,
453  []() {return prefs::get().turn_dialog();},
454  [](bool v) {prefs::get().set_turn_dialog(v);});
455 
456  /* ENABLE PLANNING MODE */
457  register_bool("whiteboard_on_start", true,
458  []() {return prefs::get().enable_planning_mode_on_start();},
459  [](bool v) {prefs::get().set_enable_planning_mode_on_start(v);});
460 
461  /* HIDE ALLY PLANS */
462  register_bool("whiteboard_hide_allies", true,
463  []() {return prefs::get().hide_whiteboard();},
464  [](bool v) {prefs::get().set_hide_whiteboard(v);});
465 
466  /* INTERRUPT ON SIGHTING */
467  register_bool("interrupt_move_when_ally_sighted", true,
468  []() {return prefs::get().ally_sighted_interrupts();},
469  [](bool v) {prefs::get().set_ally_sighted_interrupts(v);});
470 
471  /* SAVE REPLAYS */
472  register_bool("save_replays", true,
473  []() {return prefs::get().save_replays();},
474  [](bool v) {prefs::get().set_save_replays(v);});
475 
476  /* DELETE AUTOSAVES */
477  register_bool("delete_saves", true,
478  []() {return prefs::get().delete_saves();},
479  [](bool v) {prefs::get().set_delete_saves(v);});
480 
481  /* MAX AUTO SAVES */
482  register_integer("max_saves_slider", true,
483  []() {return prefs::get().auto_save_max();},
484  [](int v) {prefs::get().set_auto_save_max(v);});
485 
486  /* CACHE MANAGE */
487  connect_signal_mouse_left_click(find_widget<button>("cachemg"),
488  [](auto&&...) { dialogs::game_cache_options::display(); });
489 
490  //
491  // DISPLAY PANEL
492  //
493 
494  /* FULLSCREEN TOGGLE */
495  toggle_button& toggle_fullscreen = find_widget<toggle_button>("fullscreen");
496  toggle_fullscreen.set_value(prefs::get().fullscreen());
497 #ifdef __ANDROID__
498  toggle_fullscreen.set_active(false);
499 #endif
500 
501  // We bind a special callback function, so setup_single_toggle() is not used
503  [this](auto&&...) { fullscreen_toggle_callback(); });
504 
505  /* SET RESOLUTION */
506  menu_button& res_list = find_widget<menu_button>("resolution_set");
507 
508  res_list.set_use_markup(true);
509 #ifdef __ANDROID__
510  res_list.set_active(false);
511 #else
512  res_list.set_active(!prefs::get().fullscreen());
513 #endif
514 
515  set_resolution_list(res_list);
516 
518  [this](auto&&...) { handle_res_select(); });
519 
520  connect_signal<event::SDL_VIDEO_RESIZE>(
521  [this, &res_list](auto&&...) { set_resolution_list(res_list); });
522 
523  if (video::get_max_pixel_scale() > 1) {
524  /* PIXEL SCALE */
525  register_integer("pixel_scale_slider", true,
526  []() {return prefs::get().pixel_scale();},
527  [](int v) {prefs::get().set_pixel_scale(v);});
528 
529  slider& ps_slider = find_widget<slider>("pixel_scale_slider");
530  ps_slider.set_value_range(1, video::get_max_pixel_scale());
532  [this](auto&&...) { apply_pixel_scale(); });
533 
534  /* AUTOMATIC PIXEL SCALE */
535  register_bool("auto_pixel_scale", true,
536  []() {return prefs::get().auto_pixel_scale();},
537  [](bool v) {prefs::get().set_auto_pixel_scale(v);},
538  [&](widget& w) { disable_widget_on_toggle_inverted<slider>(*this, w, "pixel_scale_slider"); }, true);
539  } else {
540  find_widget<slider>("pixel_scale_slider").set_active(false);
541  find_widget<toggle_button>("auto_pixel_scale").set_active(false);
542  }
543 
544  toggle_button& auto_ps_toggle =
545  find_widget<toggle_button>("auto_pixel_scale");
546  connect_signal_mouse_left_click(auto_ps_toggle,
547  [this](auto&&...) { apply_pixel_scale(); });
548 
549  /* SHOW TIPS PANEL ON TITLESCREEN */
550  register_bool("show_tips", true,
551  []() {return prefs::get().show_tips();},
552  [&](bool v) {
553  // if changed once: different value, reload
554  // if changed twice: double toggle, same value, don't reload
556  prefs::get().set_show_tips(v);
557  });
558 
559  /* SHOW FLOATING LABELS */
560  register_bool("show_floating_labels", true,
561  []() {return prefs::get().floating_labels();},
562  [](bool v) {prefs::get().set_floating_labels(v);});
563 
564  /* SHOW TEAM COLORS */
565  register_bool("show_ellipses", true,
566  []() {return prefs::get().show_side_colors();},
567  [](bool v) {prefs::get().set_show_side_colors(v);});
568 
569  /* SHOW GRID */
570  register_bool("show_grid", true,
571  []() {return prefs::get().grid();},
572  [](bool v) {prefs::get().set_grid(v);});
573 
574  /* ANIMATE MAP */
575  register_bool("animate_terrains", true,
576  []() {return prefs::get().animate_map();},
577  [](bool v) {prefs::get().set_animate_map(v);},
578  [&](widget& w) { disable_widget_on_toggle<toggle_button>(*this, w, "animate_water"); }, true);
579 
580  /* ANIMATE WATER */
581  register_bool("animate_water", true,
582  []() {return prefs::get().animate_water();},
583  [](bool v) {prefs::get().set_animate_water(v);});
584 
585  /* SHOW UNIT STANDING ANIMS */
586  register_bool("animate_units_standing", true,
587  []() {return prefs::get().show_standing_animations();},
588  [](bool v) {prefs::get().set_show_standing_animations(v);});
589 
590  /* SHOW UNIT IDLE ANIMS */
591  register_bool("animate_units_idle", true,
592  []() {return prefs::get().idle_anim();},
593  [](bool v) {prefs::get().set_idle_anim(v);},
594  [&](widget& w) { disable_widget_on_toggle<slider>(*this, w, "idle_anim_frequency"); }, true);
595 
596  register_integer("idle_anim_frequency", true,
597  []() {return prefs::get().idle_anim_rate();},
598  [](int v) {prefs::get().set_idle_anim_rate(v);});
599 
600  /* FONT SCALING */
601  //register_integer("scaling_slider", true,
602  // font_scaling, set_font_scaling);
603 
604  /* VSYNC */
605  register_bool("vsync", true,
606  []() {return prefs::get().vsync();},
607  [](bool v) {prefs::get().set_vsync(v);});
608 
609  /* SELECT THEME */
610  menu_button& theme_list = find_widget<menu_button>("choose_theme");
613  [this](auto&&...) { handle_theme_select(); });
614 
615  /* SELECT GUI2 THEME */
616  menu_button& gui2_theme_list = find_widget<menu_button>("choose_gui2_theme");
617  button& apply_btn = find_widget<button>("apply");
618  set_gui2_theme_list(gui2_theme_list);
619  connect_signal_notify_modified(gui2_theme_list, [&](auto&&...) { apply_btn.set_active(true); });
620  apply_btn.set_active(false);
622  [this](auto&&...) { handle_gui2_theme_select(); });
623 
624  //
625  // SOUND PANEL
626  //
627 
628  /* SOUND FX */
629  initialize_sound_option_group<sound, set_sound, sound_volume, set_sound_volume>("sfx");
630 
631  /* MUSIC */
632  initialize_sound_option_group<music_on, set_music, music_volume, set_music_volume>("music");
633 
634  register_bool("sound_toggle_stop_music_in_background", true,
635  []() {return prefs::get().stop_music_in_background();},
636  [](bool v) {prefs::get().set_stop_music_in_background(v);});
637 
638  /* TURN BELL */
639  initialize_sound_option_group<turn_bell, set_turn_bell, bell_volume, set_bell_volume>("bell");
640 
641  /* UI FX */
642  initialize_sound_option_group<ui_sound_on, set_ui_sound, ui_volume, set_ui_volume>("uisfx");
643 
644  //
645  // MULTIPLAYER PANEL
646  //
647 
648  /* CHAT LINES */
649  register_integer("chat_lines", true,
650  []() {return prefs::get().chat_lines();},
651  [](int v) {prefs::get().set_chat_lines(v);});
652 
653  /* CHAT TIMESTAMPPING */
654  register_bool("chat_timestamps", true,
655  []() {return prefs::get().chat_timestamp();},
656  [](bool v) {prefs::get().set_chat_timestamp(v);});
657 
658  /* SAVE PASSWORD */
659  register_bool("remember_password", true,
660  []() {return prefs::get().remember_password();},
661  [](bool v) {prefs::get().set_remember_password(v);});
662 
663  /* WHISPERS FROM FRIENDS ONLY */
664  register_bool("lobby_whisper_friends_only", true,
665  []() {return prefs::get().lobby_whisper_friends_only();},
666  [](bool v) {prefs::get().set_lobby_whisper_friends_only(v);});
667 
668  /* LOBBY JOIN NOTIFICATIONS */
669  lobby_joins_group.add_member(find_widget<toggle_button>("lobby_joins_none", false, true), pref_constants::lobby_joins::show_none);
670  lobby_joins_group.add_member(find_widget<toggle_button>("lobby_joins_friends", false, true), pref_constants::lobby_joins::show_friends);
671  lobby_joins_group.add_member(find_widget<toggle_button>("lobby_joins_all", false, true), pref_constants::lobby_joins::show_all);
672 
674 
677  });
678 
679  /* FRIENDS LIST */
680  listbox& friends_list = find_widget<listbox>("friends_list");
681 
682  friends_list.clear();
683 
684  for(const auto& entry : prefs::get().get_acquaintances()) {
685  friends_list.add_row(get_friends_list_row_data(entry.second));
686  }
687 
688  update_friends_list_controls(friends_list);
689 
690  text_box& textbox = find_widget<text_box>("friend_name_box");
691 
692  connect_signal_mouse_left_click(find_widget<button>("add_friend"),
693  [&, this](auto&&...) { add_friend_list_entry(true, textbox); });
694 
695  connect_signal_mouse_left_click(find_widget<button>("add_ignored"),
696  [&, this](auto&&...) { add_friend_list_entry(false, textbox); });
697 
698  connect_signal_mouse_left_click(find_widget<button>("remove"),
699  [&, this](auto&&...) { remove_friend_list_entry(friends_list, textbox); });
700 
701  connect_signal_notify_modified(friends_list,
702  [&, this](auto&&...) { on_friends_list_select(friends_list, textbox); });
703 
704  /* ALERTS */
705  connect_signal_mouse_left_click(find_widget<button>("mp_alerts"),
706  [](auto&&...) { mp_alerts_options::display(); });
707 
708  /* SET WESNOTHD PATH */
709  connect_signal_mouse_left_click(find_widget<button>("mp_wesnothd"),
710  [](auto&&...) { prefs::get().show_wesnothd_server_search(); });
711 
712 
713  //
714  // ADVANCED PANEL
715  //
716 
717  listbox& advanced = find_widget<listbox>("advanced_prefs");
718 
719  widget_data row_data;
720 
721  for(const auto& option : prefs::get().get_advanced_preferences()) {
722  const std::string pref_name = option.field;
723 
724  row_data["pref_name"]["label"] = option.name;
725  grid* main_grid = &advanced.add_row(row_data);
726 
727  grid& details_grid = main_grid->find_widget<grid>("prefs_setter_grid");
729 
730  // The toggle widget for toggle-type options (hidden for other types)
731  toggle_button& toggle_box = main_grid->find_widget<toggle_button>("value_toggle");
733 
734  if(!option.description.empty()) {
735  main_grid->find_widget<styled_widget>("description").set_label(option.description);
736  }
737 
738  switch(option.type) {
740 
742  toggle_box.set_value(preferences_dialog_friend::get(pref_name, option.cfg["default"].to_bool()));
743 
745  [&, pref_name](auto&&...) { preferences_dialog_friend::set(pref_name, toggle_box.get_value_bool()); });
746 
747  gui2::bind_default_status_label(toggle_box, "value");
748  break;
749  }
750 
752  auto setter_widget = build_single_widget_instance<slider>(config {"definition", "minimal"});
753  setter_widget->set_id("setter");
754  // Maximum must be set first or this will assert
755  setter_widget->set_value_range(option.cfg["min"].to_int(), option.cfg["max"].to_int());
756  setter_widget->set_step_size(option.cfg["step"].to_int(1));
757 
758  details_grid.swap_child("setter", std::move(setter_widget), true);
759 
760  slider& slide = details_grid.find_widget<slider>("setter");
761 
762  slide.set_value(preferences_dialog_friend::get(pref_name, option.cfg["default"].to_int()));
763 
765  [&, pref_name](auto&&...) { preferences_dialog_friend::set(pref_name, slide.get_value()); });
766 
767  gui2::bind_default_status_label(slide, "value");
768  break;
769  }
770 
772  std::vector<config> menu_data;
773  std::vector<std::string> option_ids;
774 
775  for(const config& choice : option.cfg.child_range("option")) {
776  config menu_item;
777  menu_item["label"] = choice["name"];
778  if(choice.has_attribute("description")) {
779  menu_item["details"] = markup::span_color("#777", choice["description"]);
780  }
781  menu_data.push_back(menu_item);
782  option_ids.push_back(choice["id"]);
783  }
784 
785  // Attempt to find an initial selection
786  int selected = std::distance(option_ids.begin(), std::find(option_ids.begin(), option_ids.end(),
787  preferences_dialog_friend::get(pref_name, option.cfg["default"].str())
788  ));
789 
790  // If the saved option value was invalid, reset selection to 0.
791  if(selected < 0 || selected >= static_cast<int>(option_ids.size())) {
792  selected = 0;
793  }
794 
795  auto setter_widget = build_single_widget_instance<menu_button>();
796  setter_widget->set_id("setter");
797 
798  details_grid.swap_child("setter", std::move(setter_widget), true);
799 
800  menu_button& menu = details_grid.find_widget<menu_button>("setter");
801 
802  menu.set_use_markup(true);
803  menu.set_values(menu_data, selected);
804 
806  [=](widget& w, auto&&...) { preferences_dialog_friend::set(pref_name, option_ids[dynamic_cast<menu_button&>(w).get_value()]); });
807 
808  gui2::bind_default_status_label(menu, "value");
809  break;
810  }
811 
813  //main_grid->remove_child("setter");
814 
815  auto value_widget = build_single_widget_instance<image>();
816  value_widget->set_label("icons/arrows/arrows_blank_right_25.png~CROP(3,3,18,18)");
817 
818  main_grid->swap_child("value", std::move(value_widget), true);
819  break;
820  }
821  }
822  }
823 
825  [this, &advanced](auto&&...) { on_advanced_prefs_list_select(advanced); });
826 
828 
829  //
830  // HOTKEYS PANEL
831  //
832 
833  multimenu_button& hotkey_menu = find_widget<multimenu_button>("hotkey_category_menu");
834  connect_signal_notify_modified(hotkey_menu,
835  [this](auto&&...) { hotkey_filter_callback(); });
836 
838 
839  text_box& filter = find_widget<text_box>("filter");
840  filter.on_modified([this](const auto&) { hotkey_filter_callback(); });
841 
842  hotkey_list.set_sorters(
843  // Action column
844  [this](const std::size_t i) { return visible_hotkeys_[i]->description; },
845 
846  // Hotkey column
847  [this](const std::size_t i) { return hotkey::get_names(visible_hotkeys_[i]->id); },
848 
849  // Scope columns
850  [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_GAME]; },
851  [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_EDITOR]; },
852  [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_MAIN_MENU]; }
853  );
854 
855  hotkey_list.set_active_sorter("sort_0", sort_order::type::ascending, true);
856 
857  connect_signal_mouse_left_click(find_widget<button>("btn_add_hotkey"),
858  [this, &hotkey_list](auto&&...) { add_hotkey_callback(hotkey_list); });
859 
860  connect_signal_mouse_left_click(find_widget<button>("btn_clear_hotkey"),
861  [this, &hotkey_list](auto&&...) { remove_hotkey_callback(hotkey_list); });
862 
863  connect_signal_mouse_left_click(find_widget<button>("btn_reset_hotkeys"),
864  [this](auto&&...) { default_hotkey_callback(); });
865 }
866 
868 {
869  widget_data row_data;
870 
871  t_string& row_icon = row_data["img_icon"]["label"];
872  t_string& row_action = row_data["lbl_desc"]["label"];
873  t_string& row_hotkey = row_data["lbl_hotkey"]["label"];
874 
875  t_string& row_is_g = row_data["lbl_is_game"]["label"];
876  t_string& row_is_e = row_data["lbl_is_editor"]["label"];
877  t_string& row_is_m = row_data["lbl_is_mainmenu"]["label"];
878 
879  listbox& hotkey_list = find_widget<listbox>("list_hotkeys");
880 
881  hotkey_list.clear();
882  visible_hotkeys_.clear();
883  visible_categories_.clear();
884 
885  //
886  // Main hotkeys list
887  //
888 
889  // These translated initials should match those used in data/gui/window/preferences/02_hotkeys.cfg
890  const std::string gh = markup::span_color("#0f0", _("game_hotkeys^G"));
891  const std::string eh = markup::span_color("#0f0", _("editor_hotkeys^E"));
892  const std::string mh = markup::span_color("#0f0", _("mainmenu_hotkeys^M"));
893 
894  for(const auto& [id, hotkey_item] : hotkey::get_hotkey_commands()) {
895  if(hotkey_item.hidden) {
896  continue;
897  }
898 
899  visible_hotkeys_.push_back(&hotkey_item);
900  visible_categories_.insert(hotkey_item.category);
901 
902  if(filesystem::file_exists(game_config::path + "/images/icons/action/" + hotkey_item.id + "_25.png")) {
903  row_icon = "icons/action/" + hotkey_item.id + "_25.png~CROP(3,3,18,18)";
904  } else {
905  row_icon = "";
906  }
907 
908  row_action = hotkey_item.description;
909  row_hotkey = hotkey::get_names(hotkey_item.id);
910 
911  row_is_g = hotkey_item.scope[hotkey::SCOPE_GAME] ? gh : "";
912  row_is_e = hotkey_item.scope[hotkey::SCOPE_EDITOR] ? eh : "";
913  row_is_m = hotkey_item.scope[hotkey::SCOPE_MAIN_MENU] ? mh : "";
914 
915  hotkey_list.add_row(row_data);
916  }
917 
918  //
919  // Filter options
920  //
921 
922  std::vector<config> filter_ops;
923  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
924  filter_ops.emplace_back("label", hotkey::get_translatable_category_name(cat), "checkbox", false);
925  }
926 
927  find_widget<multimenu_button>("hotkey_category_menu").set_values(filter_ops);
928 
929  return hotkey_list;
930 }
931 
933 {
934  int row_number = hotkeys.get_selected_row();
935  if(row_number < 0) {
936  gui2::show_transient_message("", _("No hotkey selected"));
937  return;
938  }
939 
940  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
941 
942  gui2::dialogs::hotkey_bind bind_dlg(hotkey_item.id);
943  bind_dlg.show();
944 
945  hotkey::hotkey_ptr newhk = bind_dlg.get_new_binding();
946  hotkey::hotkey_ptr oldhk;
947 
948  // only if not cancelled.
949  if(newhk.get() == nullptr) {
950  return;
951  }
952 
953  for(const hotkey::hotkey_ptr& hk : hotkey::get_hotkeys()) {
954  if(!hk->is_disabled() && newhk->bindings_equal(hk)) {
955  oldhk = hk;
956  }
957  }
958 
959  if(oldhk && oldhk->get_command() == hotkey_item.id) {
960  return;
961  }
962 
963  if(oldhk && oldhk->get_command() != "null") {
964  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>”?", {
965  {"hotkey_sequence", oldhk->get_name()},
966  {"old_hotkey_action", hotkey::get_hotkey_command(oldhk->get_command()).description},
967  {"new_hotkey_action", hotkey::get_hotkey_command(newhk->get_command()).description}
968  });
969 
970  const int res = gui2::show_message(_("Reassign Hotkey"), text, gui2::dialogs::message::yes_no_buttons, true);
971  if(res != gui2::retval::OK) {
972  return;
973  }
974  }
975 
976  hotkey::add_hotkey(newhk);
977 
978  // We need to recalculate all hotkey names in because we might have removed a hotkey from another command.
979  for(std::size_t i = 0; i < hotkeys.get_item_count(); ++i) {
980  const hotkey::hotkey_command& hotkey_item_row = *visible_hotkeys_[i];
981  hotkeys.get_row_grid(i)->find_widget<label>("lbl_hotkey").set_label(hotkey::get_names(hotkey_item_row.id));
982  }
983 }
984 
986 {
987  gui2::show_transient_message(_("Hotkeys Reset"), _("All hotkeys have been reset to their default values."));
988 
990 
991  // Set up the list again and reselect the default sorting option.
993  hotkey_list.set_active_sorter("sort_0", sort_order::type::ascending, true);
994 }
995 
997 {
998  int row_number = hotkeys.get_selected_row();
999  if(row_number < 0) {
1000  gui2::show_transient_message("", _("No hotkey selected"));
1001  return;
1002  }
1003 
1004  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
1005  hotkey::clear_hotkeys(hotkey_item.id);
1006  hotkeys.get_row_grid(row_number)->find_widget<label>("lbl_hotkey").set_label(hotkey::get_names(hotkey_item.id));
1007 }
1008 
1010 {
1011  const multimenu_button& hotkey_menu = find_widget<const multimenu_button>("hotkey_category_menu");
1012  const text_box& name_filter = find_widget<const text_box>("filter");
1013 
1014  boost::dynamic_bitset<> toggle_states = hotkey_menu.get_toggle_states();
1015  boost::dynamic_bitset<> res(visible_hotkeys_.size());
1016 
1017  std::string text = name_filter.get_value();
1018 
1019  // Nothing selected. It means that *all* categories are shown.
1020  if(toggle_states.none()) {
1021  toggle_states = ~toggle_states;
1022  }
1023 
1024  for(std::size_t h = 0; h < visible_hotkeys_.size(); ++h) {
1025  // Default to true if there is no filter text
1026  bool found = true;
1027 
1028  if(!text.empty()) {
1029  const std::string description = visible_hotkeys_[h]->description.str();
1030 
1031  for(const auto& word : utils::split(text, ' ')) {
1032  found = translation::ci_search(description, word);
1033 
1034  // No match, we're excluding this hotkey
1035  if(!found) {
1036  break;
1037  }
1038  }
1039  }
1040 
1041  unsigned cat_index = 0;
1042 
1043  // Filter categories
1044  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
1045  if(visible_hotkeys_[h]->category == cat) {
1046  break;
1047  } else {
1048  ++cat_index;
1049  }
1050  }
1051 
1052  if(cat_index < toggle_states.size() && found) {
1053  res[h] = toggle_states[cat_index];
1054  } else {
1055  res[h] = false;
1056  }
1057  }
1058 
1059  find_widget<listbox>("list_hotkeys").set_row_shown(res);
1060 }
1061 
1063 {
1064  const int selected_row = list.get_selected_row();
1065  const auto& pref = prefs::get().get_advanced_preferences()[selected_row];
1066 
1067  if(pref.type == preferences::option::avd_type::SPECIAL) {
1068  if(pref.field == "logging") {
1069  gui2::dialogs::log_settings::display();
1070  } else if(pref.field == "orb_color") {
1071  gui2::dialogs::select_orb_colors::display();
1072  } else if(pref.field == "reach_map") {
1073  gui2::dialogs::reachmap_options::display();
1074  } else {
1075  WRN_GUI_L << "Invalid or unimplemented custom advanced prefs option: " << pref.field;
1076  }
1077 
1078  // Add more options here as needed
1079  }
1080 
1081  const bool has_description = !pref.description.empty();
1082 
1083  if(has_description || (pref.type != preferences::option::avd_type::SPECIAL && pref.type != preferences::option::avd_type::TOGGLE)) {
1084  list.get_row_grid(selected_row)->find_widget<widget>("prefs_setter_grid")
1086  }
1087 
1088  if(last_selected_item_ != selected_row) {
1089  list.get_row_grid(last_selected_item_)->find_widget<widget>("prefs_setter_grid")
1091 
1092  last_selected_item_ = selected_row;
1093  }
1094 }
1095 
1097 {
1098  //
1099  // MULTIPLAYER TABS
1100  //
1102  [this](auto&&...) { on_tab_select(); });
1103 }
1104 
1106 {
1107  set_always_save_fields(true);
1108 
1109  connect_signal_mouse_left_click(find_widget<button>("about"),
1110  [](auto&&...) { game_version::display(); });
1111 
1112  //
1113  // Status labels
1114  // These need to be set here in pre_show, once the fields are initialized. For some reason, this
1115  // is not the case for those in Advanced
1116  //
1117 
1118  gui2::bind_default_status_label(find_widget<slider>("max_saves_slider"));
1119  gui2::bind_default_status_label(find_widget<slider>("turbo_slider"));
1120  gui2::bind_default_status_label(find_widget<slider>("pixel_scale_slider"));
1121 
1122  listbox& selector = find_widget<listbox>("selector");
1123  stacked_widget& pager = find_widget<stacked_widget>("pager");
1124 
1125  pager.set_find_in_all_layers(true);
1126 
1128  [this](auto&&...) { on_page_select(); });
1129 
1130  keyboard_capture(&selector);
1131 
1132  VALIDATE(selector.get_item_count() == pager.get_layer_count(),
1133  "The preferences pager and its selector listbox do not have the same number of items.");
1134 
1135  const int main_index = index_in_pager_range(initial_index_.first, pager);
1136 
1137  // Loops through each pager layer and checks if it has both a tab bar
1138  // and stack. If so, it initializes the options for the former and
1139  // selects the specified layer of the latter.
1140  for(unsigned int i = 0; i < pager.get_layer_count(); ++i) {
1141  listbox* tab_selector = pager.get_layer_grid(i)->find_widget<listbox>("tab_selector", false, false);
1142 
1143  stacked_widget* tab_pager = pager.get_layer_grid(i)->find_widget<stacked_widget>("tab_pager", false, false);
1144 
1145  if(tab_pager && tab_selector) {
1146  const int ii = static_cast<int>(i);
1147  const int tab_index = index_in_pager_range(initial_index_.second, *tab_pager);
1148  const int to_select = (ii == main_index ? tab_index : 0);
1149 
1150  // Initialize tabs for this page
1151  initialize_tabs(*tab_selector);
1152 
1153  tab_selector->select_row(to_select);
1154  tab_pager->select_layer(to_select);
1155  }
1156  }
1157 
1158  // Finally, select the initial main page
1159  selector.select_row(main_index);
1160  pager.select_layer(main_index);
1161 }
1162 
1163 void preferences_dialog::set_visible_page(unsigned int page, const std::string& pager_id)
1164 {
1165  find_widget<stacked_widget>(pager_id).select_layer(page);
1166 }
1167 
1168 // Special fullsceen callback
1170 {
1171  const bool ison = find_widget<toggle_button>("fullscreen").get_value_bool();
1172  video::set_fullscreen(ison);
1173 
1174  menu_button& res_list = find_widget<menu_button>("resolution_set");
1175 
1176  set_resolution_list(res_list);
1177  res_list.set_active(!ison);
1178 }
1179 
1181 {
1182  menu_button& res_list = find_widget<menu_button>("resolution_set");
1183 
1184  if(video::set_resolution(resolutions_[res_list.get_value()])) {
1185  set_resolution_list(res_list);
1186  }
1187 }
1188 
1190 {
1191  menu_button& theme_list = find_widget<menu_button>("choose_theme");
1192 
1193  const auto selection = theme_list.get_value();
1194  const auto& theme = themes_.at(selection);
1195  auto* display = display::get_singleton();
1196 
1197  prefs::get().set_theme(theme.id);
1198  if(display && resources::gamedata && resources::gamedata->get_theme().empty()) {
1199  display->set_theme(theme.id);
1200  }
1201 
1202 }
1203 
1205 {
1206  menu_button& gui2_theme_list = find_widget<menu_button>("choose_gui2_theme");
1207  unsigned selected_theme = gui2_theme_list.get_value();
1208  if (selected_theme != current_gui_theme_) {
1209  current_gui_theme_ = selected_theme;
1210  prefs::get().set_gui2_theme(gui2_themes_.at(selected_theme));
1212  }
1213 }
1214 
1216 {
1217  const int selected_row =
1218  std::max(0, find_widget<listbox>("selector").get_selected_row());
1219  set_visible_page(static_cast<unsigned int>(selected_row), "pager");
1220 }
1221 
1223 {
1224  const int selected_row =
1225  std::max(0, find_widget<listbox>("tab_selector").get_selected_row());
1226  set_visible_page(static_cast<unsigned int>(selected_row), "tab_pager");
1227 }
1228 
1230 {
1232 
1233  // Save new prefs to disk. This also happens on app close, but doing
1234  // it here too ensures nothing is lost in case of, say, a crash.
1236 
1237  // Needed for applying changes to tip panel visiblity on dialog close
1238  if (is_reload_needed_) {
1240  }
1241 }
1242 
1243 } // 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:1198
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
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:732
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:141
std::vector< point > get_available_resolutions(const bool include_current)
Returns the list of available screen resolutions.
Definition: video.cpp:741
int get_max_pixel_scale()
Definition: video.cpp:503
point current_resolution()
The current window size in desktop coordinates.
Definition: video.cpp:793
void set_fullscreen(bool fullscreen)
Set the fullscreen state.
Definition: video.cpp:809
bool set_resolution(const point &resolution)
Set the window resolution.
Definition: video.cpp:838
void toggle_fullscreen()
Toggle fullscreen mode.
Definition: video.cpp:833
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
Definition: video.cpp:868
int w
Definition: pathfind.cpp:188
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