The Battle for Wesnoth  1.19.0-dev
outro.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 - 2024
3  by Charles Dang <exodia339@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
18 #include "gui/dialogs/outro.hpp"
19 
20 #include "about.hpp"
21 #include "formula/variant.hpp"
22 #include "game_classification.hpp"
23 #include "gettext.hpp"
24 #include "gui/core/timer.hpp"
25 #include "gui/widgets/window.hpp"
26 
27 #include <cmath>
28 
29 namespace
30 {
31 
32 // How long text fading should take - currently a hardcoded value.
33 const unsigned FADE_DURATION_MS = 500;
34 
35 } // end unnamed namespace
36 
37 namespace gui2::dialogs
38 {
39 REGISTER_DIALOG(outro)
40 
42  : modal_dialog(window_id())
43  , text_()
44  , current_text_()
45  , text_index_(0)
46  , duration_(info.end_text_duration)
47  , fade_alpha_(0)
48  , fade_start_(0)
49  , fading_in_(true)
50  , timer_id_(0)
51 {
52  if(!info.end_text.empty()) {
53  text_.push_back(info.end_text);
54  } else {
55  text_.push_back(_("The End"));
56  }
57 
58  if(info.end_credits) {
59  text_.push_back("<span size='large'>" + info.campaign_name + "</span>");
60 
61  if(const auto campaign_credits = about::get_campaign_credits(info.campaign)) {
62  for(const auto& about : (*campaign_credits)->sections) {
63  if(about.names.empty()) {
64  continue;
65  }
66 
67  // Split the names into chunks of 5. Use float for proper ceil function!
68  static const float chunk_size = 5.0;
69 
70  const unsigned num_names = about.names.size();
71  const unsigned num_chunks = std::ceil(num_names / chunk_size);
72 
73  for(std::size_t i = 0; i < num_chunks; ++i) {
74  std::stringstream ss;
75 
76  // Only include section title on first chunk
77  if(i == 0) {
78  ss << about.title << "\n\n";
79  }
80 
81  for(std::size_t k = i * chunk_size; k < std::min<unsigned>((i + 1) * chunk_size, num_names); ++k) {
82  ss << "<span size='xx-small'>" << about.names[k].first << "</span>\n";
83  }
84 
85  // Clean up the trailing newline
86  std::string section_text = ss.str();
87  section_text.pop_back();
88 
89  text_.push_back(std::move(section_text));
90  }
91  }
92  }
93  }
94 
95  current_text_ = text_[0];
96 
97  if(!duration_) {
98  duration_ = 3500; // 3.5 seconds
99  }
100 }
101 
103 {
106 }
107 
109 {
110  // window doesn't immediately close, keep returning until it does
111  if(text_index_ >= text_.size()) {
112  return;
113  }
114 
115  if(fade_start_ == 0) {
116  fade_start_ = SDL_GetTicks();
117  }
118 
119  // If we've faded fully in...
120  if(fading_in_ && fade_alpha_ >= 255) {
121  // Schedule the fadeout after the provided delay.
122  if(timer_id_ == 0) {
123  timer_id_ = add_timer(duration_, [this](std::size_t) {
124  fading_in_ = false;
125  fade_start_ = 0;
126  });
127  }
128 
129  return;
130  }
131 
132  canvas& window_canvas = window::get_canvas(0);
133 
134  // If we've faded fully out...
135  if(!fading_in_ && fade_alpha_ == 0) {
136  // ...and we've just showed the last text bit, close the window.
137  text_index_++;
138  if(text_index_ >= text_.size()) {
139  window::close();
140  return;
141  }
143 
144  // ...else show the next bit.
145  window_canvas.set_variable("outro_text", wfl::variant(current_text_));
146 
147  fading_in_ = true;
148 
150  timer_id_ = 0;
151 
152  fade_start_ = SDL_GetTicks();
153  }
154 
155  window_canvas.set_variable("fade_alpha", wfl::variant(fade_alpha_));
156  window_canvas.update_size_variables();
157  queue_redraw();
158 
159  auto current_ticks = SDL_GetTicks();
160 
161  if(fade_start_ > current_ticks) {
162  // 32-bit ticks counter wraps around after about 49 days, the 64-bit version
163  // requires SDL 2.0.18+. Just restart the counter in the worst case and let
164  // the player deal with the sheer ridiculousness of their predicament.
165  fade_start_ = current_ticks;
166  }
167 
168  fade_alpha_ = std::clamp<int>(
169  std::round(255.0 * double(current_ticks - fade_start_) / double(FADE_DURATION_MS)),
170  0, 255);
171  if(!fading_in_) {
172  fade_alpha_ = 255 - fade_alpha_;
173  }
174 }
175 
176 void outro::post_show(window& /*window*/)
177 {
179  timer_id_ = 0;
180 }
181 
182 } // namespace dialogs
A simple canvas which can be drawn upon.
Definition: canvas.hpp:44
void set_variable(const std::string &key, wfl::variant &&value)
Definition: canvas.hpp:153
void update_size_variables()
Update WFL size variables.
Definition: canvas.cpp:648
Abstract base class for all modal dialogs.
Dialog to display 'The End' at the end of a campaign.
Definition: outro.hpp:26
virtual void post_show(window &window) override
Actions to be taken after the window has been shown.
Definition: outro.cpp:176
virtual void update() override
Displays a simple fading screen with any user-provided text.
Definition: outro.cpp:108
unsigned int duration_
Definition: outro.hpp:55
std::size_t text_index_
Definition: outro.hpp:53
std::string current_text_
Definition: outro.hpp:52
std::vector< std::string > text_
Definition: outro.hpp:51
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Definition: outro.cpp:102
std::size_t timer_id_
Definition: outro.hpp:61
uint32_t fade_start_
Definition: outro.hpp:57
canvas & get_canvas(const unsigned index)
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:455
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:63
void set_enter_disabled(const bool enter_disabled)
Disable the enter key.
Definition: window.hpp:327
void close()
Requests to close the window.
Definition: window.hpp:223
std::size_t i
Definition: function.cpp:968
static std::string _(const char *str)
Definition: gettext.hpp:93
This file contains the window object, this object is a top level container which has the event manage...
Display credits about all contributors.
std::optional< credits_data::const_iterator > get_campaign_credits(const std::string &campaign)
Gets credits for a given campaign.
Definition: about.cpp:99
REGISTER_DIALOG(tod_new_schedule)
std::size_t add_timer(const uint32_t interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:127
bool remove_timer(const std::size_t id)
Removes a timer.
Definition: timer.cpp:168
logger & info()
Definition: log.cpp:314
Contains the gui2 timer routines.