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