The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
loading_screen.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 - 2025
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13*/
14
15/**
16 * @file
17 * Screen with logo and loading status info during program-startup.
18 */
19
20#define GETTEXT_DOMAIN "wesnoth-lib"
21
23
24#include "cursor.hpp"
25#include "draw_manager.hpp"
26#include "gettext.hpp"
28#include "gui/widgets/label.hpp"
30#include "log.hpp"
31#include "video.hpp"
32
33#include <chrono>
34#include <functional>
35#include <utility>
36
37static lg::log_domain log_loadscreen("loadscreen");
38#define LOG_LS LOG_STREAM(info, log_loadscreen)
39#define ERR_LS LOG_STREAM(err, log_loadscreen)
40#define WRN_LS LOG_STREAM(warn, log_loadscreen)
41
42static lg::log_domain log_display("display");
43#define DBG_DP LOG_STREAM(debug, log_display)
44
45static const std::map<loading_stage, std::string> stage_names {
46 { loading_stage::build_terrain, N_("Building terrain rules") },
47 { loading_stage::create_cache, N_("Reading files and creating cache") },
48 { loading_stage::init_display, N_("Initializing display") },
49 { loading_stage::init_fonts, N_("Reinitialize fonts for the current language") },
50 { loading_stage::init_teams, N_("Initializing teams") },
51 { loading_stage::init_theme, N_("Initializing display") },
52 { loading_stage::load_config, N_("Loading game configuration") },
53 { loading_stage::load_data, N_("Loading data files") },
54 { loading_stage::load_level, N_("Loading level") },
55 { loading_stage::init_lua, N_("Initializing scripting engine") },
56 { loading_stage::init_whiteboard, N_("Initializing planning mode") },
57 { loading_stage::load_unit_types, N_("Reading unit files") },
58 { loading_stage::load_units, N_("Loading units") },
59 { loading_stage::refresh_addons, N_("Searching for installed add-ons") },
60 { loading_stage::start_game, N_("Starting game") },
61 { loading_stage::verify_cache, N_("Verifying cache") },
62 { loading_stage::connect_to_server, N_("Connecting to server") },
63 { loading_stage::login_response, N_("Logging in") },
64 { loading_stage::waiting, N_("Waiting for server") },
65 { loading_stage::redirect, N_("Connecting to redirected server") },
66 { loading_stage::next_scenario, N_("Waiting for next scenario") },
67 { loading_stage::download_level_data, N_("Getting game data") },
68 { loading_stage::download_lobby_data, N_("Downloading lobby data") },
69};
70
71namespace { std::chrono::steady_clock::time_point last_spin; }
72
73namespace gui2::dialogs
74{
75REGISTER_DIALOG(loading_screen)
76
77loading_screen* loading_screen::singleton_ = nullptr;
78
79loading_screen::loading_screen(std::function<void()> f)
80 : modal_dialog(window_id())
81 , load_funcs_{std::move(f)}
82 , worker_result_()
83 , cursor_setter_()
84 , progress_stage_label_(nullptr)
85 , animation_(nullptr)
86 , animation_start_()
87 , current_stage_(loading_stage::none)
88 , visible_stages_()
89 , current_visible_stage_()
90 , running_(false)
91{
92 for(const auto& [stage, description] : stage_names) {
93 visible_stages_[stage] = t_string(description, "wesnoth-lib") + "...";
94 }
95
97 singleton_ = this;
99}
100
102{
103 set_enter_disabled(true);
105
107
108 progress_stage_label_ = find_widget<label>("status", false, true);
109 animation_ = find_widget<drawing>("animation", false, true);
110}
111
113{
114 cursor_setter_.reset();
115}
116
118{
119 if(singleton_ && stage != loading_stage::none) {
120 singleton_->current_stage_.store(stage, std::memory_order_release);
121 // Allow display to update, close events to be handled, etc.
123 }
124}
125
127{
128 // If we're not showing a loading screen, do nothing.
129 if (!singleton_) {
130 return;
131 }
132
133 // If we're not the main thread, do nothing.
135 return;
136 }
137
138 // Restrict actual update rate.
139 auto now = std::chrono::steady_clock::now();
140 auto elapsed = now - last_spin;
141 if (elapsed > draw_manager::get_frame_length()) {
142 last_spin = now;
144 }
145}
146
153
154// This will be run inside the window::show() loop.
156{
157 if (load_funcs_.empty()) {
158 return;
159 }
160
161 // Do not automatically recurse.
162 if (running_) { return; }
163 running_ = true;
164
165 // Run the loading function.
166 auto func = load_funcs_.back();
167 load_funcs_.pop_back();
168 LOG_LS << "Executing loading screen worker function.";
169 func();
170
171 running_ = false;
172
173 // If there's nothing more to do, close.
174 if (load_funcs_.empty()) {
175 queue_redraw();
177 }
178}
179
181{
183
184 DBG_DP << "loading_screen::layout";
185
186 loading_stage stage = current_stage_.load(std::memory_order_acquire);
187
188 if(stage != loading_stage::none && (current_visible_stage_ == visible_stages_.end() || stage != current_visible_stage_->first)) {
189 auto iter = visible_stages_.find(stage);
190 if(iter == visible_stages_.end()) {
191 WRN_LS << "Stage missing description.";
192 return;
193 }
194
196 progress_stage_label_->set_label(iter->second);
197 }
198
199 using namespace std::chrono;
200 const auto now = steady_clock::now();
201
202 // We only need to set the start time once;
203 if(!animation_start_.has_value()) {
204 animation_start_ = now;
205 }
206
207 animation_->get_drawing_canvas().set_variable("time", wfl::variant(duration_cast<milliseconds>(now - *animation_start_).count()));
209}
210
212{
213 LOG_LS << "Loading screen destroyed.";
214 singleton_ = nullptr;
215}
216
217void loading_screen::display(const std::function<void()>& f)
218{
219 if(singleton_ || video::headless()) {
220 LOG_LS << "Directly executing loading function.";
221 f();
222 } else {
223 LOG_LS << "Creating new loading screen.";
225 }
226}
227
228} // namespace dialogs
void set_variable(const std::string &key, wfl::variant &&value)
Definition canvas.hpp:165
static void progress(loading_stage stage=loading_stage::none)
Report what is being loaded to the loading screen.
virtual void layout() override
Called by draw_manager to assign concrete layout.
std::atomic< loading_stage > current_stage_
static loading_screen * singleton_
static void raise()
Raise the loading screen to the top of the draw stack.
std::vector< std::function< void()> > load_funcs_
std::unique_ptr< cursor::setter > cursor_setter_
stage_map::const_iterator current_visible_stage_
virtual void process() override
Inherited from events::pump_monitor.
static void display(const std::function< void()> &f)
utils::optional< decltype(std::chrono::steady_clock::now())> animation_start_
loading_screen(std::function< void()> f)
static void spin()
Indicate to the player that loading is progressing.
virtual void post_show() override
Actions to be taken after the window has been shown.
virtual void pre_show() override
Actions to be taken before showing the window.
Abstract base class for all modal dialogs.
void set_allow_plugin_skip(const bool allow_plugin_skip)
bool show(const unsigned auto_close_time=0)
Shows the window.
canvas & get_drawing_canvas()
Definition drawing.hpp:34
virtual void set_label(const t_string &text)
virtual void layout()
Finalize the size and position of the drawable and its children, and invalidate any regions requiring...
void queue_redraw()
Indicates that this widget should be redrawn.
Definition widget.cpp:464
void set_enter_disabled(const bool enter_disabled)
Disable the enter key.
Definition window.hpp:313
void close()
Requests to close the window.
Definition window.hpp:216
void set_escape_disabled(const bool escape_disabled)
Disable the escape key.
Definition window.hpp:326
#define DBG_DP
Definition display.cpp:79
#define N_(String)
Definition gettext.hpp:108
This file contains the window object, this object is a top level container which has the event manage...
static lg::log_domain log_loadscreen("loadscreen")
#define WRN_LS
#define LOG_LS
static const std::map< loading_stage, std::string > stage_names
static lg::log_domain log_display("display")
loading_stage
Loading screen stage IDs.
Standard logging facilities (interface).
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
@ WAIT
Definition cursor.hpp:28
std::chrono::milliseconds get_frame_length()
Returns the length of one display frame, in milliseconds.
void raise_drawable(top_level_drawable *tld)
Raise a TLD to the top of the drawing stack.
bool is_in_main_thread()
Definition events.cpp:475
void pump_and_draw()
pump() then immediately draw()
Definition events.hpp:156
STL namespace.
bool headless()
The game is running headless.
Definition video.cpp:146
#define f