15 #include <unordered_map>
25 namespace visualization {
34 const char *text,
bool is_checked, std::function<
void(
bool)> on_toggled)
39 impl_->checkbox_ = std::make_shared<Checkbox>(
" ");
40 impl_->checkbox_->SetChecked(is_checked);
41 impl_->checkbox_->SetOnChecked(on_toggled);
42 impl_->label_ = std::make_shared<Label>(text);
50 return impl_->checkbox_;
59 auto check_pref = impl_->checkbox_->CalcPreferredSize(
context, constraints);
60 auto label_pref = impl_->label_->CalcPreferredSize(
context, constraints);
61 return Size(check_pref.width + label_pref.width,
62 std::max(check_pref.height, label_pref.height));
69 impl_->checkbox_->SetFrame(
71 auto x = impl_->checkbox_->GetFrame().GetRight();
72 impl_->label_->SetFrame(
87 std::function<
void(
bool)> on_enabled,
88 std::function<
void(
const Color &)> on_color_changed)
93 impl_->checkbox_ = std::make_shared<Checkbox>(
" ");
94 impl_->checkbox_->SetChecked(is_checked);
95 impl_->checkbox_->SetOnChecked(on_enabled);
96 impl_->label_ = std::make_shared<Label>(text);
97 impl_->color_ = std::make_shared<ColorEdit>();
98 impl_->color_->SetValue(
color);
99 impl_->color_->SetOnValueChanged(on_color_changed);
108 return impl_->checkbox_;
117 auto check_pref = impl_->checkbox_->CalcPreferredSize(
context, constraints);
118 auto label_pref = impl_->label_->CalcPreferredSize(
context, constraints);
119 auto color_pref = impl_->color_->CalcPreferredSize(
context, constraints);
120 return Size(check_pref.width + label_pref.width + color_pref.width,
122 std::max(label_pref.height, color_pref.height)));
126 auto em =
context.theme.font_size;
132 auto min_color_width = 8 *
context.theme.font_size;
133 color_width =
std::max(min_color_width, color_width);
134 if (
frame.width - (color_width + check_width) < 8 * em) {
135 color_width =
frame.width - check_width - 8 * em;
137 impl_->checkbox_->SetFrame(
139 impl_->color_->SetFrame(
Rect(
frame.GetRight() - color_width,
frame.y,
140 color_width,
frame.height));
141 auto x = impl_->checkbox_->GetFrame().GetRight();
142 impl_->label_->SetFrame(
155 std::function<
void(
double)> on_value_changed,
156 std::function<
void(
const Color &)> on_color_changed)
159 impl_->value_->SetDecimalPrecision(3);
160 impl_->value_->SetLimits(0.0, 1.0);
161 impl_->value_->SetValue(value);
162 impl_->value_->SetOnValueChanged(on_value_changed);
163 impl_->color_ = std::make_shared<ColorEdit>();
164 impl_->color_->SetValue(
color);
165 impl_->color_->SetOnValueChanged(on_color_changed);
173 return impl_->value_;
177 return impl_->color_;
182 auto number_pref = impl_->value_->CalcPreferredSize(
context, constraints);
183 auto color_pref = impl_->color_->CalcPreferredSize(
context, constraints);
184 return Size(number_pref.width + color_pref.width,
185 std::max(number_pref.height, color_pref.height));
191 impl_->value_->SetFrame(
193 auto x = impl_->value_->GetFrame().GetRight();
194 impl_->color_->SetFrame(
200 static int g_treeview_id = 1;
203 struct TreeView::Impl {
218 std::unordered_map<TreeView::ItemId, Item *>
id2item_;
227 impl_->id_ = g_treeview_id++;
229 impl_->id2item_[impl_->root_.id] = &impl_->root_;
237 std::shared_ptr<Widget> w) {
242 s <<
"treeview" << impl_->id_ <<
"item" << item.
id;
247 auto parent_it = impl_->id2item_.find(parent_id);
248 if (parent_it != impl_->id2item_.end()) {
249 parent = parent_it->second;
253 impl_->id2item_[item.
id] = &parent->
children.back();
259 std::shared_ptr<Widget> w = std::make_shared<Label>(text);
264 auto item_it = impl_->id2item_.find(item_id);
265 if (item_it != impl_->id2item_.end()) {
266 auto item = item_it->second;
269 impl_->id2item_.erase(item_it);
277 while (!item->children.empty()) {
283 for (
auto sibling = item->parent->children.begin();
284 sibling != item->parent->children.end(); ++sibling) {
285 if (sibling->id == item_id) {
286 item->parent->children.erase(sibling);
295 impl_->selected_id_ = -1;
296 impl_->id2item_.clear();
297 impl_->root_.children.clear();
301 auto item_it = impl_->id2item_.find(item_id);
302 if (item_it != impl_->id2item_.end()) {
303 return item_it->second->cell;
310 std::vector<TreeView::ItemId> children;
311 auto item_it = impl_->id2item_.find(parent_id);
312 if (item_it != impl_->id2item_.end()) {
313 auto *parent = item_it->second->parent;
315 children.reserve(parent->children.size());
316 for (
auto &child : parent->children) {
317 children.push_back(child.id);
325 return impl_->can_select_parents_;
329 impl_->can_select_parents_ = can_select;
333 if (impl_->selected_id_ < 0) {
334 return impl_->root_.id;
336 return impl_->selected_id_;
341 impl_->selected_id_ = item_id;
345 std::function<
void(
ItemId)> on_selection_changed) {
346 impl_->on_selection_changed_ = on_selection_changed;
369 float outer_scroll_y = ImGui::GetScrollY();
370 ImGui::SetCursorScreenPos(
371 ImVec2(
float(
frame.x),
float(
frame.y) - outer_scroll_y));
382 ImGui::PushStyleColor(ImGuiCol_HeaderActive,
384 ImGui::PushStyleColor(ImGuiCol_HeaderHovered,
387 ImGui::PushStyleColor(ImGuiCol_ChildBg,
392 ImGui::BeginChild(impl_->id_,
393 ImVec2(
float(
frame.width),
float(
frame.height)),
true);
407 if (item.id == impl_->selected_id_) {
412 auto y =
frame.y - outer_scroll_y + ImGui::GetCursorPosY() -
414 ImGui::GetWindowDrawList()->AddRectFilled(
415 ImVec2(
float(
frame.x), y),
420 int flags = ImGuiTreeNodeFlags_DefaultOpen |
421 ImGuiTreeNodeFlags_AllowItemOverlap;
422 if (impl_->can_select_parents_) {
423 flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick;
424 flags |= ImGuiTreeNodeFlags_OpenOnArrow;
426 if (item.children.empty()) {
427 flags |= ImGuiTreeNodeFlags_Leaf;
430 (item.children.empty() || impl_->can_select_parents_);
431 auto DrawThis = [
this, &tree_frame =
frame, &
context, &new_selection,
433 bool is_selectable) {
434 ImGui::SameLine(0, 0);
435 auto x = int(std::round(ImGui::GetCursorScreenPos().x));
436 auto y = int(std::round(
437 ImGui::GetCursorScreenPos().y ));
438 auto scroll_y = ImGui::GetScrollY();
439 auto scroll_width = int(ImGui::GetStyle().ScrollbarSize);
440 auto indent = x - tree_frame.x;
446 item.cell->SetFrame(
Rect(x, y + scroll_y,
447 tree_frame.width - indent - scroll_width,
456 auto this_result = item.cell->Draw(
context);
462 if (ImGui::IsItemClicked() && is_selectable) {
463 impl_->selected_id_ = item.id;
464 new_selection = &item;
468 if (ImGui::TreeNodeEx(item.id_string.c_str(), flags,
"%s",
"")) {
469 DrawThis(item,
height, is_selectable);
471 for (
auto &child : item.children) {
476 DrawThis(item,
height, is_selectable);
479 for (
auto &top : impl_->root_.children) {
485 ImGui::PopStyleColor(3);
493 if (impl_->on_selection_changed_) {
494 impl_->on_selection_changed_(new_selection->
id);
CheckableTextTreeCell(const char *text, bool is_checked, std::function< void(bool)> on_toggled)
std::shared_ptr< Checkbox > GetCheckbox()
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
std::shared_ptr< Label > GetLabel()
void Layout(const LayoutContext &context) override
void Layout(const LayoutContext &context) override
ColormapTreeCell(double value, const Color &color, std::function< void(double)> on_value_changed, std::function< void(const Color &)> on_color_changed)
std::shared_ptr< NumberEdit > GetNumberEdit()
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
std::shared_ptr< ColorEdit > GetColorEdit()
std::shared_ptr< Label > GetLabel()
void Layout(const LayoutContext &context) override
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
std::shared_ptr< ColorEdit > GetColorEdit()
std::shared_ptr< Checkbox > GetCheckbox()
LUTTreeCell(const char *text, bool is_checked, const Color &color, std::function< void(bool)> on_enabled, std::function< void(const Color &)> on_color_changed)
std::shared_ptr< Widget > GetItem(ItemId item_id) const
Returns item, or nullptr if item_id cannot be found.
void Clear()
Clears all the items.
void SetOnSelectionChanged(std::function< void(ItemId)> on_selection_changed)
void SetSelectedItemId(ItemId item_id)
Selects the indicated item of the list. Does not call onValueChanged.
ItemId AddTextItem(ItemId parent_id, const char *text)
Adds a text item to the tree.
void Layout(const LayoutContext &context) override
void SetCanSelectItemsWithChildren(bool can_select)
void RemoveItem(ItemId item_id)
Removes an item an all its children (if any) from the tree.
std::vector< ItemId > GetItemChildren(ItemId parent_id) const
ItemId GetRootItem() const
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
bool GetCanSelectItemsWithChildren() const
DrawResult Draw(const DrawContext &context) override
ItemId GetSelectedItemId() const
Returns the currently selected item id in the tree.
ItemId AddItem(ItemId parent_id, std::shared_ptr< Widget > item)
Adds an item to the tree.
Size CalcMinimumSize(const LayoutContext &context) const override
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
uint32_t colorToImguiRGBA(const Color &color)
ImVec4 colorToImgui(const Color &color)
Generic file read and write utility for python interface.
std::shared_ptr< Label > label_
std::shared_ptr< Checkbox > checkbox_
std::shared_ptr< ColorEdit > color_
std::shared_ptr< NumberEdit > value_
float color_width_percent
std::shared_ptr< Label > label_
std::shared_ptr< Checkbox > checkbox_
std::shared_ptr< ColorEdit > color_
std::shared_ptr< Widget > cell
std::list< Item > children
TreeView::ItemId selected_id_
std::function< void(TreeView::ItemId)> on_selection_changed_
std::unordered_map< TreeView::ItemId, Item * > id2item_
static TreeView::ItemId g_next_id