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