Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
- Fix linker error "library limit of 65535 objects exceeded" with Ninja generator on MSVC (PR #7335)
- Download tarballs instead of Git repos for "3rdparty/uvatlas" (PR #7371)
- macOS x86_64 not longer supported, only macOS arm64 is supported.
- Add expand/collapse state support for TreeView items in GUI (PR #7451)


## 0.13
Expand Down
31 changes: 28 additions & 3 deletions cpp/open3d/visualization/gui/TreeView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <cmath>
#include <list>
#include <optional>
#include <sstream>
#include <unordered_map>

Expand Down Expand Up @@ -212,6 +213,7 @@ struct TreeView::Impl {
std::shared_ptr<Widget> cell;
Item *parent = nullptr;
std::list<Item> children;
std::optional<bool> expanded;
};
int id_;
Item root_;
Expand Down Expand Up @@ -361,6 +363,22 @@ void TreeView::Layout(const LayoutContext &context) {
// to defer layout to Draw().
}

bool TreeView::IsItemExpanded(ItemId item_id) const {
auto it = impl_->id2item_.find(item_id);
if (it == impl_->id2item_.end()) {
return false;
}
return it->second->expanded.value_or(true);
}

void TreeView::SetItemExpanded(ItemId item_id, bool expanded) {
auto it = impl_->id2item_.find(item_id);
if (it == impl_->id2item_.end()) {
return;
}
it->second->expanded = expanded;
}

Widget::DrawResult TreeView::Draw(const DrawContext &context) {
auto result = Widget::DrawResult::NONE;
auto &frame = GetFrame();
Expand Down Expand Up @@ -417,8 +435,12 @@ Widget::DrawResult TreeView::Draw(const DrawContext &context) {
colorToImguiRGBA(context.theme.tree_selected_color));
}

int flags = ImGuiTreeNodeFlags_DefaultOpen |
ImGuiTreeNodeFlags_AllowItemOverlap;
int flags = ImGuiTreeNodeFlags_AllowItemOverlap;
bool expanded = item.expanded.value_or(true);

if (expanded) {
flags |= ImGuiTreeNodeFlags_DefaultOpen;
}
if (impl_->can_select_parents_) {
flags |= ImGuiTreeNodeFlags_OpenOnDoubleClick;
flags |= ImGuiTreeNodeFlags_OpenOnArrow;
Expand Down Expand Up @@ -465,7 +487,10 @@ Widget::DrawResult TreeView::Draw(const DrawContext &context) {
}
};

if (ImGui::TreeNodeEx(item.id_string.c_str(), flags, "%s", "")) {
bool open = ImGui::TreeNodeEx(item.id_string.c_str(), flags, "%s", "");
item.expanded = open;

if (open) {
DrawThis(item, height, is_selectable);

for (auto &child : item.children) {
Expand Down
3 changes: 3 additions & 0 deletions cpp/open3d/visualization/gui/TreeView.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ class TreeView : public Widget {
void SetOnSelectionChanged(
std::function<void(ItemId)> on_selection_changed);

bool IsItemExpanded(ItemId item_id) const;
void SetItemExpanded(ItemId item_id, bool expanded);

private:
struct Impl;
std::unique_ptr<Impl> impl_;
Expand Down
4 changes: 3 additions & 1 deletion cpp/pybind/visualization/gui/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1664,7 +1664,9 @@ void pybind_gui_definitions(py::module &m) {
"The currently selected item")
.def("set_on_selection_changed", &TreeView::SetOnSelectionChanged,
"Sets f(new_item_id) which is called when the user "
"changes the selection.");
"changes the selection.")
.def("is_item_expanded", &TreeView::IsItemExpanded)
.def("set_item_expanded", &TreeView::SetItemExpanded);

// ---- TreeView cells ----
auto checkable_cell = static_cast<
Expand Down
14 changes: 14 additions & 0 deletions cpp/tests/visualization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,17 @@ if (BUILD_GUI)
rendering/MaterialModifier.cpp
)
endif()


add_executable(TreeViewTest
TreeViewTest.cpp
)

target_link_libraries(TreeViewTest
PRIVATE
Open3D::Open3D
)

set_target_properties(TreeViewTest PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
45 changes: 45 additions & 0 deletions cpp/tests/visualization/TreeViewTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <thread>
#include <chrono>

#include "open3d/visualization/gui/Application.h"
#include "open3d/visualization/gui/Window.h"
#include "open3d/visualization/gui/TreeView.h"
#include "open3d/visualization/gui/Layout.h"

using namespace open3d::visualization::gui;

int main() {
auto& app = Application::GetInstance();
app.Initialize();

auto window = std::make_shared<Window>("TreeView GUI Test", 400, 300);

// Layout
auto layout = std::make_shared<Vert>(10); // spacing = 10

// TreeView
auto tree = std::make_shared<TreeView>();
auto root = tree->GetRootItem();
tree->AddTextItem(root, "Item A");
tree->AddTextItem(root, "Item B");

layout->AddChild(tree);
window->AddChild(layout);

app.AddWindow(window);

// Close automatically after 2 seconds
app.PostToMainThread(nullptr, []() {
// NOTE:
// This is a GUI smoke test.
// The window is shown briefly to ensure TreeView can be
// created, attached, and rendered without crashing.
// The application exits automatically to avoid blocking CI.

std::this_thread::sleep_for(std::chrono::seconds(2));
Application::GetInstance().Quit();
});

app.Run();
return 0;
}
Empty file added git
Empty file.
Empty file added treeview-clean
Empty file.