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