The Battle for Wesnoth  1.19.8+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/widgets/window.hpp"
25 #include "serialization/chrono.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 constexpr auto fade_duration = 500ms;
37 
38 }
39 
40 namespace gui2::dialogs
41 {
42 REGISTER_DIALOG(outro)
43 
45  : modal_dialog(window_id())
46  , text_()
47  , text_index_(0)
48  , display_duration_(info.end_text_duration)
49  , stage_(stage::fading_in)
50  , stage_start_()
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(markup::span_size("large", info.campaign_name));
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 << markup::span_size("xx-small", about.names[k].first) << "\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  if(display_duration_ == 0ms) {
96  display_duration_ = 3500ms; // 3.5 seconds
97  }
98 }
99 
100 void outro::pre_show()
101 {
102  set_enter_disabled(true);
103  get_canvas(0).set_variable("outro_text", wfl::variant(text_[0]));
104  get_canvas(0).set_variable("fade_alpha", wfl::variant(0));
105 }
106 
108 {
109  // window doesn't immediately close, keep returning until it does
110  if(text_index_ >= text_.size()) {
111  return;
112  }
113 
114  const auto now = std::chrono::steady_clock::now();
115  canvas& window_canvas = window::get_canvas(0);
116 
117  // TODO: Setting this in pre_show doesn't work, since it looks like it gets
118  // overwritten by styled_widget::update_canvas. But it's also weird to have
119  // this here. Find a better way to do this...
120  window_canvas.set_variable("text_wrap_mode", wfl::variant(PANGO_ELLIPSIZE_NONE));
121 
122  const auto goto_stage = [this, &now](stage new_stage) {
123  stage_ = new_stage;
124  stage_start_ = now;
125  };
126 
127  if(stage_start_ == std::chrono::steady_clock::time_point{}) {
128  stage_start_ = now;
129  }
130 
131  switch(stage_) {
132  case stage::fading_in:
133  if(now <= stage_start_ + fade_duration) {
134  window_canvas.set_variable("fade_alpha", wfl::variant(float_to_color(get_fade_progress(now))));
135  } else {
136  goto_stage(stage::waiting);
137  }
138  break;
139 
140  case stage::waiting:
141  if(now <= stage_start_ + display_duration_) {
142  return; // zzzzzzz....
143  } else {
144  goto_stage(stage::fading_out);
145  }
146  break;
147 
148  case stage::fading_out:
149  if(now <= stage_start_ + fade_duration) {
150  window_canvas.set_variable("fade_alpha", wfl::variant(float_to_color(1.0 - get_fade_progress(now))));
151  } else if(++text_index_ < text_.size()) {
152  window_canvas.set_variable("outro_text", wfl::variant(text_[text_index_]));
153  goto_stage(stage::fading_in);
154  } else {
155  window::close();
156  }
157  break;
158 
159  default:
160  break;
161  }
162 
163  window_canvas.update_size_variables();
164  queue_redraw();
165 }
166 
167 double outro::get_fade_progress(const std::chrono::steady_clock::time_point& now) const
168 {
169  return chrono::normalize_progress(now - stage_start_, fade_duration);
170 }
171 
172 } // 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
stage
Tracks whether we're fading in, displaying text, or fading out.
Definition: outro.hpp:59
constexpr uint8_t float_to_color(double n)
Convert a double in the range [0.0,1.0] to an 8-bit colour value.
Definition: color.hpp:280
std::size_t i
Definition: function.cpp:1029
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
constexpr double normalize_progress(const std::chrono::duration< RepE, PeriodE > &elapsed, const std::chrono::duration< RepD, PeriodD > &duration)
Definition: chrono.hpp:77
static void update()
logger & info()
Definition: log.cpp:319
std::string span_size(std::string_view size, Args &&... data)
Applies Pango markup to the input specifying its display size.
Definition: markup.hpp:123