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