@@ -269,7 +269,7 @@ struct ExampleTreeNode
269
269
270
270
// Leaf Data
271
271
bool HasData = false; // All leaves have data
272
- bool DataMyBool = false ;
272
+ bool DataMyBool = true ;
273
273
int DataMyInt = 128;
274
274
ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f);
275
275
};
@@ -304,6 +304,7 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl
304
304
}
305
305
306
306
// Create example tree data
307
+ // (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
307
308
static ExampleTreeNode* ExampleTree_CreateDemoTree()
308
309
{
309
310
static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
@@ -8600,101 +8601,121 @@ static void ShowExampleAppLayout(bool* p_open)
8600
8601
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
8601
8602
//-----------------------------------------------------------------------------
8602
8603
// Some of the interactions are a bit lack-luster:
8603
- // - We would want the table scrolling window to use NavFlattened.
8604
8604
// - We would want pressing validating or leaving the filter to somehow restore focus.
8605
8605
// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
8606
+ // - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
8606
8607
//-----------------------------------------------------------------------------
8607
8608
8608
8609
struct ExampleAppPropertyEditor
8609
8610
{
8610
8611
ImGuiTextFilter Filter;
8612
+ ExampleTreeNode* VisibleNode = NULL;
8611
8613
8612
8614
void Draw(ExampleTreeNode* root_node)
8613
8615
{
8614
- ImGui::SetNextItemWidth(-FLT_MIN);
8615
- ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
8616
- ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
8617
- if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
8618
- Filter.Build();
8619
- ImGui::PopItemFlag();
8616
+ // Left side: draw tree
8617
+ // - Currently using a table to benefit from RowBg feature
8618
+ // - Using ImGuiChildFlags_NavFlattened exhibit a bug where clicking on root window decoration sets focus to root window
8619
+ if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Border))
8620
+ {
8621
+ ImGui::SetNextItemWidth(-FLT_MIN);
8622
+ ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
8623
+ ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
8624
+ if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
8625
+ Filter.Build();
8626
+ ImGui::PopItemFlag();
8620
8627
8621
- ImGuiTableFlags table_flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg;
8622
- if (ImGui::BeginTable("##split", 2, table_flags))
8628
+ if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg))
8629
+ {
8630
+ for (ExampleTreeNode* node : root_node->Childs)
8631
+ if (Filter.PassFilter(node->Name)) // Filter root node
8632
+ DrawTreeNode(node);
8633
+ ImGui::EndTable();
8634
+ }
8635
+ }
8636
+ ImGui::EndChild();
8637
+
8638
+ // Right side: draw properties
8639
+ ImGui::SameLine();
8640
+
8641
+ ImGui::BeginGroup(); // Lock X position
8642
+ if (ExampleTreeNode* node = VisibleNode)
8623
8643
{
8624
- ImGui::TableSetupColumn("Object", ImGuiTableColumnFlags_WidthStretch, 1.0f);
8625
- ImGui::TableSetupColumn("Contents", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
8626
- //ImGui::TableSetupScrollFreeze(0, 1);
8627
- //ImGui::TableHeadersRow();
8644
+ ImGui::Text("%s", node->Name);
8645
+ ImGui::TextDisabled("UID: 0x%08X", node->UID);
8646
+ ImGui::Separator();
8647
+ if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
8648
+ {
8649
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
8650
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
8628
8651
8629
- for (ExampleTreeNode* node : root_node->Childs)
8630
- if (Filter.PassFilter(node->Name)) // Filter root node
8631
- DrawTreeNode(node);
8632
- ImGui::EndTable();
8652
+ if (node && node->HasData)
8653
+ {
8654
+ // In a typical application, the structure description would be derived from a data-driven system.
8655
+ // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
8656
+ // - Limits and some details are hard-coded to simplify the demo.
8657
+ for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
8658
+ {
8659
+ ImGui::TableNextRow();
8660
+ ImGui::PushID(field_desc.Name);
8661
+ ImGui::TableNextColumn();
8662
+ ImGui::TextUnformatted(field_desc.Name);
8663
+ ImGui::TableNextColumn();
8664
+ void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
8665
+ switch (field_desc.DataType)
8666
+ {
8667
+ case ImGuiDataType_Bool:
8668
+ {
8669
+ IM_ASSERT(field_desc.DataCount == 1);
8670
+ ImGui::Checkbox("##Editor", (bool*)field_ptr);
8671
+ break;
8672
+ }
8673
+ case ImGuiDataType_S32:
8674
+ {
8675
+ int v_min = INT_MIN, v_max = INT_MAX;
8676
+ ImGui::SetNextItemWidth(-FLT_MIN);
8677
+ ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
8678
+ break;
8679
+ }
8680
+ case ImGuiDataType_Float:
8681
+ {
8682
+ float v_min = 0.0f, v_max = 1.0f;
8683
+ ImGui::SetNextItemWidth(-FLT_MIN);
8684
+ ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
8685
+ break;
8686
+ }
8687
+ }
8688
+ ImGui::PopID();
8689
+ }
8690
+ }
8691
+ ImGui::EndTable();
8692
+ }
8633
8693
}
8694
+ ImGui::EndGroup();
8634
8695
}
8635
8696
8636
8697
void DrawTreeNode(ExampleTreeNode* node)
8637
8698
{
8638
- // Object tree node
8639
- ImGui::PushID(node->UID);
8640
8699
ImGui::TableNextRow();
8641
- ImGui::TableSetColumnIndex(0 );
8642
- ImGui::AlignTextToFramePadding( );
8700
+ ImGui::TableNextColumn( );
8701
+ ImGui::PushID(node->UID );
8643
8702
ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
8644
- tree_flags |= ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_AllowOverlap; // Highlight whole row for visibility
8645
8703
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
8646
8704
tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
8647
- bool node_open = ImGui::TreeNodeEx("##Object", tree_flags, "%s", node->Name);
8648
- ImGui::TableSetColumnIndex(1);
8649
- ImGui::TextDisabled("UID: 0x%08X", node->UID);
8650
-
8651
- // Display child and data
8705
+ if (node == VisibleNode)
8706
+ tree_flags |= ImGuiTreeNodeFlags_Selected;
8707
+ if (node->Childs.Size == 0)
8708
+ tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
8709
+ if (node->DataMyBool == false)
8710
+ ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
8711
+ bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
8712
+ if (node->DataMyBool == false)
8713
+ ImGui::PopStyleColor();
8714
+ if (ImGui::IsItemFocused())
8715
+ VisibleNode = node;
8652
8716
if (node_open)
8653
8717
for (ExampleTreeNode* child : node->Childs)
8654
8718
DrawTreeNode(child);
8655
- if (node_open && node->HasData)
8656
- {
8657
- // In a typical application, the structure description would be derived from a data-driven system.
8658
- // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
8659
- // - Limits and some details are hard-coded to simplify the demo.
8660
- // - Text and Selectable are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the selectable lines equal high.
8661
- for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
8662
- {
8663
- ImGui::TableNextRow();
8664
- ImGui::TableSetColumnIndex(0);
8665
- ImGui::AlignTextToFramePadding();
8666
- ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop | ImGuiItemFlags_NoNav, true);
8667
- ImGui::Selectable(field_desc.Name, false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
8668
- ImGui::PopItemFlag();
8669
- ImGui::TableSetColumnIndex(1);
8670
- ImGui::PushID(field_desc.Name);
8671
- void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
8672
- switch (field_desc.DataType)
8673
- {
8674
- case ImGuiDataType_Bool:
8675
- {
8676
- IM_ASSERT(field_desc.DataCount == 1);
8677
- ImGui::Checkbox("##Editor", (bool*)field_ptr);
8678
- break;
8679
- }
8680
- case ImGuiDataType_S32:
8681
- {
8682
- int v_min = INT_MIN, v_max = INT_MAX;
8683
- ImGui::SetNextItemWidth(-FLT_MIN);
8684
- ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
8685
- break;
8686
- }
8687
- case ImGuiDataType_Float:
8688
- {
8689
- float v_min = 0.0f, v_max = 1.0f;
8690
- ImGui::SetNextItemWidth(-FLT_MIN);
8691
- ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
8692
- break;
8693
- }
8694
- }
8695
- ImGui::PopID();
8696
- }
8697
- }
8698
8719
if (node_open)
8699
8720
ImGui::TreePop();
8700
8721
ImGui::PopID();
0 commit comments