Internals: moved LastItem data to a shared structure (instead of one per window)

(should be a no-op as we are restoring things in Begin/End. Toward faciliate backup/restore of LastItemData and favor pulling from here instead of CurrentItemFlags, toward #211)
This commit is contained in:
ocornut 2021-07-19 21:08:22 +02:00
parent 1ad153056a
commit 6b8a059fc9
5 changed files with 159 additions and 165 deletions

174
imgui.cpp
View File

@ -3132,7 +3132,7 @@ void ImGui::MarkItemEdited(ImGuiID id)
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
g.ActiveIdHasBeenEditedThisFrame = true; g.ActiveIdHasBeenEditedThisFrame = true;
g.ActiveIdHasBeenEditedBefore = true; g.ActiveIdHasBeenEditedBefore = true;
g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
} }
static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
@ -3163,13 +3163,13 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (g.NavDisableMouseHover && !g.NavDisableHighlight) if (g.NavDisableMouseHover && !g.NavDisableHighlight)
{ {
if ((window->DC.LastItemInFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false; return false;
return IsItemFocused(); return IsItemFocused();
} }
// Test for bounding box overlap, as updated as ItemAdd() // Test for bounding box overlap, as updated as ItemAdd()
ImGuiItemStatusFlags status_flags = window->DC.LastItemStatusFlags; ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags;
if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
return false; return false;
IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
@ -3185,7 +3185,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
// Test if another item is active (e.g. being dragged) // Test if another item is active (e.g. being dragged)
if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
return false; return false;
// Test if interactions on this window are blocked by an active popup or modal. // Test if interactions on this window are blocked by an active popup or modal.
@ -3194,12 +3194,12 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false; return false;
// Test if the item is disabled // Test if the item is disabled
if ((window->DC.LastItemInFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false; return false;
// Special handling for calling after Begin() which represent the title bar or tab. // Special handling for calling after Begin() which represent the title bar or tab.
// When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
if (window->DC.LastItemId == window->MoveId && window->WriteAccessed) if (g.LastItemData.ID == window->MoveId && window->WriteAccessed)
return false; return false;
return true; return true;
} }
@ -3268,22 +3268,12 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged
return false; return false;
} }
// This is also inlined in ItemAdd()
// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect!
void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags item_status_flags, const ImRect& item_rect)
{
window->DC.LastItemId = item_id;
window->DC.LastItemInFlags = item_flags;
window->DC.LastItemStatusFlags = item_status_flags;
window->DC.LastItemRect = item_rect;
}
// Called by ItemAdd() // Called by ItemAdd()
// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out. // Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id) void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(id != 0 && id == window->DC.LastItemId); IM_ASSERT(id != 0 && id == g.LastItemData.ID);
// Increment counters // Increment counters
// FIXME: ImGuiItemFlags_Disabled should disable more. // FIXME: ImGuiItemFlags_Disabled should disable more.
@ -3309,13 +3299,13 @@ void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{ {
if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular) if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular)
{ {
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByCode; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
return; return;
} }
if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop) if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
{ {
g.NavJustTabbedId = id; g.NavJustTabbedId = id;
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
return; return;
} }
@ -4858,10 +4848,7 @@ bool ImGui::IsItemActive()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.ActiveId) if (g.ActiveId)
{ return g.ActiveId == g.LastItemData.ID;
ImGuiWindow* window = g.CurrentWindow;
return g.ActiveId == window->DC.LastItemId;
}
return false; return false;
} }
@ -4869,21 +4856,17 @@ bool ImGui::IsItemActivated()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.ActiveId) if (g.ActiveId)
{ if (g.ActiveId == g.LastItemData.ID && g.ActiveIdPreviousFrame != g.LastItemData.ID)
ImGuiWindow* window = g.CurrentWindow;
if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
return true; return true;
}
return false; return false;
} }
bool ImGui::IsItemDeactivated() bool ImGui::IsItemDeactivated()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated)
if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated) return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID);
return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
} }
bool ImGui::IsItemDeactivatedAfterEdit() bool ImGui::IsItemDeactivatedAfterEdit()
@ -4896,9 +4879,7 @@ bool ImGui::IsItemDeactivatedAfterEdit()
bool ImGui::IsItemFocused() bool ImGui::IsItemFocused()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; if (g.NavId != g.LastItemData.ID || g.NavId == 0)
if (g.NavId != window->DC.LastItemId || g.NavId == 0)
return false; return false;
return true; return true;
} }
@ -4913,13 +4894,13 @@ bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
bool ImGui::IsItemToggledOpen() bool ImGui::IsItemToggledOpen()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
} }
bool ImGui::IsItemToggledSelection() bool ImGui::IsItemToggledSelection()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false; return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
} }
bool ImGui::IsAnyItemHovered() bool ImGui::IsAnyItemHovered()
@ -4942,14 +4923,14 @@ bool ImGui::IsAnyItemFocused()
bool ImGui::IsItemVisible() bool ImGui::IsItemVisible()
{ {
ImGuiWindow* window = GetCurrentWindowRead(); ImGuiContext& g = *GImGui;
return window->ClipRect.Overlaps(window->DC.LastItemRect); return g.CurrentWindow->ClipRect.Overlaps(g.LastItemData.Rect);
} }
bool ImGui::IsItemEdited() bool ImGui::IsItemEdited()
{ {
ImGuiWindow* window = GetCurrentWindowRead(); ImGuiContext& g = *GImGui;
return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0; return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0;
} }
// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
@ -4957,7 +4938,7 @@ bool ImGui::IsItemEdited()
void ImGui::SetItemAllowOverlap() void ImGui::SetItemAllowOverlap()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiID id = g.CurrentWindow->DC.LastItemId; ImGuiID id = g.LastItemData.ID;
if (g.HoveredId == id) if (g.HoveredId == id)
g.HoveredIdAllowOverlap = true; g.HoveredIdAllowOverlap = true;
if (g.ActiveId == id) if (g.ActiveId == id)
@ -4967,7 +4948,7 @@ void ImGui::SetItemAllowOverlap()
void ImGui::SetItemUsingMouseWheel() void ImGui::SetItemUsingMouseWheel()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiID id = g.CurrentWindow->DC.LastItemId; ImGuiID id = g.LastItemData.ID;
if (g.HoveredId == id) if (g.HoveredId == id)
g.HoveredIdUsingMouseWheel = true; g.HoveredIdUsingMouseWheel = true;
if (g.ActiveId == id) if (g.ActiveId == id)
@ -4986,20 +4967,20 @@ void ImGui::SetActiveIdUsingNavAndKeys()
ImVec2 ImGui::GetItemRectMin() ImVec2 ImGui::GetItemRectMin()
{ {
ImGuiWindow* window = GetCurrentWindowRead(); ImGuiContext& g = *GImGui;
return window->DC.LastItemRect.Min; return g.LastItemData.Rect.Min;
} }
ImVec2 ImGui::GetItemRectMax() ImVec2 ImGui::GetItemRectMax()
{ {
ImGuiWindow* window = GetCurrentWindowRead(); ImGuiContext& g = *GImGui;
return window->DC.LastItemRect.Max; return g.LastItemData.Rect.Max;
} }
ImVec2 ImGui::GetItemRectSize() ImVec2 ImGui::GetItemRectSize()
{ {
ImGuiWindow* window = GetCurrentWindowRead(); ImGuiContext& g = *GImGui;
return window->DC.LastItemRect.GetSize(); return g.LastItemData.Rect.GetSize();
} }
bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
@ -5104,7 +5085,7 @@ void ImGui::EndChild()
ItemAdd(bb, 0); ItemAdd(bb, 0);
} }
if (g.HoveredWindow == window) if (g.HoveredWindow == window)
parent_window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
} }
g.WithinEndChild = false; g.WithinEndChild = false;
g.LogLinePosY = -FLT_MAX; // To enforce a carriage return g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
@ -5811,7 +5792,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
} }
// Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;
ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
@ -5821,7 +5802,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Add to stack // Add to stack
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
g.CurrentWindowStack.push_back(window); ImGuiWindowStackData window_stack_data;
window_stack_data.Window = window;
window_stack_data.ParentLastItemDataBackup = g.LastItemData;
g.CurrentWindowStack.push_back(window_stack_data);
g.CurrentWindow = window; g.CurrentWindow = window;
window->DC.StackSizesOnBegin.SetToCurrentState(); window->DC.StackSizesOnBegin.SetToCurrentState();
g.CurrentWindow = NULL; g.CurrentWindow = NULL;
@ -6334,11 +6318,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
// This is useful to allow creating context menus on title bar only, etc. // This is useful to allow creating context menus on title bar only, etc.
SetLastItemData(window, window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); g.LastItemData.ID = window->MoveId;
g.LastItemData.InFlags = g.CurrentItemFlags;
g.LastItemData.StatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
g.LastItemData.Rect = title_bar_rect;
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId); IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.Rect, g.LastItemData.ID);
#endif #endif
} }
else else
@ -6430,11 +6417,12 @@ void ImGui::End()
LogFinish(); LogFinish();
// Pop from window stack // Pop from window stack
g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup;
g.CurrentWindowStack.pop_back(); g.CurrentWindowStack.pop_back();
if (window->Flags & ImGuiWindowFlags_Popup) if (window->Flags & ImGuiWindowFlags_Popup)
g.BeginPopupStack.pop_back(); g.BeginPopupStack.pop_back();
window->DC.StackSizesOnBegin.CompareWithCurrentState(); window->DC.StackSizesOnBegin.CompareWithCurrentState();
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);
} }
void ImGui::BringWindowToFocusFront(ImGuiWindow* window) void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
@ -7060,8 +7048,8 @@ void ImGui::SetItemDefaultFocus()
if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent) if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent)
{ {
g.NavInitRequest = false; g.NavInitRequest = false;
g.NavInitResultId = window->DC.LastItemId; g.NavInitResultId = g.LastItemData.ID;
g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); g.NavInitResultRectRel = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos);
NavUpdateAnyRequestFlag(); NavUpdateAnyRequestFlag();
if (!IsItemVisible()) if (!IsItemVisible())
SetScrollHereY(); SetScrollHereY();
@ -7456,11 +7444,11 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
// Equivalent to calling SetLastItemData() // Set item data
window->DC.LastItemId = id; g.LastItemData.ID = id;
window->DC.LastItemRect = bb; g.LastItemData.Rect = bb;
window->DC.LastItemInFlags = g.CurrentItemFlags; g.LastItemData.InFlags = g.CurrentItemFlags;
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None;
g.NextItemData.Flags = ImGuiNextItemDataFlags_None; g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
// Directional navigation processing // Directional navigation processing
@ -7509,7 +7497,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
if (IsMouseHoveringRect(bb.Min, bb.Max)) if (IsMouseHoveringRect(bb.Min, bb.Max))
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
return true; return true;
} }
@ -7841,24 +7829,24 @@ void ImGui::EndGroup()
const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true); const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
if (group_contains_curr_active_id) if (group_contains_curr_active_id)
window->DC.LastItemId = g.ActiveId; g.LastItemData.ID = g.ActiveId;
else if (group_contains_prev_active_id) else if (group_contains_prev_active_id)
window->DC.LastItemId = g.ActiveIdPreviousFrame; g.LastItemData.ID = g.ActiveIdPreviousFrame;
window->DC.LastItemRect = group_bb; g.LastItemData.Rect = group_bb;
// Forward Hovered flag // Forward Hovered flag
const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0; const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;
if (group_contains_curr_hovered_id) if (group_contains_curr_hovered_id)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
// Forward Edited flag // Forward Edited flag
if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
// Forward Deactivated flag // Forward Deactivated flag
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated;
g.GroupStack.pop_back(); g.GroupStack.pop_back();
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
@ -8047,7 +8035,7 @@ void ImGui::SetScrollHereX(float center_x_ratio)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x); float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x);
float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio); float target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio);
SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
// Tweak: snap on edges when aiming at an item very close to the edge // Tweak: snap on edges when aiming at an item very close to the edge
@ -8443,12 +8431,13 @@ void ImGui::EndPopup()
// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup() // - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags) void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
{ {
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
OpenPopupEx(id, popup_flags); OpenPopupEx(id, popup_flags);
} }
} }
@ -8471,11 +8460,12 @@ void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags
// The main difference being that this is tweaked to avoid computing the ID twice. // The main difference being that this is tweaked to avoid computing the ID twice.
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags) bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems) if (window->SkipItems)
return false; return false;
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
OpenPopupEx(id, popup_flags); OpenPopupEx(id, popup_flags);
@ -8484,7 +8474,8 @@ bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flag
bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags) bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (!str_id) if (!str_id)
str_id = "window_context"; str_id = "window_context";
ImGuiID id = window->GetID(str_id); ImGuiID id = window->GetID(str_id);
@ -8497,7 +8488,8 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_fl
bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags) bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (!str_id) if (!str_id)
str_id = "void_context"; str_id = "void_context";
ImGuiID id = window->GetID(str_id); ImGuiID id = window->GetID(str_id);
@ -8608,7 +8600,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
// Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
// This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
IM_ASSERT(g.CurrentWindow == window); IM_ASSERT(g.CurrentWindow == window);
ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2].Window;
float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x).
ImRect r_avoid; ImRect r_avoid;
if (parent_window->DC.MenuBarAppending) if (parent_window->DC.MenuBarAppending)
@ -8672,8 +8664,8 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
g.NavLayer = nav_layer; g.NavLayer = nav_layer;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
window->NavLastIds[nav_layer] = id; window->NavLastIds[nav_layer] = id;
if (window->DC.LastItemId == id) if (g.LastItemData.ID == id)
window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); window->NavRectRel[nav_layer] = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos);
if (g.ActiveIdSource == ImGuiInputSource_Nav) if (g.ActiveIdSource == ImGuiInputSource_Nav)
g.NavDisableMouseHover = true; g.NavDisableMouseHover = true;
@ -8770,7 +8762,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
else else
{ {
// Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)
quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
} }
#if IMGUI_DEBUG_NAV_SCORING #if IMGUI_DEBUG_NAV_SCORING
@ -8858,7 +8850,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
//if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
// return; // return;
const ImGuiItemFlags item_flags = window->DC.LastItemInFlags; const ImGuiItemFlags item_flags = g.LastItemData.InFlags;
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
// Process Init Request // Process Init Request
@ -9853,7 +9845,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
ImGuiID source_parent_id = 0; ImGuiID source_parent_id = 0;
if (!(flags & ImGuiDragDropFlags_SourceExtern)) if (!(flags & ImGuiDragDropFlags_SourceExtern))
{ {
source_id = window->DC.LastItemId; source_id = g.LastItemData.ID;
if (source_id != 0) if (source_id != 0)
{ {
// Common path: items with ID // Common path: items with ID
@ -9880,7 +9872,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
} }
// Early out // Early out
if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
return false; return false;
// Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
@ -9888,8 +9880,8 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
// THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
// We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
// Rely on keeping other window->LastItemXXX fields intact. // Rely on keeping other window->LastItemXXX fields intact.
source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id); bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id);
if (is_hovered && g.IO.MouseClicked[mouse_button]) if (is_hovered && g.IO.MouseClicked[mouse_button])
{ {
SetActiveID(source_id, window); SetActiveID(source_id, window);
@ -9945,7 +9937,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
} }
if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
return true; return true;
} }
@ -10045,14 +10037,14 @@ bool ImGui::BeginDragDropTarget()
return false; return false;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect))
return false; return false;
ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow) if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
return false; return false;
const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect;
ImGuiID id = window->DC.LastItemId; ImGuiID id = g.LastItemData.ID;
if (id == 0) if (id == 0)
id = window->GetIDFromRectangle(display_rect); id = window->GetIDFromRectangle(display_rect);
if (g.DragDropPayload.SourceId == id) if (g.DragDropPayload.SourceId == id)

View File

@ -61,7 +61,7 @@ Index of this file:
// Version // Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
#define IMGUI_VERSION "1.84 WIP" #define IMGUI_VERSION "1.84 WIP"
#define IMGUI_VERSION_NUM 18310 #define IMGUI_VERSION_NUM 18311
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE

View File

@ -116,7 +116,7 @@ struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
struct ImGuiLastItemDataBackup; // Backup and restore IsItemHovered() internal data struct ImGuiLastItemData; // Status storage for last submitted items
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result
struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions
@ -1172,6 +1172,25 @@ struct ImGuiNextItemData
inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()! inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()!
}; };
// Status storage for the last submitted item
struct ImGuiLastItemData
{
ImGuiID ID;
ImGuiItemFlags InFlags;
ImGuiItemStatusFlags StatusFlags;
ImRect Rect;
ImRect DisplayRect;
ImGuiLastItemData() { memset(this, 0, sizeof(*this)); }
};
// Data saved for each window pushed into the stack
struct ImGuiWindowStackData
{
ImGuiWindow* Window;
ImGuiLastItemData ParentLastItemDataBackup;
};
struct ImGuiShrinkWidthItem struct ImGuiShrinkWidthItem
{ {
int Index; int Index;
@ -1414,7 +1433,7 @@ struct ImGuiContext
ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front
ImVector<ImGuiWindow*> WindowsFocusOrder; // Root windows, sorted in focus order, back to front. ImVector<ImGuiWindow*> WindowsFocusOrder; // Root windows, sorted in focus order, back to front.
ImVector<ImGuiWindow*> WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child ImVector<ImGuiWindow*> WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child
ImVector<ImGuiWindow*> CurrentWindowStack; ImVector<ImGuiWindowStackData> CurrentWindowStack;
ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow*
int WindowsActiveCount; // Number of unique windows submitted by frame int WindowsActiveCount; // Number of unique windows submitted by frame
ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING) ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING)
@ -1427,7 +1446,6 @@ struct ImGuiContext
float WheelingWindowTimer; float WheelingWindowTimer;
// Item/widgets state and tracking information // Item/widgets state and tracking information
ImGuiItemFlags CurrentItemFlags; // == g.ItemFlagsStack.back()
ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredId; // Hovered widget, filled during the frame
ImGuiID HoveredIdPreviousFrame; ImGuiID HoveredIdPreviousFrame;
bool HoveredIdAllowOverlap; bool HoveredIdAllowOverlap;
@ -1461,8 +1479,10 @@ struct ImGuiContext
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
// Next window/item data // Next window/item data
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions ImGuiItemFlags CurrentItemFlags; // == g.ItemFlagsStack.back()
ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions
ImGuiLastItemData LastItemData; // Storage for last submitted item (setup by ItemAdd)
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
// Shared stacks // Shared stacks
ImVector<ImGuiColorMod> ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin() ImVector<ImGuiColorMod> ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin()
@ -1659,7 +1679,6 @@ struct ImGuiContext
WheelingWindow = NULL; WheelingWindow = NULL;
WheelingWindowTimer = 0.0f; WheelingWindowTimer = 0.0f;
CurrentItemFlags = ImGuiItemFlags_None;
HoveredId = HoveredIdPreviousFrame = 0; HoveredId = HoveredIdPreviousFrame = 0;
HoveredIdAllowOverlap = false; HoveredIdAllowOverlap = false;
HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = false; HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = false;
@ -1689,6 +1708,8 @@ struct ImGuiContext
LastActiveId = 0; LastActiveId = 0;
LastActiveIdTimer = 0.0f; LastActiveIdTimer = 0.0f;
CurrentItemFlags = ImGuiItemFlags_None;
NavWindow = NULL; NavWindow = NULL;
NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0;
NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0;
@ -1806,13 +1827,6 @@ struct IMGUI_API ImGuiWindowTempData
ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
ImVec1 GroupOffset; ImVec1 GroupOffset;
// Last item status
ImGuiID LastItemId; // ID for last item
ImGuiItemFlags LastItemInFlags; // Copy of flags for last item (see ImGuiItemflags_), named "In" to avoid probably confusion with status flags
ImGuiItemStatusFlags LastItemStatusFlags; // Status flags for last item (see ImGuiItemStatusFlags_)
ImRect LastItemRect; // Interaction rect for last item
ImRect LastItemDisplayRect; // End-user display rect for last item (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
// Keyboard/Gamepad navigation // Keyboard/Gamepad navigation
ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
short NavLayersActiveMask; // Which layers have been written to (result from previous frame) short NavLayersActiveMask; // Which layers have been written to (result from previous frame)
@ -1959,20 +1973,6 @@ public:
ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
}; };
// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data.
struct ImGuiLastItemDataBackup
{
ImGuiID LastItemId;
ImGuiItemFlags LastItemInFlags;
ImGuiItemStatusFlags LastItemStatusFlags;
ImRect LastItemRect;
ImRect LastItemDisplayRect;
ImGuiLastItemDataBackup() { Backup(); }
void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemInFlags = window->DC.LastItemInFlags; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; }
void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemInFlags = LastItemInFlags; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; }
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Tab bar, Tab item support // [SECTION] Tab bar, Tab item support
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2381,11 +2381,11 @@ namespace ImGui
IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect); IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect);
// Basic Accessors // Basic Accessors
inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand) inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.LastItemData.ID; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand)
inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; } inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; }
inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; }
inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; }
inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; }
inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.CurrentItemFlags; }
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window);
IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window);
IMGUI_API void ClearActiveID(); IMGUI_API void ClearActiveID();
@ -2403,7 +2403,6 @@ namespace ImGui
IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id);
IMGUI_API void ItemFocusable(ImGuiWindow* window, ImGuiID id); IMGUI_API void ItemFocusable(ImGuiWindow* window, ImGuiID id);
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
IMGUI_API void SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect);
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h);
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
IMGUI_API void PushMultiItemsWidths(int components, float width_full); IMGUI_API void PushMultiItemsWidths(int components, float width_full);
@ -2667,7 +2666,7 @@ namespace ImGui
// Debug Tools // Debug Tools
IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); } inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); }
inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; }
IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas);

View File

@ -1956,8 +1956,9 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
window->SkipItems = column->IsSkipItems; window->SkipItems = column->IsSkipItems;
if (column->IsSkipItems) if (column->IsSkipItems)
{ {
window->DC.LastItemId = 0; ImGuiContext& g = *GImGui;
window->DC.LastItemStatusFlags = 0; g.LastItemData.ID = 0;
g.LastItemData.StatusFlags = 0;
} }
if (table->Flags & ImGuiTableFlags_NoClip) if (table->Flags & ImGuiTableFlags_NoClip)

View File

@ -502,7 +502,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
g.HoveredWindow = window; g.HoveredWindow = window;
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
if (id != 0 && window->DC.LastItemId != id) if (id != 0 && g.LastItemData.ID != id)
IMGUI_TEST_ENGINE_ITEM_ADD(bb, id); IMGUI_TEST_ENGINE_ITEM_ADD(bb, id);
#endif #endif
@ -699,7 +699,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
// CloseCurrentPopup(); // CloseCurrentPopup();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed; return pressed;
} }
@ -1076,7 +1076,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
ItemSize(total_bb, style.FramePadding.y); ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id)) if (!ItemAdd(total_bb, id))
{ {
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false; return false;
} }
@ -1112,7 +1112,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(label_pos, label); RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed; return pressed;
} }
@ -1214,7 +1214,7 @@ bool ImGui::RadioButton(const char* label, bool active)
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(label_pos, label); RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed; return pressed;
} }
@ -1438,7 +1438,7 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float
bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));
ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap);
if (hovered) if (hovered)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb
if (g.ActiveId != id) if (g.ActiveId != id)
SetItemAllowOverlap(); SetItemAllowOverlap();
@ -1696,9 +1696,9 @@ bool ImGui::BeginComboPreview()
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; ImGuiComboPreviewData* preview_data = &g.ComboPreviewData;
if (window->SkipItems || !window->ClipRect.Overlaps(window->DC.LastItemRect)) // FIXME: Because we don't have a ImGuiItemStatusFlags_Visible flag to test last ItemAdd() result if (window->SkipItems || !window->ClipRect.Overlaps(g.LastItemData.Rect)) // FIXME: Because we don't have a ImGuiItemStatusFlags_Visible flag to test last ItemAdd() result
return false; return false;
IM_ASSERT(window->DC.LastItemRect.Min.x == preview_data->PreviewRect.Min.x && window->DC.LastItemRect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag?
if (!window->ClipRect.Contains(preview_data->PreviewRect)) // Narrower test (optional) if (!window->ClipRect.Contains(preview_data->PreviewRect)) // Narrower test (optional)
return false; return false;
@ -1807,8 +1807,9 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
} }
EndCombo(); EndCombo();
if (value_changed) if (value_changed)
MarkItemEdited(g.CurrentWindow->DC.LastItemId); MarkItemEdited(g.LastItemData.ID);
return value_changed; return value_changed;
} }
@ -2398,7 +2399,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
if (!temp_input_is_active) if (!temp_input_is_active)
{ {
const bool focus_requested = temp_input_allowed && (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Focused) != 0; const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0;
const bool clicked = (hovered && g.IO.MouseClicked[0]); const bool clicked = (hovered && g.IO.MouseClicked[0]);
const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]); const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]);
if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id) if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id)
@ -2447,7 +2448,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return value_changed; return value_changed;
} }
@ -3014,7 +3015,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
if (!temp_input_is_active) if (!temp_input_is_active)
{ {
const bool focus_requested = temp_input_allowed && (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Focused) != 0; const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0;
const bool clicked = (hovered && g.IO.MouseClicked[0]); const bool clicked = (hovered && g.IO.MouseClicked[0]);
if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id) if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id)
{ {
@ -3059,7 +3060,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
if (label_size.x > 0.0f) if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return value_changed; return value_changed;
} }
@ -3471,7 +3472,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format);
} }
if (value_changed) if (value_changed)
MarkItemEdited(window->DC.LastItemId); MarkItemEdited(g.LastItemData.ID);
return value_changed; return value_changed;
} }
@ -4005,8 +4006,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// We are only allowed to access the state if we are already the active widget. // We are only allowed to access the state if we are already the active widget.
ImGuiInputTextState* state = GetInputTextState(id); ImGuiInputTextState* state = GetInputTextState(id);
const bool focus_requested_by_code = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_FocusedByCode) != 0; const bool focus_requested_by_code = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByCode) != 0;
const bool focus_requested_by_tabbing = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; const bool focus_requested_by_tabbing = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;
const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_clicked = hovered && io.MouseClicked[0];
const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard)); const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard));
@ -4725,7 +4726,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited))
MarkItemEdited(id); MarkItemEdited(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
return enter_pressed; return enter_pressed;
else else
@ -4908,7 +4909,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
// Store current color and open a picker // Store current color and open a picker
g.ColorPickerRef = col_v4; g.ColorPickerRef = col_v4;
OpenPopup("picker"); OpenPopup("picker");
SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1, style.ItemSpacing.y)); SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(-1, style.ItemSpacing.y));
} }
} }
if (!(flags & ImGuiColorEditFlags_NoOptions)) if (!(flags & ImGuiColorEditFlags_NoOptions))
@ -4965,7 +4966,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
// Drag and Drop Target // Drag and Drop Target
// NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test.
if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget())
{ {
bool accepted_drag_drop = false; bool accepted_drag_drop = false;
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
@ -4987,10 +4988,10 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
// When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4(). // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4().
if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)
window->DC.LastItemId = g.ActiveId; g.LastItemData.ID = g.ActiveId;
if (value_changed) if (value_changed)
MarkItemEdited(window->DC.LastItemId); MarkItemEdited(g.LastItemData.ID);
return value_changed; return value_changed;
} }
@ -5386,7 +5387,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0)
value_changed = false; value_changed = false;
if (value_changed) if (value_changed)
MarkItemEdited(window->DC.LastItemId); MarkItemEdited(g.LastItemData.ID);
PopID(); PopID();
@ -5819,14 +5820,14 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
bool item_add = ItemAdd(interact_bb, id); bool item_add = ItemAdd(interact_bb, id);
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
window->DC.LastItemDisplayRect = frame_bb; g.LastItemData.DisplayRect = frame_bb;
if (!item_add) if (!item_add)
{ {
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushOverrideID(id); TreePushOverrideID(id);
IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open; return is_open;
} }
@ -5900,7 +5901,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
{ {
is_open = !is_open; is_open = !is_open;
window->DC.StateStorage->SetInt(id, is_open); window->DC.StateStorage->SetInt(id, is_open);
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
} }
} }
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
@ -5908,7 +5909,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger.
if (selected != was_selected) //-V547 if (selected != was_selected) //-V547
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
// Render // Render
const ImU32 text_col = GetColorU32(ImGuiCol_Text); const ImU32 text_col = GetColorU32(ImGuiCol_Text);
@ -5952,7 +5953,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushOverrideID(id); TreePushOverrideID(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open; return is_open;
} }
@ -6056,14 +6057,14 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl
// FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
// FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiLastItemDataBackup last_item_backup; ImGuiLastItemData last_item_backup = g.LastItemData;
float button_size = g.FontSize; float button_size = g.FontSize;
float button_x = ImMax(window->DC.LastItemRect.Min.x, window->DC.LastItemRect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size);
float button_y = window->DC.LastItemRect.Min.y; float button_y = g.LastItemData.Rect.Min.y;
ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id);
if (CloseButton(close_button_id, ImVec2(button_x, button_y))) if (CloseButton(close_button_id, ImVec2(button_x, button_y)))
*p_visible = false; *p_visible = false;
last_item_backup.Restore(); g.LastItemData = last_item_backup;
} }
return is_open; return is_open;
@ -6206,7 +6207,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// In this branch, Selectable() cannot toggle the selection so this will never trigger. // In this branch, Selectable() cannot toggle the selection so this will never trigger.
if (selected != was_selected) //-V547 if (selected != was_selected) //-V547
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
// Render // Render
if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld))
@ -6232,7 +6233,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (disabled_item && !disabled_global) if (disabled_item && !disabled_global)
PopDisabled(); PopDisabled();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed; return pressed;
} }
@ -6365,8 +6366,9 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
PopID(); PopID();
} }
EndListBox(); EndListBox();
if (value_changed) if (value_changed)
MarkItemEdited(g.CurrentWindow->DC.LastItemId); MarkItemEdited(g.LastItemData.ID);
return value_changed; return value_changed;
} }
@ -6928,7 +6930,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None)) if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None))
ClosePopupToLevel(g.BeginPopupStack.Size, true); ClosePopupToLevel(g.BeginPopupStack.Size, true);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));
PopID(); PopID();
if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size)
@ -7025,7 +7027,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
if (selected) if (selected)
RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
} }
IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
if (!enabled) if (!enabled)
PopDisabled(); PopDisabled();
PopID(); PopID();
@ -7842,7 +7844,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// If the user called us with *p_open == false, we early out and don't render. // If the user called us with *p_open == false, we early out and don't render.
// We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. // We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID.
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
if (p_open && !*p_open) if (p_open && !*p_open)
{ {
PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true);
@ -8146,12 +8148,12 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
if (close_button_visible) if (close_button_visible)
{ {
ImGuiLastItemDataBackup last_item_backup; ImGuiLastItemData last_item_backup = g.LastItemData;
PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding);
if (CloseButton(close_button_id, button_pos)) if (CloseButton(close_button_id, button_pos))
close_button_pressed = true; close_button_pressed = true;
PopStyleVar(); PopStyleVar();
last_item_backup.Restore(); g.LastItemData = last_item_backup;
// Close with middle mouse button // Close with middle mouse button
if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))