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();
|
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)
|
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
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);
|
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)
|
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
@ -4904,7 +4766,6 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
|
|||||||
ClosePopup(id);
|
ClosePopup(id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return is_open;
|
return is_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4920,19 +4781,6 @@ void ImGui::EndPopup()
|
|||||||
End();
|
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.
|
// 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 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.
|
// 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
|
SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
|
||||||
g.ActiveIdSource = ImGuiInputSource_Nav;
|
g.ActiveIdSource = ImGuiInputSource_Nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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;
|
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
|
// NAVIGATION
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user