The Battle for Wesnoth  1.19.5+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 #include "serialization/markup.hpp"
27 
28 #include <cmath>
29 
30 using namespace std::chrono_literals;
31 
32 namespace
33 {
34 
35 // How long text fading should take - currently a hardcoded value.
36 const auto fade_duration = 500ms;
37 
38 } // end unnamed namespace
39 
40 namespace gui2::dialogs
41 {
42 REGISTER_DIALOG(outro)
43 
45  : modal_dialog(window_id())
46  , text_()
47  , current_text_()
48  , text_index_(0)
49  , duration_(info.end_text_duration)
50  , fade_alpha_(0)
51  , fade_start_(0)
52  , fading_in_(true)
53  , timer_id_(0)
54 {
55  if(!info.end_text.empty()) {
56  text_.push_back(info.end_text);
57  } else {
58  text_.push_back(_("The End"));
59  }
60 
61  if(info.end_credits) {
62  text_.push_back(markup::span_size("large", info.campaign_name));
63 
64  if(const auto campaign_credits = about::get_campaign_credits(info.campaign)) {
65  for(const auto& about : (*campaign_credits)->sections) {
66  if(about.names.empty()) {
67  continue;
68  }
69 
70  // Split the names into chunks of 5. Use float for proper ceil function!
71  static const float chunk_size = 5.0;
72 
73  const unsigned num_names = about.names.size();
74  const unsigned num_chunks = std::ceil(num_names / chunk_size);
75 
76  for(std::size_t i = 0; i < num_chunks; ++i) {
77  std::stringstream ss;
78 
79  // Only include section title on first chunk
80  if(i == 0) {
81  ss << about.title << "\n\n";
82  }
83 
84  for(std::size_t k = i * chunk_size; k < std::min<unsigned>((i + 1) * chunk_size, num_names); ++k) {
85  ss << markup::span_size("xx-small", about.names[k].first) << "\n";
86  }
87 
88  // Clean up the trailing newline
89  std::string section_text = ss.str();
90  section_text.pop_back();
91 
92  text_.push_back(std::move(section_text));
93  }
94  }
95  }
96  }
97 
98  current_text_ = text_[0];
99 
100  if(duration_ == 0ms) {
101  duration_ = 3500ms; // 3.5 seconds
102  }
103 }
104 
105 void outro::pre_show()
106 {
107  set_enter_disabled(true);
108  get_canvas(0).set_variable("outro_text", wfl::variant(current_text_));
109 }
110 
112 {
113  // window doesn't immediately close, keep returning until it does
114  if(text_index_ >= text_.size()) {
115  return;
116  }
117 
118  if(fade_start_ == 0) {
119  fade_start_ = SDL_GetTicks();
120  }
121 
122  // If we've faded fully in...
123  if(fading_in_ && fade_alpha_ >= 255) {
124  // Schedule the fadeout after the provided delay.
125  if(timer_id_ == 0) {
126  timer_id_ = add_timer(duration_, [this](std::size_t) {
127  fading_in_ = false;
128  fade_start_ = 0;
129  });
130  }
131 
132  return;
133  }
134 
135  canvas& window_canvas = window::get_canvas(0);
136 
137  // If we've faded fully out...
138  if(!fading_in_ && fade_alpha_ == 0) {
139  // ...and we've just showed the last text bit, close the window.
140  text_index_++;
141  if(text_index_ >= text_.size()) {
142  window::close();
143  return;
144  }
145  current_text_ = text_[text_index_];
146 
147  // ...else show the next bit.
148  window_canvas.set_variable("outro_text", wfl::variant(current_text_));
149 
150  fading_in_ = true;
151 
152  remove_timer(timer_id_);
153  timer_id_ = 0;
154 
155  fade_start_ = SDL_GetTicks();
156  }
157 
158  window_canvas.set_variable("fade_alpha", wfl::variant(fade_alpha_));
159  window_canvas.update_size_variables();
160  queue_redraw();
161 
162  auto current_ticks = SDL_GetTicks();
163 
164  if(fade_start_ > current_ticks) {
165  // 32-bit ticks counter wraps around after about 49 days, the 64-bit version
166  // requires SDL 2.0.18+. Just restart the counter in the worst case and let
167  // the player deal with the sheer ridiculousness of their predicament.
168  fade_start_ = current_ticks;
169  }
170 
171  fade_alpha_ = std::clamp<int>(
172  std::round(255.0 * double(current_ticks - fade_start_) / double(fade_duration.count())),
173  0, 255);
174  if(!fading_in_) {
175  fade_alpha_ = 255 - fade_alpha_;
176  }
177 }
178 
179 void outro::post_show()
180 {
181  remove_timer(timer_id_);
182  timer_id_ = 0;
183 }
184 
185 } // namespace dialogs
A simple canvas which can be drawn upon.
Definition: canvas.hpp:45
void set_variable(const std::string &key, wfl::variant &&value)
Definition: canvas.hpp:154
void update_size_variables()
Update WFL size variables.
Definition: canvas.cpp:702
Abstract base class for all modal dialogs.
Dialog to display 'The End' at the end of a campaign.
Definition: outro.hpp:28
std::size_t i
Definition: function.cpp:1028
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...
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
Display credits about all contributors.
utils::optional< credits_data::const_iterator > get_campaign_credits(const std::string &campaign)
Gets credits for a given campaign.
Definition: about.cpp:99
static void update()
std::size_t add_timer(const std::chrono::milliseconds &interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:123
bool remove_timer(const std::size_t id)
Removes a timer.
Definition: timer.cpp:164
logger & info()
Definition: log.cpp:319
std::string span_size(const std::string &size, Args &&... data)
Definition: markup.hpp:110
Contains the gui2 timer routines.