The Battle for Wesnoth  1.19.7+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_view id, const bool must_be_active) override;
195 
196  /** See @ref widget::find. */
197  const widget* find(const std::string_view id, const bool must_be_active) const override;
198 
199  /**
200  * The number of children in this widget.
201  */
202  std::size_t count_children() const
203  {
204  return children_.size();
205  }
206 
207  /**
208  * Removes all child items from the widget.
209  */
210  void clear();
211 
212  /***** ***** ***** setters / getters for members ***** ****** *****/
213 
214  /**
215  * Returns the parent node.
216  *
217  * @pre is_root_node() == false.
218  */
220 
221  /** The const version of @ref parent_node. */
222  const tree_view_node& parent_node() const;
223 
225  {
226  return *tree_view_;
227  }
228 
229  const tree_view& get_tree_view() const
230  {
231  return *tree_view_;
232  }
233 
235 
236  /**
237  * Calculates the node indices needed to get from the root node to this node.
238  */
239  std::vector<int> describe_path() const;
240 
246  void select_node(bool expand_parents = false);
247  grid& get_grid() { return grid_; }
248  void layout_initialize(const bool full_initialization) override;
249 
250  void clear_before_destruct();
251 
252 private:
253  int calculate_ypos();
254 
255  /** See @ref widget::request_reduce_width. */
256  virtual void request_reduce_width(const unsigned maximum_width) override;
257 
258  /**
259  * Our parent node.
260  *
261  * All nodes except the root node have a parent node.
262  */
264 
265  /** The tree view that owns us. */
267 
268  /** Grid holding our contents. */
270 
271  /**
272  * Our children.
273  *
274  * We want the returned child nodes to remain stable so store pointers.
275  */
277 
278  /** The toggle for the folded state. */
280 
281  /** The label to show our selected state. */
283 
284  bool unfolded_;
285  void fold_internal();
286  void unfold_internal();
287 
288  /** See @ref widget::calculate_best_size. */
289  virtual point calculate_best_size() const override;
290 
291  /** See @ref widget::disable_click_dismiss. */
292  bool disable_click_dismiss() const override;
293 
294  point calculate_best_size(const int indentation_level,
295  const unsigned indentation_step_size) const;
296  /** @param assume_visible if false (default) it will return 0 if the parent node is folded*/
297  point get_current_size(bool assume_visible = false) const;
298  point get_folded_size() const;
299  point get_unfolded_size() const;
300 
301  /** See @ref widget::set_origin. */
302  virtual void set_origin(const point& origin) override;
303 
304  /** See @ref widget::place. */
305  virtual void place(const point& origin, const point& size) override;
306 
307  unsigned
308  place(const unsigned indentation_step_size, point origin, unsigned width);
309 
310  /** See @ref widget::set_visible_rectangle. */
311  virtual void set_visible_rectangle(const SDL_Rect& rectangle) override;
312 
313  /** See @ref widget::impl_draw_children. */
314  virtual void impl_draw_children() override;
315 
317 
319  bool& handled,
320  bool& halt);
321 
322  void
324  const widget_data& data);
325 
326  /**
327  * Returns the control_type of the @ref tree_view_node.
328  *
329  * This class does not derive from @ref styled_widget but the function behaves
330  * similar as @ref styled_widget::get_control_type.
331  */
332  const std::string& get_control_type() const;
333 };
334 
335 } // 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
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
tree_view_node * get_node_above()
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 size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
std::string_view data
Definition: picture.cpp:178
Holds a 2D point.
Definition: point.hpp:25