The Battle for Wesnoth  1.19.7+dev
scroll_text.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2023 - 2024
3  by Subhraman Sarkar (babaissarkar) <suvrax@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 
19 
24 #include "gettext.hpp"
25 #include "wml_exception.hpp"
26 
27 #include <functional>
28 
29 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
30 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
31 
32 namespace gui2
33 {
34 
35 // ------------ WIDGET -----------{
36 
37 REGISTER_WIDGET(scroll_text)
38 
39 scroll_text::scroll_text(const implementation::builder_scroll_text& builder)
40  : scrollbar_container(builder, type())
41  , state_(ENABLED)
42  , wrap_on_(false)
43  , text_alignment_(builder.text_alignment)
44  , editable_(builder.editable)
45  , max_size_(point(0,0))
46  , link_aware_(builder.link_aware)
47 {
48  connect_signal<event::LEFT_BUTTON_DOWN>(
49  std::bind(&scroll_text::signal_handler_left_button_down, this, std::placeholders::_2),
51 }
52 
54 {
55  if(content_grid()) {
56  return dynamic_cast<multiline_text*>(content_grid()->find("_text", false));
57  }
58 
59  return nullptr;
60 }
61 
63 {
65  widget->set_value(label);
66  widget->set_label(label);
67 
68  bool resize_needed = !content_resize_request();
69  if(resize_needed && get_size() != point()) {
71  }
72  widget->goto_start_of_data();
73  }
74 }
75 
77 {
79  return widget->get_value();
80  } else {
81  return "";
82  }
83 }
84 
86 {
87  link_aware_ = l;
88 
90  widget->set_link_aware(l);
91  }
92 }
93 
94 void scroll_text::set_text_alignment(const PangoAlignment text_alignment)
95 {
96  // Inherit.
97  styled_widget::set_text_alignment(text_alignment);
98 
99  text_alignment_ = text_alignment;
100 
102  widget->set_text_alignment(text_alignment_);
103  }
104 }
105 
106 void scroll_text::set_self_active(const bool active)
107 {
108  state_ = active ? ENABLED : DISABLED;
109 }
110 
112 {
113  return state_ != DISABLED;
114 }
115 
116 unsigned scroll_text::get_state() const
117 {
118  return state_;
119 }
120 
122 {
124  assert(text);
125 
126  text->set_editable(is_editable());
127  text->set_label(get_label());
131 }
132 
133 void scroll_text::place(const point& origin, const point& size) {
135 
137  const SDL_Rect& visible_area = content_visible_area();
138 
139  if (widget->get_cursor_pos().x < visible_area.w/2.0) {
141  } else {
142  scroll_horizontal_scrollbar_by(widget->get_cursor_pos().x - visible_area.w/2.0);
143  }
144 
145  if (widget->get_cursor_pos().y >= (widget->get_text_end_pos().y - visible_area.h/2.0)) {
146  if (widget->get_lines_count() > 1) {
148  } else {
150  }
151  } else if (widget->get_cursor_pos().y < visible_area.h/2.0) {
153  } else {
154  scroll_vertical_scrollbar_by(widget->get_cursor_pos().y - visible_area.h/2.0);
155  }
156 
157  if (widget->get_length() == 0) {
160  }
161 
162  set_max_size(widget->get_config_default_size());
163  }
164 }
165 
167 {
169 
170  if ((calc_size.x > max_size_.x) && (max_size_.x != 0)) {
171  calc_size.x = max_size_.x;
172  }
173 
174  if ((calc_size.y > max_size_.y) && (max_size_.y != 0)) {
175  calc_size.y = max_size_.y;
176  }
177 
178  return calc_size;
179 }
180 
182 {
183  // ------ get vertical scrollbar size ------
185  ? point()
187 
188  // ------ get horizontal scrollbar size ------
190  ? point()
192 
193  // padding = 3
194  max_size_ = point(max_size.x + vertical_scrollbar.x + 3, max_size.y + horizontal_scrollbar.y + 3);
195 }
196 
197 
198 
199 void scroll_text::set_can_wrap(bool can_wrap)
200 {
201  wrap_on_ = can_wrap;
202 }
203 
205 {
206  return true;
207 }
208 
210 {
211  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
212 
213  get_window()->keyboard_capture(this);
214 }
215 
216 // }---------- DEFINITION ---------{
217 
220 {
221  DBG_GUI_P << "Parsing scroll text " << id;
222 
223  load_resolutions<resolution>(cfg);
224 }
225 
227  : resolution_definition(cfg), grid(nullptr)
228 {
229  // Note the order should be the same as the enum state_t is scroll_text.hpp.
230  state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", missing_mandatory_wml_tag("scroll_text", "state_enabled")));
231  state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", missing_mandatory_wml_tag("scroll_text", "state_disabled")));
232 
233  auto child = VALIDATE_WML_CHILD(cfg, "grid", missing_mandatory_wml_tag("scroll_text", "grid"));
234  grid = std::make_shared<builder_grid>(child);
235 }
236 
237 // }---------- BUILDER -----------{
238 
239 namespace implementation
240 {
241 
242 builder_scroll_text::builder_scroll_text(const config& cfg)
244  , text_alignment(decode_text_alignment(cfg["text_alignment"]))
245  , editable(cfg["editable"].to_bool(true))
246  , link_aware(cfg["link_aware"].to_bool(false))
247 {
248  // Scrollbar default to auto. AUTO_VISIBLE_FIRST_RUN doesn't work.
251  }
252 
255  }
256 }
257 
258 std::unique_ptr<widget> builder_scroll_text::build() const
259 {
260  auto widget = std::make_unique<scroll_text>(*this);
261 
262  const auto conf = widget->cast_config_to<scroll_text_definition>();
263  assert(conf);
264 
265  widget->init_grid(*conf->grid);
266  widget->finalize_setup();
267 
268  DBG_GUI_G << "Window builder: placed scroll text '" << id
269  << "' with definition '" << definition << "'.";
270 
271  return widget;
272 }
273 
274 } // namespace implementation
275 
276 // }------------ END --------------
277 
278 } // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
Base container class.
Definition: grid.hpp:32
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:645
void set_link_aware(bool l)
void set_max_size(point max_size)
Sets the size of the text beyond which scrollbars should be visible.
void signal_handler_left_button_down(const event::ui_event event)
virtual unsigned get_state() const override
See styled_widget::get_state.
std::string get_value()
Definition: scroll_text.cpp:76
multiline_text * get_internal_text_box()
Definition: scroll_text.cpp:53
PangoAlignment text_alignment_
void set_link_aware(bool l)
Definition: scroll_text.cpp:85
void set_can_wrap(bool can_wrap)
void finalize_subclass() override
Function for the subclasses to do their setup.
virtual void set_label(const t_string &label) override
Definition: scroll_text.cpp:62
bool is_editable() const
Definition: scroll_text.hpp:83
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
void place(const point &origin, const point &size) override
See widget::place.
point calculate_best_size() const override
See widget::calculate_best_size.
virtual bool get_active() const override
See styled_widget::get_active.
state_t state_
Current state of the widget.
virtual void set_text_alignment(const PangoAlignment text_alignment) override
See styled_widget::set_text_alignment.
Definition: scroll_text.cpp:94
bool can_wrap() const override
See widget::can_wrap.
@ END
Go to the end position.
Definition: scrollbar.hpp:58
@ BEGIN
Go to begin position.
Definition: scrollbar.hpp:53
Base class for creating containers with one or two scrollbar(s).
void scroll_vertical_scrollbar(const scrollbar_base::scroll_mode scroll)
Scrolls the vertical scrollbar.
@ AUTO_VISIBLE_FIRST_RUN
Like AUTO_VISIBLE, but when not needed upon the initial layout phase, the bars are not shown and no s...
@ AUTO_VISIBLE
The scrollbar is shown when the number of items is larger as the visible items.
virtual void place(const point &origin, const point &size) override
See widget::place.
void scroll_horizontal_scrollbar(const scrollbar_base::scroll_mode scroll)
Scrolls the horizontal scrollbar.
virtual point calculate_best_size() const override
See widget::calculate_best_size.
void scroll_horizontal_scrollbar_by(const int pixels)
Scrolls the horizontal scrollbar by pixel.
bool content_resize_request(const bool force_sizing=false)
Notification if the content of a child needs a resize.
const SDL_Rect & content_visible_area() const
void scroll_vertical_scrollbar_by(const int pixels)
Scrolls the vertical scrollbar by pixel.
const t_string & get_label() const
virtual void set_text_alignment(const PangoAlignment text_alignment)
virtual void set_label(const t_string &text)
virtual void set_use_markup(bool use_markup)
bool get_use_markup() const
void set_editable(bool editable)
Set or unset whether text can be edited or not Text can only be copied and scrolled through when edit...
Base class for all widgets.
Definition: widget.hpp:55
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:203
visibility get_visible() const
Definition: widget.cpp:506
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:311
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:316
window * get_window()
Get the parent window.
Definition: widget.cpp:117
@ invisible
The user set the widget invisible, that means:
void keyboard_capture(widget *widget)
Definition: window.cpp:1207
#define DBG_GUI_G
Definition: log.hpp:41
#define DBG_GUI_P
Definition: log.hpp:66
#define DBG_GUI_E
Definition: log.hpp:35
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:202
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
Generic file dialog.
PangoAlignment decode_text_alignment(const std::string &alignment)
Converts a text alignment string to a text alignment.
Definition: helper.cpp:89
Contains the implementation details for lexical_cast and shouldn't be used directly.
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
#define LOG_HEADER
Definition: scroll_text.cpp:30
virtual std::unique_ptr< widget > build() const override
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
std::string definition
Parameters for the styled_widget.
std::vector< state_definition > state
scroll_text_definition(const config &cfg)
Holds a 2D point.
Definition: point.hpp:25
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WML_CHILD(cfg, key, message)