The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
tree_view.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2010 - 2025
3 by Mark de Wever <koraq@xs4all.nl>
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
20#include "gettext.hpp"
21#include "gui/core/log.hpp"
25#include <functional>
26#include "wml_exception.hpp"
27
28#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
29#define LOG_HEADER LOG_SCOPE_HEADER + ':'
30
31namespace gui2
32{
33// ------------ WIDGET -----------{
34
35REGISTER_WIDGET(tree_view)
36
37tree_view::tree_view(const implementation::builder_tree_view& builder)
38 : scrollbar_container(builder, type())
39 , node_definitions_(builder.nodes)
40 , indentation_step_size_(builder.indentation_step_size)
41 , has_minimum_(builder.has_minimum)
42 , need_layout_(false)
43 , root_node_(nullptr)
44 , selected_item_(nullptr)
45{
46 connect_signal<event::LEFT_BUTTON_DOWN>(
48}
49
56
58 const std::string& id, const widget_data& data, const int index)
59{
60 return get_root_node().add_child(id, data, index);
61}
62
63std::pair<std::shared_ptr<tree_view_node>, int> tree_view::remove_node(tree_view_node* node)
64{
65 assert(node && node != root_node_ && node->parent_node_);
66 const point node_size = node->get_size();
67
69
70 auto node_itor = utils::ranges::find(siblings, node, [](const auto& c) { return c.get(); });
71 assert(node_itor != siblings.end());
72
73 auto old_node = std::move(*node_itor);
74 old_node->parent_node_ = nullptr;
75
76 const int position = std::distance(siblings.begin(), node_itor);
77
78 siblings.erase(node_itor);
79
80 if(get_size() != point()) {
81 // Don't shrink the width, need to think about a good algorithm to do so.
82 resize_content(0, -node_size.y);
83 }
84
85 return std::pair(std::move(old_node), position);
86}
87
93
94void tree_view::set_self_active(const bool /*active*/)
95{
96 /* DO NOTHING */
97}
98
99bool tree_view::empty() const
100{
101 return root_node_->empty();
102}
103
105{
106 layout_children(false);
107}
108
109void tree_view::resize_content(const int width_modification,
110 const int height_modification,
111 const int width_modification_pos,
112 const int height_modification_pos)
113{
114 DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " width_modification "
115 << width_modification << " height_modification " << height_modification << ".";
116
118 width_modification,
119 height_modification,
120 width_modification_pos,
121 height_modification_pos
122 )) {
123 // Calculate new size.
124 point size = content_grid()->get_size();
125 size.x += width_modification;
126 size.y += height_modification;
127
128 // Set new size.
129 content_grid()->set_size(size);
130
131 // Set status.
132 need_layout_ = true;
133 // If the content grows assume it "overwrites" the old content.
134 if(width_modification < 0 || height_modification < 0) {
135 queue_redraw();
136 }
138 DBG_GUI_L << LOG_HEADER << " succeeded.";
139 } else {
140 DBG_GUI_L << LOG_HEADER << " failed.";
141 }
142}
143
156
158{
159 // Inherited.
161
162 auto root = std::make_unique<tree_view_node>(root_node_id, nullptr, *this, widget_data{});
163 root_node_ = root.get();
164
165 assert(content_grid());
169}
170
172{
173 DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
174
176}
177
178template<tree_view_node* (tree_view_node::*func)()>
180{
181 tree_view_node* selected = selected_item();
182 if(!selected) {
183 return nullptr;
184 }
185
186 tree_view_node* visible = selected->get_last_visible_parent_node();
187 if(visible != selected) {
188 return visible;
189 }
190
191 return (selected->*func)();
192}
193
194template<tree_view_node* (tree_view_node::*func)()>
196{
197 if(tree_view_node* next = get_next_node<func>()) {
198 next->select_node();
200 rect rect = next->get_grid().get_rectangle();
201 visible.y = rect.y; // - content_grid()->get_y();
202 visible.h = rect.h;
204 return true;
205 }
206
207 return false;
208}
209
210void tree_view::handle_key_up_arrow(SDL_Keymod modifier, bool& handled)
211{
212 if(handle_up_down_arrow<&tree_view_node::get_selectable_node_above>()) {
213 handled = true;
214 } else {
216 }
217}
218
219void tree_view::handle_key_down_arrow(SDL_Keymod modifier, bool& handled)
220{
221 if(handle_up_down_arrow<&tree_view_node::get_selectable_node_below>()) {
222 handled = true;
223 } else {
225 }
226}
227
228void tree_view::handle_key_left_arrow(SDL_Keymod modifier, bool& handled)
229{
230 tree_view_node* selected = selected_item();
231 if(!selected || selected->is_folded()) {
233 return;
234 }
235
236 selected->fold();
237 handled = true;
238}
239
240void tree_view::handle_key_right_arrow(SDL_Keymod modifier, bool& handled)
241{
242 tree_view_node* selected = selected_item();
243 if(!selected || !selected->is_folded()) {
245 return;
246 }
247
248 selected->unfold();
249 handled = true;
250}
251
252// }---------- DEFINITION ---------{
253
256{
257 DBG_GUI_P << "Parsing tree view " << id;
258
259 load_resolutions<resolution>(cfg);
260}
261
264 , grid(nullptr)
265{
266 // Note the order should be the same as the enum state_t is listbox.hpp.
267 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", missing_mandatory_wml_tag("tree_view_definition][resolution", "state_enabled")));
268 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", missing_mandatory_wml_tag("tree_view_definition][resolution", "state_disabled")));
269
270 auto child = VALIDATE_WML_CHILD(cfg, "grid", missing_mandatory_wml_tag("tree_view_definition][resolution", "grid"));
271
272 grid = std::make_shared<builder_grid>(child);
273}
274
275// }---------- BUILDER -----------{
276
277namespace implementation
278{
279builder_tree_view::builder_tree_view(const config& cfg)
281 , indentation_step_size(cfg["indentation_step_size"].to_unsigned())
282 , has_minimum(cfg["has_minimum"].to_bool(true))
283 , nodes()
284{
285 for(const auto& node : cfg.child_range("node")) {
286 nodes.emplace_back(node);
287 }
288
289 VALIDATE(!nodes.empty(), _("No nodes defined for a tree view."));
290}
291
292std::unique_ptr<widget> builder_tree_view::build() const
293{
294 /*
295 * TODO see how much we can move in the constructor instead of
296 * building in several steps.
297 */
298 auto widget = std::make_unique<tree_view>(*this);
299
300 DBG_GUI_G << "Window builder: placed tree_view '" << id << "' with definition '" << definition << "'.";
301
302 const auto conf = widget->cast_config_to<tree_view_definition>();
303 assert(conf);
304
305 widget->init_grid(*conf->grid);
306 widget->finalize_setup();
307
308 return widget;
309}
310
312 : id(cfg["id"])
313 , unfolded(cfg["unfolded"].to_bool(false))
314 , builder(nullptr)
315{
316 VALIDATE(!id.empty(), missing_mandatory_wml_key("node", "id"));
317
318 // TODO: interpolate this value into the error message
319 VALIDATE(id != tree_view::root_node_id, _("[node]id ‘root’ is reserved for the implementation."));
320
321 auto node_definition = VALIDATE_WML_CHILD(cfg, "node_definition", missing_mandatory_wml_tag("node", "node_definition"));
322 builder = std::make_shared<builder_grid>(node_definition);
323}
324
325} // namespace implementation
326
327// }------------ END --------------
328
329} // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
child_itors child_range(std::string_view key)
Definition config.cpp:268
Base container class.
Definition grid.hpp:32
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT
Definition grid.hpp:56
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT
Definition grid.hpp:49
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition grid.cpp:711
void set_child(std::unique_ptr< widget > widget, const unsigned row, const unsigned col, const unsigned flags, const unsigned border_size)
Sets a child in the grid.
Definition grid.cpp:71
Base class for creating containers with one or two scrollbar(s).
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool &handled)
Down arrow key pressed.
void show_content_rect(const rect &rect)
Shows a certain part of the content.
rect content_visible_area_
Cache for the visible area for the content.
void finalize_setup()
The builder needs to call us so we do our setup.
const rect & content_visible_area() const
bool content_resize_request(const bool force_sizing=false)
Notification if the content of a child needs a resize.
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)
Up arrow key pressed.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)
Right arrow key pressed.
void clear()
Removes all child items from the widget.
bool empty() const
Does the node have children?
tree_view_node * parent_node_
Our parent node.
virtual void set_visible_rectangle(const rect &rectangle) override
See widget::set_visible_rectangle.
node_children_vector children_
Our children.
tree_view_node & add_child(const std::string &id, const widget_data &data, const int index=-1)
Constructs a new child node.
std::vector< std::shared_ptr< tree_view_node > > node_children_vector
virtual void place(const point &origin, const point &size) override
See widget::place.
tree_view_node * selected_item()
void resize_content(const int width_modification, const int height_modification, const int width_modification_pos=-1, const int height_modification_pos=-1)
Resizes the content.
unsigned indentation_step_size_
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
Definition tree_view.cpp:94
static const std::string root_node_id
tree_view_node * get_next_node()
tree_view_node * root_node_
virtual void finalize_setup()
Inherited from container_base.
bool empty() const
Definition tree_view.cpp:99
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
void handle_key_left_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
tree_view_node & add_node(const std::string &id, const widget_data &data, const int index=-1)
Definition tree_view.cpp:57
void signal_handler_left_button_down(const event::ui_event event)
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
virtual void layout_children() override
See widget::layout_children.
bool handle_up_down_arrow()
std::pair< std::shared_ptr< tree_view_node >, int > remove_node(tree_view_node *node)
Removes the given node as a child of its parent node.
Definition tree_view.cpp:63
const tree_view_node & get_root_node() const
Definition tree_view.hpp:53
Base class for all widgets.
Definition widget.hpp:55
void queue_redraw()
Indicates that this widget should be redrawn.
Definition widget.cpp:464
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
@ visible
The user sets the widget visible, that means:
virtual void set_size(const point &size)
Sets the size of the widget.
Definition widget.cpp:236
void keyboard_capture(widget *widget)
Definition window.cpp:1197
#define LOG_HEADER
const config * cfg
static std::string _(const char *str)
Definition gettext.hpp:100
Define the common log macros for the gui toolkit.
#define DBG_GUI_L
Definition log.hpp:55
#define DBG_GUI_G
Definition log.hpp:41
#define DBG_GUI_P
Definition log.hpp:66
#define DBG_GUI_E
Definition log.hpp:35
std::string id
Text to match against addon_info.tags()
Definition manager.cpp:199
This file contains the window object, this object is a top level container which has the event manage...
ui_event
The event sent to the dispatcher.
Definition handler.hpp:115
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition widget.hpp:36
Contains the implementation details for lexical_cast and shouldn't be used directly.
auto find(Container &container, const Value &value, const Projection &projection={})
Definition general.hpp:213
const std::vector< findroute_node > & nodes
Definition pathfind.cpp:220
std::string_view data
Definition picture.cpp:188
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
std::string definition
Parameters for the styled_widget.
std::vector< tree_node > nodes
The types of nodes in the tree view.
virtual std::unique_ptr< widget > build() const override
std::vector< state_definition > state
tree_view_definition(const config &cfg)
Holds a 2D point.
Definition point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
std::string missing_mandatory_wml_key(const std::string &section, const std::string &key, const std::string &primary_key, const std::string &primary_value)
Returns a standard message for a missing wml key (attribute).
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)
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
#define c