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_mouse_left_click(find_widget<button>(this, "apply", false),
596 
597  //
598  // SOUND PANEL
599  //
600 
601  /* SOUND FX */
602  initialize_sound_option_group<sound, set_sound, sound_volume, set_sound_volume>("sfx");
603 
604  /* MUSIC */
605  initialize_sound_option_group<music_on, set_music, music_volume, set_music_volume>("music");
606 
607  register_bool("sound_toggle_stop_music_in_background", true,
608  []() {return prefs::get().stop_music_in_background();},
609  [](bool v) {prefs::get().set_stop_music_in_background(v);});
610 
611  /* TURN BELL */
612  initialize_sound_option_group<turn_bell, set_turn_bell, bell_volume, set_bell_volume>("bell");
613 
614  /* UI FX */
615  initialize_sound_option_group<ui_sound_on, set_ui_sound, ui_volume, set_ui_volume>("uisfx");
616 
617  //
618  // MULTIPLAYER PANEL
619  //
620 
621  /* CHAT LINES */
622  register_integer("chat_lines", true,
623  []() {return prefs::get().chat_lines();},
624  [](int v) {prefs::get().set_chat_lines(v);});
625 
626  /* CHAT TIMESTAMPPING */
627  register_bool("chat_timestamps", true,
628  []() {return prefs::get().chat_timestamp();},
629  [](bool v) {prefs::get().set_chat_timestamp(v);});
630 
631  /* SAVE PASSWORD */
632  register_bool("remember_password", true,
633  []() {return prefs::get().remember_password();},
634  [](bool v) {prefs::get().set_remember_password(v);});
635 
636  /* WHISPERS FROM FRIENDS ONLY */
637  register_bool("lobby_whisper_friends_only", true,
638  []() {return prefs::get().lobby_whisper_friends_only();},
639  [](bool v) {prefs::get().set_lobby_whisper_friends_only(v);});
640 
641  /* LOBBY JOIN NOTIFICATIONS */
642  lobby_joins_group.add_member(find_widget<toggle_button>(this, "lobby_joins_none", false, true), pref_constants::lobby_joins::show_none);
643  lobby_joins_group.add_member(find_widget<toggle_button>(this, "lobby_joins_friends", false, true), pref_constants::lobby_joins::show_friends);
644  lobby_joins_group.add_member(find_widget<toggle_button>(this, "lobby_joins_all", false, true), pref_constants::lobby_joins::show_all);
645 
647 
650  });
651 
652  /* FRIENDS LIST */
653  listbox& friends_list = find_widget<listbox>(this, "friends_list", false);
654 
655  friends_list.clear();
656 
657  for(const auto& entry : prefs::get().get_acquaintances()) {
658  friends_list.add_row(get_friends_list_row_data(entry.second));
659  }
660 
661  update_friends_list_controls(friends_list);
662 
663  text_box& textbox = find_widget<text_box>(this, "friend_name_box", false);
664 
666  find_widget<button>(this, "add_friend", false), std::bind(
668  this, true,
669  std::ref(textbox)));
670 
672  find_widget<button>(this, "add_ignored", false), std::bind(
674  this, false,
675  std::ref(textbox)));
676 
678  find_widget<button>(this, "remove", false), std::bind(
680  this,
681  std::ref(friends_list),
682  std::ref(textbox)));
683 
684  connect_signal_notify_modified(friends_list, std::bind(
686  this,
687  std::ref(friends_list),
688  std::ref(textbox)));
689 
690  /* ALERTS */
692  find_widget<button>(this, "mp_alerts", false),
693  std::bind(&gui2::dialogs::mp_alerts_options::display<>));
694 
695  /* SET WESNOTHD PATH */
697  find_widget<button>(this, "mp_wesnothd", false), std::bind([]() {return prefs::get().show_wesnothd_server_search();}));
698 
699 
700  //
701  // ADVANCED PANEL
702  //
703 
704  listbox& advanced = find_widget<listbox>(this, "advanced_prefs", false);
705 
706  widget_data row_data;
707 
708  for(const auto& option : prefs::get().get_advanced_preferences()) {
709  const std::string pref_name = option.field;
710 
711  row_data["pref_name"]["label"] = option.name;
712  grid* main_grid = &advanced.add_row(row_data);
713 
714  grid& details_grid = find_widget<grid>(main_grid, "prefs_setter_grid", false);
716 
717  // The toggle widget for toggle-type options (hidden for other types)
718  toggle_button& toggle_box = find_widget<toggle_button>(main_grid, "value_toggle", false);
720 
721  if(!option.description.empty()) {
722  find_widget<styled_widget>(main_grid, "description", false).set_label(option.description);
723  }
724 
725  switch(option.type) {
727 
729  toggle_box.set_value(preferences_dialog_friend::get(pref_name, option.cfg["default"].to_bool()));
730 
731  // A lambda alone would be more verbose because it'd need to specify all the parameters.
732  connect_signal_mouse_left_click(toggle_box, std::bind(
733  [&, pref_name]() { preferences_dialog_friend::set(pref_name, toggle_box.get_value_bool()); }
734  ));
735 
736  gui2::bind_status_label<toggle_button>(
737  main_grid, "value_toggle", default_status_value_getter<toggle_button>, "value");
738 
739  break;
740  }
741 
743  auto setter_widget = build_single_widget_instance<slider>(config {"definition", "minimal"});
744  setter_widget->set_id("setter");
745  // Maximum must be set first or this will assert
746  setter_widget->set_value_range(option.cfg["min"].to_int(), option.cfg["max"].to_int());
747  setter_widget->set_step_size(option.cfg["step"].to_int(1));
748 
749  details_grid.swap_child("setter", std::move(setter_widget), true);
750 
751  slider& slide = find_widget<slider>(&details_grid, "setter", false);
752 
753  slide.set_value(preferences_dialog_friend::get(pref_name, option.cfg["default"].to_int()));
754 
755  // A lambda alone would be more verbose because it'd need to specify all the parameters.
756  connect_signal_notify_modified(slide, std::bind(
757  [&, pref_name]() { preferences_dialog_friend::set(pref_name, slide.get_value()); }
758  ));
759 
760  gui2::bind_status_label<slider>(main_grid, "setter", default_status_value_getter<slider>, "value");
761 
762  break;
763  }
764 
766  std::vector<config> menu_data;
767  std::vector<std::string> option_ids;
768 
769  for(const config& choice : option.cfg.child_range("option")) {
770  config menu_item;
771  menu_item["label"] = choice["name"];
772  if(choice.has_attribute("description")) {
773  menu_item["details"] = std::string("<span color='#777'>") + choice["description"] + "</span>";
774  }
775  menu_data.push_back(menu_item);
776  option_ids.push_back(choice["id"]);
777  }
778 
779  // Attempt to find an initial selection
780  int selected = std::distance(option_ids.begin(), std::find(option_ids.begin(), option_ids.end(),
781  preferences_dialog_friend::get(pref_name, option.cfg["default"].str())
782  ));
783 
784  // If the saved option value was invalid, reset selection to 0.
785  if(selected < 0 || selected >= static_cast<int>(option_ids.size())) {
786  selected = 0;
787  }
788 
789  auto setter_widget = build_single_widget_instance<menu_button>();
790  setter_widget->set_id("setter");
791 
792  details_grid.swap_child("setter", std::move(setter_widget), true);
793 
794  menu_button& menu = find_widget<menu_button>(&details_grid, "setter", false);
795 
796  menu.set_use_markup(true);
797  menu.set_values(menu_data, selected);
798 
799  // A lambda alone would be more verbose because it'd need to specify all the parameters.
801  std::bind([=](widget& w) { preferences_dialog_friend::set(pref_name, option_ids[dynamic_cast<menu_button&>(w).get_value()]); }, std::placeholders::_1));
802 
803  gui2::bind_status_label<menu_button>(main_grid, "setter", default_status_value_getter<menu_button>, "value");
804 
805  break;
806  }
807 
809  //main_grid->remove_child("setter");
810 
811  auto value_widget = build_single_widget_instance<image>();
812  value_widget->set_label("icons/arrows/arrows_blank_right_25.png~CROP(3,3,18,18)");
813 
814  main_grid->swap_child("value", std::move(value_widget), true);
815 
816  break;
817  }
818  }
819  }
820 
821  connect_signal_notify_modified(advanced, std::bind(
823  this,
824  std::ref(advanced)));
825 
827 
828  //
829  // HOTKEYS PANEL
830  //
831 
832  multimenu_button& hotkey_menu = find_widget<multimenu_button>(this, "hotkey_category_menu", false);
833  connect_signal_notify_modified(hotkey_menu,
835 
837 
838  text_box& filter = find_widget<text_box>(this, "filter", false);
840 
841  // Action column
842  hotkey_list.register_translatable_sorting_option(0, [this](const int i) { return visible_hotkeys_[i]->description.str(); });
843 
844  // Hotkey column
845  hotkey_list.register_sorting_option(1, [this](const int i) { return hotkey::get_names(visible_hotkeys_[i]->id); });
846 
847  // Scope columns
848  hotkey_list.register_sorting_option(2, [this](const int i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_GAME]; });
849  hotkey_list.register_sorting_option(3, [this](const int i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_EDITOR]; });
850  hotkey_list.register_sorting_option(4, [this](const int i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_MAIN_MENU]; });
851 
852  hotkey_list.set_active_sorting_option({0, sort_order::type::ascending}, true);
853 
855  find_widget<button>(this, "btn_add_hotkey", false), std::bind(
857  this,
858  std::ref(hotkey_list)));
859 
861  find_widget<button>(this, "btn_clear_hotkey", false), std::bind(
863  this,
864  std::ref(hotkey_list)));
865 
867  find_widget<button>(this, "btn_reset_hotkeys", false), std::bind(
869  this));
870 }
871 
873 {
874  widget_data row_data;
875 
876  t_string& row_icon = row_data["img_icon"]["label"];
877  t_string& row_action = row_data["lbl_desc"]["label"];
878  t_string& row_hotkey = row_data["lbl_hotkey"]["label"];
879 
880  t_string& row_is_g = row_data["lbl_is_game"]["label"];
881  t_string& row_is_e = row_data["lbl_is_editor"]["label"];
882  t_string& row_is_m = row_data["lbl_is_mainmenu"]["label"];
883 
884  listbox& hotkey_list = find_widget<listbox>(this, "list_hotkeys", false);
885 
886  hotkey_list.clear();
887  visible_hotkeys_.clear();
888  visible_categories_.clear();
889 
890  //
891  // Main hotkeys list
892  //
893 
894  // These translated initials should match those used in data/gui/window/preferences/02_hotkeys.cfg
895  const std::string gh = "<span color='#0f0'>" + _("game_hotkeys^G") + "</span>";
896  const std::string eh = "<span color='#0f0'>" + _("editor_hotkeys^E") + "</span>";
897  const std::string mh = "<span color='#0f0'>" + _("mainmenu_hotkeys^M") + "</span>";
898 
899  for(const auto& [id, hotkey_item] : hotkey::get_hotkey_commands()) {
900  if(hotkey_item.hidden) {
901  continue;
902  }
903 
904  visible_hotkeys_.push_back(&hotkey_item);
905  visible_categories_.insert(hotkey_item.category);
906 
907  if(filesystem::file_exists(game_config::path + "/images/icons/action/" + hotkey_item.id + "_25.png")) {
908  row_icon = "icons/action/" + hotkey_item.id + "_25.png~CROP(3,3,18,18)";
909  } else {
910  row_icon = "";
911  }
912 
913  row_action = hotkey_item.description;
914  row_hotkey = hotkey::get_names(hotkey_item.id);
915 
916  row_is_g = hotkey_item.scope[hotkey::SCOPE_GAME] ? gh : "";
917  row_is_e = hotkey_item.scope[hotkey::SCOPE_EDITOR] ? eh : "";
918  row_is_m = hotkey_item.scope[hotkey::SCOPE_MAIN_MENU] ? mh : "";
919 
920  hotkey_list.add_row(row_data);
921  }
922 
923  //
924  // Filter options
925  //
926 
927  std::vector<config> filter_ops;
928  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
929  filter_ops.emplace_back("label", hotkey::get_translatable_category_name(cat), "checkbox", false);
930  }
931 
932  find_widget<multimenu_button>(this, "hotkey_category_menu", false).set_values(filter_ops);
933 
934  return hotkey_list;
935 }
936 
938 {
939  int row_number = hotkeys.get_selected_row();
940  if(row_number < 0) {
941  gui2::show_transient_message("", _("No hotkey selected"));
942  return;
943  }
944 
945  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
946 
947  gui2::dialogs::hotkey_bind bind_dlg(hotkey_item.id);
948  bind_dlg.show();
949 
950  hotkey::hotkey_ptr newhk = bind_dlg.get_new_binding();
951  hotkey::hotkey_ptr oldhk;
952 
953  // only if not cancelled.
954  if(newhk.get() == nullptr) {
955  return;
956  }
957 
958  for(const hotkey::hotkey_ptr& hk : hotkey::get_hotkeys()) {
959  if(!hk->is_disabled() && newhk->bindings_equal(hk)) {
960  oldhk = hk;
961  }
962  }
963 
964  if(oldhk && oldhk->get_command() == hotkey_item.id) {
965  return;
966  }
967 
968  if(oldhk && oldhk->get_command() != "null") {
969  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>”?", {
970  {"hotkey_sequence", oldhk->get_name()},
971  {"old_hotkey_action", hotkey::get_hotkey_command(oldhk->get_command()).description},
972  {"new_hotkey_action", hotkey::get_hotkey_command(newhk->get_command()).description}
973  });
974 
975  const int res = gui2::show_message(_("Reassign Hotkey"), text, gui2::dialogs::message::yes_no_buttons, true);
976  if(res != gui2::retval::OK) {
977  return;
978  }
979  }
980 
981  hotkey::add_hotkey(newhk);
982 
983  // We need to recalculate all hotkey names in because we might have removed a hotkey from another command.
984  for(std::size_t i = 0; i < hotkeys.get_item_count(); ++i) {
985  const hotkey::hotkey_command& hotkey_item_row = *visible_hotkeys_[i];
986  find_widget<label>(hotkeys.get_row_grid(i), "lbl_hotkey", false).set_label(hotkey::get_names(hotkey_item_row.id));
987  }
988 }
989 
991 {
992  gui2::show_transient_message(_("Hotkeys Reset"), _("All hotkeys have been reset to their default values."));
993 
995 
996  // Set up the list again and reselect the default sorting option.
998  hotkey_list.set_active_sorting_option({0, sort_order::type::ascending}, true);
999 }
1000 
1002 {
1003  int row_number = hotkeys.get_selected_row();
1004  if(row_number < 0) {
1005  gui2::show_transient_message("", _("No hotkey selected"));
1006  return;
1007  }
1008 
1009  const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
1010  hotkey::clear_hotkeys(hotkey_item.id);
1011  find_widget<label>(hotkeys.get_row_grid(row_number), "lbl_hotkey", false).set_label(hotkey::get_names(hotkey_item.id));
1012 }
1013 
1015 {
1016  const multimenu_button& hotkey_menu = find_widget<const multimenu_button>(this, "hotkey_category_menu", false);
1017  const text_box& name_filter = find_widget<const text_box>(this, "filter", false);
1018 
1019  boost::dynamic_bitset<> toggle_states = hotkey_menu.get_toggle_states();
1020  boost::dynamic_bitset<> res(visible_hotkeys_.size());
1021 
1022  std::string text = name_filter.get_value();
1023 
1024  // Nothing selected. It means that *all* categories are shown.
1025  if(toggle_states.none()) {
1026  toggle_states = ~toggle_states;
1027  }
1028 
1029  for(std::size_t h = 0; h < visible_hotkeys_.size(); ++h) {
1030  // Default to true if there is no filter text
1031  bool found = true;
1032 
1033  if(!text.empty()) {
1034  const std::string description = visible_hotkeys_[h]->description.str();
1035 
1036  for(const auto& word : utils::split(text, ' ')) {
1037  found = translation::ci_search(description, word);
1038 
1039  // No match, we're excluding this hotkey
1040  if(!found) {
1041  break;
1042  }
1043  }
1044  }
1045 
1046  unsigned cat_index = 0;
1047 
1048  // Filter categories
1049  for(const hotkey::HOTKEY_CATEGORY& cat : visible_categories_) {
1050  if(visible_hotkeys_[h]->category == cat) {
1051  break;
1052  } else {
1053  ++cat_index;
1054  }
1055  }
1056 
1057  if(cat_index < toggle_states.size() && found) {
1058  res[h] = toggle_states[cat_index];
1059  } else {
1060  res[h] = false;
1061  }
1062  }
1063 
1064  find_widget<listbox>(this, "list_hotkeys", false).set_row_shown(res);
1065 }
1066 
1068 {
1069  const int selected_row = list.get_selected_row();
1070  const auto& pref = prefs::get().get_advanced_preferences()[selected_row];
1071 
1072  if(pref.type == preferences::option::avd_type::SPECIAL) {
1073  if(pref.field == "logging") {
1074  gui2::dialogs::log_settings::display();
1075  } else if(pref.field == "orb_color") {
1076  gui2::dialogs::select_orb_colors::display();
1077  } else {
1078  WRN_GUI_L << "Invalid or unimplemented custom advanced prefs option: " << pref.field;
1079  }
1080 
1081  // Add more options here as needed
1082  }
1083 
1084  const bool has_description = !pref.description.empty();
1085 
1086  if(has_description || (pref.type != preferences::option::avd_type::SPECIAL && pref.type != preferences::option::avd_type::TOGGLE)) {
1087  find_widget<widget>(list.get_row_grid(selected_row), "prefs_setter_grid", false)
1088  .set_visible(widget::visibility::visible);
1089  }
1090 
1091  if(last_selected_item_ != selected_row) {
1092  find_widget<widget>(list.get_row_grid(last_selected_item_), "prefs_setter_grid", false)
1093  .set_visible(widget::visibility::invisible);
1094 
1095  last_selected_item_ = selected_row;
1096  }
1097 }
1098 
1100 {
1101  //
1102  // MULTIPLAYER TABS
1103  //
1105  std::bind(&preferences_dialog::on_tab_select, this));
1106 }
1107 
1109 {
1110  set_always_save_fields(true);
1111 
1112  connect_signal_mouse_left_click(find_widget<button>(&window, "about", false), std::bind(&game_version::display<>));
1113 
1114  //
1115  // Status labels
1116  // These need to be set here in pre_show, once the fields are initialized. For some reason, this
1117  // is not the case for those in Advanced
1118  //
1119 
1120  gui2::bind_status_label<slider>(&window, "max_saves_slider");
1121  gui2::bind_status_label<slider>(&window, "turbo_slider");
1122  gui2::bind_status_label<slider>(&window, "pixel_scale_slider");
1123 
1124  //gui2::bind_status_label<slider>(&window, "scaling_slider", [](slider& s)->std::string {
1125  // return s.get_value_label() + "%";
1126  //});
1127 
1128  listbox& selector = find_widget<listbox>(&window, "selector", false);
1129  stacked_widget& pager = find_widget<stacked_widget>(&window, "pager", false);
1130 
1131  pager.set_find_in_all_layers(true);
1132 
1134  std::bind(&preferences_dialog::on_page_select, this));
1135 
1136  window.keyboard_capture(&selector);
1137 
1138  VALIDATE(selector.get_item_count() == pager.get_layer_count(),
1139  "The preferences pager and its selector listbox do not have the same number of items.");
1140 
1141  const int main_index = index_in_pager_range(initial_index_.first, pager);
1142 
1143  // Loops through each pager layer and checks if it has both a tab bar
1144  // and stack. If so, it initializes the options for the former and
1145  // selects the specified layer of the latter.
1146  for(unsigned int i = 0; i < pager.get_layer_count(); ++i) {
1147  listbox* tab_selector = find_widget<listbox>(
1148  pager.get_layer_grid(i), "tab_selector", false, false);
1149 
1150  stacked_widget* tab_pager = find_widget<stacked_widget>(
1151  pager.get_layer_grid(i), "tab_pager", false, false);
1152 
1153  if(tab_pager && tab_selector) {
1154  const int ii = static_cast<int>(i);
1155  const int tab_index = index_in_pager_range(initial_index_.second, *tab_pager);
1156  const int to_select = (ii == main_index ? tab_index : 0);
1157 
1158  // Initialize tabs for this page
1159  initialize_tabs(*tab_selector);
1160 
1161  tab_selector->select_row(to_select);
1162  tab_pager->select_layer(to_select);
1163  }
1164  }
1165 
1166  // Finally, select the initial main page
1167  selector.select_row(main_index);
1168  pager.select_layer(main_index);
1169 }
1170 
1171 void preferences_dialog::set_visible_page(unsigned int page, const std::string& pager_id)
1172 {
1173  find_widget<stacked_widget>(this, pager_id, false).select_layer(page);
1174 }
1175 
1176 // Special fullsceen callback
1178 {
1179  const bool ison = find_widget<toggle_button>(this, "fullscreen", false).get_value_bool();
1180  video::set_fullscreen(ison);
1181 
1182  menu_button& res_list = find_widget<menu_button>(this, "resolution_set", false);
1183 
1184  set_resolution_list(res_list);
1185  res_list.set_active(!ison);
1186 }
1187 
1189 {
1190  menu_button& res_list = find_widget<menu_button>(this, "resolution_set", false);
1191 
1192  if(video::set_resolution(resolutions_[res_list.get_value()])) {
1193  set_resolution_list(res_list);
1194  }
1195 }
1196 
1198 {
1199  menu_button& theme_list = find_widget<menu_button>(this, "choose_theme", false);
1200 
1201  const auto selection = theme_list.get_value();
1202  const auto& theme = themes_.at(selection);
1203  auto* display = display::get_singleton();
1204 
1205  prefs::get().set_theme(theme.id);
1206  if(display && resources::gamedata && resources::gamedata->get_theme().empty()) {
1207  display->set_theme(theme.id);
1208  }
1209 
1210 }
1211 
1213 {
1214  menu_button& gui2_theme_list = find_widget<menu_button>(this, "choose_gui2_theme", false);
1215  unsigned selected_theme = gui2_theme_list.get_value();
1216  if (selected_theme != current_gui_theme_) {
1217  current_gui_theme_ = selected_theme;
1218  prefs::get().set_gui2_theme(gui2_themes_.at(selected_theme));
1220  }
1221 }
1222 
1224 {
1225  const int selected_row =
1226  std::max(0, find_widget<listbox>(this, "selector", false).get_selected_row());
1227  set_visible_page(static_cast<unsigned int>(selected_row), "pager");
1228 }
1229 
1231 {
1232  const int selected_row =
1233  std::max(0, find_widget<listbox>(this, "tab_selector", false).get_selected_row());
1234  set_visible_page(static_cast<unsigned int>(selected_row), "tab_pager");
1235 }
1236 
1238 {
1240 
1241  // Save new prefs to disk. This also happens on app close, but doing
1242  // it here too ensures nothing is lost in case of, say, a crash.
1244 }
1245 
1246 } // 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