The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
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
33namespace gui2
34{
35tree_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_);
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_) {
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
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
124tree_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
184std::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
282void tree_view_node::request_reduce_width(const unsigned /*maximum_width*/)
283{
284 /* DO NOTHING */
285}
286
287void tree_view_node::fold(const bool recursive)
288{
289 if(!is_folded()) {
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
303void tree_view_node::unfold(const bool recursive)
304{
305 if(is_folded()) {
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{
384private:
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
397public:
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
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
416widget* 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
421const 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
426widget* 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
448const 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
480point 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
486 point size = get_folded_size();
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{
507 point size = grid_.get_best_size();
508 if(get_indentation_level() > 1) {
510 }
511
512 return size;
513}
514
516{
517 point size = grid_.get_best_size();
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
536point 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
574void tree_view_node::place(const point& origin, const point& size)
575{
576 // Inherited.
577 widget::place(origin, size);
578
580}
581
582unsigned 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
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
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
725const 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
737std::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
859void 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
877
878 if (fire_event) {
880 }
881
882 label_->set_value_bool(true);
883}
884
885void 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
void connect_signal(const F &func, const queue_position position=back_child)
Adds a callback to the appropriate queue based on event type.
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
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 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 set_visible_rectangle(const rect &rectangle) override
See widget::set_visible_rectangle.
Definition grid.cpp:608
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_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)
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.
virtual void set_visible_rectangle(const rect &rectangle) override
See widget::set_visible_rectangle.
tree_view & get_tree_view()
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.
unsigned indentation_step_size_
tree_view_node * selected_item_
bool has_minimum() const
If true, adding an item when no item is selected will automatically select that item.
static const std::string root_node_id
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.
virtual void layout_children() override
See widget::layout_children.
const tree_view_node & get_root_node() const
Definition tree_view.hpp:53
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
#define LOG_HEADER
static std::string _(const char *str)
Definition gettext.hpp:100
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_SCOPE_HEADER
Definition button.cpp:34
#define log_scope2(domain, description)
Definition log.hpp:276
ui_event
The event sent to the dispatcher.
Definition handler.hpp:115
@ 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
typename const_clone< D, S >::reference const_clone_ref
const std::vector< findroute_node > & nodes
Definition pathfind.cpp:220
std::string_view data
Definition picture.cpp:188
Contains the SDL_Rect helper code.
static W * find_at_aux(It begin, It end, const point &coordinate, const bool must_be_active)
static W * find_at(utils::const_clone_ref< tree_view_node, W > tree_view_node, const point &coordinate, const bool must_be_active)
Holds a 2D point.
Definition point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
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 i
#define g
#define d