The Battle for Wesnoth  1.15.2+dev
tree_view.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2018 by Mark de Wever <koraq@xs4all.nl>
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 "gettext.hpp"
20 #include "gui/core/log.hpp"
23 #include "gui/widgets/settings.hpp"
24 #include "gui/widgets/window.hpp"
25 #include "utils/functional.hpp"
26 #include "wml_exception.hpp"
27 
28 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
29 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
30 
31 namespace gui2
32 {
33 // ------------ WIDGET -----------{
34 
35 REGISTER_WIDGET(tree_view)
36 
37 tree_view::tree_view(const implementation::builder_tree_view& builder)
38  : scrollbar_container(builder, type())
39  , node_definitions_(builder.nodes)
40  , indentation_step_size_(0)
41  , need_layout_(false)
42  , root_node_(new tree_view_node("root", nullptr, *this, std::map<std::string, string_map>()))
43  , selected_item_(nullptr)
44 {
45  connect_signal<event::LEFT_BUTTON_DOWN>(
47 }
48 
50 {
51  if(root_node_) {
53  }
54 }
55 
57  const std::string& id, const std::map<std::string /* widget id */, string_map>& data, const int index)
58 {
59  return get_root_node().add_child(id, data, index);
60 }
61 
62 std::pair<tree_view_node::ptr_t, int> tree_view::remove_node(tree_view_node* node)
63 {
64  assert(node && node != root_node_ && node->parent_node_);
65  const point node_size = node->get_size();
66 
68 
69  auto node_itor = std::find_if(siblings.begin(), siblings.end(), [node](const auto& c) { return c.get() == node; });
70 
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::make_pair(std::move(old_node), position);
86 }
87 
89 {
90  get_root_node().clear();
92 }
93 
94 void
96  const std::vector<widget*>& call_stack)
97 {
98  // Inherited.
100 
101  assert(root_node_);
102  root_node_->impl_populate_dirty_list(caller, call_stack);
103 }
104 
105 void tree_view::set_self_active(const bool /*active*/)
106 {
107  /* DO NOTHING */
108 }
109 
110 bool tree_view::empty() const
111 {
112  return root_node_->empty();
113 }
114 
116 {
117  layout_children(false);
118 }
119 
120 void tree_view::resize_content(const int width_modification,
121  const int height_modification,
122  const int width__modification_pos,
123  const int height_modification_pos)
124 {
125  DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " width_modification "
126  << width_modification << " height_modification " << height_modification << ".\n";
127 
129  width_modification,
130  height_modification,
131  width__modification_pos,
132  height_modification_pos
133  )) {
134  // Calculate new size.
136  size.x += width_modification;
137  size.y += height_modification;
138 
139  // Set new size.
140  content_grid()->set_size(size);
141 
142  // Set status.
143  need_layout_ = true;
144  // If the content grows assume it "overwrites" the old content.
145  if(width_modification < 0 || height_modification < 0) {
146  set_is_dirty(true);
147  }
149  DBG_GUI_L << LOG_HEADER << " succeeded.\n";
150  } else {
151  DBG_GUI_L << LOG_HEADER << " failed.\n";
152  }
153 }
154 
155 void tree_view::layout_children(const bool force)
156 {
157  assert(root_node_ && content_grid());
158 
159  if(need_layout_ || force) {
162 
163  need_layout_ = false;
165  }
166 }
167 
169 {
170  // Inherited.
172 
173  assert(content_grid());
174  content_grid()->set_rows_cols(1, 1);
177 }
178 
180 {
181  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
182 
183  get_window()->keyboard_capture(this);
184 }
185 
186 template<tree_view_node* (tree_view_node::*func)()>
188 {
190  if(!selected) {
191  return nullptr;
192  }
193 
194  tree_view_node* visible = selected->get_last_visible_parent_node();
195  if(visible != selected) {
196  return visible;
197  }
198 
199  return (selected->*func)();
200 }
201 
202 template<tree_view_node* (tree_view_node::*func)()>
204 {
205  if(tree_view_node* next = get_next_node<func>()) {
206  next->select_node();
207  SDL_Rect visible = content_visible_area();
208  SDL_Rect rect = next->get_grid().get_rectangle();
209  visible.y = rect.y; // - content_grid()->get_y();
210  visible.h = rect.h;
211  show_content_rect(visible);
212  return true;
213  }
214 
215  return false;
216 }
217 
218 void tree_view::handle_key_up_arrow(SDL_Keymod modifier, bool& handled)
219 {
220  if(handle_up_down_arrow<&tree_view_node::get_selectable_node_above>()) {
221  handled = true;
222  } else {
223  scrollbar_container::handle_key_up_arrow(modifier, handled);
224  }
225 }
226 
227 void tree_view::handle_key_down_arrow(SDL_Keymod modifier, bool& handled)
228 {
229  if(handle_up_down_arrow<&tree_view_node::get_selectable_node_below>()) {
230  handled = true;
231  } else {
233  }
234 }
235 
236 void tree_view::handle_key_left_arrow(SDL_Keymod modifier, bool& handled)
237 {
239  if(!selected || selected->is_folded()) {
241  return;
242  }
243 
244  selected->fold();
245  handled = true;
246 }
247 
248 void tree_view::handle_key_right_arrow(SDL_Keymod modifier, bool& handled)
249 {
251  if(!selected || !selected->is_folded()) {
253  return;
254  }
255 
256  selected->unfold();
257  handled = true;
258 }
259 
260 // }---------- DEFINITION ---------{
261 
264 {
265  DBG_GUI_P << "Parsing tree view " << id << '\n';
266 
267  load_resolutions<resolution>(cfg);
268 }
269 
270 /*WIKI
271  * @page = GUIWidgetDefinitionWML
272  * @order = 1_tree_view
273  *
274  * == Tree view ==
275  *
276  * @macro = tree_view_description
277  *
278  * The documentation is not written yet.
279  *
280  * The following states exist:
281  * * state_enabled, the listbox is enabled.
282  * * state_disabled, the listbox is disabled.
283  * @begin{parent}{name="gui/"}
284  * @begin{tag}{name="ree_view_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
285  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="generic/widget_definition/resolution"}
286  * @allow{link}{name="gui/window/resolution/grid"}
287  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
288  * @end{tag}{name="state_enabled"}
289  * @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
290  * @end{tag}{name="state_disabled"}
291  * @end{tag}{name="resolution"}
292  * @end{tag}{name="ree_view_definition"}
293  * @end{parent}{name="gui/"}
294  */
296  : resolution_definition(cfg)
297  , grid(nullptr)
298 {
299  // Note the order should be the same as the enum state_t is listbox.hpp.
300  state.emplace_back(cfg.child("state_enabled"));
301  state.emplace_back(cfg.child("state_disabled"));
302 
303  const config& child = cfg.child("grid");
304  VALIDATE(child, _("No grid defined."));
305 
306  grid = std::make_shared<builder_grid>(child);
307 }
308 
309 // }---------- BUILDER -----------{
310 
311 /*WIKI_MACRO
312  * @begin{macro}{tree_view_description}
313  *
314  * A tree view is a styled_widget that holds several items of the same or
315  * different types. The items shown are called tree view nodes and when
316  * a node has children, these can be shown or hidden. Nodes that contain
317  * children need to provide a clickable button in order to fold or
318  * unfold the children.
319  * @end{macro}
320  */
321 
322 /*WIKI
323  * @page = GUIWidgetInstanceWML
324  * @order = 2_tree_view
325  *
326  * == Tree view ==
327  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
328  * @begin{tag}{name="tree_view"}{min=0}{max=-1}{super="generic/widget_instance"}
329  * @macro = tree_view_description
330  *
331  * List with the tree view specific variables:
332  * @begin{table}{config}
333  * vertical_scrollbar_mode & scrollbar_mode & initial_auto &
334  * Determines whether or not to show the
335  * scrollbar. $
336  * horizontal_scrollbar_mode & scrollbar_mode & initial_auto &
337  * Determines whether or not to show the
338  * scrollbar. $
339  *
340  * indentation_step_size & unsigned & 0 &
341  * The number of pixels every level of
342  * nodes is indented from the previous
343  * level. $
344  *
345  * node & section & & The tree view can contain multiple node
346  * sections. This part needs more
347  * documentation. $
348  * @end{table}
349  * @begin{tag}{name="node"}{min=0}{max=-1}
350  * @begin{table}{config}
351  * id & string & "" & $
352  * @end{table}
353  * @begin{tag}{name="node_definition"}{min=0}{max=-1}{super="gui/window/resolution/grid"}
354  * @begin{table}{config}
355  * return_value_id & string & "" & $
356  * @end{table}
357  * @end{tag}{name="node_definition"}
358  * @end{tag}{name="node"}
359  * @end{tag}{name="tree_view"}
360  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
361  * NOTE more documentation and examples are needed.
362  */ // TODO annotate node
363 
364 namespace implementation
365 {
366 builder_tree_view::builder_tree_view(const config& cfg)
367  : builder_styled_widget(cfg)
368  , vertical_scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
369  , horizontal_scrollbar_mode(get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
370  , indentation_step_size(cfg["indentation_step_size"])
371  , nodes()
372 {
373  for(const auto& node : cfg.child_range("node")) {
374  nodes.emplace_back(node);
375  }
376 
377  VALIDATE(!nodes.empty(), _("No nodes defined for a tree view."));
378 }
379 
381 {
382  /*
383  * TODO see how much we can move in the constructor instead of
384  * building in several steps.
385  */
386  tree_view* widget = new tree_view(*this);
387 
390 
392 
393  DBG_GUI_G << "Window builder: placed tree_view '" << id << "' with definition '" << definition << "'.\n";
394 
395  const auto conf = widget->cast_config_to<tree_view_definition>();
396  assert(conf);
397 
398  widget->init_grid(conf->grid);
399  widget->finalize_setup();
400 
401  return widget;
402 }
403 
405  : id(cfg["id"])
406  , unfolded(cfg["unfolded"].to_bool(false))
407  , builder(nullptr)
408 {
409  VALIDATE(!id.empty(), missing_mandatory_wml_key("node", "id"));
410 
411  VALIDATE(id != "root", _("[node]id 'root' is reserved for the implementation."));
412 
413  const config& node_definition = cfg.child("node_definition");
414 
415  VALIDATE(node_definition, _("No node defined."));
416 
417  builder = std::make_shared<builder_grid>(node_definition);
418 }
419 
420 } // namespace implementation
421 
422 // }------------ END --------------
423 
424 } // 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:1282
#define DBG_GUI_P
Definition: log.hpp:68
virtual void finalize_setup()
Inherited from container_base.
Definition: tree_view.cpp:168
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:420
std::vector< state_definition > state
const std::vector< node > & nodes
void set_horizontal_scrollbar_mode(const scrollbar_mode scrollbar_mode)
#define DBG_GUI_L
Definition: log.hpp:57
#define LOG_HEADER
Definition: tree_view.cpp:29
void finalize_setup()
The builder needs to call us so we do our setup.
unsigned indentation_step_size_
Definition: tree_view.hpp:133
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:53
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
Definition: tree_view.cpp:105
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:362
void set_vertical_scrollbar_mode(const scrollbar_mode scrollbar_mode)
Base class for all widgets.
Definition: widget.hpp:47
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:227
tree_view_node * selected_item()
Definition: tree_view.hpp:95
STL namespace.
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: tree_view.hpp:214
std::pair< tree_view_node::ptr_t, int > remove_node(tree_view_node *node)
Removes the given node as a child of its parent node.
Definition: tree_view.cpp:62
void signal_handler_left_button_down(const event::ui_event event)
Definition: tree_view.cpp:179
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:44
Generic file dialog.
Definition: field-fwd.hpp:22
bool empty() const
Does the node have children?
bool is_folded() const
Is the node folded?
Base container class.
Definition: grid.hpp:30
node_children_vector children_
Our children.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
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:86
#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:463
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:218
std::string selected
bool handle_up_down_arrow()
Definition: tree_view.cpp:203
tree_view_node * root_node_
Definition: tree_view.hpp:137
std::vector< tree_node > nodes
The types of nodes in the tree view.
Definition: tree_view.hpp:225
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:236
void set_indentation_step_size(const unsigned indentation_step_size)
Definition: tree_view.hpp:90
void fold(const bool recursive=false)
void init_grid(const std::shared_ptr< builder_grid > &grid_builder)
Initializes and builds the grid.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
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:120
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)
Right arrow key pressed.
void set_child(widget *widget, const unsigned row, const unsigned col, const unsigned flags, const unsigned border_size)
Sets a child in the grid.
Definition: grid.cpp:69
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:34
std::shared_ptr< const typename T::resolution > cast_config_to() const
Casts the current resolution definition config to the respective type of a derived widget...
window * get_window()
Get the parent window.
Definition: widget.cpp:114
tree_view_node * get_last_visible_parent_node()
const SDL_Rect & content_visible_area() const
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
Holds a 2D point.
Definition: point.hpp:23
void unfold(const bool recursive=false)
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:55
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:71
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:48
scrollbar_mode get_scrollbar_mode(const std::string &scrollbar_mode)
Returns the scrollbar mode flags.
Definition: helper.cpp:120
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:722
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:95
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:302
#define next(ls)
Definition: llex.cpp:32
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:110
tree_view_node * get_next_node()
Definition: tree_view.cpp:187
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: tree_view.hpp:215
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:224
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:262
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:115
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)
Up arrow key pressed.
std::vector< ptr_t > node_children_vector
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
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:47
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:63
#define DBG_GUI_G
Definition: log.hpp:40
static std::deque< std::string > call_stack
Definition: function.cpp:39
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:248
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:297
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55
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:56
tree_node(const config &cfg)
Definition: tree_view.cpp:404