The Battle for Wesnoth  1.19.0-dev
tree_view_node.cpp
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 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
20 #include "gettext.hpp"
23 #include "gui/core/log.hpp"
26 #include "sdl/rect.hpp"
27 #include <functional>
28 
29 #define LOG_SCOPE_HEADER get_control_type() + " [" + get_tree_view().id() + "] " + __func__
30 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
31 
32 namespace gui2
33 {
34 tree_view_node::tree_view_node(const std::string& id,
35  tree_view_node* parent_node,
36  tree_view& parent_tree_view,
37  const widget_data& data)
38  : widget()
39  , parent_node_(parent_node)
40  , tree_view_(&parent_tree_view)
41  , grid_()
42  , children_()
43  , toggle_(nullptr)
44  , label_(nullptr)
45  , unfolded_(false)
46 {
47  grid_.set_parent(this);
48  set_parent(&parent_tree_view);
49 
50  if(id == tree_view::root_node_id) {
51  unfolded_ = true;
52  return;
53  }
54 
55  if(const auto opt = get_tree_view().get_node_definition(id)) {
56  const auto& node_definition = **opt;
57 
58  node_definition.builder->build(grid_);
59  init_grid(&grid_, data);
60 
63  }
64 
65  if(node_definition.unfolded) {
66  unfolded_ = true;
67  }
68 
69  widget* toggle_widget = grid_.find("tree_view_node_toggle", false);
70  toggle_ = dynamic_cast<selectable_item*>(toggle_widget);
71 
72  if(toggle_) {
74 
76  std::bind(&tree_view_node::signal_handler_left_button_click, this, std::placeholders::_2));
77 
79  std::bind(&tree_view_node::signal_handler_left_button_click, this, std::placeholders::_2),
81 
82  if(unfolded_) {
83  toggle_->set_value(1);
84  }
85  }
86 
87  widget* label_widget = grid_.find("tree_view_node_label", false);
88  label_ = dynamic_cast<selectable_item*>(label_widget);
89 
90  if(label_) {
92  std::bind(&tree_view_node::signal_handler_label_left_button_click, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
94 
96  std::bind(&tree_view_node::signal_handler_label_left_button_click, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
98 
100  get_tree_view().selected_item_ = this;
101  label_->set_value(true);
102  }
103  }
104  } else {
105  FAIL_WITH_DEV_MESSAGE(_("Unknown builder id for tree view node."), id);
106  }
107 }
108 
110 {
111  if(tree_view_ && get_tree_view().selected_item_ == this) {
112  get_tree_view().selected_item_ = nullptr;
113  }
114 }
115 
117 {
118  tree_view_ = nullptr;
119  for(auto& child : children_) {
120  child->clear_before_destruct();
121  }
122 }
123 
124 tree_view_node& tree_view_node::add_child_impl(std::shared_ptr<tree_view_node>&& new_node, const int index)
125 {
126  auto itor = children_.end();
127 
128  if(static_cast<std::size_t>(index) < children_.size()) {
129  itor = children_.begin() + index;
130  }
131 
132  tree_view_node& node = **children_.insert(itor, std::move(new_node));
133 
134  // NOTE: we currently don't support moving nodes between different trees, so this
135  // just ensures that wasn't tried. Remove this if we implement support for that.
136  assert(node.tree_view_ == tree_view_);
137 
138  // Safety check. Might only fail if someone accidentally removed the parent_node_
139  // setter in add_child().
140  assert(node.parent_node_ == this);
141 
142  if(is_folded() /*|| is_root_node()*/) {
143  return node;
144  }
145 
146  if(get_tree_view().get_size() == point()) {
147  return node;
148  }
149 
150  assert(get_tree_view().content_grid());
151  const point current_size = get_tree_view().content_grid()->get_size();
152 
153  // Calculate width modification.
154  // This increases tree width if the width of the new node is greater than the current width.
155  point best_size = node.get_best_size();
157 
158  const int width_modification = best_size.x > current_size.x
159  ? best_size.x - current_size.x
160  : 0;
161 
162  // Calculate height modification.
163  // For this, we only increase height if the best size of the tree (that is, the size with the new node)
164  // is larger than its current size. This prevents the scrollbar being reserved even when there's obviously
165  // enough visual space.
166 
167  // Throw away cached best size to force a recalculation.
169 
170  const point tree_best_size = get_tree_view().get_best_size();
171 
172  const int height_modification = tree_best_size.y > current_size.y && get_tree_view().layout_size() == point()
173  ? tree_best_size.y - current_size.y
174  : 0;
175 
176  assert(height_modification >= 0);
177 
178  // Request new size.
179  get_tree_view().resize_content(width_modification, height_modification, -1, node.calculate_ypos());
180 
181  return node;
182 }
183 
184 std::vector<std::shared_ptr<gui2::tree_view_node>> tree_view_node::replace_children(const std::string& id, const std::vector<widget_data>& data)
185 {
186  std::vector<std::shared_ptr<gui2::tree_view_node>> nodes;
187  clear();
188 
189  if(data.size() == 0) {
190  return nodes;
191  }
192 
193  int width_modification = 0;
194 
195  for(const auto& d : data) {
196  std::shared_ptr<gui2::tree_view_node> new_node = std::make_shared<tree_view_node>(id, this, get_tree_view(), d);
197  std::shared_ptr<gui2::tree_view_node> node = *children_.insert(children_.end(), std::move(new_node));
198 
199  // NOTE: we currently don't support moving nodes between different trees, so this
200  // just ensures that wasn't tried. Remove this if we implement support for that.
201  assert(node->tree_view_ == tree_view_);
202 
203  // Safety check. Might only fail if someone accidentally removed the parent_node_ setter in add_child().
204  assert(node->parent_node_ == this);
205 
206  nodes.push_back(node);
207 
208  if(is_folded()) {
209  continue;
210  }
211 
212  assert(get_tree_view().content_grid());
213  const point current_size = get_tree_view().content_grid()->get_size();
214 
215  // Calculate width modification.
216  // This increases tree width if the width of the new node is greater than the current width.
217  int best_size = node->get_best_size().x;
219 
220  int new_width = best_size > current_size.x
221  ? best_size - current_size.x
222  : 0;
223 
224  if(new_width > width_modification)
225  {
226  width_modification = new_width;
227  }
228  }
229 
230  if(is_folded()) {
231  return nodes;
232  }
233 
234  // Calculate height modification.
235  // For this, we only increase height if the best size of the tree (that is, the size with the new node)
236  // is larger than its current size. This prevents the scrollbar being reserved even when there's obviously
237  // enough visual space.
238 
239  // Throw away cached best size to force a recalculation.
241 
242  const point current_size = get_tree_view().content_grid()->get_size();
243  const point tree_best_size = get_tree_view().get_best_size();
244 
245  const int height_modification = tree_best_size.y > current_size.y && get_tree_view().layout_size() == point()
246  ? tree_best_size.y - current_size.y
247  : 0;
248 
249  assert(height_modification >= 0);
250 
251  // Request new size.
252  auto& last_node = children_.at(children_.size()-1);
253  get_tree_view().resize_content(width_modification, height_modification, -1, last_node->calculate_ypos());
254 
255  return nodes;
256 }
257 
259 {
260  unsigned level = 0;
261 
262  const tree_view_node* node = this;
263  while(!node->is_root_node()) {
264  node = &node->parent_node();
265  ++level;
266  }
267 
268  return level;
269 }
270 
272 {
273  assert(!is_root_node());
274  return *parent_node_;
275 }
276 
278 {
279  assert(!is_root_node());
280  return *parent_node_;
281 }
282 
283 void tree_view_node::request_reduce_width(const unsigned /*maximum_width*/)
284 {
285  /* DO NOTHING */
286 }
287 
288 void tree_view_node::fold(const bool recursive)
289 {
290  if(!is_folded()) {
291  fold_internal();
292  if(toggle_) {
293  toggle_->set_value(false);
294  }
295  }
296 
297  if(recursive) {
298  for(auto& child_node : children_) {
299  child_node->fold(true);
300  }
301  }
302 }
303 
304 void tree_view_node::unfold(const bool recursive)
305 {
306  if(is_folded()) {
307  unfold_internal();
308  if(toggle_) {
309  toggle_->set_value(true);
310  }
311  }
312 
313  if(recursive) {
314  for(auto& child_node : children_) {
315  child_node->unfold(true);
316  }
317  }
318 }
319 
321 {
322  const point current_size(get_current_size().x, get_unfolded_size().y);
323  const point new_size = get_folded_size();
324 
325  const int width_modification = std::max(0, new_size.x - current_size.x);
326  const int height_modification = new_size.y - current_size.y;
327  assert(height_modification <= 0);
328 
329  get_tree_view().resize_content(width_modification, height_modification, -1, calculate_ypos());
330  unfolded_ = false;
331 }
332 
334 {
335  const point current_size(get_current_size().x, get_folded_size().y);
336  const point new_size = get_unfolded_size();
337 
338  const int width_modification = std::max(0, new_size.x - current_size.x);
339  const int height_modification = new_size.y - current_size.y;
340  assert(height_modification >= 0);
341 
342  get_tree_view().resize_content(width_modification, height_modification, -1, calculate_ypos());
343  unfolded_ = true;
344 }
345 
347 {
348  /** @todo Also try to find the optimal width. */
349  int height_reduction = 0;
350 
351  if(!is_folded()) {
352  for(const auto& node : children_) {
353  height_reduction += node->get_current_size().y;
354  }
355  }
356 
357  children_.clear();
358 
359  if(height_reduction == 0) {
360  return;
361  }
362 
363  get_tree_view().resize_content(0, -height_reduction, -1, calculate_ypos());
364 }
365 
367 {
368 private:
369  template<class W, class It>
370  static W* find_at_aux(It begin, It end, const point& coordinate, const bool must_be_active)
371  {
372  for(It it = begin; it != end; ++it) {
373  if(W* widget = (*it)->find_at(coordinate, must_be_active)) {
374  return widget;
375  }
376  }
377 
378  return nullptr;
379  }
380 
381 public:
382  template<class W>
384  const point& coordinate,
385  const bool must_be_active)
386  {
387  if(W* widget = tree_view_node.grid_.find_at(coordinate, must_be_active)) {
388  return widget;
389  }
390 
391  if(tree_view_node.is_folded()) {
392  return nullptr;
393  }
394 
395  return find_at_aux<W>(
396  tree_view_node.children_.begin(), tree_view_node.children_.end(), coordinate, must_be_active);
397  }
398 };
399 
400 widget* tree_view_node::find_at(const point& coordinate, const bool must_be_active)
401 {
402  return tree_view_node_implementation::find_at<widget>(*this, coordinate, must_be_active);
403 }
404 
405 const widget* tree_view_node::find_at(const point& coordinate, const bool must_be_active) const
406 {
407  return tree_view_node_implementation::find_at<const widget>(*this, coordinate, must_be_active);
408 }
409 
410 widget* tree_view_node::find(const std::string& id, const bool must_be_active)
411 {
412  widget* result = widget::find(id, must_be_active);
413  if(result) {
414  return result;
415  }
416 
417  result = grid_.find(id, must_be_active);
418  if(result) {
419  return result;
420  }
421 
422  for(auto& child : children_) {
423  result = child->find(id, must_be_active);
424  if(result) {
425  return result;
426  }
427  }
428 
429  return nullptr;
430 }
431 
432 const widget* tree_view_node::find(const std::string& id, const bool must_be_active) const
433 {
434  const widget* result = widget::find(id, must_be_active);
435  if(result) {
436  return result;
437  }
438 
439  result = grid_.find(id, must_be_active);
440  if(result) {
441  return result;
442  }
443 
444  for(const auto& child : children_) {
445  result = child->find(id, must_be_active);
446  if(result) {
447  return result;
448  }
449  }
450 
451  return nullptr;
452 }
453 
455 {
456  return calculate_best_size(-1, get_tree_view().indentation_step_size_);
457 }
458 
460 {
461  return true;
462 }
463 
464 point tree_view_node::get_current_size(bool assume_visible) const
465 {
466  if(!assume_visible && parent_node_ && parent_node_->is_folded()) {
467  return point();
468  }
469 
471  if(is_folded()) {
472  return size;
473  }
474 
475  for(const auto& node : children_) {
476  if(node->grid_.get_visible() == widget::visibility::invisible) {
477  continue;
478  }
479 
480  point node_size = node->get_current_size();
481 
482  size.y += node_size.y;
483  size.x = std::max(size.x, node_size.x);
484  }
485 
486  return size;
487 }
488 
490 {
492  if(get_indentation_level() > 1) {
494  }
495 
496  return size;
497 }
498 
500 {
502  if(get_indentation_level() > 1) {
504  }
505 
506  for(const auto& node : children_) {
507  if(node->grid_.get_visible() == widget::visibility::invisible) {
508  continue;
509  }
510 
511  point node_size = node->get_current_size(true);
512 
513  size.y += node_size.y;
514  size.x = std::max(size.x, node_size.x);
515  }
516 
517  return size;
518 }
519 
520 point tree_view_node::calculate_best_size(const int indentation_level, const unsigned indentation_step_size) const
521 {
523 
524  point best_size = grid_.get_best_size();
525  if(indentation_level > 0) {
526  best_size.x += indentation_level * indentation_step_size;
527  }
528 
529  DBG_GUI_L << LOG_HEADER << " own grid best size " << best_size << ".";
530 
531  for(const auto& node : children_) {
532  if(node->grid_.get_visible() == widget::visibility::invisible) {
533  continue;
534  }
535 
536  const point node_size = node->calculate_best_size(indentation_level + 1, indentation_step_size);
537 
538  if(!is_folded()) {
539  best_size.y += node_size.y;
540  }
541 
542  best_size.x = std::max(best_size.x, node_size.x);
543  }
544 
545  DBG_GUI_L << LOG_HEADER << " result " << best_size << ".";
546  return best_size;
547 }
548 
550 {
551  // Inherited.
552  widget::set_origin(origin);
553 
554  // Using layout_children seems to fail.
555  place(get_tree_view().indentation_step_size_, origin, get_size().x);
556 }
557 
558 void tree_view_node::place(const point& origin, const point& size)
559 {
560  // Inherited.
561  widget::place(origin, size);
562 
564 }
565 
566 unsigned tree_view_node::place(const unsigned indentation_step_size, point origin, unsigned width)
567 {
569  DBG_GUI_L << LOG_HEADER << " origin " << origin << ".";
570 
571  const unsigned offset = origin.y;
572  point best_size = grid_.get_best_size();
573  best_size.x = width;
574 
575  grid_.place(origin, best_size);
576 
577  if(!is_root_node()) {
578  origin.x += indentation_step_size;
579  assert(width >= indentation_step_size);
580  width -= indentation_step_size;
581  }
582 
583  origin.y += best_size.y;
584 
585  if(is_folded()) {
586  DBG_GUI_L << LOG_HEADER << " folded node done.";
587  return origin.y - offset;
588  }
589 
590  DBG_GUI_L << LOG_HEADER << " set children.";
591  for(auto& node : children_) {
592  origin.y += node->place(indentation_step_size, origin, width);
593  }
594 
595  // Inherited.
596  widget::set_size(point(width, origin.y - offset));
597 
598  DBG_GUI_L << LOG_HEADER << " result " << (origin.y - offset) << ".";
599  return origin.y - offset;
600 }
601 
602 void tree_view_node::set_visible_rectangle(const SDL_Rect& rectangle)
603 {
605  DBG_GUI_L << LOG_HEADER << " rectangle " << rectangle << ".";
606  grid_.set_visible_rectangle(rectangle);
607 
608  if(is_folded()) {
609  DBG_GUI_L << LOG_HEADER << " folded node done.";
610  return;
611  }
612 
613  for(auto& node : children_) {
614  node->set_visible_rectangle(rectangle);
615  }
616 }
617 
619 {
621 
622  if(is_folded()) {
623  return;
624  }
625 
626  for(auto& node : children_) {
627  node->impl_draw_children();
628  }
629 }
630 
632 {
633  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
634 
635  /**
636  * @todo Rewrite this sizing code for the folding/unfolding.
637  *
638  * The code works but feels rather hacky, so better move back to the
639  * drawingboard for 1.9.
640  */
641  const bool unfolded_new = toggle_->get_value_bool();
642  if(unfolded_ == unfolded_new) {
643  return;
644  }
645 
646  unfolded_ = unfolded_new;
648 
650 }
651 
653 {
654  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
655 
656  assert(label_);
657 
658  // Normally, this is only an event hook and not full handling; however, if
659  // the currently selected item was selected, we halt the event to prevent
660  // deselection (which would leave no items selected).
661  if(label_->get_value()) {
662  halt = handled = true;
663  return;
664  }
665 
666  // Select the new item if a different one was selected
667  if(get_tree_view().selected_item_ && get_tree_view().selected_item_->label_) {
669  }
670 
671  get_tree_view().selected_item_ = this;
672 
674 }
675 
677 {
678  assert(g);
679 
680  for(unsigned row = 0; row < g->get_rows(); ++row) {
681  for(unsigned col = 0; col < g->get_cols(); ++col) {
682  widget* wgt = g->get_widget(row, col);
683  assert(wgt);
684 
685  // toggle_button* btn = dynamic_cast<toggle_button*>(widget);
686 
687  if(toggle_panel* panel = dynamic_cast<toggle_panel*>(wgt)) {
688  panel->set_child_members(data);
689  } else if(grid* child_grid = dynamic_cast<grid*>(wgt)) {
690  init_grid(child_grid, data);
691  } else if(styled_widget* control = dynamic_cast<styled_widget*>(wgt)) {
692  auto itor = data.find(control->id());
693 
694  if(itor == data.end()) {
695  itor = data.find("");
696  }
697 
698  if(itor != data.end()) {
699  control->set_members(itor->second);
700  }
701  // control->set_members(data);
702  } else {
703  // ERROR_LOG("Widget type '" << typeid(*widget).name() << "'.");
704  }
705  }
706  }
707 }
708 
709 const std::string& tree_view_node::get_control_type() const
710 {
711  static const std::string type = "tree_view_node";
712  return type;
713 }
714 
716 {
717  assert(static_cast<std::size_t>(index) < children_.size());
718  return *children_[index];
719 }
720 
722 {
723  if(is_root_node()) {
724  return std::vector<int>();
725  }
726 
727  std::vector<int> res = parent_node_->describe_path();
728  for(std::size_t i = 0; i < parent_node_->count_children(); ++i) {
729  if(parent_node_->children_[i].get() == this) {
730  res.push_back(i);
731  return res;
732  }
733  }
734 
735  assert(!"tree_view_node was not found in parent nodes children");
736  throw "assertion ignored"; // To silence 'no return value in this codepath' warning.
737 }
738 
740 {
741  if(!parent_node_) {
742  return 0;
743  }
744 
745  int res = parent_node_->calculate_ypos();
746  for(const auto& node : parent_node_->children_) {
747  if(node.get() == this) {
748  break;
749  }
750 
751  res += node->get_current_size(true).y;
752  }
753 
754  return res;
755 }
756 
758 {
759  if(!parent_node_) {
760  return this;
761  }
762 
764  return res == parent_node_ && !res->is_folded() ? this : res;
765 }
766 
768 {
769  assert(!is_root_node());
770 
771  tree_view_node* cur = nullptr;
772  for(std::size_t i = 0; i < parent_node_->count_children(); ++i) {
773  if(parent_node_->children_[i].get() == this) {
774  if(i == 0) {
775  return parent_node_->is_root_node() ? nullptr : parent_node_;
776  } else {
777  cur = parent_node_->children_[i - 1].get();
778  break;
779  }
780  }
781  }
782 
783  while(cur && !cur->is_folded() && cur->count_children() > 0) {
784  cur = &cur->get_child_at(cur->count_children() - 1);
785  }
786 
787  if(!cur) {
788  throw std::domain_error(
789  "tree_view_node::get_node_above(): Cannot determine which node is this line, or which "
790  "node is the line above this one, if any.");
791  }
792 
793  return cur;
794 }
795 
797 {
798  assert(!is_root_node());
799  if(!is_folded() && count_children() > 0) {
800  return &get_child_at(0);
801  }
802 
803  tree_view_node* cur = this;
804  while(cur->parent_node_ != nullptr) {
806 
807  for(std::size_t i = 0; i < parent.count_children(); ++i) {
808  if(parent.children_[i].get() == cur) {
809  if(i < parent.count_children() - 1) {
810  return parent.children_[i + 1].get();
811  } else {
812  cur = &parent;
813  }
814 
815  break;
816  }
817  }
818  }
819 
820  return nullptr;
821 }
822 
824 {
825  tree_view_node* above = this;
826  do {
827  above = above->get_node_above();
828  } while(above != nullptr && above->label_ == nullptr);
829 
830  return above;
831 }
832 
834 {
835  tree_view_node* below = this;
836  do {
837  below = below->get_node_below();
838  } while(below != nullptr && below->label_ == nullptr);
839 
840  return below;
841 }
842 
843 void tree_view_node::select_node(bool expand_parents)
844 {
845  if(!label_ || label_->get_value_bool()) {
846  return;
847  }
848 
849  if(expand_parents) {
851  for(tree_view_node* cur = parent_node_; cur != root; cur = cur->parent_node_) {
852  cur->unfold();
853  }
854  }
855 
856  if(get_tree_view().selected_item_ && get_tree_view().selected_item_->label_) {
858  }
859 
860  get_tree_view().selected_item_ = this;
861 
863 
864  label_->set_value_bool(true);
865 }
866 
867 void tree_view_node::layout_initialize(const bool full_initialization)
868 {
869  // Inherited.
870  widget::layout_initialize(full_initialization);
871  grid_.layout_initialize(full_initialization);
872 
873  // Clear child caches.
874  for(auto& child : children_) {
875  child->layout_initialize(full_initialization);
876  }
877 }
878 
880 {
881  return std::make_unique<gui2::iteration::tree_node>(*this, children_);
882 }
883 
884 } // namespace gui2
double g
Definition: astarsearch.cpp:63
void connect_signal(const F &func, const queue_position position=back_child)
Adds a callback to the appropriate queue based on event type.
Definition: dispatcher.hpp:351
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:74
Base container class.
Definition: grid.hpp:32
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: grid.cpp:484
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override
See widget::set_visible_rectangle.
Definition: grid.cpp:608
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: grid.cpp:632
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:645
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: grid.cpp:190
A panel is a visible container to hold multiple widgets.
Definition: panel.hpp:55
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Small abstract helper class.
void set_value_bool(bool value, bool fire_event=false)
virtual void set_value(unsigned value, bool fire_event=false)=0
Select the styled_widget.
virtual unsigned get_value() const =0
Is the styled_widget selected?
Base class for all visible items.
t_string label_
Contain the non-editable text associated with styled_widget.
Class for a toggle button.
grid grid_
Grid holding our contents.
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 & 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.
selectable_item * label_
The label to show our selected state.
tree_view_node * get_selectable_node_above()
void signal_handler_left_button_click(const event::ui_event event)
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)
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()
std::vector< int > describe_path()
Calculates the node indices needed to get from the root node to this node.
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.
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()
virtual void place(const point &origin, const point &size) override
See widget::place.
A tree view is a control that holds several items of the same or different types.
Definition: tree_view.hpp:60
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:109
unsigned indentation_step_size_
Definition: tree_view.hpp:150
tree_view_node * selected_item_
Definition: tree_view.hpp:156
static const std::string root_node_id
Definition: tree_view.hpp:140
tree_view_node & get_root_node()
Definition: tree_view.hpp:74
virtual void layout_children() override
See widget::layout_children.
Definition: tree_view.cpp:104
Base class for all widgets.
Definition: widget.hpp:53
const point & layout_size() const
Definition: widget.cpp:342
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:193
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:239
void set_visible(const visibility visible)
Definition: widget.cpp:470
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:167
virtual widget * find(const std::string &id, const bool must_be_active)
Returns a widget with the wanted id.
Definition: widget.cpp:555
void set_parent(widget *parent)
Definition: widget.cpp:155
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:307
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:394
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:221
@ visible
The user sets the widget visible, that means:
@ invisible
The user set the widget invisible, that means:
@ hidden
The user sets the widget hidden, that means:
virtual widget * find_at(const point &coordinate, const bool must_be_active)
Returns the widget at the wanted coordinates.
Definition: widget.cpp:544
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:227
widget * parent()
Definition: widget.cpp:160
std::size_t i
Definition: function.cpp:968
const std::vector< node > & nodes
static std::string _(const char *str)
Definition: gettext.hpp:93
Define the common log macros for the gui toolkit.
#define DBG_GUI_L
Definition: log.hpp:55
#define DBG_GUI_E
Definition: log.hpp:35
#define log_scope2(domain, description)
Definition: log.hpp:275
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:202
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
@ NOTIFY_MODIFIED
Definition: handler.hpp:158
@ LEFT_BUTTON_CLICK
Definition: handler.hpp:122
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:42
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:34
lg::log_domain log_gui_layout("gui/layout")
Definition: log.hpp:54
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
typename const_clone< D, S >::reference const_clone_ref
Definition: const_clone.hpp:63
std::string_view data
Definition: picture.cpp:194
Contains the SDL_Rect helper code.
static W * find_at(utils::const_clone_ref< tree_view_node, W > tree_view_node, const point &coordinate, const bool must_be_active)
static W * find_at_aux(It begin, It end, const point &coordinate, const bool must_be_active)
Holds a 2D point.
Definition: point.hpp:25
#define LOG_HEADER
#define LOG_SCOPE_HEADER
#define FAIL_WITH_DEV_MESSAGE(message, dev_message)
#define d