The Battle for Wesnoth  1.17.0-dev
tree_view_node.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2021
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 #pragma once
16 
17 #include "gui/widgets/widget.hpp"
18 #include "gui/widgets/grid.hpp"
19 
20 #include <memory>
21 
22 namespace gui2
23 {
24 
25 namespace implementation {
26  struct tree_node;
27 }
28 
29 class selectable_item;
30 class tree_view;
31 
32 class tree_view_node : public widget
33 {
35  friend class tree_view;
36 
37 public:
38  using node_children_vector = std::vector<std::shared_ptr<tree_view_node>>;
39 
40  bool operator==(const tree_view_node& node)
41  {
42  return &node == this;
43  }
44 
46  const std::string& id,
47  tree_view_node* parent_node,
48  tree_view& parent_tree_view,
49  const std::map<std::string /* widget id */, string_map>& data);
50 
51  ~tree_view_node();
52 
53  /**
54  * Constructs a new child node.
55  *
56  * @param id The id of the node definition to use for the
57  * new node.
58  * @param data The data to send to the set_members of the
59  * widgets. If the member id is not an empty
60  * string it is only send to the widget that has
61  * the wanted id (if any). If the member id is an
62  * empty string, it is send to all members.
63  * Having both empty and non-empty id's gives
64  * undefined behavior.
65  * @param index The item before which to add the new item,
66  * 0 == begin, -1 == end.
67  */
68  tree_view_node& add_child(const std::string& id,
69  const std::map<std::string /* widget id */, string_map>& data,
70  const int index = -1)
71  {
72  return add_child_impl(std::make_shared<tree_view_node>(id, this, get_tree_view(), data), index);
73  }
74 
75  /**
76  * Replaces all children of this tree with new children.
77  * The motivation here is to provide a way to add multiple children without calculating the trees size for each child added.
78  * This is a waste of time since the results of that resizing will be immediately thrown out except for the final child added.
79  *
80  * @param id The id of the node definition to use for the new nodes.
81  * @param data data.first is a unique identifying value to be associated to the respective tree_view_node that's returned.
82  * data.second is the data to provide to the tree_node_view's constructor.
83  * @return return_value.first is data.first
84  * return_value.second is the tree_view_node created from data.second
85  */
86  std::map<std::string, std::shared_ptr<gui2::tree_view_node>> replace_children(const std::string& id, const std::map<std::string, std::map<std::string /* widget id */, string_map>>& data);
87 
88  /**
89  * Adds a previously-constructed node as a child of this node at the given position.
90  *
91  * @param new_node A smart pointer to the node object to insert.
92  * @param index The item before which to add the new item,
93  * 0 == begin, -1 == end.
94  */
95  tree_view_node& add_child(std::shared_ptr<tree_view_node> new_node, const int index = -1)
96  {
97  new_node->parent_node_ = this;
98  return add_child_impl(std::move(new_node), index);
99  }
100 
101  /**
102  * Adds a sibbling for a node at the end of the list.
103  *
104  * @param id The id of the node definition to use for the
105  * new node.
106  * @param data The data to send to the set_members of the
107  * widgets. If the member id is not an empty
108  * string it is only send to the widget that has
109  * the wanted id (if any). If the member id is an
110  * empty string, it is send to all members.
111  * Having both empty and non-empty id's gives
112  * undefined behavior.
113  */
115  add_sibling(const std::string& id,
116  const std::map<std::string /* widget id */, string_map>& data)
117  {
118  assert(!is_root_node());
119  return parent_node().add_child(id, data);
120  }
121 
122 private:
123  /** Implementation detail for @ref add_child. */
124  tree_view_node& add_child_impl(std::shared_ptr<tree_view_node>&& new_node, const int index);
125 
126 public:
127  /**
128  * Is this node the root node?
129  *
130  * When the parent tree view is created it adds one special node, the root
131  * node. This node has no parent node and some other special features so
132  * several code paths need to check whether they are the parent node.
133  *
134  * This also returns true for a detecthed node returned with @ref tree_view::remove_node.
135  */
136  bool is_root_node() const
137  {
138  return parent_node_ == nullptr;
139  }
140 
141  /**
142  * The indentation level of the node.
143  *
144  * The root node starts at level 0.
145  */
146  unsigned get_indentation_level() const;
147 
148  /** Does the node have children? */
149  bool empty() const
150  {
151  return children_.empty();
152  }
153 
154  /** Is the node folded? */
155  bool is_folded() const
156  {
157  return !unfolded_;
158  }
159 
160 #if 0
161  // TODO: implement if different expand modes become necessary
162  enum expand_mode {
163  recursive_restore, // recursively restores collapse mode
164  recursive_expand, // recursively expands the children
165  not_recursive
166  };
167 #endif
168 
169  void fold(const bool recursive = false);
170  void unfold(const bool recursive = false);
171 
172  /**
173  * See @ref widget::create_walker.
174  *
175  * @todo Implement properly.
176  */
177  virtual iteration::walker_base* create_walker() override;
178 
180  {
181  return children_;
182  }
183 
185  {
186  assert(!is_root_node());
187  return parent_node().children();
188  }
189 
190  /** See @ref widget::find_at. */
191  virtual widget* find_at(const point& coordinate,
192  const bool must_be_active) override;
193 
194  /** See @ref widget::find_at. */
195  virtual const widget* find_at(const point& coordinate,
196  const bool must_be_active) const override;
197 
198  /** See @ref widget::find. */
199  widget* find(const std::string& id, const bool must_be_active) override;
200 
201  /** See @ref widget::find. */
202  const widget* find(const std::string& id,
203  const bool must_be_active) const override;
204 
205  /**
206  * The number of children in this widget.
207  */
208  std::size_t count_children() const
209  {
210  return children_.size();
211  }
212 
213  /**
214  * Removes all child items from the widget.
215  */
216  void clear();
217 
218  /***** ***** ***** setters / getters for members ***** ****** *****/
219 
220  /**
221  * Returns the parent node.
222  *
223  * @pre is_root_node() == false.
224  */
225  tree_view_node& parent_node();
226 
227  /** The const version of @ref parent_node. */
228  const tree_view_node& parent_node() const;
229 
231  {
232  return *tree_view_;
233  }
234 
235  const tree_view& get_tree_view() const
236  {
237  return *tree_view_;
238  }
239 
240  tree_view_node& get_child_at(int index);
241 
242  /**
243  * Calculates the node indices needed to get from the root node to this node.
244  */
245  std::vector<int> describe_path();
246 
247  tree_view_node* get_last_visible_parent_node();
248  tree_view_node* get_node_above();
249  tree_view_node* get_node_below();
250  tree_view_node* get_selectable_node_above();
251  tree_view_node* get_selectable_node_below();
252  void select_node(bool expand_parents = false);
253  grid& get_grid() { return grid_; }
254  void layout_initialize(const bool full_initialization) override;
255 
256  void clear_before_destruct();
257 
258 private:
259  int calculate_ypos();
260 
261  /** See @ref widget::request_reduce_width. */
262  virtual void request_reduce_width(const unsigned maximum_width) override;
263 
264  /**
265  * Our parent node.
266  *
267  * All nodes except the root node have a parent node.
268  */
270 
271  /** The tree view that owns us. */
273 
274  /** Grid holding our contents. */
276 
277  /**
278  * Our children.
279  *
280  * We want the returned child nodes to remain stable so store pointers.
281  */
283 
284  /** The toggle for the folded state. */
286 
287  /** The label to show our selected state. */
289 
290  bool unfolded_;
291  void fold_internal();
292  void unfold_internal();
293 
294  /**
295  * "Inherited" from widget.
296  *
297  * This version needs to call its children, which are it's child nodes.
298  */
299  void impl_populate_dirty_list(window& caller,
300  const std::vector<widget*>& call_stack);
301 
302  /** See @ref widget::calculate_best_size. */
303  virtual point calculate_best_size() const override;
304 
305  /** See @ref widget::disable_click_dismiss. */
306  bool disable_click_dismiss() const override;
307 
308  point calculate_best_size(const int indentation_level,
309  const unsigned indentation_step_size) const;
310  /** @param assume_visible if false (default) it will return 0 if the parent node is folded*/
311  point get_current_size(bool assume_visible = false) const;
312  point get_folded_size() const;
313  point get_unfolded_size() const;
314 
315  /** See @ref widget::set_origin. */
316  virtual void set_origin(const point& origin) override;
317 
318  /** See @ref widget::place. */
319  virtual void place(const point& origin, const point& size) override;
320 
321  unsigned
322  place(const unsigned indentation_step_size, point origin, unsigned width);
323 
324  /** See @ref widget::set_visible_rectangle. */
325  virtual void set_visible_rectangle(const SDL_Rect& rectangle) override;
326 
327  /** See @ref widget::impl_draw_children. */
328  virtual void impl_draw_children(surface& frame_buffer,
329  int x_offset,
330  int y_offset) override;
331 
332  // FIXME rename to icon
333  void signal_handler_left_button_click(const event::ui_event event);
334 
335  void signal_handler_label_left_button_click(const event::ui_event event,
336  bool& handled,
337  bool& halt);
338 
339  void
340  init_grid(grid* grid,
341  const std::map<std::string /* widget id */, string_map>& data);
342 
343  /**
344  * Returns the control_type of the @ref tree_view_node.
345  *
346  * This class does not derive from @ref styled_widget but the function behaves
347  * similar as @ref styled_widget::get_control_type.
348  */
349  const std::string& get_control_type() const;
350 };
351 
352 } // namespace gui2
Small abstract helper class.
tree_view_node * parent_node_
Our parent node.
std::vector< std::shared_ptr< tree_view_node > > node_children_vector
bool is_root_node() const
Is this node the root node?
selectable_item * toggle_
The toggle for the folded state.
Base class for all widgets.
Definition: widget.hpp:48
void clear(const std::string &key)
Definition: general.cpp:185
tree_view_node & add_child(std::shared_ptr< tree_view_node > new_node, const int index=-1)
Adds a previously-constructed node as a child of this node at the given position. ...
const tree_view & get_tree_view() const
std::size_t count_children() const
The number of children in this widget.
Generic file dialog.
Definition: field-fwd.hpp:22
bool empty() const
Does the node have children?
bool operator==(const tree_view_node &node)
bool is_folded() const
Is the node folded?
Base container class.
Definition: grid.hpp:30
node_children_vector children_
Our children.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:84
The walker abstract base class.
Definition: walker.hpp:26
grid grid_
Grid holding our contents.
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:46
A tree view is a control that holds several items of the same or different types. ...
Definition: tree_view.hpp:59
selectable_item * label_
The label to show our selected state.
Holds a 2D point.
Definition: point.hpp:23
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:69
tree_view & get_tree_view()
node_children_vector & children()
node_children_vector & siblings()
tree_view_node & add_sibling(const std::string &id, const std::map< std::string, string_map > &data)
Adds a sibbling for a node at the end of the list.
tree_view * tree_view_
The tree view that owns us.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
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.
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
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:47