The Battle for Wesnoth  1.19.13+dev
tree_view_node.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2025
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"
22 #include "gui/core/log.hpp"
25 #include "sdl/rect.hpp"
26 #include "wml_exception.hpp"
27 
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  const auto opt = get_tree_view().get_node_definition(id);
57  VALIDATE_WITH_DEV_MESSAGE(opt, _("Unknown builder id for tree view node."), id);
58 
59  const auto& node_definition = **opt;
60 
61  node_definition.builder->build(grid_);
62  init_grid(&grid_, data);
63 
66  }
67 
68  if(node_definition.unfolded) {
69  unfolded_ = true;
70  }
71 
72  widget* toggle_widget = grid_.find("tree_view_node_toggle", false);
73  toggle_ = dynamic_cast<selectable_item*>(toggle_widget);
74 
75  if(toggle_) {
77 
79  std::bind(&tree_view_node::signal_handler_toggle_left_click, this, std::placeholders::_2));
80 
82  std::bind(&tree_view_node::signal_handler_toggle_left_click, this, std::placeholders::_2),
84 
85  if(unfolded_) {
86  toggle_->set_value(1);
87  }
88  }
89 
90  widget* label_widget = grid_.find("tree_view_node_label", false);
91  label_ = dynamic_cast<selectable_item*>(label_widget);
92 
93  if(label_) {
95  std::bind(&tree_view_node::signal_handler_label_left_button_click, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
97 
99  std::bind(&tree_view_node::signal_handler_label_left_button_click, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4),
101 
103  get_tree_view().selected_item_ = this;
104  label_->set_value(true);
105  }
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  auto& node = children_.emplace_back(std::make_shared<tree_view_node>(id, this, get_tree_view(), d));
197 
198  // NOTE: we currently don't support moving nodes between different trees, so this
199  // just ensures that wasn't tried. Remove this if we implement support for that.
200  assert(node->tree_view_ == tree_view_);
201 
202  // Safety check. Might only fail if someone accidentally removed the parent_node_ setter in add_child().
203  assert(node->parent_node_ == this);
204 
205  nodes.push_back(node);
206 
207  if(is_folded()) {
208  continue;
209  }
210 
211  assert(get_tree_view().content_grid());
212  const point current_size = get_tree_view().content_grid()->get_size();
213 
214  // Calculate width modification.
215  // This increases tree width if the width of the new node is greater than the current width.
216  int best_size = node->get_best_size().x;
218 
219  int new_width = best_size > current_size.x
220  ? best_size - current_size.x
221  : 0;
222 
223  if(new_width > width_modification)
224  {
225  width_modification = new_width;
226  }
227  }
228 
229  if(is_folded()) {
230  return nodes;
231  }
232 
233  // Calculate height modification.
234  // For this, we only increase height if the best size of the tree (that is, the size with the new node)
235  // is larger than its current size. This prevents the scrollbar being reserved even when there's obviously
236  // enough visual space.
237 
238  // Throw away cached best size to force a recalculation.
240 
241  const point current_size = get_tree_view().content_grid()->get_size();
242  const point tree_best_size = get_tree_view().get_best_size();
243 
244  const int height_modification = tree_best_size.y > current_size.y && get_tree_view().layout_size() == point()
245  ? tree_best_size.y - current_size.y
246  : 0;
247 
248  assert(height_modification >= 0);
249 
250  // Request new size.
251  auto& last_node = children_.at(children_.size()-1);
252  get_tree_view().resize_content(width_modification, height_modification, -1, last_node->calculate_ypos());
253 
254  return nodes;
255 }
256 
258 {
259  unsigned level = 0;
260 
261  const tree_view_node* node = this;
262  while(!node->is_root_node()) {
263  node = &node->parent_node();
264  ++level;
265  }
266 
267  return level;
268 }
269 
271 {
272  assert(!is_root_node());
273  return *parent_node_;
274 }
275 
277 {
278  assert(!is_root_node());
279  return *parent_node_;
280 }
281 
282 void tree_view_node::request_reduce_width(const unsigned /*maximum_width*/)
283 {
284  /* DO NOTHING */
285 }
286 
287 void tree_view_node::fold(const bool recursive)
288 {
289  if(!is_folded()) {
290  fold_internal();
291  if(toggle_) {
292  toggle_->set_value(false);
293  }
294  }
295 
296  if(recursive) {
297  for(auto& child_node : children_) {
298  child_node->fold(true);
299  }
300  }
301 }
302 
303 void tree_view_node::unfold(const bool recursive)
304 {
305  if(is_folded()) {
306  unfold_internal();
307  if(toggle_) {
308  toggle_->set_value(true);
309  }
310  }
311 
312  if(recursive) {
313  for(auto& child_node : children_) {
314  child_node->unfold(true);
315  }
316  }
317 }
318 
320 {
321  /**
322  * Important! Set this first. See issues #8689 and #9146.
323  *
324  * For context, when the unfolded_ flag was introduced in 21001bcb3201b46f4c4b15de1388d4bb843a2403, it
325  * was set at the end of this function, and of unfold_internal. Commentary in #8689 indicates that there
326  * were no folding issues until recently, and it seems possible tha the graphics overhaul was caused a
327  * subtly-hidden flaw to reveal itself.
328  *
329  * The bugs above technically only involve this function (not unfold_internal), and *only* if unfolded_
330  * is set after the call to resize_content. My best guess is because tree_view::resize_content calls
331  * queue_redraw, and that somehow still being in an "unfolded state" causes things to draw incorrectly.
332  *
333  * - vultraz, 2024-08-12
334  */
335  unfolded_ = false;
336 
337  const point current_size(get_current_size().x, get_unfolded_size().y);
338  const point new_size = get_folded_size();
339 
340  const int width_modification = std::max(0, new_size.x - current_size.x);
341  const int height_modification = new_size.y - current_size.y;
342  assert(height_modification <= 0);
343 
344  get_tree_view().resize_content(width_modification, height_modification, -1, calculate_ypos());
345 }
346 
348 {
349  /** Important! Set this first. See comment in @ref fold_internal */
350  unfolded_ = true;
351 
352  const point current_size(get_current_size().x, get_folded_size().y);
353  const point new_size = get_unfolded_size();
354 
355  const int width_modification = std::max(0, new_size.x - current_size.x);
356  const int height_modification = new_size.y - current_size.y;
357  assert(height_modification >= 0);
358 
359  get_tree_view().resize_content(width_modification, height_modification, -1, calculate_ypos());
360 }
361 
363 {
364  /** @todo Also try to find the optimal width. */
365  int height_reduction = 0;
366 
367  if(!is_folded()) {
368  for(const auto& node : children_) {
369  height_reduction += node->get_current_size().y;
370  }
371  }
372 
373  children_.clear();
374 
375  if(height_reduction == 0) {
376  return;
377  }
378 
379  get_tree_view().resize_content(0, -height_reduction, -1, calculate_ypos());
380 }
381 
383 {
384 private:
385  template<class W, class It>
386  static W* find_at_aux(It begin, It end, const point& coordinate, const bool must_be_active)
387  {
388  for(It it = begin; it != end; ++it) {
389  if(W* widget = (*it)->find_at(coordinate, must_be_active)) {
390  return widget;
391  }
392  }
393 
394  return nullptr;
395  }
396 
397 public:
398  template<class W>
400  const point& coordinate,
401  const bool must_be_active)
402  {
403  if(W* widget = tree_view_node.grid_.find_at(coordinate, must_be_active)) {
404  return widget;
405  }
406 
407  if(tree_view_node.is_folded()) {
408  return nullptr;
409  }
410 
411  return find_at_aux<W>(
412  tree_view_node.children_.begin(), tree_view_node.children_.end(), coordinate, must_be_active);
413  }
414 };
415 
416 widget* tree_view_node::find_at(const point& coordinate, const bool must_be_active)
417 {
418  return tree_view_node_implementation::find_at<widget>(*this, coordinate, must_be_active);
419 }
420 
421 const widget* tree_view_node::find_at(const point& coordinate, const bool must_be_active) const
422 {
423  return tree_view_node_implementation::find_at<const widget>(*this, coordinate, must_be_active);
424 }
425 
426 widget* tree_view_node::find(const std::string_view id, const bool must_be_active)
427 {
428  widget* result = widget::find(id, must_be_active);
429  if(result) {
430  return result;
431  }
432 
433  result = grid_.find(id, must_be_active);
434  if(result) {
435  return result;
436  }
437 
438  for(auto& child : children_) {
439  result = child->find(id, must_be_active);
440  if(result) {
441  return result;
442  }
443  }
444 
445  return nullptr;
446 }
447 
448 const widget* tree_view_node::find(const std::string_view id, const bool must_be_active) const
449 {
450  const widget* result = widget::find(id, must_be_active);
451  if(result) {
452  return result;
453  }
454 
455  result = grid_.find(id, must_be_active);
456  if(result) {
457  return result;
458  }
459 
460  for(const auto& child : children_) {
461  result = child->find(id, must_be_active);
462  if(result) {
463  return result;
464  }
465  }
466 
467  return nullptr;
468 }
469 
471 {
472  return calculate_best_size(-1, get_tree_view().indentation_step_size_);
473 }
474 
476 {
477  return true;
478 }
479 
480 point tree_view_node::get_current_size(bool assume_visible) const
481 {
482  if(!assume_visible && parent_node_ && parent_node_->is_folded()) {
483  return point();
484  }
485 
487  if(is_folded()) {
488  return size;
489  }
490 
491  for(const auto& node : children_) {
492  if(node->grid_.get_visible() == widget::visibility::invisible) {
493  continue;
494  }
495 
496  point node_size = node->get_current_size();
497 
498  size.y += node_size.y;
499  size.x = std::max(size.x, node_size.x);
500  }
501 
502  return size;
503 }
504 
506 {
508  if(get_indentation_level() > 1) {
510  }
511 
512  return size;
513 }
514 
516 {
518  if(get_indentation_level() > 1) {
520  }
521 
522  for(const auto& node : children_) {
523  if(node->grid_.get_visible() == widget::visibility::invisible) {
524  continue;
525  }
526 
527  point node_size = node->get_current_size(true);
528 
529  size.y += node_size.y;
530  size.x = std::max(size.x, node_size.x);
531  }
532 
533  return size;
534 }
535 
536 point tree_view_node::calculate_best_size(const int indentation_level, const unsigned indentation_step_size) const
537 {
539 
540  point best_size = grid_.get_best_size();
541  if(indentation_level > 0) {
542  best_size.x += indentation_level * indentation_step_size;
543  }
544 
545  DBG_GUI_L << LOG_HEADER << " own grid best size " << best_size << ".";
546 
547  for(const auto& node : children_) {
548  if(node->grid_.get_visible() == widget::visibility::invisible) {
549  continue;
550  }
551 
552  const point node_size = node->calculate_best_size(indentation_level + 1, indentation_step_size);
553 
554  if(!is_folded()) {
555  best_size.y += node_size.y;
556  }
557 
558  best_size.x = std::max(best_size.x, node_size.x);
559  }
560 
561  DBG_GUI_L << LOG_HEADER << " result " << best_size << ".";
562  return best_size;
563 }
564 
566 {
567  // Inherited.
568  widget::set_origin(origin);
569 
570  // Using layout_children seems to fail.
571  place(get_tree_view().indentation_step_size_, origin, get_size().x);
572 }
573 
574 void tree_view_node::place(const point& origin, const point& size)
575 {
576  // Inherited.
577  widget::place(origin, size);
578 
580 }
581 
582 unsigned tree_view_node::place(const unsigned indentation_step_size, point origin, unsigned width)
583 {
585  DBG_GUI_L << LOG_HEADER << " origin " << origin << ".";
586 
587  const unsigned offset = origin.y;
588  point best_size = grid_.get_best_size();
589  best_size.x = width;
590 
591  grid_.place(origin, best_size);
592 
593  if(!is_root_node()) {
594  origin.x += indentation_step_size;
595  assert(width >= indentation_step_size);
596  width -= indentation_step_size;
597  }
598 
599  origin.y += best_size.y;
600 
601  if(is_folded()) {
602  DBG_GUI_L << LOG_HEADER << " folded node done.";
603  return origin.y - offset;
604  }
605 
606  DBG_GUI_L << LOG_HEADER << " set children.";
607  for(auto& node : children_) {
608  origin.y += node->place(indentation_step_size, origin, width);
609  }
610 
611  // Inherited.
612  widget::set_size(point(width, origin.y - offset));
613 
614  DBG_GUI_L << LOG_HEADER << " result " << (origin.y - offset) << ".";
615  return origin.y - offset;
616 }
617 
618 void tree_view_node::set_visible_rectangle(const SDL_Rect& rectangle)
619 {
621  DBG_GUI_L << LOG_HEADER << " rectangle " << rectangle << ".";
622  grid_.set_visible_rectangle(rectangle);
623 
624  if(is_folded()) {
625  DBG_GUI_L << LOG_HEADER << " folded node done.";
626  return;
627  }
628 
629  for(auto& node : children_) {
630  node->set_visible_rectangle(rectangle);
631  }
632 }
633 
635 {
637 
638  if(is_folded()) {
639  return;
640  }
641 
642  for(auto& node : children_) {
643  node->impl_draw_children();
644  }
645 }
646 
648 {
649  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
650 
651  /**
652  * @todo Rewrite this sizing code for the folding/unfolding.
653  *
654  * The code works but feels rather hacky, so better move back to the
655  * drawingboard for 1.9.
656  */
657  const bool unfolded_new = toggle_->get_value_bool();
658  if(unfolded_ == unfolded_new) {
659  return;
660  }
661 
662  unfolded_ = unfolded_new;
664 
666 }
667 
669 {
670  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
671 
672  assert(label_);
673 
674  // Normally, this is only an event hook and not full handling; however, if
675  // the currently selected item was selected, we halt the event to prevent
676  // deselection (which would leave no items selected).
677  if(label_->get_value()) {
678  halt = handled = true;
679  return;
680  }
681 
682  // Select the new item if a different one was selected
683  if(get_tree_view().selected_item_ && get_tree_view().selected_item_->label_) {
685  }
686 
687  get_tree_view().selected_item_ = this;
688 
690 }
691 
693 {
694  assert(g);
695 
696  for(unsigned row = 0; row < g->get_rows(); ++row) {
697  for(unsigned col = 0; col < g->get_cols(); ++col) {
698  widget* wgt = g->get_widget(row, col);
699  assert(wgt);
700 
701  // toggle_button* btn = dynamic_cast<toggle_button*>(widget);
702 
703  if(toggle_panel* panel = dynamic_cast<toggle_panel*>(wgt)) {
704  panel->set_child_members(data);
705  } else if(grid* child_grid = dynamic_cast<grid*>(wgt)) {
706  init_grid(child_grid, data);
707  } else if(styled_widget* control = dynamic_cast<styled_widget*>(wgt)) {
708  auto itor = data.find(control->id());
709 
710  if(itor == data.end()) {
711  itor = data.find("");
712  }
713 
714  if(itor != data.end()) {
715  control->set_members(itor->second);
716  }
717  // control->set_members(data);
718  } else {
719  // ERROR_LOG("Widget type '" << typeid(*widget).name() << "'.");
720  }
721  }
722  }
723 }
724 
725 const std::string& tree_view_node::get_control_type() const
726 {
727  static const std::string type = "tree_view_node";
728  return type;
729 }
730 
732 {
733  assert(static_cast<std::size_t>(index) < children_.size());
734  return *children_[index];
735 }
736 
737 std::vector<int> tree_view_node::describe_path() const
738 {
739  if(is_root_node()) {
740  return std::vector<int>();
741  }
742 
743  std::vector<int> res = parent_node_->describe_path();
744  for(std::size_t i = 0; i < parent_node_->count_children(); ++i) {
745  if(parent_node_->children_[i].get() == this) {
746  res.push_back(i);
747  return res;
748  }
749  }
750 
751  assert(!"tree_view_node was not found in parent nodes children");
752  throw "assertion ignored"; // To silence 'no return value in this codepath' warning.
753 }
754 
756 {
757  if(!parent_node_) {
758  return 0;
759  }
760 
761  int res = parent_node_->calculate_ypos();
762  for(const auto& node : parent_node_->children_) {
763  if(node.get() == this) {
764  break;
765  }
766 
767  res += node->get_current_size(true).y;
768  }
769 
770  return res;
771 }
772 
774 {
775  if(!parent_node_) {
776  return this;
777  }
778 
780  return res == parent_node_ && !res->is_folded() ? this : res;
781 }
782 
784 {
785  assert(!is_root_node());
786 
787  tree_view_node* cur = nullptr;
788  for(std::size_t i = 0; i < parent_node_->count_children(); ++i) {
789  if(parent_node_->children_[i].get() == this) {
790  if(i == 0) {
791  return parent_node_->is_root_node() ? nullptr : parent_node_;
792  } else {
793  cur = parent_node_->children_[i - 1].get();
794  break;
795  }
796  }
797  }
798 
799  while(cur && !cur->is_folded() && cur->count_children() > 0) {
800  cur = &cur->get_child_at(cur->count_children() - 1);
801  }
802 
803  if(!cur) {
804  throw std::domain_error(
805  "tree_view_node::get_node_above(): Cannot determine which node is this line, or which "
806  "node is the line above this one, if any.");
807  }
808 
809  return cur;
810 }
811 
813 {
814  assert(!is_root_node());
815  if(!is_folded() && count_children() > 0) {
816  return &get_child_at(0);
817  }
818 
819  tree_view_node* cur = this;
820  while(cur->parent_node_ != nullptr) {
822 
823  for(std::size_t i = 0; i < parent.count_children(); ++i) {
824  if(parent.children_[i].get() == cur) {
825  if(i < parent.count_children() - 1) {
826  return parent.children_[i + 1].get();
827  } else {
828  cur = &parent;
829  }
830 
831  break;
832  }
833  }
834  }
835 
836  return nullptr;
837 }
838 
840 {
841  tree_view_node* above = this;
842  do {
843  above = above->get_node_above();
844  } while(above != nullptr && above->label_ == nullptr);
845 
846  return above;
847 }
848 
850 {
851  tree_view_node* below = this;
852  do {
853  below = below->get_node_below();
854  } while(below != nullptr && below->label_ == nullptr);
855 
856  return below;
857 }
858 
859 void tree_view_node::select_node(bool expand_parents, bool fire_event)
860 {
861  if(!label_ || label_->get_value_bool()) {
862  return;
863  }
864 
865  if(expand_parents) {
867  for(tree_view_node* cur = parent_node_; cur != root; cur = cur->parent_node_) {
868  cur->unfold();
869  }
870  }
871 
872  if(get_tree_view().selected_item_ && get_tree_view().selected_item_->label_) {
874  }
875 
876  get_tree_view().selected_item_ = this;
877 
878  if (fire_event) {
880  }
881 
882  label_->set_value_bool(true);
883 }
884 
885 void tree_view_node::layout_initialize(const bool full_initialization)
886 {
887  // Inherited.
888  widget::layout_initialize(full_initialization);
889  grid_.layout_initialize(full_initialization);
890 
891  // Clear child caches.
892  for(auto& child : children_) {
893  child->layout_initialize(full_initialization);
894  }
895 }
896 
898 {
899  return std::make_unique<gui2::iteration::tree_node>(*this, children_);
900 }
901 
902 } // 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_view 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
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?
t_string label_
Contain the non-editable text associated with styled_widget.
grid grid_
Grid holding our contents.
std::vector< int > describe_path() const
Calculates the node indices needed to get from the root node to this node.
point get_current_size(bool assume_visible=false) const
void signal_handler_label_left_button_click(const event::ui_event event, bool &handled, bool &halt)
void clear()
Removes all child items from the widget.
selectable_item * toggle_
The toggle for the folded state.
tree_view & get_tree_view()
tree_view_node & get_child_at(int index)
tree_view * tree_view_
The tree view that owns us.
void fold(const bool recursive=false)
void select_node(bool expand_parents=false, bool fire_event=true)
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?
virtual void set_origin(const point &origin) override
See widget::set_origin.
void signal_handler_toggle_left_click(const event::ui_event event)
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()
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
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
tree_view_node * get_node_above()
unsigned get_indentation_level() const
The indentation level of the node.
std::size_t count_children() const
The number of children in this widget.
void init_grid(grid *grid, const widget_data &data)
void layout_initialize(const bool full_initialization) override
How the layout engine works.
virtual point calculate_best_size() const override
See widget::calculate_best_size.
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.
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
const tree_view_node & get_root_node() const
Definition: tree_view.hpp:53
unsigned indentation_step_size_
Definition: tree_view.hpp:139
tree_view_node * selected_item_
Definition: tree_view.hpp:145
static const std::string root_node_id
Definition: tree_view.hpp:129
utils::optional< decltype(node_definitions_)::const_iterator > get_node_definition(const std::string &id) const
Optionally returns the node definition with the given id, or nullopt if not found.
Definition: tree_view.hpp:180
virtual void layout_children() override
See widget::layout_children.
Definition: tree_view.cpp:104
Base class for all widgets.
Definition: widget.hpp:55
const point & layout_size() const
Definition: widget.cpp:351
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:203
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:248
void set_visible(const visibility visible)
Definition: widget.cpp:479
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:177
virtual widget * find(const std::string_view id, const bool must_be_active)
Returns a widget with the wanted id.
Definition: widget.cpp:560
void set_parent(widget *parent)
Definition: widget.cpp:165
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:316
void draw_children()
Draws the children of a widget.
Definition: widget.cpp:402
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:230
@ 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:549
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:236
widget * parent()
Definition: widget.cpp:170
std::size_t i
Definition: function.cpp:1032
const std::vector< node > & nodes
static std::string _(const char *str)
Definition: gettext.hpp:97
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:276
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:211
bool fire_event(const ui_event event, const std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
@ NOTIFY_MODIFIED
Definition: handler.hpp:175
@ LEFT_BUTTON_CLICK
Definition: handler.hpp:122
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:44
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:36
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 size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
typename const_clone< D, S >::reference const_clone_ref
Definition: const_clone.hpp:63
std::string_view data
Definition: picture.cpp:188
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
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WITH_DEV_MESSAGE(cond, message, dev_message)
#define d