The Battle for Wesnoth  1.17.4+dev
tree_view.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2022
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"
24 #include "gui/widgets/settings.hpp"
25 #include "gui/widgets/window.hpp"
26 #include <functional>
27 #include "wml_exception.hpp"
28 
29 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
30 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
31 
32 namespace gui2
33 {
34 // ------------ WIDGET -----------{
35 
36 REGISTER_WIDGET(tree_view)
37 
38 tree_view::tree_view(const implementation::builder_tree_view& builder)
39  : scrollbar_container(builder, type())
40  , node_definitions_(builder.nodes)
41  , indentation_step_size_(0)
42  , need_layout_(false)
43  , root_node_(nullptr)
44  , selected_item_(nullptr)
45 {
46  connect_signal<event::LEFT_BUTTON_DOWN>(
47  std::bind(&tree_view::signal_handler_left_button_down, this, std::placeholders::_2), event::dispatcher::back_pre_child);
48 }
49 
51 {
52  if(root_node_) {
54  }
55 }
56 
58  const std::string& id, const std::map<std::string /* widget id */, string_map>& data, const int index)
59 {
60  return get_root_node().add_child(id, data, index);
61 }
62 
63 std::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 = std::find_if(siblings.begin(), siblings.end(), [node](const auto& c) { return c.get() == node; });
71 
72  assert(node_itor != siblings.end());
73 
74  auto old_node = std::move(*node_itor);
75  old_node->parent_node_ = nullptr;
76 
77  const int position = std::distance(siblings.begin(), node_itor);
78 
79  siblings.erase(node_itor);
80 
81  if(get_size() != point()) {
82  // Don't shrink the width, need to think about a good algorithm to do so.
83  resize_content(0, -node_size.y);
84  }
85 
86  return std::pair(std::move(old_node), position);
87 }
88 
90 {
91  get_root_node().clear();
93 }
94 
95 void
97  const std::vector<widget*>& call_stack)
98 {
99  // Inherited.
101 
102  assert(root_node_);
103  root_node_->impl_populate_dirty_list(caller, call_stack);
104 }
105 
106 void tree_view::set_self_active(const bool /*active*/)
107 {
108  /* DO NOTHING */
109 }
110 
111 bool tree_view::empty() const
112 {
113  return root_node_->empty();
114 }
115 
117 {
118  layout_children(false);
119 }
120 
121 void tree_view::resize_content(const int width_modification,
122  const int height_modification,
123  const int width_modification_pos,
124  const int height_modification_pos)
125 {
126  DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " width_modification "
127  << width_modification << " height_modification " << height_modification << ".\n";
128 
130  width_modification,
131  height_modification,
132  width_modification_pos,
133  height_modification_pos
134  )) {
135  // Calculate new size.
137  size.x += width_modification;
138  size.y += height_modification;
139 
140  // Set new size.
141  content_grid()->set_size(size);
142 
143  // Set status.
144  need_layout_ = true;
145  // If the content grows assume it "overwrites" the old content.
146  if(width_modification < 0 || height_modification < 0) {
147  set_is_dirty(true);
148  }
150  DBG_GUI_L << LOG_HEADER << " succeeded.\n";
151  } else {
152  DBG_GUI_L << LOG_HEADER << " failed.\n";
153  }
154 }
155 
156 void tree_view::layout_children(const bool force)
157 {
158  assert(root_node_ && content_grid());
159 
160  if(need_layout_ || force) {
163 
164  need_layout_ = false;
166  }
167 }
168 
170 {
171  // Inherited.
173 
174  auto root = std::make_unique<tree_view_node>(root_node_id, nullptr, *this, std::map<std::string, string_map>{});
175  root_node_ = root.get();
176 
177  assert(content_grid());
178  content_grid()->set_rows_cols(1, 1);
181 }
182 
184 {
185  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
186 
187  get_window()->keyboard_capture(this);
188 }
189 
190 template<tree_view_node* (tree_view_node::*func)()>
192 {
194  if(!selected) {
195  return nullptr;
196  }
197 
198  tree_view_node* visible = selected->get_last_visible_parent_node();
199  if(visible != selected) {
200  return visible;
201  }
202 
203  return (selected->*func)();
204 }
205 
206 template<tree_view_node* (tree_view_node::*func)()>
208 {
209  if(tree_view_node* next = get_next_node<func>()) {
210  next->select_node();
211  SDL_Rect visible = content_visible_area();
212  SDL_Rect rect = next->get_grid().get_rectangle();
213  visible.y = rect.y; // - content_grid()->get_y();
214  visible.h = rect.h;
215  show_content_rect(visible);
216  return true;
217  }
218 
219  return false;
220 }
221 
222 void tree_view::handle_key_up_arrow(SDL_Keymod modifier, bool& handled)
223 {
224  if(handle_up_down_arrow<&tree_view_node::get_selectable_node_above>()) {
225  handled = true;
226  } else {
227  scrollbar_container::handle_key_up_arrow(modifier, handled);
228  }
229 }
230 
231 void tree_view::handle_key_down_arrow(SDL_Keymod modifier, bool& handled)
232 {
233  if(handle_up_down_arrow<&tree_view_node::get_selectable_node_below>()) {
234  handled = true;
235  } else {
237  }
238 }
239 
240 void tree_view::handle_key_left_arrow(SDL_Keymod modifier, bool& handled)
241 {
243  if(!selected || selected->is_folded()) {
245  return;
246  }
247 
248  selected->fold();
249  handled = true;
250 }
251 
252 void tree_view::handle_key_right_arrow(SDL_Keymod modifier, bool& handled)
253 {
255  if(!selected || !selected->is_folded()) {
257  return;
258  }
259 
260  selected->unfold();
261  handled = true;
262 }
263 
264 // }---------- DEFINITION ---------{
265 
268 {
269  DBG_GUI_P << "Parsing tree view " << id << '\n';
270 
271  load_resolutions<resolution>(cfg);
272 }
273 
275  : resolution_definition(cfg)
276  , grid(nullptr)
277 {
278  // Note the order should be the same as the enum state_t is listbox.hpp.
279  state.emplace_back(cfg.child("state_enabled"));
280  state.emplace_back(cfg.child("state_disabled"));
281 
282  const config& child = cfg.child("grid");
283  VALIDATE(child, _("No grid defined."));
284 
285  grid = std::make_shared<builder_grid>(child);
286 }
287 
288 // }---------- BUILDER -----------{
289 
290 namespace implementation
291 {
292 builder_tree_view::builder_tree_view(const config& cfg)
293  : builder_styled_widget(cfg)
294  , vertical_scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
295  , horizontal_scrollbar_mode(get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
296  , indentation_step_size(cfg["indentation_step_size"])
297  , nodes()
298 {
299  for(const auto& node : cfg.child_range("node")) {
300  nodes.emplace_back(node);
301  }
302 
303  VALIDATE(!nodes.empty(), _("No nodes defined for a tree view."));
304 }
305 
306 std::unique_ptr<widget> builder_tree_view::build() const
307 {
308  /*
309  * TODO see how much we can move in the constructor instead of
310  * building in several steps.
311  */
312  auto widget = std::make_unique<tree_view>(*this);
313 
314  widget->set_vertical_scrollbar_mode(vertical_scrollbar_mode);
315  widget->set_horizontal_scrollbar_mode(horizontal_scrollbar_mode);
316 
317  widget->set_indentation_step_size(indentation_step_size);
318 
319  DBG_GUI_G << "Window builder: placed tree_view '" << id << "' with definition '" << definition << "'.\n";
320 
321  const auto conf = widget->cast_config_to<tree_view_definition>();
322  assert(conf);
323 
324  widget->init_grid(*conf->grid);
325  widget->finalize_setup();
326 
327  return widget;
328 }
329 
331  : id(cfg["id"])
332  , unfolded(cfg["unfolded"].to_bool(false))
333  , builder(nullptr)
334 {
335  VALIDATE(!id.empty(), missing_mandatory_wml_key("node", "id"));
336 
337  // TODO: interpolate this value into the error message
338  VALIDATE(id != tree_view::root_node_id, _("[node]id 'root' is reserved for the implementation."));
339 
340  const config& node_definition = cfg.child("node_definition");
341 
342  VALIDATE(node_definition, _("No node defined."));
343 
344  builder = std::make_shared<builder_grid>(node_definition);
345 }
346 
347 } // namespace implementation
348 
349 // }------------ END --------------
350 
351 } // namespace gui2
Define the common log macros for the gui toolkit.
void show_content_rect(const SDL_Rect &rect)
Shows a certain part of the content.
Base class of a resolution, contains the common keys for a resolution.
void keyboard_capture(widget *widget)
Definition: window.cpp:1251
#define DBG_GUI_P
Definition: log.hpp:66
virtual void finalize_setup()
Inherited from container_base.
Definition: tree_view.cpp:169
tree_view_node * parent_node_
Our parent node.
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
std::vector< state_definition > state
const std::vector< node > & nodes
std::vector< std::shared_ptr< tree_view_node > > node_children_vector
#define DBG_GUI_L
Definition: log.hpp:55
#define LOG_HEADER
Definition: tree_view.cpp:30
void finalize_setup()
The builder needs to call us so we do our setup.
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
unsigned indentation_step_size_
Definition: tree_view.hpp:158
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
tree_view_node & get_root_node()
Definition: tree_view.hpp:75
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
Definition: tree_view.cpp:106
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool &handled)
Down arrow key pressed.
This file contains the window object, this object is a top level container which has the event manage...
child_itors child_range(config_key_type key)
Definition: config.cpp:344
Base class for all widgets.
Definition: widget.hpp:49
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:231
tree_view_node * selected_item()
Definition: tree_view.hpp:117
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: tree_view.hpp:249
static std::string _(const char *str)
Definition: gettext.hpp:93
void signal_handler_left_button_down(const event::ui_event event)
Definition: tree_view.cpp:183
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.
int x
x coordinate.
Definition: point.hpp:45
Generic file dialog.
Definition: field-fwd.hpp:23
bool empty() const
Does the node have children?
bool is_folded() const
Is the node folded?
Base container class.
Definition: grid.hpp:31
node_children_vector children_
Our children.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
std::string definition
Parameters for the styled_widget.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:464
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:222
virtual std::unique_ptr< widget > build() const override
Definition: tree_view.cpp:306
std::string selected
static thread_local std::deque< std::string > call_stack
For printing error messages when WFL parsing or evaluation fails, this contains the names of the WFL ...
Definition: function.cpp:47
bool handle_up_down_arrow()
Definition: tree_view.cpp:207
tree_view_node * root_node_
Definition: tree_view.hpp:162
std::vector< tree_node > nodes
The types of nodes in the tree view.
Definition: tree_view.hpp:260
bool content_resize_request(const bool force_sizing=false)
Notification if the content of a child needs a resize.
void handle_key_left_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:240
A tree view is a control that holds several items of the same or different types. ...
Definition: tree_view.hpp:60
void fold(const bool recursive=false)
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.
Definition: tree_view.cpp:121
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
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)
Right arrow key pressed.
void clear()
Removes all child items from the widget.
std::string id
Parameters for the widget.
Base class for creating containers with one or two scrollbar(s).
void impl_populate_dirty_list(window &caller, const std::vector< widget *> &call_stack)
"Inherited" from widget.
#define DBG_GUI_E
Definition: log.hpp:35
window * get_window()
Get the parent window.
Definition: widget.cpp:118
tree_view_node * get_last_visible_parent_node()
const SDL_Rect & content_visible_area() const
Holds a 2D point.
Definition: point.hpp:24
void unfold(const bool recursive=false)
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:56
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:72
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:49
scrollbar_mode get_scrollbar_mode(const std::string &scrollbar_mode)
Returns the scrollbar mode flags.
Definition: helper.cpp:121
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:727
virtual void child_populate_dirty_list(window &caller, const std::vector< widget *> &call_stack) override
See widget::child_populate_dirty_list.
Definition: tree_view.cpp:96
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:306
virtual void child_populate_dirty_list(window &caller, const std::vector< widget *> &call_stack) override
See widget::child_populate_dirty_list.
SDL_Rect content_visible_area_
Cache for the visible area for the content.
bool empty() const
Definition: tree_view.cpp:111
tree_view_node * get_next_node()
Definition: tree_view.cpp:191
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: tree_view.hpp:250
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:228
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override
See widget::set_visible_rectangle.
tree_view_definition(const config &cfg)
Definition: tree_view.cpp:266
virtual void place(const point &origin, const point &size) override
See widget::place.
virtual void layout_children() override
See widget::layout_children.
Definition: tree_view.cpp:116
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)
Up arrow key pressed.
static const std::string root_node_id
Definition: tree_view.hpp:148
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
mock_char c
tree_view_node & add_child(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Constructs a new child node.
int y
y coordinate.
Definition: point.hpp:48
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:66
#define DBG_GUI_G
Definition: log.hpp:41
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:252
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:301
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
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
tree_view_node & add_node(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Definition: tree_view.cpp:57
tree_node(const config &cfg)
Definition: tree_view.cpp:330