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