From f2699de24241bedad05b18dfe5beba623ba77dcf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 14:18:10 +0200 Subject: [PATCH] Fix using IsItemActive() after EndGroup() or any widget using groups (#840, #479) --- imgui.cpp | 19 ++++++++++++------- imgui_internal.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 71cc3a42b..afd587246 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7609,11 +7609,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const ImGuiIO& io = g.IO; const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; + if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn + BeginGroup(); + const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); @@ -7622,7 +7624,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 ImGuiWindow* draw_window = window; if (is_multiline) { - BeginGroup(); if (!BeginChildFrame(id, frame_bb.GetSize())) { EndChildFrame(); @@ -8149,8 +8150,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line EndChildFrame(); EndGroup(); - if (g.ActiveId == id || is_currently_scrolling) // Set LastItemId which was lost by EndChild/EndGroup, so user can use IsItemActive() - window->DC.LastItemId = g.ActiveId; } if (is_password) @@ -8204,7 +8203,7 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data if (!(extra_flags & ImGuiInputTextFlags_CharsHexadecimal)) extra_flags |= ImGuiInputTextFlags_CharsDecimal; extra_flags |= ImGuiInputTextFlags_AutoSelectAll; - if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) + if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format); // Step buttons @@ -9155,6 +9154,7 @@ void ImGui::BeginGroup() group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupLogLinePosY = window->DC.LogLinePosY; + group_data.BackupActiveIdIsAlive = GImGui->ActiveIdIsAlive; group_data.AdvanceCursor = true; window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; @@ -9166,15 +9166,15 @@ void ImGui::BeginGroup() void ImGui::EndGroup() { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - ImGuiStyle& style = GetStyle(); IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls ImGuiGroupData& group_data = window->DC.GroupStack.back(); ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); - group_bb.Max.y -= style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. + group_bb.Max.y -= g.Style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. group_bb.Max = ImMax(group_bb.Min, group_bb.Max); window->DC.CursorPos = group_data.BackupCursorPos; @@ -9192,6 +9192,11 @@ void ImGui::EndGroup() ItemAdd(group_bb, NULL); } + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will function on the entire group. + // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but if you search for LastItemId you'll notice it is only used in that context. + if (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow) + window->DC.LastItemId = g.ActiveId; + window->DC.GroupStack.pop_back(); //window->DrawList->AddRect(group_bb.Min, group_bb.Max, 0xFFFF00FF); // Debug diff --git a/imgui_internal.h b/imgui_internal.h index f4a0d6889..4bfec9dcd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -266,6 +266,7 @@ struct ImGuiGroupData float BackupCurrentLineHeight; float BackupCurrentLineTextBaseOffset; float BackupLogLinePosY; + bool BackupActiveIdIsAlive; bool AdvanceCursor; };