mirror of
https://github.com/Drezil/imgui.git
synced 2025-07-04 12:08:47 +02:00
Merge branch 'master' into viewport
# Conflicts: # imgui.cpp
This commit is contained in:
104
imgui.cpp
104
imgui.cpp
@ -2658,7 +2658,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
|
||||
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
|
||||
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiTestEngineHook_ItemAdd(id, bb);
|
||||
ImGuiTestEngineHook_ItemAdd(bb, id);
|
||||
#endif
|
||||
|
||||
// Clipping test
|
||||
@ -3433,7 +3433,7 @@ void ImGui::NewFrame()
|
||||
// No window should be open at the beginning of the frame.
|
||||
// But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
|
||||
g.CurrentWindowStack.resize(0);
|
||||
g.CurrentPopupStack.resize(0);
|
||||
g.BeginPopupStack.resize(0);
|
||||
ClosePopupsOverWindow(g.NavWindow);
|
||||
|
||||
// Create implicit/fallback window - which we will only render it if the user has added something to it.
|
||||
@ -3520,7 +3520,7 @@ void ImGui::Shutdown(ImGuiContext* context)
|
||||
g.StyleModifiers.clear();
|
||||
g.FontStack.clear();
|
||||
g.OpenPopupStack.clear();
|
||||
g.CurrentPopupStack.clear();
|
||||
g.BeginPopupStack.clear();
|
||||
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
|
||||
for (int i = 0; i < g.Viewports.Size; i++)
|
||||
IM_DELETE(g.Viewports[i]);
|
||||
@ -4149,8 +4149,8 @@ ImVec2 ImGui::GetMousePos()
|
||||
ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.CurrentPopupStack.Size > 0)
|
||||
return g.OpenPopupStack[g.CurrentPopupStack.Size-1].OpenMousePos;
|
||||
if (g.BeginPopupStack.Size > 0)
|
||||
return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos;
|
||||
return g.IO.MousePos;
|
||||
}
|
||||
|
||||
@ -4423,7 +4423,7 @@ static void CheckStacksSize(ImGuiWindow* window, bool write)
|
||||
short* p_backup = &window->DC.StackSizesBackup[0];
|
||||
{ int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop()
|
||||
{ int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup()
|
||||
{ int current = g.CurrentPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
|
||||
{ int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
|
||||
// For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
|
||||
{ int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor()
|
||||
{ int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar()
|
||||
@ -4852,7 +4852,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0);
|
||||
if (flags & ImGuiWindowFlags_Popup)
|
||||
{
|
||||
ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
|
||||
ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
||||
window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
|
||||
window_just_activated_by_user |= (window != popup_ref.Window);
|
||||
}
|
||||
@ -4886,9 +4886,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
CheckStacksSize(window, true);
|
||||
if (flags & ImGuiWindowFlags_Popup)
|
||||
{
|
||||
ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
|
||||
ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
||||
popup_ref.Window = window;
|
||||
g.CurrentPopupStack.push_back(popup_ref);
|
||||
g.BeginPopupStack.push_back(popup_ref);
|
||||
window->PopupId = popup_ref.PopupId;
|
||||
}
|
||||
|
||||
@ -5076,7 +5076,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
{
|
||||
window->AutoPosLastDirection = ImGuiDir_None;
|
||||
if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
|
||||
window->Pos = g.CurrentPopupStack.back().OpenPopupPos;
|
||||
window->Pos = g.BeginPopupStack.back().OpenPopupPos;
|
||||
}
|
||||
|
||||
// Position child window
|
||||
@ -5553,7 +5553,7 @@ void ImGui::End()
|
||||
// Pop from window stack
|
||||
g.CurrentWindowStack.pop_back();
|
||||
if (window->Flags & ImGuiWindowFlags_Popup)
|
||||
g.CurrentPopupStack.pop_back();
|
||||
g.BeginPopupStack.pop_back();
|
||||
CheckStacksSize(window, false);
|
||||
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
|
||||
if (g.CurrentWindow)
|
||||
@ -6781,13 +6781,13 @@ void ImGui::SetTooltip(const char* fmt, ...)
|
||||
bool ImGui::IsPopupOpen(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
|
||||
return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
|
||||
}
|
||||
|
||||
bool ImGui::IsPopupOpen(const char* str_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
|
||||
return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
|
||||
}
|
||||
|
||||
ImGuiWindow* ImGui::GetFrontMostPopupModal()
|
||||
@ -6814,7 +6814,7 @@ void ImGui::OpenPopupEx(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* parent_window = g.CurrentWindow;
|
||||
int current_stack_size = g.CurrentPopupStack.Size;
|
||||
int current_stack_size = g.BeginPopupStack.Size;
|
||||
ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
|
||||
popup_ref.PopupId = id;
|
||||
popup_ref.Window = NULL;
|
||||
@ -6873,12 +6873,13 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
|
||||
|
||||
// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
|
||||
// Don't close our own child popup windows.
|
||||
int n = 0;
|
||||
int popup_count_to_keep = 0;
|
||||
if (ref_window)
|
||||
{
|
||||
for (; n < g.OpenPopupStack.Size; n++)
|
||||
// Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
|
||||
for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
|
||||
{
|
||||
ImGuiPopupRef& popup = g.OpenPopupStack[n];
|
||||
ImGuiPopupRef& popup = g.OpenPopupStack[popup_count_to_keep];
|
||||
if (!popup.Window)
|
||||
continue;
|
||||
IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
|
||||
@ -6886,47 +6887,60 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
|
||||
continue;
|
||||
|
||||
// Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
|
||||
bool has_focus = false;
|
||||
for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
|
||||
has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow);
|
||||
if (!has_focus)
|
||||
bool popup_or_descendent_has_focus = false;
|
||||
for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++)
|
||||
if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow)
|
||||
popup_or_descendent_has_focus = true;
|
||||
if (!popup_or_descendent_has_focus)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
|
||||
ClosePopupToLevel(n);
|
||||
if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
|
||||
{
|
||||
//IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
|
||||
ClosePopupToLevel(popup_count_to_keep, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::ClosePopupToLevel(int remaining)
|
||||
void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under)
|
||||
{
|
||||
IM_ASSERT(remaining >= 0);
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow;
|
||||
if (g.NavLayer == 0)
|
||||
focus_window = NavRestoreLastChildNavWindow(focus_window);
|
||||
FocusWindow(focus_window);
|
||||
focus_window->DC.NavHideHighlightOneFrame = true;
|
||||
g.OpenPopupStack.resize(remaining);
|
||||
}
|
||||
|
||||
void ImGui::ClosePopup(ImGuiID id)
|
||||
{
|
||||
if (!IsPopupOpen(id))
|
||||
return;
|
||||
ImGuiContext& g = *GImGui;
|
||||
ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
||||
// FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely.
|
||||
// Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing.
|
||||
// The current code will set focus to the parent of the popup window which is incorrect.
|
||||
// It rarely manifested until now because UpdateMouseMovingWindow() would call FocusWindow() again on the clicked window,
|
||||
// leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again.
|
||||
// However if the clicked window has the _NoMove flag set we would be left with B focused.
|
||||
// For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway,
|
||||
// but we should inspect and fix this properly.
|
||||
if (apply_focus_to_window_under)
|
||||
{
|
||||
if (g.NavLayer == 0)
|
||||
focus_window = NavRestoreLastChildNavWindow(focus_window);
|
||||
FocusWindow(focus_window);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the popup we have begin-ed into.
|
||||
void ImGui::CloseCurrentPopup()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
int popup_idx = g.CurrentPopupStack.Size - 1;
|
||||
if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
|
||||
int popup_idx = g.BeginPopupStack.Size - 1;
|
||||
if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
|
||||
return;
|
||||
while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
|
||||
popup_idx--;
|
||||
ClosePopupToLevel(popup_idx);
|
||||
ClosePopupToLevel(popup_idx, true);
|
||||
|
||||
// A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
|
||||
// To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
|
||||
// Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
|
||||
if (ImGuiWindow* window = g.NavWindow)
|
||||
window->DC.NavHideHighlightOneFrame = true;
|
||||
}
|
||||
|
||||
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
||||
@ -6940,7 +6954,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
||||
|
||||
char name[20];
|
||||
if (extra_flags & ImGuiWindowFlags_ChildMenu)
|
||||
ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
|
||||
ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
|
||||
else
|
||||
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
|
||||
|
||||
@ -6954,7 +6968,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
||||
bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
|
||||
if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
|
||||
{
|
||||
g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
|
||||
return false;
|
||||
@ -6963,6 +6977,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
|
||||
return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
|
||||
}
|
||||
|
||||
// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
|
||||
// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
|
||||
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -6985,7 +7001,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
|
||||
{
|
||||
EndPopup();
|
||||
if (is_open)
|
||||
ClosePopup(id);
|
||||
ClosePopupToLevel(g.BeginPopupStack.Size, true);
|
||||
return false;
|
||||
}
|
||||
return is_open;
|
||||
@ -6995,7 +7011,7 @@ void ImGui::EndPopup()
|
||||
{
|
||||
ImGuiContext& g = *GImGui; (void)g;
|
||||
IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
|
||||
IM_ASSERT(g.CurrentPopupStack.Size > 0);
|
||||
IM_ASSERT(g.BeginPopupStack.Size > 0);
|
||||
|
||||
// Make all menus and popups wrap around for now, may need to expose that policy.
|
||||
NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY);
|
||||
@ -7590,7 +7606,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
|
||||
{
|
||||
// We need to take account of the possibility that mouse may become invalid.
|
||||
// Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds.
|
||||
ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.CurrentPopupStack.back().OpenMousePos;
|
||||
ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.BeginPopupStack.back().OpenMousePos;
|
||||
bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow);
|
||||
bool mouse_valid = IsMousePosValid(&mouse_ref);
|
||||
if ((window->Appearing || (flags & ImGuiWindowFlags_Tooltip)) && (!use_mouse_ref || mouse_valid))
|
||||
@ -8403,7 +8419,7 @@ static void ImGui::NavUpdate()
|
||||
{
|
||||
// Close open popup/menu
|
||||
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
||||
ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
||||
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
|
||||
}
|
||||
else if (g.NavLayer != 0)
|
||||
{
|
||||
|
Reference in New Issue
Block a user