The Battle for Wesnoth  1.19.5+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"
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  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_toggle_left_click, this, std::placeholders::_2));
78 
80  std::bind(&tree_view_node::signal_handler_toggle_left_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  auto& node = children_.emplace_back(std::make_shared<tree_view_node>(id, this, get_tree_view(), d));
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  /**
323  * Important! Set this first. See issues #8689 and #9146.
324  *
325  * For context, when the unfolded_ flag was introduced in 21001bcb3201b46f4c4b15de1388d4bb843a2403, it
326  * was set at the end of this function, and of unfold_internal. Commentary in #8689 indicates that there
327  * were no folding issues until recently, and it seems possible tha the graphics overhaul was caused a
328  * subtly-hidden flaw to reveal itself.
329  *
330  * The bugs above technically only involve this function (not unfold_internal), and *only* if unfolded_
331  * is set after the call to resize_content. My best guess is because tree_view::resize_content calls
332  * queue_redraw, and that somehow still being in an "unfolded state" causes things to draw incorrectly.
333  *
334  * - vultraz, 2024-08-12
335  */
336  unfolded_ = false;
337 
338  const point current_size(get_current_size().x, get_unfolded_size().y);
339  const point new_size = get_folded_size();
340 
341  const int width_modification = std::max(0, new_size.x - current_size.x);
342  const int height_modification = new_size.y - current_size.y;
343  assert(height_modification <= 0);
344 
345  get_tree_view().resize_content(width_modification, height_modification, -1, calculate_ypos());
346 }
347 
349 {
350  /** Important! Set this first. See comment in @ref fold_internal */
351  unfolded_ = true;
352 
353  const point current_size(get_current_size().x, get_folded_size().y);
354  const point new_size = get_unfolded_size();
355 
356  const int width_modification = std::max(0, new_size.x - current_size.x);
357  const int height_modification = new_size.y - current_size.y;
358  assert(height_modification >= 0);
359 
360  get_tree_view().resize_content(width_modification, height_modification, -1, calculate_ypos());
361 }
362 
364 {
365  /** @todo Also try to find the optimal width. */
366  int height_reduction = 0;
367 
368  if(!is_folded()) {
369  for(const auto& node : children_) {
370  height_reduction += node->get_current_size().y;
371  }
372  }
373 
374  children_.clear();
375 
376  if(height_reduction == 0) {
377  return;
378  }
379 
380  get_tree_view().resize_content(0, -height_reduction, -1, calculate_ypos());
381 }
382 
384 {
385 private:
386  template<class W, class It>
387  static W* find_at_aux(It begin, It end, const point& coordinate, const bool must_be_active)
388  {
389  for(It it = begin; it != end; ++it) {
390  if(W* widget = (*it)->find_at(coordinate, must_be_active)) {
391  return widget;
392  }
393  }
394 
395  return nullptr;
396  }
397 
398 public:
399  template<class W>
401  const point& coordinate,
402  const bool must_be_active)
403  {
404  if(W* widget = tree_view_node.grid_.find_at(coordinate, must_be_active)) {
405  return widget;
406  }
407 
408  if(tree_view_node.is_folded()) {
409  return nullptr;
410  }
411 
412  return find_at_aux<W>(
413  tree_view_node.children_.begin(), tree_view_node.children_.end(), coordinate, must_be_active);
414  }
415 };
416 
417 widget* tree_view_node::find_at(const point& coordinate, const bool must_be_active)
418 {
419  return tree_view_node_implementation::find_at<widget>(*this, coordinate, must_be_active);
420 }
421 
422 const widget* tree_view_node::find_at(const point& coordinate, const bool must_be_active) const
423 {
424  return tree_view_node_implementation::find_at<const widget>(*this, coordinate, must_be_active);
425 }
426 
427 widget* tree_view_node::find(const std::string& id, const bool must_be_active)
428 {
429  widget* result = widget::find(id, must_be_active);
430  if(result) {
431  return result;
432  }
433 
434  result = grid_.find(id, must_be_active);
435  if(result) {
436  return result;
437  }
438 
439  for(auto& child : children_) {
440  result = child->find(id, must_be_active);
441  if(result) {
442  return result;
443  }
444  }
445 
446  return nullptr;
447 }
448 
449 const widget* tree_view_node::find(const std::string& id, const bool must_be_active) const
450 {
451  const widget* result = widget::find(id, must_be_active);
452  if(result) {
453  return result;
454  }
455 
456  result = grid_.find(id, must_be_active);
457  if(result) {
458  return result;
459  }
460 
461  for(const auto& child : children_) {
462  result = child->find(id, must_be_active);
463  if(result) {
464  return result;
465  }
466  }
467 
468  return nullptr;
469 }
470 
472 {
473  return calculate_best_size(-1, get_tree_view().indentation_step_size_);
474 }
475 
477 {
478  return true;
479 }
480 
481 point tree_view_node::get_current_size(bool assume_visible) const
482 {
483  if(!assume_visible && parent_node_ && parent_node_->is_folded()) {
484  return point();
485  }
486 
488  if(is_folded()) {
489  return size;
490  }
491 
492  for(const auto& node : children_) {
493  if(node->grid_.get_visible() == widget::visibility::invisible) {
494  continue;
495  }
496 
497  point node_size = node->get_current_size();
498 
499  size.y += node_size.y;
500  size.x = std::max(size.x, node_size.x);
501  }
502 
503  return size;
504 }
505 
507 {
509  if(get_indentation_level() > 1) {
511  }
512 
513  return size;
514 }
515 
517 {
519  if(get_indentation_level() > 1) {
521  }
522 
523  for(const auto& node : children_) {
524  if(node->grid_.get_visible() == widget::visibility::invisible) {
525  continue;
526  }
527 
528  point node_size = node->get_current_size(true);
529 
530  size.y += node_size.y;
531  size.x = std::max(size.x, node_size.x);
532  }
533 
534  return size;
535 }
536 
537 point tree_view_node::calculate_best_size(const int indentation_level, const unsigned indentation_step_size) const
538 {
540 
541  point best_size = grid_.get_best_size();
542  if(indentation_level > 0) {
543  best_size.x += indentation_level * indentation_step_size;
544  }
545 
546  DBG_GUI_L << LOG_HEADER << " own grid best size " << best_size << ".";
547 
548  for(const auto& node : children_) {
549  if(node->grid_.get_visible() == widget::visibility::invisible) {
550  continue;
551  }
552 
553  const point node_size = node->calculate_best_size(indentation_level + 1, indentation_step_size);
554 
555  if(!is_folded()) {
556  best_size.y += node_size.y;
557  }
558 
559  best_size.x = std::max(best_size.x, node_size.x);
560  }
561 
562  DBG_GUI_L << LOG_HEADER << " result " << best_size << ".";
563  return best_size;
564 }
565 
567 {
568  // Inherited.
569  widget::set_origin(origin);
570 
571  // Using layout_children seems to fail.
572  place(get_tree_view().indentation_step_size_, origin, get_size().x);
573 }
574 
575 void tree_view_node::place(const point& origin, const point& size)
576 {
577  // Inherited.
578  widget::place(origin, size);
579 
581 }
582 
583 unsigned tree_view_node::place(const unsigned indentation_step_size, point origin, unsigned width)
584 {
586  DBG_GUI_L << LOG_HEADER << " origin " << origin << ".";
587 
588  const unsigned offset = origin.y;
589  point best_size = grid_.get_best_size();
590  best_size.x = width;
591 
592  grid_.place(origin, best_size);
593 
594  if(!is_root_node()) {
595  origin.x += indentation_step_size;
596  assert(width >= indentation_step_size);
597  width -= indentation_step_size;
598  }
599 
600  origin.y += best_size.y;
601 
602  if(is_folded()) {
603  DBG_GUI_L << LOG_HEADER << " folded node done.";
604  return origin.y - offset;
605  }
606 
607  DBG_GUI_L << LOG_HEADER << " set children.";
608  for(auto& node : children_) {
609  origin.y += node->place(indentation_step_size, origin, width);
610  }
611 
612  // Inherited.
613  widget::set_size(point(width, origin.y - offset));
614 
615  DBG_GUI_L << LOG_HEADER << " result " << (origin.y - offset) << ".";
616  return origin.y - offset;
617 }
618 
619 void tree_view_node::set_visible_rectangle(const SDL_Rect& rectangle)
620 {
622  DBG_GUI_L << LOG_HEADER << " rectangle " << rectangle << ".";
623  grid_.set_visible_rectangle(rectangle);
624 
625  if(is_folded()) {
626  DBG_GUI_L << LOG_HEADER << " folded node done.";
627  return;
628  }
629 
630  for(auto& node : children_) {
631  node->set_visible_rectangle(rectangle);
632  }
633 }
634 
636 {
638 
639  if(is_folded()) {
640  return;
641  }
642 
643  for(auto& node : children_) {
644  node->impl_draw_children();
645  }
646 }
647 
649 {
650  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
651 
652  /**
653  * @todo Rewrite this sizing code for the folding/unfolding.
654  *
655  * The code works but feels rather hacky, so better move back to the
656  * drawingboard for 1.9.
657  */
658  const bool unfolded_new = toggle_->get_value_bool();
659  if(unfolded_ == unfolded_new) {
660  return;
661  }
662 
663  unfolded_ = unfolded_new;
665 
667 }
668 
670 {
671  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
672 
673  assert(label_);
674 
675  // Normally, this is only an event hook and not full handling; however, if
676  // the currently selected item was selected, we halt the event to prevent
677  // deselection (which would leave no items selected).
678  if(label_->get_value()) {
679  halt = handled = true;
680  return;
681  }
682 
683  // Select the new item if a different one was selected
684  if(get_tree_view().selected_item_ && get_tree_view().selected_item_->label_) {
686  }
687 
688  get_tree_view().selected_item_ = this;
689 
691 }
692 
694 {
695  assert(g);
696 
697  for(unsigned row = 0; row < g->get_rows(); ++row) {
698  for(unsigned col = 0; col < g->get_cols(); ++col) {
699  widget* wgt = g->get_widget(row, col);
700  assert(wgt);
701 
702  // toggle_button* btn = dynamic_cast<toggle_button*>(widget);
703 
704  if(toggle_panel* panel = dynamic_cast<toggle_panel*>(wgt)) {
705  panel->set_child_members(data);
706  } else if(grid* child_grid = dynamic_cast<grid*>(wgt)) {
707  init_grid(child_grid, data);
708  } else if(styled_widget* control = dynamic_cast<styled_widget*>(wgt)) {
709  auto itor = data.find(control->id());
710 
711  if(itor == data.end()) {
712  itor = data.find("");
713  }
714 
715  if(itor != data.end()) {
716  control->set_members(itor->second);
717  }
718  // control->set_members(data);
719  } else {
720  // ERROR_LOG("Widget type '" << typeid(*widget).name() << "'.");
721  }
722  }
723  }
724 }
725 
726 const std::string& tree_view_node::get_control_type() const
727 {
728  static const std::string type = "tree_view_node";
729  return type;
730 }
731 
733 {
734  assert(static_cast<std::size_t>(index) < children_.size());
735  return *children_[index];
736 }
737 
738 std::vector<int> tree_view_node::describe_path() const
739 {
740  if(is_root_node()) {
741  return std::vector<int>();
742  }
743 
744  std::vector<int> res = parent_node_->describe_path();
745  for(std::size_t i = 0; i < parent_node_->count_children(); ++i) {
746  if(parent_node_->children_[i].get() == this) {
747  res.push_back(i);
748  return res;
749  }
750  }
751 
752  assert(!"tree_view_node was not found in parent nodes children");
753  throw "assertion ignored"; // To silence 'no return value in this codepath' warning.
754 }
755 
757 {
758  if(!parent_node_) {
759  return 0;
760  }
761 
762  int res = parent_node_->calculate_ypos();
763  for(const auto& node : parent_node_->children_) {
764  if(node.get() == this) {
765  break;
766  }
767 
768  res += node->get_current_size(true).y;
769  }
770 
771  return res;
772 }
773 
775 {
776  if(!parent_node_) {
777  return this;
778  }
779 
781  return res == parent_node_ && !res->is_folded() ? this : res;
782 }
783 
785 {
786  assert(!is_root_node());
787 
788  tree_view_node* cur = nullptr;
789  for(std::size_t i = 0; i < parent_node_->count_children(); ++i) {
790  if(parent_node_->children_[i].get() == this) {
791  if(i == 0) {
792  return parent_node_->is_root_node() ? nullptr : parent_node_;
793  } else {
794  cur = parent_node_->children_[i - 1].get();
795  break;
796  }
797  }
798  }
799 
800  while(cur && !cur->is_folded() && cur->count_children() > 0) {
801  cur = &cur->get_child_at(cur->count_children() - 1);
802  }
803 
804  if(!cur) {
805  throw std::domain_error(
806  "tree_view_node::get_node_above(): Cannot determine which node is this line, or which "
807  "node is the line above this one, if any.");
808  }
809 
810  return cur;
811 }
812 
814 {
815  assert(!is_root_node());
816  if(!is_folded() && count_children() > 0) {
817  return &get_child_at(0);
818  }
819 
820  tree_view_node* cur = this;
821  while(cur->parent_node_ != nullptr) {
823 
824  for(std::size_t i = 0; i < parent.count_children(); ++i) {
825  if(parent.children_[i].get() == cur) {
826  if(i < parent.count_children() - 1) {
827  return parent.children_[i + 1].get();
828  } else {
829  cur = &parent;
830  }
831 
832  break;
833  }
834  }
835  }
836 
837  return nullptr;
838 }
839 
841 {
842  tree_view_node* above = this;
843  do {
844  above = above->get_node_above();
845  } while(above != nullptr && above->label_ == nullptr);
846 
847  return above;
848 }
849 
851 {
852  tree_view_node* below = this;
853  do {
854  below = below->get_node_below();
855  } while(below != nullptr && below->label_ == nullptr);
856 
857  return below;
858 }
859 
860 void tree_view_node::select_node(bool expand_parents)
861 {
862  if(!label_ || label_->get_value_bool()) {
863  return;
864  }
865 
866  if(expand_parents) {
868  for(tree_view_node* cur = parent_node_; cur != root; cur = cur->parent_node_) {
869  cur->unfold();
870  }
871  }
872 
873  if(get_tree_view().selected_item_ && get_tree_view().selected_item_->label_) {
875  }
876 
877  get_tree_view().selected_item_ = this;
878 
880 
881  label_->set_value_bool(true);
882 }
883 
884 void tree_view_node::layout_initialize(const bool full_initialization)
885 {
886  // Inherited.
887  widget::layout_initialize(full_initialization);
888  grid_.layout_initialize(full_initialization);
889 
890  // Clear child caches.
891  for(auto& child : children_) {
892  child->layout_initialize(full_initialization);
893  }
894 }
895 
897 {
898  return std::make_unique<gui2::iteration::tree_node>(*this, children_);
899 }
900 
901 } // 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
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)
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.
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
tree_view_node * get_node_above()
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.
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:129
tree_view_node * selected_item_
Definition: tree_view.hpp:135
static const std::string root_node_id
Definition: tree_view.hpp:119
tree_view_node & get_root_node()
Definition: tree_view.hpp:53
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 &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:1023
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:279
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: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 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:178
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 FAIL_WITH_DEV_MESSAGE(message, dev_message)
#define d