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