TreeNode: Internals: facilitate dissociating item ID from storage ID (useful for 1861)

This commit is contained in:
ocornut 2024-07-17 19:19:52 +02:00
parent 8bab3eab6a
commit 7c6d4ff28d
2 changed files with 31 additions and 25 deletions

View File

@ -3461,13 +3461,15 @@ namespace ImGui
IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags);
IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);
IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0);
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
IMGUI_API void TreePushOverrideID(ImGuiID id);
IMGUI_API bool TreeNodeIsOpen(ImGuiID id);
IMGUI_API void TreeNodeSetOpen(ImGuiID id, bool open);
IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.
IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data);
// Widgets: Tree Nodes
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
IMGUI_API void TreePushOverrideID(ImGuiID id);
IMGUI_API bool TreeNodeIsOpen(ImGuiID storage_id);
IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open);
IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
// e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); "

View File

@ -6195,7 +6195,8 @@ bool ImGui::TreeNode(const char* label)
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
return TreeNodeBehavior(window->GetID(label), 0, label, NULL);
ImGuiID id = window->GetID(label);
return TreeNodeBehavior(id, id, ImGuiTreeNodeFlags_None, label, NULL);
}
bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args)
@ -6213,8 +6214,8 @@ bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags)
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
return TreeNodeBehavior(window->GetID(label), flags, label, NULL);
ImGuiID id = window->GetID(label);
return TreeNodeBehavior(id, id, flags, label, NULL);
}
bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
@ -6241,9 +6242,10 @@ bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char
if (window->SkipItems)
return false;
ImGuiID id = window->GetID(str_id);
const char* label, *label_end;
ImFormatStringToTempBufferV(&label, &label_end, fmt, args);
return TreeNodeBehavior(window->GetID(str_id), flags, label, label_end);
return TreeNodeBehavior(id, id, flags, label, label_end);
}
bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
@ -6252,26 +6254,27 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char
if (window->SkipItems)
return false;
ImGuiID id = window->GetID(ptr_id);
const char* label, *label_end;
ImFormatStringToTempBufferV(&label, &label_end, fmt, args);
return TreeNodeBehavior(window->GetID(ptr_id), flags, label, label_end);
return TreeNodeBehavior(id, id, flags, label, label_end);
}
bool ImGui::TreeNodeIsOpen(ImGuiID id)
bool ImGui::TreeNodeIsOpen(ImGuiID storage_id)
{
ImGuiContext& g = *GImGui;
ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage;
return storage->GetInt(id, 0) != 0;
return storage->GetInt(storage_id, 0) != 0;
}
void ImGui::TreeNodeSetOpen(ImGuiID id, bool open)
void ImGui::TreeNodeSetOpen(ImGuiID storage_id, bool open)
{
ImGuiContext& g = *GImGui;
ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage;
storage->SetInt(id, open ? 1 : 0);
storage->SetInt(storage_id, open ? 1 : 0);
}
bool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags)
{
if (flags & ImGuiTreeNodeFlags_Leaf)
return true;
@ -6287,16 +6290,16 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
if (g.NextItemData.OpenCond & ImGuiCond_Always)
{
is_open = g.NextItemData.OpenVal;
TreeNodeSetOpen(id, is_open);
TreeNodeSetOpen(storage_id, is_open);
}
else
{
// We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently.
const int stored_value = storage->GetInt(id, -1);
const int stored_value = storage->GetInt(storage_id, -1);
if (stored_value == -1)
{
is_open = g.NextItemData.OpenVal;
TreeNodeSetOpen(id, is_open);
TreeNodeSetOpen(storage_id, is_open);
}
else
{
@ -6306,7 +6309,7 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
}
else
{
is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
is_open = storage->GetInt(storage_id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
}
// When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior).
@ -6333,7 +6336,8 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags)
window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth);
}
bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
// When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced user code doing storage queries outside of UI loop.
bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@ -6386,7 +6390,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
}
// Compute open and multi-select states before ItemAdd() as it clear NextItem data.
bool is_open = TreeNodeUpdateNextOpen(id, flags);
bool is_open = TreeNodeUpdateNextOpen(storage_id, flags);
bool item_add = ItemAdd(interact_bb, id);
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
g.LastItemData.DisplayRect = frame_bb;
@ -6498,7 +6502,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (toggled)
{
is_open = !is_open;
window->DC.StateStorage->SetInt(id, is_open);
window->DC.StateStorage->SetInt(storage_id, is_open);
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
}
}
@ -6639,8 +6643,8 @@ bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags)
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label);
ImGuiID id = window->GetID(label);
return TreeNodeBehavior(id, id, flags | ImGuiTreeNodeFlags_CollapsingHeader, label);
}
// p_visible == NULL : regular collapsing header
@ -6660,7 +6664,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl
flags |= ImGuiTreeNodeFlags_CollapsingHeader;
if (p_visible)
flags |= ImGuiTreeNodeFlags_AllowOverlap | (ImGuiTreeNodeFlags)ImGuiTreeNodeFlags_ClipLabelForTrailingButton;
bool is_open = TreeNodeBehavior(id, flags, label);
bool is_open = TreeNodeBehavior(id, id, flags, label);
if (p_visible != NULL)
{
// Create a small overlapping close button