The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
preferences_dialog.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 - 2025
3 by Charles Dang <exodia339gmail.com>
4 Copyright (C) 2011, 2015 by Iris Morelle <shadowm2006@gmail.com>
5 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY.
13
14 See the COPYING file for more details.
15*/
16
17#define GETTEXT_DOMAIN "wesnoth-lib"
18
20
21#include "display.hpp"
22#include "events.hpp"
23#include "filesystem.hpp"
24#include "formatter.hpp"
26#include "game_data.hpp"
27#include "gettext.hpp"
30#include "lexical_cast.hpp"
31#include "resources.hpp"
32#include "sound.hpp"
33#include "theme.hpp"
34#include "video.hpp"
35
36// Sub-dialog includes
44
51#include "gui/widgets/grid.hpp"
52#include "gui/widgets/image.hpp"
53#include "gui/widgets/label.hpp"
61
63#include "wml_exception.hpp"
64
65#include <functional>
66#include <numeric>
67
68namespace gui2::dialogs
69{
70namespace
71{
72template<typename W>
73void disable_widget_on_toggle(window& window, widget& w, const std::string& id)
74{
75 window.find_widget<W>(id).set_active(dynamic_cast<selectable_item&>(w).get_value_bool());
76}
77
78template<typename W>
79void disable_widget_on_toggle_inverted(window& window, widget& w, const std::string& id)
80{
81 window.find_widget<W>(id).set_active(!dynamic_cast<selectable_item&>(w).get_value_bool());
82}
83
84} // end anon namespace
85
86REGISTER_DIALOG(preferences_dialog)
87
88preferences_dialog::preferences_dialog(const pref_constants::PREFERENCE_VIEW initial_view, bool allow_gui2_theme_change)
89 : modal_dialog(window_id())
90 , resolutions_() // should be populated by set_resolution_list before use
91 , themes_() // populated by set_theme_list
92 , gui2_themes_() // populated by set_gui2_theme_list
93 , last_selected_item_(0)
94 , current_gui_theme_(0)
95 , is_reload_needed_(false)
96 , allow_gui2_theme_change_(allow_gui2_theme_change)
97 , accl_speeds_({0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 3, 4, 8, 16})
98 , visible_hotkeys_()
99 , visible_categories_()
100 , initial_index_(pef_view_map[initial_view])
101{
102 initialize_callbacks();
103}
104
105// Helper function to refresh resolution list
107{
109
110 std::vector<config> options;
111 for(const point& res : resolutions_) {
112 config option;
113 option["label"] = formatter() << res.x << font::unicode_multiplication_sign << res.y;
114
115 const int div = std::gcd(res.x, res.y);
116 const int x_ratio = res.x / div;
117 const int y_ratio = res.y / div;
118
119 if(x_ratio <= 10 || y_ratio <= 10) {
120 option["details"] = markup::span_color("#777777", "(", x_ratio, ':', y_ratio, ")");
121 }
122
123 options.push_back(std::move(option));
124 }
125
126 const unsigned current_res = std::distance(resolutions_.begin(), std::find(
128
129 res_list.set_values(options, current_res);
130}
131
133{
135
136 std::vector<config> options;
137 std::size_t current_theme = 0;
138 for(std::size_t i = 0; i < themes_.size(); ++i) {
139 options.emplace_back("label", themes_[i].name, "tooltip", themes_[i].description);
140 if(themes_[i].id == prefs::get().theme()) {
141 current_theme = i;
142 }
143 }
144
145 theme_list.set_values(options, current_theme);
146}
147
149{
150 std::string current_gui_theme_name = prefs::get().gui2_theme();
151
152 std::vector<config> options;
153 bool theme_found = false;
154 unsigned i = 0;
155 for(auto& gui : guis) {
156 gui2_themes_.emplace_back(gui.first);
157 options.emplace_back("label", gui.second.description());
158 if (current_gui_theme_name == gui.first) {
160 theme_found = true;
161 }
162 if (!theme_found) {
163 i++;
164 }
165 }
166
167 theme_list.set_values(options);
168 theme_list.set_selected(current_gui_theme_);
169}
170
172{
174 widget_item item;
175
176 std::string image = "friend.png";
177 std::string descriptor = _("friend");
178 std::string notes;
179
180 if(entry.get_status() == "ignore") {
181 image = "ignore.png";
182 descriptor = _("ignored");
183 }
184
185 if(!entry.get_notes().empty()) {
186 notes = " " + markup::tag("small", "(", entry.get_notes(), ")");
187 }
188
189 item["use_markup"] = "true";
190
191 item["label"] = "misc/status-" + image;
192 data.emplace("friend_icon", item);
193
194 item["label"] = entry.get_nick() + notes;
195 data.emplace("friend_name", item);
196
197 item["label"] = markup::tag("small", descriptor);
198 data.emplace("friend_status", item);
199
200 return data;
201}
202
204{
205 const int num_friends = prefs::get().get_acquaintances().size();
206 const int sel = list.get_selected_row();
207
208 if(sel < 0 || sel >= num_friends) {
209 return;
210 }
211
212 std::map<std::string, preferences::acquaintance>::const_iterator who = prefs::get().get_acquaintances().begin();
213 std::advance(who, sel);
214
215 textbox.set_value(who->second.get_nick() + " " + who->second.get_notes());
216}
217
219{
220 const bool list_empty = list.get_item_count() == 0;
221
222 if(!list_empty) {
223 list.select_row(std::min(static_cast<int>(list.get_item_count()) - 1, list.get_selected_row()));
224 }
225
226 find_widget<button>("remove").set_active(!list_empty);
227
228 find_widget<label>("no_friends_notice").set_visible(list_empty);
229}
230
231void preferences_dialog::add_friend_list_entry(const bool is_friend, text_box& textbox)
232{
233 std::string username = textbox.text();
234 if(username.empty()) {
235 gui2::show_transient_message("", _("No username specified"));
236 return;
237 }
238
239 std::string reason;
240
241 std::size_t pos = username.find_first_of(' ');
242 if(pos != std::string::npos) {
243 reason = username.substr(pos + 1);
244 username = username.substr(0, pos);
245 }
246
247 auto [entry, added_new] = prefs::get().add_acquaintance(username, (is_friend ? "friend": "ignore"), reason);
248
249 if(!entry) {
250 gui2::show_transient_message(_("Error"), _("Invalid username"));
251 return;
252 }
253
254 textbox.clear();
255
256 listbox& list = find_widget<listbox>("friends_list");
257
258 //
259 // If this is a new entry, just add a new row. If it's not, we find the relevant
260 // row, remove it, and add a new row with the updated data. Should probably come
261 // up with a more elegant way to do .. the only reason I'm using the remove
262 // -and-replace method is to prevent any issues with the widgets' layout sizes.
263 //
264 if(added_new) {
266 } else {
267 for(unsigned i = 0; i < list.get_item_count(); ++i) {
268 grid* row_grid = list.get_row_grid(i);
269
270 if(row_grid->find_widget<label>("friend_name").get_label() == entry->get_nick()) {
271 list.remove_row(i);
272 list.add_row(get_friends_list_row_data(*entry), i);
273
274 break;
275 }
276 }
277 }
278
280}
281
283{
284 const int selected_row = std::max(0, friends_list.get_selected_row());
285
286 std::map<std::string, preferences::acquaintance>::const_iterator who = prefs::get().get_acquaintances().begin();
287 std::advance(who, selected_row);
288
289 const std::string to_remove = !textbox.text().empty() ? textbox.text() : who->second.get_nick();
290
291 if(to_remove.empty()) {
292 gui2::show_transient_message("", _("No username specified"));
293 return;
294 }
295
296 if(!prefs::get().remove_acquaintance(to_remove)) {
297 gui2::show_transient_error_message(_("Not on friends or ignore lists"));
298 return;
299 }
300
301 textbox.clear();
302
303 listbox& list = find_widget<listbox>("friends_list");
304 list.remove_row(selected_row);
305
307}
308
310{
311 // Update pixel scale preference.
312 slider& ps_slider = find_widget<slider>("pixel_scale_slider");
313 prefs::get().set_pixel_scale(ps_slider.get_value());
314
315 // Update auto pixel scale preference.
316 toggle_button& auto_ps_toggle =
317 find_widget<toggle_button>("auto_pixel_scale");
318 prefs::get().set_auto_pixel_scale(auto_ps_toggle.get_value_bool());
319
320 // Update draw buffers, taking these into account.
322
323 // Update game display, if active
324 if(::display* disp = display::get_singleton()) {
325 disp->queue_rerender();
326 }
327
328 // Raise a window resize event so we can react to the change
330}
331
332template<typename ToggleGet, typename ToggleSet, typename VolumeGet, typename VolumeSet>
334 const std::string& id_suffix,
335 ToggleGet&& toggle_getter,
336 ToggleSet&& toggle_setter,
337 VolumeGet&& volume_getter,
338 VolumeSet&& volume_setter)
339{
340 const std::string toggle_widget_id = "sound_toggle_" + id_suffix;
341 const std::string volume_widget_id = "sound_volume_" + id_suffix;
342
343 // Set up the volume slider.
344 register_integer(volume_widget_id, true, volume_getter, volume_setter);
345 auto& volume_slider = find_widget<slider>(volume_widget_id);
346
347 // Callback to actually immediately apply the volume effect. field_integer doesn't
348 // have a callback-on-changed mechanism. To add one would either mean adding it to
349 // the base field class or make it a proper class of is own.
350 connect_signal_notify_modified(volume_slider,
351 [=](widget& w, auto&&...) {
352 std::invoke(volume_setter, dynamic_cast<integer_selector&>(w).get_value());
353 });
354
355 const auto toggle_changed =
356 [=, &volume_slider](widget& w) {
357 const bool sound_enabled = dynamic_cast<selectable_item&>(w).get_value_bool();
358 std::invoke(toggle_setter, sound_enabled); // FIXME: we should use this return value
359 volume_slider.set_active(sound_enabled);
360 };
361
362 // Set up the toggle. We utilize field_bool's callback-on-changed mechanism instead
363 // of manually registering the callback. Since we want the effects to apply immediately,
364 // the callback the setter callback is duplicated in the on-change callback. The field
365 // class could possibly use some reworking to make this less redundant, but for now it
366 // works well enough.
367 register_bool(toggle_widget_id, true, toggle_getter, toggle_setter, toggle_changed, true);
368}
369
370/**
371 * Sets up states and callbacks for each of the widgets
372 */
374{
375 //
376 // GENERAL PANEL
377 //
378
379 /* SCROLL SPEED */
380 register_integer("scroll_speed", true,
381 []() {return prefs::get().scroll_speed();},
382 [](int v) {prefs::get().set_scroll_speed(v);});
383
384 /* ACCELERATED SPEED */
385 register_bool("turbo_toggle", true,
386 []() {return prefs::get().turbo();},
387 [](bool v) {prefs::get().set_turbo(v);});
388
389 const auto accl_load = [this]()->int {
390 return std::distance(accl_speeds_.begin(), std::find(accl_speeds_.begin(), accl_speeds_.end(), prefs::get().turbo_speed()));
391 };
392
393 const auto accl_save = [this](int i) {
394 prefs::get().set_turbo_speed(accl_speeds_[i]);
395 };
396
397 register_integer("turbo_slider", true,
398 accl_load, accl_save);
399
400 // Set the value label transform function.
401 find_widget<slider>("turbo_slider").set_value_labels(
402 // TODO: this should probably be a locale dependent string (use comma/dot depending on language)
403 [this](int pos, int /*max*/)->t_string { return lexical_cast<std::string>(accl_speeds_[pos]); }
404 );
405
406 /* SKIP AI MOVES */
407 register_bool("skip_ai_moves", true,
408 []() {return prefs::get().skip_ai_moves();},
409 [](bool v) {prefs::get().set_skip_ai_moves(v);});
410
411 /* DISABLE AUTO MOVES */
412 register_bool("disable_auto_moves", true,
413 []() {return prefs::get().disable_auto_moves();},
414 [](bool v) {prefs::get().set_disable_auto_moves(v);});
415
416 /* TURN DIALOG */
417 register_bool("show_turn_dialog", true,
418 []() {return prefs::get().turn_dialog();},
419 [](bool v) {prefs::get().set_turn_dialog(v);});
420
421 /* ENABLE PLANNING MODE */
422 register_bool("whiteboard_on_start", true,
423 []() {return prefs::get().enable_planning_mode_on_start();},
424 [](bool v) {prefs::get().set_enable_planning_mode_on_start(v);});
425
426 /* HIDE ALLY PLANS */
427 register_bool("whiteboard_hide_allies", true,
428 []() {return prefs::get().hide_whiteboard();},
429 [](bool v) {prefs::get().set_hide_whiteboard(v);});
430
431 /* INTERRUPT ON SIGHTING */
432 register_bool("interrupt_move_when_ally_sighted", true,
433 []() {return prefs::get().ally_sighted_interrupts();},
434 [](bool v) {prefs::get().set_ally_sighted_interrupts(v);});
435
436 /* SAVE REPLAYS */
437 register_bool("save_replays", true,
438 []() {return prefs::get().save_replays();},
439 [](bool v) {prefs::get().set_save_replays(v);});
440
441 /* DELETE AUTOSAVES */
442 register_bool("delete_saves", true,
443 []() {return prefs::get().delete_saves();},
444 [](bool v) {prefs::get().set_delete_saves(v);});
445
446 /* MAX AUTO SAVES */
447 register_integer("max_saves_slider", true,
448 []() {return prefs::get().auto_save_max();},
449 [](int v) {prefs::get().set_auto_save_max(v);});
450
451 /* CACHE MANAGE */
452 connect_signal_mouse_left_click(find_widget<button>("cachemg"),
453 [](auto&&...) { dialogs::game_cache_options::display(); });
454
455 /* DISPLAY->ACCESSIBILITY */
456 connect_signal_mouse_left_click(find_widget<button>("custom_orb_color"),
457 [](auto&&...) { dialogs::select_orb_colors::display(); });
458 connect_signal_mouse_left_click(find_widget<button>("custom_reach_map"),
459 [](auto&&...) { dialogs::reachmap_options::display(); });
460
461 //
462 // DISPLAY PANEL
463 //
464
465 /* FULLSCREEN TOGGLE */
466 toggle_button& toggle_fullscreen = find_widget<toggle_button>("fullscreen");
467 toggle_fullscreen.set_value(prefs::get().fullscreen());
468#ifdef __ANDROID__
469 toggle_fullscreen.set_active(false);
470#endif
471
472 // We bind a special callback function, so setup_single_toggle() is not used
473 connect_signal_mouse_left_click(toggle_fullscreen,
474 [this](auto&&...) { fullscreen_toggle_callback(); });
475
476 /* SET RESOLUTION */
477 menu_button& res_list = find_widget<menu_button>("resolution_set");
478
479 res_list.set_use_markup(true);
480#ifdef __ANDROID__
481 res_list.set_active(false);
482#else
483 res_list.set_active(!prefs::get().fullscreen());
484#endif
485
486 set_resolution_list(res_list);
487
488 connect_signal_notify_modified(res_list,
489 [this](auto&&...) { handle_res_select(); });
490
491 connect_signal<event::SDL_VIDEO_RESIZE>(
492 [this, &res_list](auto&&...) { set_resolution_list(res_list); });
493
494 // Toggling full-screen via hot-key by-passes fullscreen_toggle_callback()
495 // So watch for the window actually entering/leaving full-screen to refresh
496 // resolution list enablement and full-screen status
497 connect_signal<event::SDL_WINDOW_ENTER_FULLSCREEN>(
498 [this](auto&&...) { fullscreen_entered_callback(); });
499
500 connect_signal<event::SDL_WINDOW_LEAVE_FULLSCREEN>(
501 [this](auto&&...) { fullscreen_left_callback(); });
502
503 /* PIXEL SCALE */
504 register_integer("pixel_scale_slider", true,
505 []() {return prefs::get().pixel_scale();},
506 [](int v) {prefs::get().set_pixel_scale(v);});
507
508 slider& ps_slider = find_widget<slider>("pixel_scale_slider");
509 ps_slider.set_value_range(1, video::get_max_pixel_scale());
510 connect_signal_mouse_left_release(ps_slider,
511 [this](auto&&...) { apply_pixel_scale(); });
512
513 /* AUTOMATIC PIXEL SCALE */
514 register_bool("auto_pixel_scale", true,
515 []() {return prefs::get().auto_pixel_scale();},
516 [](bool v) {prefs::get().set_auto_pixel_scale(v);},
517 [&](widget& w) { disable_widget_on_toggle_inverted<slider>(*this, w, "pixel_scale_slider"); }, true);
518
519 if (video::get_max_pixel_scale() <= 1) {
520 find_widget<slider>("pixel_scale_slider").set_active(false);
521 find_widget<toggle_button>("auto_pixel_scale").set_active(false);
522 }
523
524 toggle_button& auto_ps_toggle =
525 find_widget<toggle_button>("auto_pixel_scale");
526 connect_signal_mouse_left_click(auto_ps_toggle,
527 [this](auto&&...) { apply_pixel_scale(); });
528
529 /* SHOW TIPS PANEL ON TITLESCREEN */
530 register_bool("show_tips", true,
531 []() {return prefs::get().show_tips();},
532 [&](bool v) {
533 // if changed once: different value, reload
534 // if changed twice: double toggle, same value, don't reload
536 prefs::get().set_show_tips(v);
537 });
538
539 /* SHOW FLOATING LABELS */
540 register_bool("show_floating_labels", true,
541 []() {return prefs::get().floating_labels();},
542 [](bool v) {prefs::get().set_floating_labels(v);});
543
544 /* SHOW TEAM COLORS */
545 register_bool("show_ellipses", true,
546 []() {return prefs::get().show_side_colors();},
547 [](bool v) {prefs::get().set_show_side_colors(v);});
548
549 /* SHOW GRID */
550 register_bool("show_grid", true,
551 []() {return prefs::get().grid();},
552 [](bool v) {prefs::get().set_grid(v);});
553
554 /* ANIMATE MAP */
555 register_bool("animate_terrains", true,
556 []() {return prefs::get().animate_map();},
557 [](bool v) {prefs::get().set_animate_map(v);},
558 [&](widget& w) { disable_widget_on_toggle<toggle_button>(*this, w, "animate_water"); }, true);
559
560 /* ANIMATE WATER */
561 register_bool("animate_water", true,
562 []() {return prefs::get().animate_water();},
563 [](bool v) {prefs::get().set_animate_water(v);});
564
565 /* SHOW UNIT STANDING ANIMS */
566 register_bool("animate_units_standing", true,
567 []() {return prefs::get().show_standing_animations();},
568 [](bool v) {prefs::get().set_show_standing_animations(v);});
569
570 /* SHOW UNIT IDLE ANIMS */
571 register_bool("animate_units_idle", true,
572 []() {return prefs::get().idle_anim();},
573 [](bool v) {prefs::get().set_idle_anim(v);},
574 [&](widget& w) { disable_widget_on_toggle<slider>(*this, w, "idle_anim_frequency"); }, true);
575
576 register_integer("idle_anim_frequency", true,
577 []() {return prefs::get().idle_anim_rate();},
578 [](int v) {prefs::get().set_idle_anim_rate(v);});
579
580 /* FONT SCALING */
581 //register_integer("scaling_slider", true,
582 // font_scaling, set_font_scaling);
583
584 /* VSYNC */
585 register_bool("vsync", true,
586 []() {return prefs::get().vsync();},
587 [](bool v) {prefs::get().set_vsync(v);});
588
589 /* SELECT THEME */
590 menu_button& theme_list = find_widget<menu_button>("choose_theme");
592 connect_signal_notify_modified(theme_list,
593 [this](auto&&...) { handle_theme_select(); });
594
595 /* SELECT GUI2 THEME */
596 menu_button& gui2_theme_list = find_widget<menu_button>("choose_gui2_theme");
597 button& apply_btn = find_widget<button>("apply");
598 set_gui2_theme_list(gui2_theme_list);
599 connect_signal_notify_modified(gui2_theme_list, [&](auto&&...) { apply_btn.set_active(true); });
600 apply_btn.set_active(false);
601 connect_signal_mouse_left_click(apply_btn,
602 [this](auto&&...) { handle_gui2_theme_select(); });
603
605 // Switching the GUI2 theme only affects windows built afterwards, so it's only
606 // useful from the title screen, which rebuilds itself on RELOAD_UI. Elsewhere,
607 // leave the control visible but non-interactive rather than have it silently
608 // do nothing until the next restart.
609 gui2_theme_list.set_active(false);
610 }
611
612 //
613 // SOUND PANEL
614 //
615
616 /* SOUND FX */
618 [] { return prefs::get().sound(); },
619 [](bool v) { return prefs::get().set_sound(v); },
620 [] { return prefs::get().sound_volume().as_percent(); },
622
623 /* MUSIC */
625 [] { return prefs::get().music_on(); },
626 [](bool v) { return prefs::get().set_music(v); },
627 [] { return prefs::get().music_volume().as_percent(); },
629
630 register_bool("sound_toggle_stop_music_in_background", true,
631 []() {return prefs::get().stop_music_in_background();},
632 [](bool v) {prefs::get().set_stop_music_in_background(v);});
633
634 /* TURN BELL */
636 [] { return prefs::get().turn_bell(); },
637 [](bool v) { return prefs::get().set_turn_bell(v); },
638 [] { return prefs::get().bell_volume().as_percent(); },
640
641 /* UI FX */
643 [] { return prefs::get().ui_sound_on(); },
644 [](bool v) { return prefs::get().set_ui_sound(v); },
645 [] { return prefs::get().ui_volume().as_percent(); },
647
648 //
649 // MULTIPLAYER PANEL
650 //
651
652 /* GENERAL TAB */
653
654 /* CHAT LINES */
655 register_integer("chat_lines", true,
656 []() {return prefs::get().chat_lines();},
657 [](int v) {prefs::get().set_chat_lines(v);});
658
659 /* CHAT TIMESTAMPPING */
660 register_bool("chat_timestamps", true,
661 []() {return prefs::get().chat_timestamp();},
662 [](bool v) {prefs::get().set_chat_timestamp(v);});
663
664 /* SAVE PASSWORD */
665 register_bool("remember_password", true,
666 []() {return prefs::get().remember_password();},
667 [](bool v) {prefs::get().set_remember_password(v);});
668
669 /* WHISPERS FROM FRIENDS ONLY */
670 register_bool("lobby_whisper_friends_only", true,
671 []() {return prefs::get().lobby_whisper_friends_only();},
672 [](bool v) {prefs::get().set_lobby_whisper_friends_only(v);});
673
674 /* LOBBY JOIN NOTIFICATIONS */
675 lobby_joins_group.add_member(find_widget<toggle_button>("lobby_joins_none", false, true), pref_constants::lobby_joins::show_none);
676 lobby_joins_group.add_member(find_widget<toggle_button>("lobby_joins_friends", false, true), pref_constants::lobby_joins::show_friends);
677 lobby_joins_group.add_member(find_widget<toggle_button>("lobby_joins_all", false, true), pref_constants::lobby_joins::show_all);
678
680
683 });
684
685 /* ALERTS */
686 connect_signal_mouse_left_click(find_widget<button>("mp_alerts"),
687 [](auto&&...) { mp_alerts_options::display(); });
688
689 /* SET WESNOTHD PATH */
690 connect_signal_mouse_left_click(find_widget<button>("mp_wesnothd"),
691 [](auto&&...) { prefs::get().show_wesnothd_server_search(); });
692
693
694 /* FRIENDS TAB */
695
696 listbox& friends_list = find_widget<listbox>("friends_list");
697 friends_list.clear();
698
699 for(const auto& entry : prefs::get().get_acquaintances()) {
700 friends_list.add_row(get_friends_list_row_data(entry.second));
701 }
702
703 update_friends_list_controls(friends_list);
704
705 text_box& textbox = find_widget<text_box>("friend_name_box");
706
707 connect_signal_mouse_left_click(find_widget<button>("add_friend"),
708 [&, this](auto&&...) { add_friend_list_entry(true, textbox); });
709
710 connect_signal_mouse_left_click(find_widget<button>("add_ignored"),
711 [&, this](auto&&...) { add_friend_list_entry(false, textbox); });
712
713 connect_signal_mouse_left_click(find_widget<button>("remove"),
714 [&, this](auto&&...) { remove_friend_list_entry(friends_list, textbox); });
715
716 connect_signal_notify_modified(friends_list,
717 [&, this](auto&&...) { on_friends_list_select(friends_list, textbox); });
718
719 //
720 // ADVANCED PANEL
721 //
722
723 listbox& advanced = find_widget<listbox>("advanced_prefs");
724
725 widget_data row_data;
726
727 for(const auto& option : prefs::get().get_advanced_preferences()) {
728 const std::string pref_name = option.field;
729
730 row_data["pref_name"]["label"] = option.name;
731 grid* main_grid = &advanced.add_row(row_data);
732
733 grid& details_grid = main_grid->find_widget<grid>("prefs_setter_grid");
735
736 // The toggle widget for toggle-type options (hidden for other types)
737 toggle_button& toggle_box = main_grid->find_widget<toggle_button>("value_toggle");
739
740 if(!option.description.empty()) {
741 main_grid->find_widget<styled_widget>("description").set_label(option.description);
742 }
743
744 switch(option.type) {
746
748 toggle_box.set_value(preferences_dialog_friend::get(pref_name, option.cfg["default"].to_bool()));
749
750 connect_signal_mouse_left_click(toggle_box,
751 [&, pref_name](auto&&...) { preferences_dialog_friend::set(pref_name, toggle_box.get_value_bool()); });
752
753 gui2::bind_default_status_label(toggle_box, "value");
754 break;
755 }
756
758 auto setter_widget = build_single_widget_instance<slider>(config {"definition", "minimal"});
759 setter_widget->set_id("setter");
760 // Maximum must be set first or this will assert
761 setter_widget->set_value_range(option.cfg["min"].to_int(), option.cfg["max"].to_int());
762 setter_widget->set_step_size(option.cfg["step"].to_int(1));
763
764 details_grid.swap_child("setter", std::move(setter_widget), true);
765
766 slider& slide = details_grid.find_widget<slider>("setter");
767
768 slide.set_value(preferences_dialog_friend::get(pref_name, option.cfg["default"].to_int()));
769
770 connect_signal_notify_modified(slide,
771 [&, pref_name](auto&&...) { preferences_dialog_friend::set(pref_name, slide.get_value()); });
772
773 gui2::bind_default_status_label(slide, "value");
774 break;
775 }
776
778 std::vector<config> menu_data;
779 std::vector<std::string> option_ids;
780
781 for(const config& choice : option.cfg.child_range("option")) {
782 config menu_item;
783 menu_item["label"] = choice["name"];
784 if(choice.has_attribute("description")) {
785 menu_item["details"] = markup::span_color("#777", choice["description"]);
786 }
787 menu_data.push_back(menu_item);
788 option_ids.push_back(choice["id"]);
789 }
790
791 // Attempt to find an initial selection
792 int selected = std::distance(option_ids.begin(), std::find(option_ids.begin(), option_ids.end(),
793 preferences_dialog_friend::get(pref_name, option.cfg["default"].str())
794 ));
795
796 // If the saved option value was invalid, reset selection to 0.
797 if(selected < 0 || selected >= static_cast<int>(option_ids.size())) {
798 selected = 0;
799 }
800
801 auto setter_widget = build_single_widget_instance<menu_button>();
802 setter_widget->set_id("setter");
803
804 details_grid.swap_child("setter", std::move(setter_widget), true);
805
806 menu_button& menu = details_grid.find_widget<menu_button>("setter");
807
808 menu.set_use_markup(true);
809 menu.set_values(menu_data, selected);
810
811 connect_signal_notify_modified(menu,
812 [=](widget& w, auto&&...) { preferences_dialog_friend::set(pref_name, option_ids[dynamic_cast<menu_button&>(w).get_value()]); });
813
814 gui2::bind_default_status_label(menu, "value");
815 break;
816 }
817
819 //main_grid->remove_child("setter");
820
821 auto value_widget = build_single_widget_instance<image>();
822 value_widget->set_label("icons/arrows/arrows_blank_right_25.png~CROP(3,3,18,18)");
823
824 main_grid->swap_child("value", std::move(value_widget), true);
825 break;
826 }
827 }
828 }
829
830 connect_signal_notify_modified(advanced,
831 [this, &advanced](auto&&...) { on_advanced_prefs_list_select(advanced); });
832
833 on_advanced_prefs_list_select(advanced, true);
834
835 //
836 // HOTKEYS PANEL
837 //
838
839 multimenu_button& hotkey_menu = find_widget<multimenu_button>("hotkey_category_menu");
840 connect_signal_notify_modified(hotkey_menu,
841 [this](auto&&...) { hotkey_filter_callback(); });
842
843 listbox& hotkey_list = setup_hotkey_list();
844
845 text_box& filter = find_widget<text_box>("filter");
846 filter.on_modified([this](const auto&) { hotkey_filter_callback(); });
847
848 hotkey_list.set_sorters(
849 // Action column
850 [this](const std::size_t i) { return visible_hotkeys_[i]->description; },
851
852 // Hotkey column
853 [this](const std::size_t i) { return hotkey::get_names(visible_hotkeys_[i]->id); },
854
855 // Scope columns
856 [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_GAME]; },
857 [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_EDITOR]; },
858 [this](const std::size_t i) { return !visible_hotkeys_[i]->scope[hotkey::SCOPE_MAIN_MENU]; }
859 );
860
861 hotkey_list.set_active_sorter("sort_0", sort_order::type::ascending, true);
862
863 connect_signal_mouse_left_click(find_widget<button>("btn_add_hotkey"),
864 [this, &hotkey_list](auto&&...) { add_hotkey_callback(hotkey_list); });
865
866 connect_signal_mouse_left_click(find_widget<button>("btn_clear_hotkey"),
867 [this, &hotkey_list](auto&&...) { remove_hotkey_callback(hotkey_list); });
868
869 connect_signal_mouse_left_click(find_widget<button>("btn_reset_hotkeys"),
870 [this](auto&&...) { default_hotkey_callback(); });
871}
872
874{
875 widget_data row_data;
876
877 t_string& row_icon = row_data["img_icon"]["label"];
878 t_string& row_action = row_data["lbl_desc"]["label"];
879 t_string& row_hotkey = row_data["lbl_hotkey"]["label"];
880
881 t_string& row_is_g = row_data["lbl_is_game"]["label"];
882 t_string& row_is_e = row_data["lbl_is_editor"]["label"];
883 t_string& row_is_m = row_data["lbl_is_mainmenu"]["label"];
884
885 listbox& hotkey_list = find_widget<listbox>("list_hotkeys");
886
887 hotkey_list.clear();
888 visible_hotkeys_.clear();
889 visible_categories_.clear();
890
891 //
892 // Main hotkeys list
893 //
894
895 // These translated initials should match those used in data/gui/window/preferences/02_hotkeys.cfg
896 const std::string gh = markup::span_color("#0f0", _("game_hotkeys^G"));
897 const std::string eh = markup::span_color("#0f0", _("editor_hotkeys^E"));
898 const std::string mh = markup::span_color("#0f0", _("mainmenu_hotkeys^M"));
899
900 for(const auto& [id, hotkey_item] : hotkey::get_hotkey_commands()) {
901 if(hotkey_item.hidden) {
902 continue;
903 }
904
905 visible_hotkeys_.push_back(&hotkey_item);
906 visible_categories_.insert(hotkey_item.category);
907
908 if(filesystem::file_exists(game_config::path + "/images/icons/action/" + hotkey_item.id + "_25.png")) {
909 row_icon = "icons/action/" + hotkey_item.id + "_25.png~CROP(3,3,18,18)";
910 } else {
911 row_icon = "";
912 }
913
914 row_action = hotkey_item.description;
915 row_hotkey = hotkey::get_names(hotkey_item.id);
916
917 row_is_g = hotkey_item.scope[hotkey::SCOPE_GAME] ? gh : "";
918 row_is_e = hotkey_item.scope[hotkey::SCOPE_EDITOR] ? eh : "";
919 row_is_m = hotkey_item.scope[hotkey::SCOPE_MAIN_MENU] ? mh : "";
920
921 hotkey_list.add_row(row_data);
922 }
923
924 //
925 // Filter options
926 //
927
928 std::vector<config> filter_ops;
930 filter_ops.emplace_back("label", hotkey::get_translatable_category_name(cat), "checkbox", false);
931 }
932
933 find_widget<multimenu_button>("hotkey_category_menu").set_values(filter_ops);
934
935 return hotkey_list;
936}
937
939{
940 int row_number = hotkeys.get_selected_row();
941 if(row_number < 0) {
942 gui2::show_transient_message("", _("No hotkey selected"));
943 return;
944 }
945
946 const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
947
948 gui2::dialogs::hotkey_bind bind_dlg(hotkey_item.id);
949 bind_dlg.show();
950
951 hotkey::hotkey_ptr newhk = bind_dlg.get_new_binding();
952 hotkey::hotkey_ptr oldhk;
953
954 // only if not cancelled.
955 if(!newhk) {
956 return;
957 }
958
959 for(const hotkey::hotkey_ptr& hk : hotkey::get_hotkeys()) {
960 if(!hk->is_disabled() && newhk->bindings_equal(hk)) {
961 oldhk = hk;
962 }
963 }
964
965 if(oldhk && oldhk->get_command() == hotkey_item.id) {
966 return;
967 }
968
969 if(oldhk && oldhk->get_command() != "null") {
970 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>”?", {
971 {"hotkey_sequence", oldhk->get_name()},
972 {"old_hotkey_action", hotkey::get_hotkey_command(oldhk->get_command()).description},
973 {"new_hotkey_action", hotkey::get_hotkey_command(newhk->get_command()).description}
974 });
975
976 const int res = gui2::show_message(_("Reassign Hotkey"), text, gui2::dialogs::message::yes_no_buttons, true);
977 if(res != gui2::retval::OK) {
978 return;
979 }
980 }
981
982 hotkey::add_hotkey(newhk);
983
984 // We need to recalculate all hotkey names in because we might have removed a hotkey from another command.
985 for(std::size_t i = 0; i < hotkeys.get_item_count(); ++i) {
986 const hotkey::hotkey_command& hotkey_item_row = *visible_hotkeys_[i];
987 hotkeys.get_row_grid(i)->find_widget<label>("lbl_hotkey").set_label(hotkey::get_names(hotkey_item_row.id));
988 }
989}
990
992{
993 gui2::show_transient_message(_("Hotkeys Reset"), _("All hotkeys have been reset to their default values."));
994
996
997 find_widget<text_box>("filter").set_value("");
998
999 // Set up the list again and reselect the default sorting option.
1000 listbox& hotkey_list = setup_hotkey_list();
1001 hotkey_list.set_active_sorter("sort_0", sort_order::type::ascending, true);
1002}
1003
1005{
1006 int row_number = hotkeys.get_selected_row();
1007 if(row_number < 0) {
1008 gui2::show_transient_message("", _("No hotkey selected"));
1009 return;
1010 }
1011
1012 const hotkey::hotkey_command& hotkey_item = *visible_hotkeys_[row_number];
1013 hotkey::clear_hotkeys(hotkey_item.id);
1014 hotkeys.get_row_grid(row_number)->find_widget<label>("lbl_hotkey").set_label(hotkey::get_names(hotkey_item.id));
1015}
1016
1018{
1019 const multimenu_button& hotkey_menu = find_widget<const multimenu_button>("hotkey_category_menu");
1020 const text_box& name_filter = find_widget<const text_box>("filter");
1021
1022 boost::dynamic_bitset<> toggle_states = hotkey_menu.get_toggle_states();
1023 boost::dynamic_bitset<> res(visible_hotkeys_.size());
1024
1025 std::string text = name_filter.get_value();
1026
1027 // Nothing selected. It means that *all* categories are shown.
1028 if(toggle_states.none()) {
1029 toggle_states = ~toggle_states;
1030 }
1031
1032 for(std::size_t h = 0; h < visible_hotkeys_.size(); ++h) {
1033 // Default to true if there is no filter text
1034 bool found = true;
1035
1036 if(!text.empty()) {
1037 const std::string description = visible_hotkeys_[h]->description.str();
1038
1039 for(const auto& word : utils::split(text, ' ')) {
1040 found = translation::ci_search(description, word);
1041
1042 // No match, we're excluding this hotkey
1043 if(!found) {
1044 break;
1045 }
1046 }
1047 }
1048
1049 unsigned cat_index = 0;
1050
1051 // Filter categories
1053 if(visible_hotkeys_[h]->category == cat) {
1054 break;
1055 } else {
1056 ++cat_index;
1057 }
1058 }
1059
1060 if(cat_index < toggle_states.size() && found) {
1061 res[h] = toggle_states[cat_index];
1062 } else {
1063 res[h] = false;
1064 }
1065 }
1066
1067 find_widget<listbox>("list_hotkeys").set_row_shown(res);
1068}
1069
1071{
1072 const int selected_row = list.get_selected_row();
1073 const auto& pref = prefs::get().get_advanced_preferences()[selected_row];
1074
1075 // In Japanese language sorting, Reach Map Options becomes the first item and is selected
1076 // automatically before the user has made any choice. Skip SPECIAL preferences if
1077 // Preferences is still being built (initial == true). GitHub #11136.
1078 if(!initial && pref.type == preferences::option::avd_type::SPECIAL) {
1079 if(pref.field == "logging") {
1080 gui2::dialogs::log_settings::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 list.get_row_grid(selected_row)->find_widget<widget>("prefs_setter_grid")
1093 }
1094
1095 if(last_selected_item_ != selected_row) {
1096 list.get_row_grid(last_selected_item_)->find_widget<widget>("prefs_setter_grid")
1098
1099 last_selected_item_ = selected_row;
1100 }
1101}
1102
1104{
1106
1107 connect_signal_mouse_left_click(find_widget<button>("about"),
1108 [](auto&&...) { game_version::display(); });
1109
1110 //
1111 // Status labels
1112 // These need to be set here in pre_show, once the fields are initialized. For some reason, this
1113 // is not the case for those in Advanced
1114 //
1115 gui2::bind_default_status_label(find_widget<slider>("max_saves_slider"));
1116 gui2::bind_default_status_label(find_widget<slider>("turbo_slider"));
1117 gui2::bind_default_status_label(find_widget<slider>("pixel_scale_slider"));
1118}
1119
1120// Special fullscreen callback
1122{
1123 const bool ison = find_widget<toggle_button>("fullscreen").get_value_bool();
1125
1126 menu_button& res_list = find_widget<menu_button>("resolution_set");
1127
1128 set_resolution_list(res_list);
1129 res_list.set_active(!ison);
1130}
1131
1133{
1134 find_widget<toggle_button>("fullscreen").set_value(true);
1135
1136 menu_button& res_list = find_widget<menu_button>("resolution_set");
1137
1138 set_resolution_list(res_list);
1139 res_list.set_active(false);
1140}
1141
1143{
1144 find_widget<toggle_button>("fullscreen").set_value(false);
1145
1146 menu_button& res_list = find_widget<menu_button>("resolution_set");
1147
1148 set_resolution_list(res_list);
1149 res_list.set_active(true);
1150}
1151
1153{
1154 menu_button& res_list = find_widget<menu_button>("resolution_set");
1155
1157 set_resolution_list(res_list);
1158 }
1159}
1160
1162{
1163 menu_button& theme_list = find_widget<menu_button>("choose_theme");
1164
1165 const auto selection = theme_list.get_value();
1166 const auto& theme = themes_.at(selection);
1168
1170 if(display && resources::gamedata && resources::gamedata->get_theme().empty()) {
1171 display->set_theme(theme.id);
1172 }
1173
1174}
1175
1177{
1178 menu_button& gui2_theme_list = find_widget<menu_button>("choose_gui2_theme");
1179 unsigned selected_theme = gui2_theme_list.get_value();
1180 if (selected_theme != current_gui_theme_) {
1181 current_gui_theme_ = selected_theme;
1182 prefs::get().set_gui2_theme(gui2_themes_.at(selected_theme));
1184 }
1185}
1186
1188{
1190
1191 // Save new prefs to disk. This also happens on app close, but doing
1192 // it here too ensures nothing is lost in case of, say, a crash.
1194
1195 // Needed for applying changes to tip panel visiblity on dialog close
1196 if (is_reload_needed_) {
1198 }
1199}
1200
1201} // namespace dialogs
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition display.hpp:88
void set_theme(const std::string &new_theme)
Definition display.cpp:246
static display * get_singleton()
Returns the display object if a display object exists.
Definition display.hpp:102
std::ostringstream wrapper.
Definition formatter.hpp:40
Simple push button.
Definition button.hpp:36
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition button.cpp:64
hotkey::hotkey_ptr get_new_binding() const
@ yes_no_buttons
Shows a yes and no button.
Definition message.hpp:81
Abstract base class for all modal dialogs.
field_bool * register_bool(const std::string &id, const bool mandatory, const std::function< bool()> &callback_load_value=nullptr, const std::function< void(bool)> &callback_save_value=nullptr, const std::function< void(widget &)> &callback_change=nullptr, const bool initial_fire=false)
Creates a new boolean field.
void set_always_save_fields(const bool always_save_fields)
field_integer * register_integer(const std::string &id, const bool mandatory, const std::function< int()> &callback_load_value=nullptr, const std::function< void(int)> &callback_save_value=nullptr)
Creates a new integer field.
bool show(const unsigned auto_close_time=0)
Shows the window.
void set_theme_list(menu_button &theme_list)
void on_advanced_prefs_list_select(listbox &tree, const bool initial=false)
Callback for selection changes.
void remove_hotkey_callback(listbox &hotkeys)
void set_resolution_list(menu_button &res_list)
void initialize_sound_option_group(const std::string &id_suffix, ToggleGet &&toggle_getter, ToggleSet &&toggle_setter, VolumeGet &&volume_getter, VolumeSet &&volume_setter)
void on_friends_list_select(listbox &list, text_box &textbox)
void add_friend_list_entry(const bool is_friend, text_box &textbox)
std::vector< const hotkey::hotkey_command * > visible_hotkeys_
widget_data get_friends_list_row_data(const preferences::acquaintance &entry)
virtual void post_show() override
Actions to be taken after the window has been shown.
std::set< hotkey::HOTKEY_CATEGORY > visible_categories_
void handle_res_select()
Special callback functions.
std::vector< std::string > gui2_themes_
virtual void pre_show() override
Actions to be taken before showing the window.
void remove_friend_list_entry(listbox &friends_list, text_box &textbox)
group< pref_constants::lobby_joins > lobby_joins_group
void set_gui2_theme_list(menu_button &theme_list)
Base container class.
Definition grid.hpp:32
std::unique_ptr< widget > swap_child(const std::string &id, std::unique_ptr< widget > w, const bool recurse, widget *new_parent=nullptr)
Exchanges a child in the grid.
Definition grid.cpp:101
unsigned add_row(const unsigned count=1)
Adds a row to end of the grid.
Definition grid.cpp:60
void on_modified(const Func &func)
Sets a common callback function for all members.
Definition group.hpp:121
void add_member(selectable_item *w, const T &value)
Adds a widget/value pair to the group map.
Definition group.hpp:41
void set_member_states(const T &value)
Sets the toggle values for all widgets besides the one associated with the specified value to false.
Definition group.hpp:110
Small abstract helper class.
The listbox class.
Definition listbox.hpp:41
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition listbox.cpp:92
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition listbox.cpp:256
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition listbox.cpp:267
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition listbox.cpp:108
int get_selected_row() const
Returns the first selected row.
Definition listbox.cpp:290
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition listbox.cpp:153
void set_values(const std::vector<::config > &values, unsigned selected=0)
virtual unsigned get_value() const override
Inherited from selectable_item.
virtual void set_active(const bool active) override
See styled_widget::set_active.
boost::dynamic_bitset get_toggle_states() const
Get the current state of the menu options.
Small abstract helper class.
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
virtual void set_label(const t_string &text)
virtual void set_use_markup(bool use_markup)
const t_string & get_label() const
const std::string & text() const
std::string get_value() const
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
A widget that allows the user to input text in single line.
Definition text_box.hpp:125
virtual void set_value(unsigned selected, bool fire_event=false) override
Inherited from selectable_item.
Base class for all widgets.
Definition widget.hpp:55
T * find_widget(const std::string_view id, const bool must_be_active, const bool must_exist)
Gets a widget with the wanted id.
Definition widget.hpp:747
void set_visible(const visibility visible)
Definition widget.cpp:479
@ visible
The user sets the widget visible, that means:
@ invisible
The user set the widget invisible, that means:
@ hidden
The user sets the widget hidden, that means:
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition window.hpp:387
const std::string & get_notes() const
const std::string & get_status() const
const std::string & get_nick() const
void set_lobby_joins(pref_constants::lobby_joins show)
const std::vector< preferences::option > & get_advanced_preferences()
bool set_music(bool ison)
void set_remember_password(bool remember)
const std::map< std::string, preferences::acquaintance > & get_acquaintances()
void set_turbo(bool ison)
static prefs & get()
sound::volume music_volume()
void set_sound_volume(sound::volume vol)
void save_hotkeys()
bool turn_bell()
void write_preferences()
sound::volume sound_volume()
bool set_ui_sound(bool ison)
sound::volume bell_volume()
int scroll_speed()
void set_theme(const std::string &theme)
bool sound()
void show_wesnothd_server_search()
bool set_turn_bell(bool ison)
sound::volume ui_volume()
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)
void set_music_volume(sound::volume vol)
std::pair< preferences::acquaintance *, bool > add_acquaintance(const std::string &nick, const std::string &mode, const std::string &notes)
bool ui_sound_on()
int pixel_scale()
bool turbo()
void set_bell_volume(sound::volume vol)
bool remember_password()
void clear_hotkeys()
bool show_standing_animations()
void set_ui_volume(sound::volume vol)
constexpr float as_percent() const
Definition sound.hpp:124
static constexpr volume from_percent(float percentage)
Definition sound.hpp:121
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:1001
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.
static std::string _(const char *str)
Definition gettext.hpp:100
#define WRN_GUI_L
Definition log.hpp:57
std::string id
Text to match against addon_info.tags()
Definition manager.cpp:199
This file contains the window object, this object is a top level container which has the event manage...
New lexcical_cast header.
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
void raise_resize_event()
Definition events.cpp:728
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
const std::string unicode_multiplication_sign
Definition constants.cpp:46
std::string path
void bind_default_status_label(W &source)
Binds a status label using the default value getter and default target ID.
gui_theme_map_t guis
Map of all known GUIs.
std::map< std::string, widget_item > widget_data
Definition widget.hpp:36
void show_transient_error_message(const std::string &message, const std::string &image, const bool message_use_markup)
Shows a transient error message to the user.
std::map< std::string, t_string > widget_item
Definition widget.hpp:33
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition message.cpp:148
@ OK
Dialog was closed with the OK button.
Definition retval.hpp:35
General purpose widgets.
const hotkey_list & get_hotkeys()
Returns the list of hotkeys.
void clear_hotkeys()
Unset the bindings for all 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
const std::map< std::string_view, hotkey::hotkey_command > & get_hotkey_commands()
returns a container that contains all currently active hotkey_commands.
const hotkey_command & get_hotkey_command(std::string_view command)
Returns the hotkey_command with the given id.
void add_hotkey(hotkey_ptr item)
Add a hotkey to the list of hotkeys.
t_string get_translatable_category_name(HOTKEY_CATEGORY category)
Gets the display name for a given hotkey category.
Functions to load and save images from/to disk.
std::string span_color(const color_t &color, Args &&... data)
Applies Pango markup to the input specifying its display color.
Definition markup.hpp:110
std::string tag(std::string_view tag, Args &&... data)
Wraps the given data in the specified tag.
Definition markup.hpp:45
game_data * gamedata
Definition resources.cpp:22
bool ci_search(const std::string &s1, const std::string &s2)
Case-insensitive search.
Definition gettext.cpp:559
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:765
int get_max_pixel_scale()
Definition video.cpp:485
point current_resolution()
The current window size in desktop coordinates.
Definition video.cpp:819
void set_fullscreen(bool fullscreen)
Set the fullscreen state.
Definition video.cpp:827
bool set_resolution(const point &resolution)
Set the window resolution.
Definition video.cpp:852
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
Definition video.cpp:882
int w
Definition pathfind.cpp:188
std::string_view data
Definition picture.cpp:188
Stores all information related to functions that can be bound to hotkeys.
std::string id
The unique ID.
Holds a 2D point.
Definition point.hpp:25
static bool get(const std::string &pref, bool def)
static void set(const std::string &pref, bool value)
Definitions related to theme-support.
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define i
#define h