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