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