The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
end_credits.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#define GETTEXT_DOMAIN "wesnoth-lib"
16
18
19#include "about.hpp"
20#include "game_config.hpp"
21#include "gui/widgets/grid.hpp"
25#include "gettext.hpp"
27
28#include <SDL3/SDL_timer.h>
29
30#include <functional>
31#include <sstream>
32
33namespace gui2::dialogs
34{
35
36REGISTER_DIALOG(end_credits)
37
38end_credits::end_credits(const std::string& campaign)
39 : modal_dialog(window_id())
40 , focus_on_(campaign)
41 , backgrounds_()
42 , text_widget_(nullptr)
43 , scroll_speed_(100)
44 , last_scroll_(std::numeric_limits<uint32_t>::max())
45 , first_idx_(0)
46 , last_idx_(first_idx_ + sliding_size_)
47{
48}
49
51{
52 last_scroll_ = SDL_GetTicks();
53
54 connect_signal_pre_key_press(*this, std::bind(&end_credits::key_press_callback, this, std::placeholders::_5));
55
56 std::stringstream ss;
57 std::stringstream focus_ss;
58
60 std::stringstream& group_stream = (group.id == focus_on_) ? focus_ss : ss;
61 group_stream << "\n";
62
63 if(!group.header.empty()) {
64 group_stream << markup::span_size("xx-large", group.header) << "\n";
65 }
66
67 for(const about::credits_group::about_group& about : group.sections) {
68 group_stream << "\n" << markup::span_size("x-large", about.title) << "\n";
69
70 for(const auto& entry : about.names) {
71 group_stream << entry.first << "\n";
72 }
73 }
74 }
75
76 // If a section is focused, move it to the top
77 if(!focus_ss.str().empty()) {
78 focus_ss << ss.rdbuf();
79 }
80
81 // Get the appropriate background images
83
84 if(backgrounds_.empty()) {
86 }
87
88 // TODO: implement showing all available images as the credits scroll
89 get_canvas(0).set_variable("background_image", wfl::variant(backgrounds_[0]));
90
91 text_widget_ = find_widget<scroll_label>("text", false, true);
92
95
96 content_ = focus_ss.str().empty() ? ss.str() : focus_ss.str();
97
98 // splits the content text by newline, leaving blanks
99 // also truncates the length of the line to 200 characters
100 // 200 characters is completely arbitrary, just prevent the possibility of ridiculously wide lines
101 // NOTE: this depends on the assumption that the <span>s added above only ever wrap a single line
102 std::vector<std::string> lines = utils::split(content_, '\n', 0);
103 int i = 0;
104 for(const std::string& line : lines) {
105 if(i % lines_per_chunk_ == 0) {
106 chunks_.emplace_back();
107 }
108 std::vector<std::string>& last_chunk = chunks_[chunks_.size()-1];
109 last_chunk.emplace_back(line.size() < 200 ? line : line.substr(0, 200));
110 i++;
111 }
112
113 sliding_content_.clear();
114 for(std::size_t i = 0; i <= sliding_size_; i++){
115 sliding_content_ += utils::join(chunks_.at(i), "\n") + "\n";
116 }
117
118 //concat substring strings
120 // HACK: always hide the scrollbar, even if it's needed.
121 // This should probably be implemented as a scrollbar mode.
122 // Also, for some reason hiding the whole grid doesn't work, and the elements need to be hidden manually
123 if(grid* v_grid = dynamic_cast<grid*>(text_widget_->find("_vertical_scrollbar_grid", false))) {
124 v_grid->find_widget<scrollbar_base>("_vertical_scrollbar").set_visible(widget::visibility::hidden);
125
126 // TODO: enable again if e24336afeb7 is reverted.
127 //v_grid.find_widget<repeating_button>("_half_page_up").set_visible(widget::visibility::hidden);
128 //v_grid.find_widget<repeating_button>("_half_page_down").set_visible(widget::visibility::hidden);
129 }
130}
131
133{
134 uint32_t now = SDL_GetTicks();
135 if(last_scroll_ > now) {
136 return;
137 }
138
139 uint32_t missed_time = now - last_scroll_;
140
141 unsigned int cur_pos = text_widget_->get_vertical_scrollbar_item_position();
142
143 // Calculate how far the text should have scrolled by now
144 // The division by 1000 is to convert milliseconds to seconds.
145 unsigned int needed_dist = missed_time * scroll_speed_ / 1000;
146
147 // TODO: this doesn't allow for scrolling up again after been scrolled down
148 // only the content in the current sliding window can be scrolled up
149 if(cur_pos <= text_widget_->get_height()){
151 } else {
152 if(first_idx_ < chunks_.size() - sliding_size_ - 1){
153 first_idx_++;
155 sliding_content_.clear();
156
157 if(last_idx_ <= chunks_.size()){
158 for(std::size_t i = first_idx_; i <= last_idx_; i++) {
159 sliding_content_ += utils::join(chunks_[i], "\n") + "\n";
160 }
161 }
162
163 // updates the sliding window
165 cur_pos = 0;
166 }
167 }
168
169 last_scroll_ = now;
170}
171
172void end_credits::key_press_callback(const SDL_Keycode key)
173{
174 if(key == SDLK_UP && scroll_speed_ < 400) {
175 scroll_speed_ <<= 1;
176 }
177
178 if(key == SDLK_DOWN && scroll_speed_ > 50) {
179 scroll_speed_ >>= 1;
180 }
181}
182
183} // namespace dialogs
void set_variable(const std::string &key, wfl::variant &&value)
Definition canvas.hpp:165
virtual void pre_show() override
Actions to be taken before showing the window.
std::vector< std::string > backgrounds_
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 ...
const std::string & focus_on_
void key_press_callback(const SDL_Keycode key)
std::vector< std::vector< std::string > > chunks_
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...
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)
Base class for a scroll bar.
Definition scrollbar.hpp:39
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.
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
canvas & get_canvas(const unsigned index)
void set_visible(const visibility visible)
Definition widget.cpp:479
unsigned get_height() const
Definition widget.cpp:341
@ hidden
The user sets the widget hidden, that means:
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:95
std::string game_title_background
std::string span_size(std::string_view size, Args &&... data)
Applies Pango markup to the input specifying its display size.
Definition markup.hpp:146
STL namespace.
std::string join(const Range &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)
#define i