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_status_label<toggle_button>(
737  main_grid, "value_toggle", default_status_value_getter<toggle_button>, "value");
738 
739  break;
740  }
741 
743  auto setter_widget = build_single_widget_instance<slider>(config {"definition", "minimal"});
744  setter_widget->set_id("setter");
745  // Maximum must be set first or this will assert
746  setter_widget->set_value_range(option.cfg["min"].to_int(), option.cfg["max"].to_int());
747  setter_widget->set_step_size(option.cfg["step"].to_int(1));
748 
749  details_grid.swap_child("setter", std::move(setter_widget), true);
750 
751  slider& slide = details_grid.find_widget<slider>("setter");
752 
753  slide.set_value(preferences_dialog_friend::get(pref_name, option.cfg["default"].to_int()));
754 
756  [&, pref_name](auto&&...) { preferences_dialog_friend::set(pref_name, slide.get_value()); });
757 
758  gui2::bind_status_label<slider>(main_grid, "setter", default_status_value_getter<slider>, "value");
759 
760  break;
761  }
762 
764  std::vector<config> menu_data;
765  std::vector<std::string> option_ids;
766 
767  for(const config& choice : option.cfg.child_range("option")) {
768  config menu_item;
769  menu_item["label"] = choice["name"];
770  if(choice.has_attribute("description")) {
771  menu_item["details"] = markup::span_color("#777", choice["description"]);
772  }
773  menu_data.push_back(menu_item);
774  option_ids.push_back(choice["id"]);
775  }
776 
777  // Attempt to find an initial selection
778  int selected = std::distance(option_ids.begin(), std::find(option_ids.begin(), option_ids.end(),
779  preferences_dialog_friend::get(pref_name, option.cfg["default"].str())
780  ));
781 
782  // If the saved option value was invalid, reset selection to 0.
783  if(selected < 0 || selected >= static_cast<int>(option_ids.size())) {
784  selected = 0;
785  }
786 
787  auto setter_widget = build_single_widget_instance<menu_button>();
788  setter_widget->set_id("setter");
789 
790  details_grid.swap_child("setter", std::move(setter_widget), true);
791 
792  menu_button& menu = details_grid.find_widget<menu_button>("setter");
793 
794  menu.set_use_markup(true);
795  menu.set_values(menu_data, selected);
796 
798  [=](widget& w, auto&&...) { preferences_dialog_friend::set(pref_name, option_ids[dynamic_cast<menu_button&>(w).get_value()]); });
799 
800  gui2::bind_status_label<menu_button>(main_grid, "setter", default_status_value_getter<menu_button>, "value");
801 
802  break;
803  }
804 
806  //main_grid->remove_child("setter");
807 
808  auto value_widget = build_single_widget_instance<image>();
809  value_widget->set_label("icons/arrows/arrows_blank_right_25.png~CROP(3,3,18,18)");
810 
811  main_grid->swap_child("value", std::move(value_widget), true);
812 
813  break;
814  }
815  }
816  }
817 
819  [this, &advanced](auto&&...) { on_advanced_prefs_list_select(advanced); });
820 
822 
823  //
824  // HOTKEYS PANEL
825  //
826 
827  multimenu_button& hotkey_menu = find_widget<multimenu_button>("hotkey_category_menu");
828  connect_signal_notify_modified(hotkey_menu,
829  [this](auto&&...) { hotkey_filter_callback(); });
830 
832 
833  text_box& filter = find_widget<text_box>("filter");
834  filter.on_modified([this](const auto&) { hotkey_filter_callback(); });
835 
836  hotkey_list.set_sorters(
837  // Action column
838  [this](const std::size_t i) { return visible_hotkeys_[i]->description; },
839 
840  // Hotkey column
841  [this](const std::size_t i) { return hotkey::get_names(visible_hotkeys_[i]->id); },
842 
843  // Scope columns
844  [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_GAME]; },
845  [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_EDITOR]; },
846  [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_MAIN_MENU]; }
847  );
848 
849  hotkey_list.set_active_sorter("sort_0", sort_order::type::ascending, true);
850 
851  connect_signal_mouse_left_click(find_widget<button>("btn_add_hotkey"),
852  [this, &hotkey_list](auto&&...) { add_hotkey_callback(hotkey_list); });
853 
854  connect_signal_mouse_left_click(find_widget<button>("btn_clear_hotkey"),
855  [this, &hotkey_list](auto&&...) { remove_hotkey_callback(hotkey_list); });
856 
857  connect_signal_mouse_left_click(find_widget<button>("btn_reset_hotkeys"),
858  [this](auto&&...) { default_hotkey_callback(); });
859 }
860 
862 {
863  widget_data row_data;
864 
865  t_string& row_icon = row_data["img_icon"]["label"];
866  t_string& row_action = row_data["lbl_desc"]["label"];
867  t_string& row_hotkey = row_data["lbl_hotkey"]["label"];
868 
869  t_string& row_is_g = row_data["lbl_is_game"]["label"];
870  t_string& row_is_e = row_data["lbl_is_editor"]["label"];
871  t_string& row_is_m = row_data["lbl_is_mainmenu"]["label"];
872 
873  listbox& hotkey_list = find_widget<listbox>("list_hotkeys");
874 
875  hotkey_list.clear();
876  visible_hotkeys_.clear();
877  visible_categories_.clear();
878 
879  //
880  // Main hotkeys list
881  //
882 
883  // These translated initials should match those used in data/gui/window/preferences/02_hotkeys.cfg
884  const std::string gh = markup::span_color("#0f0", _("game_hotkeys^G"));
885  const std::string eh = markup::span_color("#0f0", _("editor_hotkeys^E"));
886  const std::string mh = markup::span_color("#0f0", _("mainmenu_hotkeys^M"));
887 
888  for(const auto& [id, hotkey_item] : hotkey::get_hotkey_commands()) {
889  if(hotkey_item.hidden) {
890  continue;
891  }
892 
893  visible_hotkeys_.push_back(&hotkey_item);
894  visible_categories_.insert(hotkey_item.category);
895 
896  if(filesystem::file_exists(game_config::path + "/images/icons/action/" + hotkey_item.id + "_25.png")) {
897  row_icon = "icons/action/" + hotkey_item.id + "_25.png~CROP(3,3,18,18)";
898  } else {
899  row_icon = "";
900  }
901 
902  row_action = hotkey_item.description;
903  row_hotkey = hotkey::get_names(hotkey_item.id);
904 
905  row_is_g = hotkey_item.scope[hotkey::SCOPE_GAME] ? gh : "";
906  row_is_e = hotkey_item.scope[hotkey::SCOPE_EDITOR] ? eh : "";
907  row_is_m = hotkey_item.scope[hotkey::SCOPE_MAIN_MENU] ? mh : "";
908 
909  hotkey_list.add_row(row_data);
910  }
911 
912  //
913  // Filter options
914  //
915 
916  std::vector<config> filter_ops;
917  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
918  filter_ops.emplace_back("label", hotkey::get_translatable_category_name(cat), "checkbox", false);
919  }
920 
921  find_widget<multimenu_button>("hotkey_category_menu").set_values(filter_ops);
922 
923  return hotkey_list;
924 }
925 
927 {
928  int row_number = hotkeys.get_selected_row();
929  if(row_number < 0) {
930  gui2::show_transient_message("", _("No hotkey selected"));
931  return;
932  }
933 
934  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
935 
936  gui2::dialogs::hotkey_bind bind_dlg(hotkey_item.id);
937  bind_dlg.show();
938 
939  hotkey::hotkey_ptr newhk = bind_dlg.get_new_binding();
940  hotkey::hotkey_ptr oldhk;
941 
942  // only if not cancelled.
943  if(newhk.get() == nullptr) {
944  return;
945  }
946 
947  for(const hotkey::hotkey_ptr& hk : hotkey::get_hotkeys()) {
948  if(!hk->is_disabled() && newhk->bindings_equal(hk)) {
949  oldhk = hk;
950  }
951  }
952 
953  if(oldhk && oldhk->get_command() == hotkey_item.id) {
954  return;
955  }
956 
957  if(oldhk && oldhk->get_command() != "null") {
958  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>”?", {
959  {"hotkey_sequence", oldhk->get_name()},
960  {"old_hotkey_action", hotkey::get_hotkey_command(oldhk->get_command()).description},
961  {"new_hotkey_action", hotkey::get_hotkey_command(newhk->get_command()).description}
962  });
963 
964  const int res = gui2::show_message(_("Reassign Hotkey"), text, gui2::dialogs::message::yes_no_buttons, true);
965  if(res != gui2::retval::OK) {
966  return;
967  }
968  }
969 
970  hotkey::add_hotkey(newhk);
971 
972  // We need to recalculate all hotkey names in because we might have removed a hotkey from another command.
973  for(std::size_t i = 0; i < hotkeys.get_item_count(); ++i) {
974  const hotkey::hotkey_command& hotkey_item_row = *visible_hotkeys_[i];
975  hotkeys.get_row_grid(i)->find_widget<label>("lbl_hotkey").set_label(hotkey::get_names(hotkey_item_row.id));
976  }
977 }
978 
980 {
981  gui2::show_transient_message(_("Hotkeys Reset"), _("All hotkeys have been reset to their default values."));
982 
984 
985  // Set up the list again and reselect the default sorting option.
987  hotkey_list.set_active_sorter("sort_0", sort_order::type::ascending, true);
988 }
989 
991 {
992  int row_number = hotkeys.get_selected_row();
993  if(row_number < 0) {
994  gui2::show_transient_message("", _("No hotkey selected"));
995  return;
996  }
997 
998  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
999  hotkey::clear_hotkeys(hotkey_item.id);
1000  hotkeys.get_row_grid(row_number)->find_widget<label>("lbl_hotkey").set_label(hotkey::get_names(hotkey_item.id));
1001 }
1002 
1004 {
1005  const multimenu_button& hotkey_menu = find_widget<const multimenu_button>("hotkey_category_menu");
1006  const text_box& name_filter = find_widget<const text_box>("filter");
1007 
1008  boost::dynamic_bitset<> toggle_states = hotkey_menu.get_toggle_states();
1009  boost::dynamic_bitset<> res(visible_hotkeys_.size());
1010 
1011  std::string text = name_filter.get_value();
1012 
1013  // Nothing selected. It means that *all* categories are shown.
1014  if(toggle_states.none()) {
1015  toggle_states = ~toggle_states;
1016  }
1017 
1018  for(std::size_t h = 0; h < visible_hotkeys_.size(); ++h) {
1019  // Default to true if there is no filter text
1020  bool found = true;
1021 
1022  if(!text.empty()) {
1023  const std::string description = visible_hotkeys_[h]->description.str();
1024 
1025  for(const auto& word : utils::split(text, ' ')) {
1026  found = translation::ci_search(description, word);
1027 
1028  // No match, we're excluding this hotkey
1029  if(!found) {
1030  break;
1031  }
1032  }
1033  }
1034 
1035  unsigned cat_index = 0;
1036 
1037  // Filter categories
1038  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
1039  if(visible_hotkeys_[h]->category == cat) {
1040  break;
1041  } else {
1042  ++cat_index;
1043  }
1044  }
1045 
1046  if(cat_index < toggle_states.size() && found) {
1047  res[h] = toggle_states[cat_index];
1048  } else {
1049  res[h] = false;
1050  }
1051  }
1052 
1053  find_widget<listbox>("list_hotkeys").set_row_shown(res);
1054 }
1055 
1057 {
1058  const int selected_row = list.get_selected_row();
1059  const auto& pref = prefs::get().get_advanced_preferences()[selected_row];
1060 
1061  if(pref.type == preferences::option::avd_type::SPECIAL) {
1062  if(pref.field == "logging") {
1063  gui2::dialogs::log_settings::display();
1064  } else if(pref.field == "orb_color") {
1065  gui2::dialogs::select_orb_colors::display();
1066  } else if(pref.field == "reach_map") {
1067  gui2::dialogs::reachmap_options::display();
1068  } else {
1069  WRN_GUI_L << "Invalid or unimplemented custom advanced prefs option: " << pref.field;
1070  }
1071 
1072  // Add more options here as needed
1073  }
1074 
1075  const bool has_description = !pref.description.empty();
1076 
1077  if(has_description || (pref.type != preferences::option::avd_type::SPECIAL && pref.type != preferences::option::avd_type::TOGGLE)) {
1078  list.get_row_grid(selected_row)->find_widget<widget>("prefs_setter_grid")
1080  }
1081 
1082  if(last_selected_item_ != selected_row) {
1083  list.get_row_grid(last_selected_item_)->find_widget<widget>("prefs_setter_grid")
1085 
1086  last_selected_item_ = selected_row;
1087  }
1088 }
1089 
1091 {
1092  //
1093  // MULTIPLAYER TABS
1094  //
1096  [this](auto&&...) { on_tab_select(); });
1097 }
1098 
1100 {
1101  set_always_save_fields(true);
1102 
1103  connect_signal_mouse_left_click(find_widget<button>("about"),
1104  [](auto&&...) { game_version::display(); });
1105 
1106  //
1107  // Status labels
1108  // These need to be set here in pre_show, once the fields are initialized. For some reason, this
1109  // is not the case for those in Advanced
1110  //
1111 
1112  gui2::bind_status_label<slider>(this, "max_saves_slider");
1113  gui2::bind_status_label<slider>(this, "turbo_slider");
1114  gui2::bind_status_label<slider>(this, "pixel_scale_slider");
1115 
1116  //gui2::bind_status_label<slider>("scaling_slider", [](slider& s)->std::string {
1117  // return s.get_value_label() + "%";
1118  //});
1119 
1120  listbox& selector = find_widget<listbox>("selector");
1121  stacked_widget& pager = find_widget<stacked_widget>("pager");
1122 
1123  pager.set_find_in_all_layers(true);
1124 
1126  [this](auto&&...) { on_page_select(); });
1127 
1128  keyboard_capture(&selector);
1129 
1130  VALIDATE(selector.get_item_count() == pager.get_layer_count(),
1131  "The preferences pager and its selector listbox do not have the same number of items.");
1132 
1133  const int main_index = index_in_pager_range(initial_index_.first, pager);
1134 
1135  // Loops through each pager layer and checks if it has both a tab bar
1136  // and stack. If so, it initializes the options for the former and
1137  // selects the specified layer of the latter.
1138  for(unsigned int i = 0; i < pager.get_layer_count(); ++i) {
1139  listbox* tab_selector = pager.get_layer_grid(i)->find_widget<listbox>("tab_selector", false, false);
1140 
1141  stacked_widget* tab_pager = pager.get_layer_grid(i)->find_widget<stacked_widget>("tab_pager", false, false);
1142 
1143  if(tab_pager && tab_selector) {
1144  const int ii = static_cast<int>(i);
1145  const int tab_index = index_in_pager_range(initial_index_.second, *tab_pager);
1146  const int to_select = (ii == main_index ? tab_index : 0);
1147 
1148  // Initialize tabs for this page
1149  initialize_tabs(*tab_selector);
1150 
1151  tab_selector->select_row(to_select);
1152  tab_pager->select_layer(to_select);
1153  }
1154  }
1155 
1156  // Finally, select the initial main page
1157  selector.select_row(main_index);
1158  pager.select_layer(main_index);
1159 }
1160 
1161 void preferences_dialog::set_visible_page(unsigned int page, const std::string& pager_id)
1162 {
1163  find_widget<stacked_widget>(pager_id).select_layer(page);
1164 }
1165 
1166 // Special fullsceen callback
1168 {
1169  const bool ison = find_widget<toggle_button>("fullscreen").get_value_bool();
1170  video::set_fullscreen(ison);
1171 
1172  menu_button& res_list = find_widget<menu_button>("resolution_set");
1173 
1174  set_resolution_list(res_list);
1175  res_list.set_active(!ison);
1176 }
1177 
1179 {
1180  menu_button& res_list = find_widget<menu_button>("resolution_set");
1181 
1182  if(video::set_resolution(resolutions_[res_list.get_value()])) {
1183  set_resolution_list(res_list);
1184  }
1185 }
1186 
1188 {
1189  menu_button& theme_list = find_widget<menu_button>("choose_theme");
1190 
1191  const auto selection = theme_list.get_value();
1192  const auto& theme = themes_.at(selection);
1193  auto* display = display::get_singleton();
1194 
1195  prefs::get().set_theme(theme.id);
1196  if(display && resources::gamedata && resources::gamedata->get_theme().empty()) {
1197  display->set_theme(theme.id);
1198  }
1199 
1200 }
1201 
1203 {
1204  menu_button& gui2_theme_list = find_widget<menu_button>("choose_gui2_theme");
1205  unsigned selected_theme = gui2_theme_list.get_value();
1206  if (selected_theme != current_gui_theme_) {
1207  current_gui_theme_ = selected_theme;
1208  prefs::get().set_gui2_theme(gui2_themes_.at(selected_theme));
1210  }
1211 }
1212 
1214 {
1215  const int selected_row =
1216  std::max(0, find_widget<listbox>("selector").get_selected_row());
1217  set_visible_page(static_cast<unsigned int>(selected_row), "pager");
1218 }
1219 
1221 {
1222  const int selected_row =
1223  std::max(0, find_widget<listbox>("tab_selector").get_selected_row());
1224  set_visible_page(static_cast<unsigned int>(selected_row), "tab_pager");
1225 }
1226 
1228 {
1230 
1231  // Save new prefs to disk. This also happens on app close, but doing
1232  // it here too ensures nothing is lost in case of, say, a crash.
1234 
1235  // Needed for applying changes to tip panel visiblity on dialog close
1236  if (is_reload_needed_) {
1238  }
1239 }
1240 
1241 } // 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:267
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:280
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:112
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:153
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:305
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:159
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:44
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 selected
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
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_command & get_hotkey_command(const std::string &command)
returns the hotkey_command with the given name
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.
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