mirror of
https://github.com/ocornut/imgui.git
synced 2024-12-05 06:57:13 +08:00
Refactor: Internals: Moved Popup functions in imgui.cpp in their own section. (part 1) (#2036)
This commit is contained in:
parent
a58e4dfd0f
commit
b1f263b34b
308
imgui.cpp
308
imgui.cpp
@ -4709,132 +4709,6 @@ void ImGui::EndTooltip()
|
||||
End();
|
||||
}
|
||||
|
||||
// Mark popup as open (toggle toward open state).
|
||||
// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
|
||||
// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
|
||||
// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
|
||||
void ImGui::OpenPopupEx(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* parent_window = g.CurrentWindow;
|
||||
int current_stack_size = g.CurrentPopupStack.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;
|
||||
popup_ref.ParentWindow = parent_window;
|
||||
popup_ref.OpenFrameCount = g.FrameCount;
|
||||
popup_ref.OpenParentId = parent_window->IDStack.back();
|
||||
popup_ref.OpenMousePos = g.IO.MousePos;
|
||||
popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
|
||||
|
||||
//printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id);
|
||||
if (g.OpenPopupStack.Size < current_stack_size + 1)
|
||||
{
|
||||
g.OpenPopupStack.push_back(popup_ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui
|
||||
// would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing
|
||||
// situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand.
|
||||
if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
|
||||
{
|
||||
g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Close child popups if any, then flag popup for open/reopen
|
||||
g.OpenPopupStack.resize(current_stack_size + 1);
|
||||
g.OpenPopupStack[current_stack_size] = popup_ref;
|
||||
}
|
||||
|
||||
// When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
|
||||
// This is equivalent to what ClosePopupToLevel() does.
|
||||
//if (g.OpenPopupStack[current_stack_size].PopupId == id)
|
||||
// FocusWindow(parent_window);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::OpenPopup(const char* str_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
OpenPopupEx(g.CurrentWindow->GetID(str_id));
|
||||
}
|
||||
|
||||
void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.OpenPopupStack.empty())
|
||||
return;
|
||||
|
||||
// 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;
|
||||
if (ref_window)
|
||||
{
|
||||
for (n = 0; n < g.OpenPopupStack.Size; n++)
|
||||
{
|
||||
ImGuiPopupRef& popup = g.OpenPopupStack[n];
|
||||
if (!popup.Window)
|
||||
continue;
|
||||
IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
|
||||
if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
|
||||
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)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below
|
||||
ClosePopupToLevel(n);
|
||||
}
|
||||
|
||||
ImGuiWindow* ImGui::GetFrontMostPopupModal()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
|
||||
if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
|
||||
if (popup->Flags & ImGuiWindowFlags_Modal)
|
||||
return popup;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ImGui::ClosePopupToLevel(int remaining)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
return;
|
||||
while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
|
||||
popup_idx--;
|
||||
ClosePopupToLevel(popup_idx);
|
||||
}
|
||||
|
||||
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -4868,18 +4742,6 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
|
||||
return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
|
||||
}
|
||||
|
||||
bool ImGui::IsPopupOpen(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.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);
|
||||
}
|
||||
|
||||
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -4904,7 +4766,6 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
|
||||
ClosePopup(id);
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_open;
|
||||
}
|
||||
|
||||
@ -4920,19 +4781,6 @@ void ImGui::EndPopup()
|
||||
End();
|
||||
}
|
||||
|
||||
bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
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)
|
||||
OpenPopupEx(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is a helper to handle the simplest case of associating one named popup to one given widget.
|
||||
// You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
|
||||
// You can pass a NULL str_id to use the identifier of the last item.
|
||||
@ -5010,7 +4858,6 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size
|
||||
SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
|
||||
g.ActiveIdSource = ImGuiInputSource_Nav;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -7761,6 +7608,161 @@ void ImGui::Unindent(float indent_w)
|
||||
window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// POPUPS
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool ImGui::IsPopupOpen(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.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);
|
||||
}
|
||||
|
||||
ImGuiWindow* ImGui::GetFrontMostPopupModal()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
|
||||
if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
|
||||
if (popup->Flags & ImGuiWindowFlags_Modal)
|
||||
return popup;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ImGui::OpenPopup(const char* str_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
OpenPopupEx(g.CurrentWindow->GetID(str_id));
|
||||
}
|
||||
|
||||
// Mark popup as open (toggle toward open state).
|
||||
// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
|
||||
// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
|
||||
// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
|
||||
void ImGui::OpenPopupEx(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* parent_window = g.CurrentWindow;
|
||||
int current_stack_size = g.CurrentPopupStack.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;
|
||||
popup_ref.ParentWindow = parent_window;
|
||||
popup_ref.OpenFrameCount = g.FrameCount;
|
||||
popup_ref.OpenParentId = parent_window->IDStack.back();
|
||||
popup_ref.OpenMousePos = g.IO.MousePos;
|
||||
popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
|
||||
|
||||
//printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id);
|
||||
if (g.OpenPopupStack.Size < current_stack_size + 1)
|
||||
{
|
||||
g.OpenPopupStack.push_back(popup_ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui
|
||||
// would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing
|
||||
// situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand.
|
||||
if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
|
||||
{
|
||||
g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Close child popups if any, then flag popup for open/reopen
|
||||
g.OpenPopupStack.resize(current_stack_size + 1);
|
||||
g.OpenPopupStack[current_stack_size] = popup_ref;
|
||||
}
|
||||
|
||||
// When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
|
||||
// This is equivalent to what ClosePopupToLevel() does.
|
||||
//if (g.OpenPopupStack[current_stack_size].PopupId == id)
|
||||
// FocusWindow(parent_window);
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
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)
|
||||
OpenPopupEx(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.OpenPopupStack.empty())
|
||||
return;
|
||||
|
||||
// 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;
|
||||
if (ref_window)
|
||||
{
|
||||
for (n = 0; n < g.OpenPopupStack.Size; n++)
|
||||
{
|
||||
ImGuiPopupRef& popup = g.OpenPopupStack[n];
|
||||
if (!popup.Window)
|
||||
continue;
|
||||
IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
|
||||
if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
|
||||
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)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below
|
||||
ClosePopupToLevel(n);
|
||||
}
|
||||
|
||||
void ImGui::ClosePopupToLevel(int remaining)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
return;
|
||||
while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
|
||||
popup_idx--;
|
||||
ClosePopupToLevel(popup_idx);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// NAVIGATION
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user