The Battle for Wesnoth  1.17.0-dev
tree_view.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2021
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 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
20 #include "gettext.hpp"
21 #include "gui/core/log.hpp"
24 #include "gui/widgets/settings.hpp"
25 #include "gui/widgets/window.hpp"
26 #include <functional>
27 #include "wml_exception.hpp"
28 
29 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
30 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
31 
32 namespace gui2
33 {
34 // ------------ WIDGET -----------{
35 
36 REGISTER_WIDGET(tree_view)
37 
38 tree_view::tree_view(const implementation::builder_tree_view& builder)
39  : scrollbar_container(builder, type())
40  , node_definitions_(builder.nodes)
41  , indentation_step_size_(0)
42  , need_layout_(false)
43  , root_node_(new tree_view_node(root_node_id, nullptr, *this, {}))
44  , selected_item_(nullptr)
45 {
46  connect_signal<event::LEFT_BUTTON_DOWN>(
47  std::bind(&tree_view::signal_handler_left_button_down, this, std::placeholders::_2), event::dispatcher::back_pre_child);
48 }
49 
51 {
52  if(root_node_) {
54  }
55 }
56 
58  const std::string& id, const std::map<std::string /* widget id */, string_map>& data, const int index)
59 {
60  return get_root_node().add_child(id, data, index);
61 }
62 
63 std::pair<std::shared_ptr<tree_view_node>, int> tree_view::remove_node(tree_view_node* node)
64 {
65  assert(node && node != root_node_ && node->parent_node_);
66  const point node_size = node->get_size();
67 
69 
70  auto node_itor = std::find_if(siblings.begin(), siblings.end(), [node](const auto& c) { return c.get() == node; });
71 
72  assert(node_itor != siblings.end());
73 
74  auto old_node = std::move(*node_itor);
75  old_node->parent_node_ = nullptr;
76 
77  const int position = std::distance(siblings.begin(), node_itor);
78 
79  siblings.erase(node_itor);
80 
81  if(get_size() != point()) {
82  // Don't shrink the width, need to think about a good algorithm to do so.
83  resize_content(0, -node_size.y);
84  }
85 
86  return std::pair(std::move(old_node), position);
87 }
88 
90 {
91  get_root_node().clear();
93 }
94 
95 void
97  const std::vector<widget*>& call_stack)
98 {
99  // Inherited.
101 
102  assert(root_node_);
103  root_node_->impl_populate_dirty_list(caller, call_stack);
104 }
105 
106 void tree_view::set_self_active(const bool /*active*/)
107 {
108  /* DO NOTHING */
109 }
110 
111 bool tree_view::empty() const
112 {
113  return root_node_->empty();
114 }
115 
117 {
118  layout_children(false);
119 }
120 
121 void tree_view::resize_content(const int width_modification,
122  const int height_modification,
123  const int width_modification_pos,
124  const int height_modification_pos)
125 {
126  DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " width_modification "
127  << width_modification << " height_modification " << height_modification << ".\n";
128 
130  width_modification,
131  height_modification,
132  width_modification_pos,
133  height_modification_pos
134  )) {
135  // Calculate new size.
137  size.x += width_modification;
138  size.y += height_modification;
139 
140  // Set new size.
141  content_grid()->set_size(size);
142 
143  // Set status.
144  need_layout_ = true;
145  // If the content grows assume it "overwrites" the old content.
146  if(width_modification < 0 || height_modification < 0) {
147  set_is_dirty(true);
148  }
150  DBG_GUI_L << LOG_HEADER << " succeeded.\n";
151  } else {
152  DBG_GUI_L << LOG_HEADER << " failed.\n";
153  }
154 }
155 
156 void tree_view::layout_children(const bool force)
157 {
158  assert(root_node_ && content_grid());
159 
160  if(need_layout_ || force) {
163 
164  need_layout_ = false;
166  }
167 }
168 
170 {
171  // Inherited.
173 
174  assert(content_grid());
175  content_grid()->set_rows_cols(1, 1);
178 }
179 
181 {
182  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
183 
184  get_window()->keyboard_capture(this);
185 }
186 
187 template<tree_view_node* (tree_view_node::*func)()>
189 {
191  if(!selected) {
192  return nullptr;
193  }
194 
195  tree_view_node* visible = selected->get_last_visible_parent_node();
196  if(visible != selected) {
197  return visible;
198  }
199 
200  return (selected->*func)();
201 }
202 
203 template<tree_view_node* (tree_view_node::*func)()>
205 {
206  if(tree_view_node* next = get_next_node<func>()) {
207  next->select_node();
208  SDL_Rect visible = content_visible_area();
209  SDL_Rect rect = next->get_grid().get_rectangle();
210  visible.y = rect.y; // - content_grid()->get_y();
211  visible.h = rect.h;
212  show_content_rect(visible);
213  return true;
214  }
215 
216  return false;
217 }
218 
219 void tree_view::handle_key_up_arrow(SDL_Keymod modifier, bool& handled)
220 {
221  if(handle_up_down_arrow<&tree_view_node::get_selectable_node_above>()) {
222  handled = true;
223  } else {
224  scrollbar_container::handle_key_up_arrow(modifier, handled);
225  }
226 }
227 
228 void tree_view::handle_key_down_arrow(SDL_Keymod modifier, bool& handled)
229 {
230  if(handle_up_down_arrow<&tree_view_node::get_selectable_node_below>()) {
231  handled = true;
232  } else {
234  }
235 }
236 
237 void tree_view::handle_key_left_arrow(SDL_Keymod modifier, bool& handled)
238 {
240  if(!selected || selected->is_folded()) {
242  return;
243  }
244 
245  selected->fold();
246  handled = true;
247 }
248 
249 void tree_view::handle_key_right_arrow(SDL_Keymod modifier, bool& handled)
250 {
252  if(!selected || !selected->is_folded()) {
254  return;
255  }
256 
257  selected->unfold();
258  handled = true;
259 }
260 
261 // }---------- DEFINITION ---------{
262 
265 {
266  DBG_GUI_P << "Parsing tree view " << id << '\n';
267 
268  load_resolutions<resolution>(cfg);
269 }
270 
272  : resolution_definition(cfg)
273  , grid(nullptr)
274 {
275  // Note the order should be the same as the enum state_t is listbox.hpp.
276  state.emplace_back(cfg.child("state_enabled"));
277  state.emplace_back(cfg.child("state_disabled"));
278 
279  const config& child = cfg.child("grid");
280  VALIDATE(child, _("No grid defined."));
281 
282  grid = std::make_shared<builder_grid>(child);
283 }
284 
285 // }---------- BUILDER -----------{
286 
287 namespace implementation
288 {
289 builder_tree_view::builder_tree_view(const config& cfg)
290  : builder_styled_widget(cfg)
291  , vertical_scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
292  , horizontal_scrollbar_mode(get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
293  , indentation_step_size(cfg["indentation_step_size"])
294  , nodes()
295 {
296  for(const auto& node : cfg.child_range("node")) {
297  nodes.emplace_back(node);
298  }
299 
300  VALIDATE(!nodes.empty(), _("No nodes defined for a tree view."));
301 }
302 
304 {
305  /*
306  * TODO see how much we can move in the constructor instead of
307  * building in several steps.
308  */
309  tree_view* widget = new tree_view(*this);
310 
313 
315 
316  DBG_GUI_G << "Window builder: placed tree_view '" << id << "' with definition '" << definition << "'.\n";
317 
318  const auto conf = widget->cast_config_to<tree_view_definition>();
319  assert(conf);
320 
321  widget->init_grid(*conf->grid);
322  widget->finalize_setup();
323 
324  return widget;
325 }
326 
328  : id(cfg["id"])
329  , unfolded(cfg["unfolded"].to_bool(false))
330  , builder(nullptr)
331 {
332  VALIDATE(!id.empty(), missing_mandatory_wml_key("node", "id"));
333 
334  // TODO: interpolate this value into the error message
335  VALIDATE(id != tree_view::root_node_id, _("[node]id 'root' is reserved for the implementation."));
336 
337  const config& node_definition = cfg.child("node_definition");
338 
339  VALIDATE(node_definition, _("No node defined."));
340 
341  builder = std::make_shared<builder_grid>(node_definition);
342 }
343 
344 } // namespace implementation
345 
346 // }------------ END --------------
347 
348 } // 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:1276
#define DBG_GUI_P
Definition: log.hpp:66
virtual void finalize_setup()
Inherited from container_base.
Definition: tree_view.cpp:169
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:402
std::vector< state_definition > state
const std::vector< node > & nodes
std::vector< std::shared_ptr< tree_view_node > > node_children_vector
void set_horizontal_scrollbar_mode(const scrollbar_mode scrollbar_mode)
#define DBG_GUI_L
Definition: log.hpp:55
#define LOG_HEADER
Definition: tree_view.cpp:30
void finalize_setup()
The builder needs to call us so we do our setup.
unsigned indentation_step_size_
Definition: tree_view.hpp:158
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:75
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
Definition: tree_view.cpp:106
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:344
void set_vertical_scrollbar_mode(const scrollbar_mode scrollbar_mode)
Base class for all widgets.
Definition: widget.hpp:49
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:228
tree_view_node * selected_item()
Definition: tree_view.hpp:117
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: tree_view.hpp:249
static std::string _(const char *str)
Definition: gettext.hpp:93
void signal_handler_left_button_down(const event::ui_event event)
Definition: tree_view.cpp:180
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:45
Generic file dialog.
Definition: field-fwd.hpp:23
bool empty() const
Does the node have children?
bool is_folded() const
Is the node folded?
Base container class.
Definition: grid.hpp:31
node_children_vector children_
Our children.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
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:87
#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:466
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:219
std::string selected
void init_grid(const builder_grid &grid_builder)
Initializes and builds the grid.
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:47
bool handle_up_down_arrow()
Definition: tree_view.cpp:204
tree_view_node * root_node_
Definition: tree_view.hpp:162
std::vector< tree_node > nodes
The types of nodes in the tree view.
Definition: tree_view.hpp:260
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:237
A tree view is a control that holds several items of the same or different types. ...
Definition: tree_view.hpp:60
void set_indentation_step_size(const unsigned indentation_step_size)
Definition: tree_view.hpp:112
void fold(const bool recursive=false)
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:121
std::pair< std::shared_ptr< tree_view_node >, int > remove_node(tree_view_node *node)
Removes the given node as a child of its parent node.
Definition: tree_view.cpp:63
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
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:70
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:35
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:117
tree_view_node * get_last_visible_parent_node()
const SDL_Rect & content_visible_area() const
Holds a 2D point.
Definition: point.hpp:24
void unfold(const bool recursive=false)
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:56
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
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:49
scrollbar_mode get_scrollbar_mode(const std::string &scrollbar_mode)
Returns the scrollbar mode flags.
Definition: helper.cpp:121
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:723
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:96
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:305
#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:111
tree_view_node * get_next_node()
Definition: tree_view.cpp:188
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: tree_view.hpp:250
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:227
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:263
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:116
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)
Up arrow key pressed.
static const std::string root_node_id
Definition: tree_view.hpp:148
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
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:48
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:65
#define DBG_GUI_G
Definition: log.hpp:41
virtual widget * build() const override
Definition: tree_view.cpp:303
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: tree_view.cpp:249
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:300
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:48
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:57
tree_node(const config &cfg)
Definition: tree_view.cpp:327