Skip to content

Commit c3dca77

Browse files
committed
Demo: rework Property Editor.
1 parent fd99494 commit c3dca77

File tree

4 files changed

+101
-75
lines changed

4 files changed

+101
-75
lines changed

docs/CHANGELOG.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ Other changes:
9898
- A helper ImGuiSelectionBasicStorage is provided to facilitate getting started in a typical app.
9999
- Documentation:
100100
- Wiki page https://github.com/ocornut/imgui/wiki/Multi-Select for API overview.
101-
- Demo code.
102-
- Headers are well commented.
101+
- Demo code + headers are well commented.
103102
- Added BeginMultiSelect(), EndMultiSelect(), SetNextItemSelectionUserData().
104103
- Added IsItemToggledSelection() for use if you need latest selection update during currnet iteration.
105104
- Added ImGuiMultiSelectIO and ImGuiSelectionRequest structures:

imgui.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -15710,6 +15710,12 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
1571015710
(flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
1571115711
(flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
1571215712
(flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
15713+
if (flags & ImGuiWindowFlags_ChildWindow)
15714+
BulletText("ChildFlags: 0x%08X (%s%s%s%s..)", window->ChildFlags,
15715+
(window->ChildFlags & ImGuiChildFlags_Border) ? "Border " : "",
15716+
(window->ChildFlags & ImGuiChildFlags_ResizeX) ? "ResizeX " : "",
15717+
(window->ChildFlags & ImGuiChildFlags_ResizeY) ? "ResizeY " : "",
15718+
(window->ChildFlags & ImGuiChildFlags_NavFlattened) ? "NavFlattened " : "");
1571315719
BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
1571415720
BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
1571515721
BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);

imgui.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ enum ImGuiWindowFlags_
10901090

10911091
// Obsolete names
10921092
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1093-
ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call.
1093+
ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call.
10941094
ImGuiWindowFlags_NavFlattened = 1 << 31, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call.
10951095
#endif
10961096
};
@@ -1115,7 +1115,7 @@ enum ImGuiChildFlags_
11151115
ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above.
11161116
ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED.
11171117
ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.
1118-
ImGuiChildFlags_NavFlattened = 1 << 8, // Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.
1118+
ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.
11191119
};
11201120

11211121
// Flags for ImGui::PushItemFlag()

imgui_demo.cpp

+92-71
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ struct ExampleTreeNode
269269

270270
// Leaf Data
271271
bool HasData = false; // All leaves have data
272-
bool DataMyBool = false;
272+
bool DataMyBool = true;
273273
int DataMyInt = 128;
274274
ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f);
275275
};
@@ -304,6 +304,7 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl
304304
}
305305

306306
// Create example tree data
307+
// (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
307308
static ExampleTreeNode* ExampleTree_CreateDemoTree()
308309
{
309310
static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
@@ -8600,101 +8601,121 @@ static void ShowExampleAppLayout(bool* p_open)
86008601
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
86018602
//-----------------------------------------------------------------------------
86028603
// Some of the interactions are a bit lack-luster:
8603-
// - We would want the table scrolling window to use NavFlattened.
86048604
// - We would want pressing validating or leaving the filter to somehow restore focus.
86058605
// - 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.
86068607
//-----------------------------------------------------------------------------
86078608

86088609
struct ExampleAppPropertyEditor
86098610
{
86108611
ImGuiTextFilter Filter;
8612+
ExampleTreeNode* VisibleNode = NULL;
86118613

86128614
void Draw(ExampleTreeNode* root_node)
86138615
{
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();
86208627

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)
86238643
{
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
86288651

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+
}
86338693
}
8694+
ImGui::EndGroup();
86348695
}
86358696

86368697
void DrawTreeNode(ExampleTreeNode* node)
86378698
{
8638-
// Object tree node
8639-
ImGui::PushID(node->UID);
86408699
ImGui::TableNextRow();
8641-
ImGui::TableSetColumnIndex(0);
8642-
ImGui::AlignTextToFramePadding();
8700+
ImGui::TableNextColumn();
8701+
ImGui::PushID(node->UID);
86438702
ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
8644-
tree_flags |= ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_AllowOverlap; // Highlight whole row for visibility
86458703
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
86468704
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;
86528716
if (node_open)
86538717
for (ExampleTreeNode* child : node->Childs)
86548718
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-
}
86988719
if (node_open)
86998720
ImGui::TreePop();
87008721
ImGui::PopID();

0 commit comments

Comments
 (0)