The Battle for Wesnoth  1.17.23+dev
end_credits.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2023
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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
19 #include "about.hpp"
20 #include "config.hpp"
21 #include "game_config.hpp"
23 #include "gui/widgets/grid.hpp"
27 #include "gui/widgets/settings.hpp"
28 #include "gui/widgets/window.hpp"
29 #include "gettext.hpp"
30 
31 #include <functional>
32 
33 #include <sstream>
34 
35 namespace gui2::dialogs
36 {
37 
38 REGISTER_DIALOG(end_credits)
39 
40 end_credits::end_credits(const std::string& campaign)
41  : modal_dialog(window_id())
42  , focus_on_(campaign)
43  , backgrounds_()
44  , text_widget_(nullptr)
45  , scroll_speed_(100)
46  , last_scroll_(std::numeric_limits<uint32_t>::max())
47  , first_idx_(0)
48  , last_idx_(first_idx_ + sliding_size_)
49 {
50 }
51 
53 {
54  last_scroll_ = SDL_GetTicks();
55 
56  connect_signal_pre_key_press(window, std::bind(&end_credits::key_press_callback, this, std::placeholders::_5));
57 
58  std::stringstream ss;
59  std::stringstream focus_ss;
60 
62  std::stringstream& group_stream = (group.id == focus_on_) ? focus_ss : ss;
63  group_stream << "\n";
64 
65  if(!group.header.empty()) {
66  group_stream << "<span size='xx-large'>" << group.header << "</span>" << "\n";
67  }
68 
69  for(const about::credits_group::about_group& about : group.sections) {
70  group_stream << "\n" << "<span size='x-large'>" << about.title << "</span>" << "\n";
71 
72  for(const auto& entry : about.names) {
73  group_stream << entry.first << "\n";
74  }
75  }
76  }
77 
78  // If a section is focused, move it to the top
79  if(!focus_ss.str().empty()) {
80  focus_ss << ss.rdbuf();
81  }
82 
83  // Get the appropriate background images
85 
86  if(backgrounds_.empty()) {
88  }
89 
90  // TODO: implement showing all available images as the credits scroll
91  window.get_canvas(0).set_variable("background_image", wfl::variant(backgrounds_[0]));
92 
93  text_widget_ = find_widget<scroll_label>(&window, "text", false, true);
94 
97 
98  content_ = focus_ss.str().empty() ? ss.str() : focus_ss.str();
99 
100  // splits the content text by newline, leaving blanks
101  // also truncates the length of the line to 200 characters
102  // 200 characters is completely arbitrary, just prevent the possibility of ridiculously wide lines
103  // NOTE: this depends on the assumption that the <span>s added above only ever wrap a single line
104  std::vector<std::string> lines = utils::split(content_, '\n', 0);
105  int i = 0;
106  for(const std::string& line : lines) {
107  if(i % lines_per_chunk_ == 0) {
108  chunks_.emplace_back();
109  }
110  std::vector<std::string>& last_chunk = chunks_[chunks_.size()-1];
111  last_chunk.emplace_back(line.size() < 200 ? line : line.substr(0, 200));
112  i++;
113  }
114 
115  sliding_content_.clear();
116  for(std::size_t i = 0; i <= sliding_size_; i++){
117  sliding_content_ += utils::join(chunks_.at(i), "\n") + "\n";
118  }
119 
120  //concat substring strings
122  // HACK: always hide the scrollbar, even if it's needed.
123  // This should probably be implemented as a scrollbar mode.
124  // Also, for some reason hiding the whole grid doesn't work, and the elements need to be hidden manually
125  if(grid* v_grid = dynamic_cast<grid*>(text_widget_->find("_vertical_scrollbar_grid", false))) {
126  find_widget<scrollbar_base>(v_grid, "_vertical_scrollbar", false).set_visible(widget::visibility::hidden);
127 
128  // TODO: enable again if e24336afeb7 is reverted.
129  //find_widget<repeating_button>(v_grid, "_half_page_up", false).set_visible(widget::visibility::hidden);
130  //find_widget<repeating_button>(v_grid, "_half_page_down", false).set_visible(widget::visibility::hidden);
131  }
132 }
133 
135 {
136  uint32_t now = SDL_GetTicks();
137  if(last_scroll_ > now) {
138  return;
139  }
140 
141  uint32_t missed_time = now - last_scroll_;
142 
143  unsigned int cur_pos = text_widget_->get_vertical_scrollbar_item_position();
144 
145  // Calculate how far the text should have scrolled by now
146  // The division by 1000 is to convert milliseconds to seconds.
147  unsigned int needed_dist = missed_time * scroll_speed_ / 1000;
148 
149  // TODO: this doesn't allow for scrolling up again after been scrolled down
150  // only the content in the current sliding window can be scrolled up
151  if(cur_pos <= text_widget_->get_height()){
152  text_widget_->set_vertical_scrollbar_item_position(cur_pos + needed_dist);
153  } else {
154  if(first_idx_ < chunks_.size() - sliding_size_ - 1){
155  first_idx_++;
157  sliding_content_.clear();
158 
159  if(last_idx_ <= chunks_.size()){
160  for(std::size_t i = first_idx_; i <= last_idx_; i++) {
161  sliding_content_ += utils::join(chunks_[i], "\n") + "\n";
162  }
163  }
164 
165  // updates the sliding window
167  cur_pos = 0;
168  }
169  }
170 
171  last_scroll_ = now;
172 }
173 
174 void end_credits::key_press_callback(const SDL_Keycode key)
175 {
176  if(key == SDLK_UP && scroll_speed_ < 400) {
177  scroll_speed_ <<= 1;
178  }
179 
180  if(key == SDLK_DOWN && scroll_speed_ > 50) {
181  scroll_speed_ >>= 1;
182  }
183 }
184 
185 } // namespace dialogs
void set_variable(const std::string &key, wfl::variant &&value)
Definition: canvas.hpp:154
std::vector< std::string > backgrounds_
Definition: end_credits.hpp:51
scroll_label * text_widget_
Definition: end_credits.hpp:53
static constexpr std::size_t lines_per_chunk_
number of lines to put in each chunk of text to display the final chunk will of course probably have ...
Definition: end_credits.hpp:69
const std::string & focus_on_
Definition: end_credits.hpp:49
void key_press_callback(const SDL_Keycode key)
std::vector< std::vector< std::string > > chunks_
Definition: end_credits.hpp:74
static constexpr std::size_t sliding_size_
sliding_size_ alters how many of the sliding contents are to be run at once n-1 = 2 => 3 strings at o...
Definition: end_credits.hpp:64
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Definition: end_credits.cpp:52
virtual void update() override
TLD override to update animations, called once per frame.
Abstract base class for all modal dialogs.
Base container class.
Definition: grid.hpp:32
virtual void set_label(const t_string &label) override
See styled_widget::set_label.
virtual void set_use_markup(bool use_markup) override
See styled_widget::set_use_markup.
void set_link_aware(bool l)
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
canvas & get_canvas(const unsigned index)
unsigned get_height() const
Definition: widget.cpp:333
@ hidden
The user sets the widget hidden, that means:
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:67
std::size_t i
Definition: function.cpp:968
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.
std::vector< std::string > get_background_images(const std::string &campaign)
Gets credit background images for a given campaign.
Definition: about.cpp:106
const credits_data & get_credits_data()
Gets all credits data.
Definition: about.cpp:94
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:181
std::string game_title_background
void connect_signal_pre_key_press(dispatcher &dispatcher, const signal_keyboard &signal)
Connects the signal for 'snooping' on the keypress.
Definition: dispatcher.cpp:174
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::string > split(const config_attribute_value &val)
This file contains the settings handling of the widget library.