Merge branch 'master' into docking

# Conflicts:
#	imgui.cpp
#	imgui_internal.h
This commit is contained in:
ocornut
2021-07-19 21:58:06 +02:00
6 changed files with 200 additions and 181 deletions

204
imgui.cpp
View File

@ -1095,7 +1095,7 @@ ImGuiIO::ImGuiIO()
DisplaySize = ImVec2(-1.0f, -1.0f);
DeltaTime = 1.0f / 60.0f;
IniSavingRate = 5.0f;
IniFilename = "imgui.ini";
IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables).
LogFilename = "imgui_log.txt";
MouseDoubleClickTime = 0.30f;
MouseDoubleClickMaxDist = 6.0f;
@ -3177,7 +3177,7 @@ void ImGui::MarkItemEdited(ImGuiID id)
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
g.ActiveIdHasBeenEditedThisFrame = true;
g.ActiveIdHasBeenEditedBefore = true;
g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
}
static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
@ -3213,10 +3213,14 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.NavDisableMouseHover && !g.NavDisableHighlight)
{
if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
return IsItemFocused();
}
// 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))
return false;
IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
@ -3232,7 +3236,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
// Test if another item is active (e.g. being dragged)
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;
// Test if interactions on this window are blocked by an active popup or modal.
@ -3241,12 +3245,12 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false;
// Test if the item is disabled
if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
// 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.
if ((window->DC.LastItemId == window->ID || window->DC.LastItemId == window->MoveId) && window->WriteAccessed)
if ((g.LastItemData.ID == window->ID || g.LastItemData.ID == window->MoveId) && window->WriteAccessed)
return false;
return true;
}
@ -3279,8 +3283,12 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
SetHoveredID(id);
// When disabled we'll return false but still set HoveredId
if (g.CurrentItemFlags & ImGuiItemFlags_Disabled)
ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags);
if (item_flags & ImGuiItemFlags_Disabled)
{
// Release active id if turning disabled
if (g.ActiveId == id)
ClearActiveID();
g.HoveredIdDisabled = true;
return false;
}
@ -3314,22 +3322,25 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged
// 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, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
{
window->DC.LastItemId = item_id;
window->DC.LastItemStatusFlags = item_flags;
window->DC.LastItemRect = item_rect;
ImGuiContext& g = *GImGui;
g.LastItemData.ID = item_id;
g.LastItemData.InFlags = in_flags;
g.LastItemData.StatusFlags = item_flags;
g.LastItemData.Rect = item_rect;
}
// Called by ItemAdd()
// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(id != 0 && id == window->DC.LastItemId);
IM_ASSERT(id != 0 && id == g.LastItemData.ID);
// Increment counters
// FIXME: ImGuiItemFlags_Disabled should disable more.
const bool is_tab_stop = (g.CurrentItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
const bool is_tab_stop = (g.LastItemData.InFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
window->DC.FocusCounterRegular++;
if (is_tab_stop)
{
@ -3351,13 +3362,13 @@ void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{
if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular)
{
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
return;
}
if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
{
g.NavJustTabbedId = id;
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
return;
}
@ -3760,8 +3771,6 @@ static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta)
window->DC.CursorPos += delta;
window->DC.CursorStartPos += delta;
window->DC.CursorMaxPos += delta;
window->DC.LastItemRect.Translate(delta);
window->DC.LastItemDisplayRect.Translate(delta);
}
static void ScaleWindow(ImGuiWindow* window, float scale)
@ -5109,10 +5118,7 @@ bool ImGui::IsItemActive()
{
ImGuiContext& g = *GImGui;
if (g.ActiveId)
{
ImGuiWindow* window = g.CurrentWindow;
return g.ActiveId == window->DC.LastItemId;
}
return g.ActiveId == g.LastItemData.ID;
return false;
}
@ -5120,21 +5126,17 @@ bool ImGui::IsItemActivated()
{
ImGuiContext& g = *GImGui;
if (g.ActiveId)
{
ImGuiWindow* window = g.CurrentWindow;
if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
if (g.ActiveId == g.LastItemData.ID && g.ActiveIdPreviousFrame != g.LastItemData.ID)
return true;
}
return false;
}
bool ImGui::IsItemDeactivated()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated)
return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID);
}
bool ImGui::IsItemDeactivatedAfterEdit()
@ -5147,14 +5149,13 @@ bool ImGui::IsItemDeactivatedAfterEdit()
bool ImGui::IsItemFocused()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.NavId != window->DC.LastItemId || g.NavId == 0)
if (g.NavId != g.LastItemData.ID || g.NavId == 0)
return false;
// Special handling for the dummy item 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.
if (window->DC.LastItemId == window->ID && window->WriteAccessed)
ImGuiWindow* window = g.CurrentWindow;
if (g.LastItemData.ID == window->ID && window->WriteAccessed)
return false;
return true;
@ -5170,13 +5171,13 @@ bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
bool ImGui::IsItemToggledOpen()
{
ImGuiContext& g = *GImGui;
return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
}
bool ImGui::IsItemToggledSelection()
{
ImGuiContext& g = *GImGui;
return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
}
bool ImGui::IsAnyItemHovered()
@ -5199,14 +5200,14 @@ bool ImGui::IsAnyItemFocused()
bool ImGui::IsItemVisible()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->ClipRect.Overlaps(window->DC.LastItemRect);
ImGuiContext& g = *GImGui;
return g.CurrentWindow->ClipRect.Overlaps(g.LastItemData.Rect);
}
bool ImGui::IsItemEdited()
{
ImGuiWindow* window = GetCurrentWindowRead();
return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
ImGuiContext& g = *GImGui;
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.
@ -5214,7 +5215,7 @@ bool ImGui::IsItemEdited()
void ImGui::SetItemAllowOverlap()
{
ImGuiContext& g = *GImGui;
ImGuiID id = g.CurrentWindow->DC.LastItemId;
ImGuiID id = g.LastItemData.ID;
if (g.HoveredId == id)
g.HoveredIdAllowOverlap = true;
if (g.ActiveId == id)
@ -5224,7 +5225,7 @@ void ImGui::SetItemAllowOverlap()
void ImGui::SetItemUsingMouseWheel()
{
ImGuiContext& g = *GImGui;
ImGuiID id = g.CurrentWindow->DC.LastItemId;
ImGuiID id = g.LastItemData.ID;
if (g.HoveredId == id)
g.HoveredIdUsingMouseWheel = true;
if (g.ActiveId == id)
@ -5243,20 +5244,20 @@ void ImGui::SetActiveIdUsingNavAndKeys()
ImVec2 ImGui::GetItemRectMin()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.LastItemRect.Min;
ImGuiContext& g = *GImGui;
return g.LastItemData.Rect.Min;
}
ImVec2 ImGui::GetItemRectMax()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.LastItemRect.Max;
ImGuiContext& g = *GImGui;
return g.LastItemData.Rect.Max;
}
ImVec2 ImGui::GetItemRectSize()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.LastItemRect.GetSize();
ImGuiContext& g = *GImGui;
return g.LastItemData.Rect.GetSize();
}
bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
@ -5361,7 +5362,7 @@ void ImGui::EndChild()
ItemAdd(bb, 0);
}
if (g.HoveredWindow == window)
parent_window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
}
g.WithinEndChild = false;
g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
@ -6189,7 +6190,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
ImGuiWindow* parent_window_in_stack = window->DockIsActive ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
ImGuiWindow* parent_window_in_stack = window->DockIsActive ? window->DockNode->HostWindow : 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;
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
@ -6199,7 +6200,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Add to stack
// 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;
window->DC.StackSizesOnBegin.SetToCurrentState();
g.CurrentWindow = NULL;
@ -6810,13 +6814,13 @@ 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().
// This is useful to allow creating context menus on title bar only, etc.
if (window->DockIsActive)
SetLastItemData(window, window->ID, window->DockTabItemStatusFlags, window->DockTabItemRect);
SetLastItemData(window->ID, g.CurrentItemFlags, window->DockTabItemStatusFlags, window->DockTabItemRect);
else
SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
#ifdef IMGUI_ENABLE_TEST_ENGINE
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
}
else
@ -6827,7 +6831,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Pull/inherit current state
g.CurrentItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack
window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : window->GetID("#FOCUSSCOPE"); // Inherit from parent only // -V595
if (!(flags & ImGuiWindowFlags_DockNodeHost))
@ -6934,11 +6937,12 @@ void ImGui::End()
host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding;
// Pop from window stack
g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup;
g.CurrentWindowStack.pop_back();
if (window->Flags & ImGuiWindowFlags_Popup)
g.BeginPopupStack.pop_back();
window->DC.StackSizesOnBegin.CompareWithCurrentState();
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);
if (g.CurrentWindow)
SetCurrentViewport(g.CurrentWindow, g.CurrentWindow->Viewport);
}
@ -7628,8 +7632,8 @@ void ImGui::SetItemDefaultFocus()
if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent)
{
g.NavInitRequest = false;
g.NavInitResultId = window->DC.LastItemId;
g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
g.NavInitResultId = g.LastItemData.ID;
g.NavInitResultRectRel = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos);
NavUpdateAnyRequestFlag();
if (!IsItemVisible())
SetScrollHereY();
@ -8064,9 +8068,16 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
// Set item data
g.LastItemData.ID = id;
g.LastItemData.Rect = bb;
g.LastItemData.InFlags = g.CurrentItemFlags;
g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None;
// Directional navigation processing
if (id != 0)
{
// Navigation processing runs prior to clipping early-out
// Runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
@ -8090,11 +8101,6 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
}
#endif
}
// Equivalent to calling SetLastItemData()
window->DC.LastItemId = id;
window->DC.LastItemRect = bb;
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
#ifdef IMGUI_ENABLE_TEST_ENGINE
@ -8115,7 +8121,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)
if (IsMouseHoveringRect(bb.Min, bb.Max))
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
return true;
}
@ -8447,24 +8453,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_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
if (group_contains_curr_active_id)
window->DC.LastItemId = g.ActiveId;
g.LastItemData.ID = g.ActiveId;
else if (group_contains_prev_active_id)
window->DC.LastItemId = g.ActiveIdPreviousFrame;
window->DC.LastItemRect = group_bb;
g.LastItemData.ID = g.ActiveIdPreviousFrame;
g.LastItemData.Rect = group_bb;
// Forward Hovered flag
const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;
if (group_contains_curr_hovered_id)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
// Forward Edited flag
if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
// Forward Deactivated flag
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated;
g.GroupStack.pop_back();
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
@ -8653,7 +8659,7 @@ void ImGui::SetScrollHereX(float center_x_ratio)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
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
// Tweak: snap on edges when aiming at an item very close to the edge
@ -9049,12 +9055,13 @@ void ImGui::EndPopup()
// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
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_);
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!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
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)
OpenPopupEx(id, popup_flags);
}
}
@ -9077,11 +9084,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.
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
{
ImGuiWindow* window = GImGui->CurrentWindow;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems)
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!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
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)
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
OpenPopupEx(id, popup_flags);
@ -9090,7 +9098,8 @@ bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flag
bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
{
ImGuiWindow* window = GImGui->CurrentWindow;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (!str_id)
str_id = "window_context";
ImGuiID id = window->GetID(str_id);
@ -9103,7 +9112,8 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_fl
bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
{
ImGuiWindow* window = GImGui->CurrentWindow;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (!str_id)
str_id = "void_context";
ImGuiID id = window->GetID(str_id);
@ -9288,8 +9298,8 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
g.NavLayer = nav_layer;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
window->NavLastIds[nav_layer] = id;
if (window->DC.LastItemId == id)
window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
if (g.LastItemData.ID == id)
window->NavRectRel[nav_layer] = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos);
if (g.ActiveIdSource == ImGuiInputSource_Nav)
g.NavDisableMouseHover = true;
@ -9386,7 +9396,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
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)
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
@ -9474,7 +9484,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.
// return;
const ImGuiItemFlags item_flags = g.CurrentItemFlags;
const ImGuiItemFlags item_flags = g.LastItemData.InFlags;
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
// Process Init Request
@ -10481,7 +10491,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
ImGuiID source_parent_id = 0;
if (!(flags & ImGuiDragDropFlags_SourceExtern))
{
source_id = window->DC.LastItemId;
source_id = g.LastItemData.ID;
if (source_id != 0)
{
// Common path: items with ID
@ -10508,15 +10518,16 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
}
// 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;
// Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
// We build a throwaway ID based on current ID stack + relative AABB of items in window.
// 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.
source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id);
// Rely on keeping other window->LastItemXXX fields intact.
source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id);
if (is_hovered && g.IO.MouseClicked[mouse_button])
{
SetActiveID(source_id, window);
@ -10572,7 +10583,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
}
if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
return true;
}
@ -10672,14 +10683,14 @@ bool ImGui::BeginDragDropTarget()
return false;
ImGuiWindow* window = g.CurrentWindow;
if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect))
return false;
ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree)
return false;
const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
ImGuiID id = window->DC.LastItemId;
const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect;
ImGuiID id = g.LastItemData.ID;
if (id == 0)
id = window->GetIDFromRectangle(display_rect);
if (g.DragDropPayload.SourceId == id)
@ -14067,8 +14078,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
node->VisibleWindow = window;
// Store last item data so it can be queried with IsItemXXX functions after the user Begin() call
window->DockTabItemStatusFlags = host_window->DC.LastItemStatusFlags;
window->DockTabItemRect = host_window->DC.LastItemRect;
window->DockTabItemStatusFlags = g.LastItemData.StatusFlags;
window->DockTabItemRect = g.LastItemData.Rect;
// Update navigation ID on menu layer
if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0)
@ -14123,7 +14134,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
{
// ImGuiButtonFlags_AllowItemOverlap + SetItemAllowOverlap() required for appending into dock node tab bar,
// otherwise dragging window will steal HoveredId and amended tabs cannot get them.
host_window->DC.LastItemId = title_bar_id;
g.LastItemData.ID = title_bar_id;
SetItemAllowOverlap();
}
if (held)
@ -15682,8 +15693,9 @@ void ImGui::BeginDockableDragDropSource(ImGuiWindow* window)
ImGuiContext& g = *GImGui;
IM_ASSERT(g.ActiveId == window->MoveId);
IM_ASSERT(g.MovingWindow == window);
IM_ASSERT(g.CurrentWindow == window);
window->DC.LastItemId = window->MoveId;
g.LastItemData.ID = window->MoveId;
window = window->RootWindowDockTree;
IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
bool is_drag_docking = ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset); // FIXME-DOCKING: Need to make this stateful and explicit