The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
tree_view.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2016 by Mark de Wever <[email protected]>
3  Part of the Battle for Wesnoth Project http://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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
19 #include "gui/core/log.hpp"
22 #include "gui/widgets/settings.hpp"
24 #include "gui/widgets/window.hpp"
25 #include "gettext.hpp"
26 #include "wml_exception.hpp"
27 
28 #include "utils/functional.hpp"
29 
30 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
31 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
32 
33 namespace gui2
34 {
35 
36 // ------------ WIDGET -----------{
37 
38 REGISTER_WIDGET(tree_view)
39 
40 ttree_view::ttree_view(const std::vector<tnode_definition>& node_definitions)
42  , node_definitions_(node_definitions)
43  , indention_step_size_(0)
44  , need_layout_(false)
45  , root_node_(new ttree_view_node("root",
46  node_definitions_,
47  nullptr,
48  *this,
49  std::map<std::string, string_map>()))
50  , selected_item_(nullptr)
51  , selection_change_callback_()
52 {
53  connect_signal<event::LEFT_BUTTON_DOWN>(
54  std::bind(&ttree_view::signal_handler_left_button_down, this, _2),
56 }
57 
59  const std::string& id,
60  const std::map<std::string /* widget id */, string_map>& data)
61 {
62  return get_root_node().add_child(id, data);
63 }
64 
66 {
67  assert(node && node != root_node_ && node->parent_node_);
68  const tpoint node_size = node->get_size();
69 
71  = node->parent_node_->children_.begin();
72 
73  for(; itor != node->parent_node_->children_.end(); ++itor) {
74  if(&*itor == node) {
75  break;
76  }
77  }
78 
79  assert(itor != node->parent_node_->children_.end());
80 
81  node->parent_node_->children_.erase(itor);
82 
83  if(get_size() == tpoint(0, 0)) {
84  return;
85  }
86 
87  // Don't shrink the width, need to think about a good algorithm to do so.
88  resize_content(0, -node_size.y);
89 }
90 
91 void
93  const std::vector<twidget*>& call_stack)
94 {
95  // Inherited.
97 
98  assert(root_node_);
99  root_node_->impl_populate_dirty_list(caller, call_stack);
100 }
101 
102 void ttree_view::set_self_active(const bool /*active*/)
103 {
104  /* DO NOTHING */
105 }
106 
107 bool ttree_view::empty() const
108 {
109  return root_node_->empty();
110 }
111 
113 {
114  layout_children(false);
115 }
116 
117 void ttree_view::resize_content(const int width_modification,
118  const int height_modification,
119  const int width__modification_pos,
120  const int height_modification_pos)
121 {
122  DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size()
123  << " width_modification " << width_modification
124  << " height_modification " << height_modification << ".\n";
125 
126  if(content_resize_request(width_modification, height_modification, width__modification_pos, height_modification_pos)) {
127 
128  // Calculate new size.
130  size.x += width_modification;
131  size.y += height_modification;
132 
133  // Set new size.
134  content_grid()->set_size(size);
135 
136  // Set status.
137  need_layout_ = true;
138  // If the content grows assume it "overwrites" the old content.
139  if(width_modification < 0 || height_modification < 0) {
140  set_is_dirty(true);
141  }
143  DBG_GUI_L << LOG_HEADER << " succeeded.\n";
144  } else {
145  DBG_GUI_L << LOG_HEADER << " failed.\n";
146  }
147 }
148 
149 void ttree_view::layout_children(const bool force)
150 {
151  assert(root_node_ && content_grid());
152 
153  if(need_layout_ || force) {
155  get_origin(),
156  content_grid()->get_size().x);
158 
159  need_layout_ = false;
161  }
162 }
163 
165 {
166  // Inherited.
168 
169  assert(content_grid());
170  content_grid()->set_rows_cols(1, 1);
172  0,
173  0,
176  0);
177 }
178 
180 {
181  static const std::string type = "tree_view";
182  return type;
183 }
184 
186 {
187  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
188 
189  get_window()->keyboard_capture(this);
190 }
191 template<ttree_view_node* (ttree_view_node::*func) ()>
193 {
195  if(!selected) {
196  return nullptr;
197  }
198  ttree_view_node* visible = selected->get_last_visible_parent_node();
199  if(visible != selected) {
200  return visible;
201  }
202  return (selected->*func)();
203 }
204 
205 template<ttree_view_node* (ttree_view_node::*func) ()>
207 {
208  if(ttree_view_node* next = get_next_node<func>())
209  {
210  next->select_node();
211  SDL_Rect visible = content_visible_area();
212  SDL_Rect rect = next->get_grid().get_rectangle();
213  visible.y = rect.y;// - content_grid()->get_y();
214  visible.h = rect.h;
215  show_content_rect(visible);
216  return true;
217  }
218  return false;
219 }
220 
221 void ttree_view::handle_key_up_arrow(SDLMod modifier, bool& handled)
222 {
223  if(handle_up_down_arrow<&ttree_view_node::get_selectable_node_above>()) {
224  handled = true;
225  }
226  else {
227  tscrollbar_container::handle_key_up_arrow(modifier, handled);
228  }
229 }
230 
231 void ttree_view::handle_key_down_arrow(SDLMod modifier, bool& handled)
232 {
233  if(handle_up_down_arrow<&ttree_view_node::get_selectable_node_below>()) {
234  handled = true;
235  }
236  else {
238  }
239 }
240 
241 
242 void ttree_view::handle_key_left_arrow(SDLMod modifier, bool& handled)
243 {
245  if(!selected || selected->is_folded()) {
247  return;
248  }
249  selected->fold();
250  handled = true;
251 }
252 
253 void ttree_view::handle_key_right_arrow(SDLMod modifier, bool& handled)
254 {
256  if(!selected || !selected->is_folded()) {
258  return;
259  }
260  selected->unfold();
261  handled = true;
262 }
263 
264 // }---------- DEFINITION ---------{
265 
267  : tcontrol_definition(cfg)
268 {
269  DBG_GUI_P << "Parsing tree view " << id << '\n';
270 
271  load_resolutions<tresolution>(cfg);
272 }
273 
274 /*WIKI
275  * @page = GUIWidgetDefinitionWML
276  * @order = 1_tree_view
277  *
278  * == Tree view ==
279  *
280  * @macro = tree_view_description
281  *
282  * The documentation is not written yet.
283  *
284  * The following states exist:
285  * * state_enabled, the listbox is enabled.
286  * * state_disabled, the listbox is disabled.
287  * @begin{parent}{name="gui/"}
288  * @begin{tag}{name="tree_view_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
289  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="generic/widget_definition/resolution"}
290  * @allow{link}{name="gui/window/resolution/grid"}
291  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
292  * @end{tag}{name="state_enabled"}
293  * @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
294  * @end{tag}{name="state_disabled"}
295  * @end{tag}{name="resolution"}
296  * @end{tag}{name="tree_view_definition"}
297  * @end{parent}{name="gui/"}
298  */
300  : tresolution_definition_(cfg), grid(nullptr)
301 {
302  // Note the order should be the same as the enum tstate is listbox.hpp.
303  state.push_back(tstate_definition(cfg.child("state_enabled")));
304  state.push_back(tstate_definition(cfg.child("state_disabled")));
305 
306  const config& child = cfg.child("grid");
307  VALIDATE(child, _("No grid defined."));
308 
309  grid = new tbuilder_grid(child);
310 }
311 
312 // }---------- BUILDER -----------{
313 
314 /*WIKI_MACRO
315  * @begin{macro}{tree_view_description}
316  *
317  * A tree view is a control that holds several items of the same or
318  * different types. The items shown are called tree view nodes and when
319  * a node has children, these can be shown or hidden. Nodes that contain
320  * children need to provide a clickable button in order to fold or
321  * unfold the children.
322  * @end{macro}
323  */
324 
325 /*WIKI
326  * @page = GUIWidgetInstanceWML
327  * @order = 2_tree_view
328  *
329  * == Tree view ==
330  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
331  * @begin{tag}{name="tree_view"}{min=0}{max=-1}{super="generic/widget_instance"}
332  * @macro = tree_view_description
333  *
334  * List with the tree view specific variables:
335  * @begin{table}{config}
336  * vertical_scrollbar_mode & scrollbar_mode & initial_auto &
337  * Determines whether or not to show the
338  * scrollbar. $
339  * horizontal_scrollbar_mode & scrollbar_mode & initial_auto &
340  * Determines whether or not to show the
341  * scrollbar. $
342  *
343  * indention_step_size & unsigned & 0 &
344  * The number of pixels every level of
345  * nodes is indented from the previous
346  * level. $
347  *
348  * node & section & & The tree view can contain multiple node
349  * sections. This part needs more
350  * documentation. $
351  * @end{table}
352  * @begin{tag}{name="node"}{min=0}{max=-1}
353  * @begin{table}{config}
354  * id & string & "" & $
355  * @end{table}
356  * @begin{tag}{name="node_definition"}{min=0}{max=-1}{super="gui/window/resolution/grid"}
357  * @begin{table}{config}
358  * return_value_id & string & "" & $
359  * @end{table}
360  * @end{tag}{name="node_definition"}
361  * @end{tag}{name="node"}
362  * @end{tag}{name="tree_view"}
363  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
364  * NOTE more documentation and examples are needed.
365  */ // TODO annotate node
366 
367 namespace implementation
368 {
369 
370 tbuilder_tree_view::tbuilder_tree_view(const config& cfg)
371  : tbuilder_control(cfg)
372  , vertical_scrollbar_mode(
373  get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
374  , horizontal_scrollbar_mode(
375  get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
376  , indention_step_size(cfg["indention_step_size"])
377  , nodes()
378 {
379 
380  for(const auto & node : cfg.child_range("node"))
381  {
382  nodes.push_back(ttree_node(node));
383  }
384 
385  VALIDATE(!nodes.empty(), _("No nodes defined for a tree view."));
386 }
387 
389 {
390  /*
391  * TODO see how much we can move in the constructor instead of
392  * building in several steps.
393  */
394  ttree_view* widget = new ttree_view(nodes);
395 
396  init_control(widget);
397 
400 
402 
403  DBG_GUI_G << "Window builder: placed tree_view '" << id
404  << "' with definition '" << definition << "'.\n";
405 
407  conf = boost::
408  dynamic_pointer_cast<const ttree_view_definition::tresolution>(
409  widget->config());
410  assert(conf);
411 
412  widget->init_grid(conf->grid);
413  widget->finalize_setup();
414 
415  return widget;
416 }
417 
419  : id(cfg["id"])
420  , unfolded(cfg["unfolded"].to_bool(false))
421  , builder(nullptr)
422 {
423  VALIDATE(!id.empty(), missing_mandatory_wml_key("node", "id"));
424 
425  VALIDATE(id != "root",
426  _("[node]id 'root' is reserved for the implementation."));
427 
428  const config& node_definition = cfg.child("node_definition");
429 
430  VALIDATE(node_definition, _("No node defined."));
431 
432  builder = new tbuilder_grid(node_definition);
433 }
434 
435 } // namespace implementation
436 
437 // }------------ END --------------
438 
439 } // namespace gui2
Define the common log macros for the gui toolkit.
#define DBG_GUI_P
Definition: log.hpp:69
child_itors child_range(const std::string &key)
Definition: config.cpp:613
tscrollbar_container::tscrollbar_mode horizontal_scrollbar_mode
Definition: tree_view.hpp:198
const std::vector< node > & nodes
#define SDLMod
Definition: compat.hpp:30
#define DBG_GUI_L
Definition: log.hpp:58
unsigned indention_step_size_
Definition: tree_view.hpp:119
#define LOG_HEADER
Definition: tree_view.cpp:31
bool empty() const
Does the node have children?
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
bool is_folded() const
Is the node folded?
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
virtual void child_populate_dirty_list(twindow &caller, const std::vector< twidget * > &call_stack) override
See twidget::child_populate_dirty_list.
bool handle_up_down_arrow()
Definition: tree_view.cpp:206
tresolution_definition_ptr config()
Definition: control.hpp:299
This file contains the window object, this object is a top level container which has the event manage...
ttree_view_node * selected_item()
Definition: tree_view.hpp:82
tscrollbar_container::tscrollbar_mode vertical_scrollbar_mode
Definition: tree_view.hpp:197
tpoint get_size() const
Returns the size of the widget.
Definition: widget.cpp:274
static const unsigned VERTICAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:41
static const unsigned HORIZONTAL_GROW_SEND_TO_CLIENT
Definition: grid.hpp:48
STL namespace.
void set_indention_step_size(const unsigned indention_step_size)
Definition: tree_view.hpp:77
virtual void finalize_setup()
Inherited from tcontainer_.
Definition: tree_view.cpp:164
virtual const std::string & get_control_type() const override
See tcontrol::get_control_type.
Definition: tree_view.cpp:179
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
tscrollbar_container::tscrollbar_mode get_scrollbar_mode(const std::string &scrollbar_mode)
Returns the scrollbar mode flags.
Definition: helper.cpp:114
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:435
ttree_view_node & add_child(const std::string &id, const std::map< std::string, string_map > &data, const int index=-1)
Adds a child item to the list of child nodes.
void handle_key_down_arrow(SDLMod modifier, bool &handled)
Inherited from tscrollbar_container.
Definition: tree_view.cpp:231
Base class of a resolution, contains the common keys for a resolution.
ttree_view_node * root_node_
Definition: tree_view.hpp:123
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.
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
ttree_view_node & add_node(const std::string &id, const std::map< std::string, string_map > &data)
Definition: tree_view.cpp:58
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
void init_control(tcontrol *control) const
Definition: control.cpp:675
std::string definition
Parameters for the control.
Definition: control.hpp:530
std::vector< ttree_node > nodes
The types of nodes in the tree view.
Definition: tree_view.hpp:208
virtual void handle_key_down_arrow(SDLMod modifier, bool &handled)
Down arrow key pressed.
bool content_resize_request(const bool force_sizing=false)
Notification if the content of a child needs a resize.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
void set_vertical_scrollbar_mode(const tscrollbar_mode scrollbar_mode)
virtual void set_self_active(const bool active) override
See tcontainer_::set_self_active.
Definition: tree_view.cpp:102
GLuint id
Definition: glew.h:1647
SDL_Rect content_visible_area_
Cache for the visible area for the content.
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
This file contains the settings handling of the widget library.
const SDL_Rect & content_visible_area() const
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override
See twidget::set_visible_rectangle.
int y
y coordinate.
Definition: point.hpp:34
std::string selected
Definition: game_config.cpp:84
void handle_key_left_arrow(SDLMod modifier, bool &handled)
Inherited from tscrollbar_container.
Definition: tree_view.cpp:242
boost::ptr_vector< ttree_view_node > children_
Our children.
void impl_populate_dirty_list(twindow &caller, const std::vector< twidget * > &call_stack)
"Inherited" from twidget.
void show_content_rect(const SDL_Rect &rect)
Shows a certain part of the content.
void init_grid(const boost::intrusive_ptr< tbuilder_grid > &grid_builder)
Initializes and builds the grid.
Definition: container.cpp:209
tevent
The event send to the dispatcher.
Definition: handler.hpp:54
Contains the state info for a resolution.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
void finalize_setup()
The builder needs to call us so we do our setup.
std::map< std::string, t_string > string_map
Definition: generator.hpp:23
int x
x coordinate.
Definition: point.hpp:31
ttree_view_definition(const config &cfg)
Definition: tree_view.cpp:266
void signal_handler_left_button_down(const event::tevent event)
Definition: tree_view.cpp:185
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
void handle_key_up_arrow(SDLMod modifier, bool &handled)
Inherited from tscrollbar_container.
Definition: tree_view.cpp:221
#define DBG_GUI_E
Definition: log.hpp:35
tpoint get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:269
ttree_view_node & get_root_node()
Definition: tree_view.hpp:51
Holds a 2D point.
Definition: point.hpp:24
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
void set_horizontal_scrollbar_mode(const tscrollbar_mode scrollbar_mode)
ttree_node(const config &cfg)
Definition: tree_view.cpp:418
void handle_key_right_arrow(SDLMod modifier, bool &handled)
Inherited from tscrollbar_container.
Definition: tree_view.cpp:253
virtual void handle_key_up_arrow(SDLMod modifier, bool &handled)
Up arrow key pressed.
virtual void handle_key_right_arrow(SDLMod modifier, bool &handled)
Right arrow key pressed.
virtual void place(const tpoint &origin, const tpoint &size) override
See twidget::place.
#define next(ls)
Definition: llex.cpp:27
GLsizeiptr size
Definition: glew.h:1649
void set_rows_cols(const unsigned rows, const unsigned cols)
Wrapper to set_rows and set_cols.
Definition: grid.cpp:679
std::vector< tstate_definition > state
cl_event event
Definition: glew.h:3070
config & child(const std::string &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:658
Base class for all widgets.
Definition: widget.hpp:49
ttree_view_node * get_next_node()
Definition: tree_view.cpp:192
bool empty() const
Definition: tree_view.cpp:107
ttree_view_node * parent_node_
Our parent node.
void remove_node(ttree_view_node *tree_view_node)
Definition: tree_view.cpp:65
void set_child(twidget *widget, const unsigned row, const unsigned col, const unsigned flags, const unsigned border_size)
Sets a child in the grid.
Definition: grid.cpp:69
void keyboard_capture(twidget *widget)
Definition: window.cpp:1394
twindow * get_window()
Get the parent window.
Definition: widget.cpp:116
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
ttree_view_node * get_last_visible_parent_node()
virtual void set_size(const tpoint &size)
Sets the size of the widget.
Definition: widget.cpp:222
virtual void layout_children() override
See twidget::layout_children.
Definition: tree_view.cpp:112
#define DBG_GUI_G
Definition: log.hpp:41
virtual void handle_key_left_arrow(SDLMod modifier, bool &handled)
Left arrow key pressed.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
Contains the implementation details for lexical_cast and shouldn't be used directly.
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:117
Base class for creating containers with one or two scrollbar(s).
virtual void child_populate_dirty_list(twindow &caller, const std::vector< twidget * > &call_stack) override
See twidget::child_populate_dirty_list.
Definition: tree_view.cpp:92