Merge branch 'master' into docking

# Conflicts:
#	imgui.cpp
This commit is contained in:
omar 2018-12-14 18:46:24 +01:00
commit ac9512e095
5 changed files with 75 additions and 58 deletions

View File

@ -2680,7 +2680,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiTestEngineHook_ItemAdd(id, bb); ImGuiTestEngineHook_ItemAdd(bb, id);
#endif #endif
// Clipping test // Clipping test
@ -3462,7 +3462,7 @@ void ImGui::NewFrame()
// No window should be open at the beginning of the frame. // 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. // 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.CurrentWindowStack.resize(0);
g.CurrentPopupStack.resize(0); g.BeginPopupStack.resize(0);
ClosePopupsOverWindow(g.NavWindow); ClosePopupsOverWindow(g.NavWindow);
// Docking // Docking
@ -3560,7 +3560,7 @@ void ImGui::Shutdown(ImGuiContext* context)
g.StyleModifiers.clear(); g.StyleModifiers.clear();
g.FontStack.clear(); g.FontStack.clear();
g.OpenPopupStack.clear(); g.OpenPopupStack.clear();
g.CurrentPopupStack.clear(); g.BeginPopupStack.clear();
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL; g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
for (int i = 0; i < g.Viewports.Size; i++) for (int i = 0; i < g.Viewports.Size; i++)
IM_DELETE(g.Viewports[i]); IM_DELETE(g.Viewports[i]);
@ -4235,8 +4235,8 @@ ImVec2 ImGui::GetMousePos()
ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.CurrentPopupStack.Size > 0) if (g.BeginPopupStack.Size > 0)
return g.OpenPopupStack[g.CurrentPopupStack.Size-1].OpenMousePos; return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos;
return g.IO.MousePos; return g.IO.MousePos;
} }
@ -4518,7 +4518,7 @@ static void CheckStacksSize(ImGuiWindow* window, bool write)
short* p_backup = &window->DC.StackSizesBackup[0]; 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->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 = 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. // 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.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() { 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()
@ -4965,7 +4965,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0); const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0);
if (flags & ImGuiWindowFlags_Popup) 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->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); window_just_activated_by_user |= (window != popup_ref.Window);
} }
@ -5015,9 +5015,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
CheckStacksSize(window, true); CheckStacksSize(window, true);
if (flags & ImGuiWindowFlags_Popup) if (flags & ImGuiWindowFlags_Popup)
{ {
ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size]; ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
popup_ref.Window = window; popup_ref.Window = window;
g.CurrentPopupStack.push_back(popup_ref); g.BeginPopupStack.push_back(popup_ref);
window->PopupId = popup_ref.PopupId; window->PopupId = popup_ref.PopupId;
} }
@ -5215,7 +5215,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{ {
window->AutoPosLastDirection = ImGuiDir_None; window->AutoPosLastDirection = ImGuiDir_None;
if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) 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 // Position child window
@ -5752,7 +5752,7 @@ void ImGui::End()
// Pop from window stack // Pop from window stack
g.CurrentWindowStack.pop_back(); g.CurrentWindowStack.pop_back();
if (window->Flags & ImGuiWindowFlags_Popup) if (window->Flags & ImGuiWindowFlags_Popup)
g.CurrentPopupStack.pop_back(); g.BeginPopupStack.pop_back();
CheckStacksSize(window, false); CheckStacksSize(window, false);
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
if (g.CurrentWindow) if (g.CurrentWindow)
@ -7019,13 +7019,13 @@ void ImGui::SetTooltip(const char* fmt, ...)
bool ImGui::IsPopupOpen(ImGuiID id) bool ImGui::IsPopupOpen(ImGuiID id)
{ {
ImGuiContext& g = *GImGui; 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) bool ImGui::IsPopupOpen(const char* str_id)
{ {
ImGuiContext& g = *GImGui; 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() ImGuiWindow* ImGui::GetFrontMostPopupModal()
@ -7052,7 +7052,7 @@ void ImGui::OpenPopupEx(ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* parent_window = g.CurrentWindow; 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. 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.PopupId = id;
popup_ref.Window = NULL; popup_ref.Window = NULL;
@ -7111,12 +7111,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. // 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. // Don't close our own child popup windows.
int n = 0; int popup_count_to_keep = 0;
if (ref_window) 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) if (!popup.Window)
continue; continue;
IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
@ -7124,15 +7125,19 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
continue; continue;
// Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow) // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
bool has_focus = false; bool popup_or_descendent_has_focus = false;
for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++) for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++)
has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow); if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow)
if (!has_focus) popup_or_descendent_has_focus = true;
if (!popup_or_descendent_has_focus)
break; break;
} }
} }
if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below 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
ClosePopupToLevel(n); {
//IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
ClosePopupToLevel(popup_count_to_keep);
}
} }
void ImGui::ClosePopupToLevel(int remaining) void ImGui::ClosePopupToLevel(int remaining)
@ -7147,20 +7152,12 @@ void ImGui::ClosePopupToLevel(int remaining)
g.OpenPopupStack.resize(remaining); 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. // Close the popup we have begin-ed into.
void ImGui::CloseCurrentPopup() void ImGui::CloseCurrentPopup()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
int popup_idx = g.CurrentPopupStack.Size - 1; int popup_idx = g.BeginPopupStack.Size - 1;
if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
return; return;
while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
popup_idx--; popup_idx--;
@ -7178,7 +7175,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
char name[20]; char name[20];
if (extra_flags & ImGuiWindowFlags_ChildMenu) 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 else
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
@ -7192,7 +7189,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
{ {
ImGuiContext& g = *GImGui; 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 g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
return false; return false;
@ -7201,6 +7198,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
return BeginPopupEx(g.CurrentWindow->GetID(str_id), 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) bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -7223,7 +7222,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
{ {
EndPopup(); EndPopup();
if (is_open) if (is_open)
ClosePopup(id); ClosePopupToLevel(g.BeginPopupStack.Size);
return false; return false;
} }
return is_open; return is_open;
@ -7233,7 +7232,7 @@ void ImGui::EndPopup()
{ {
ImGuiContext& g = *GImGui; (void)g; ImGuiContext& g = *GImGui; (void)g;
IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls 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. // Make all menus and popups wrap around for now, may need to expose that policy.
NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY); NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY);
@ -7815,7 +7814,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
{ {
// We need to take account of the possibility that mouse may become invalid. // 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. // 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 use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow);
bool mouse_valid = IsMousePosValid(&mouse_ref); bool mouse_valid = IsMousePosValid(&mouse_ref);
if ((window->Appearing || (flags & ImGuiWindowFlags_Tooltip)) && (!use_mouse_ref || mouse_valid)) if ((window->Appearing || (flags & ImGuiWindowFlags_Tooltip)) && (!use_mouse_ref || mouse_valid))

18
imgui.h
View File

@ -237,7 +237,8 @@ namespace ImGui
// which clicking will set the boolean to false when clicked. // which clicking will set the boolean to false when clicked.
// - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting
// anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value!
// [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc.
// where the EndXXX call should only be called if the corresponding BeginXXX function returned true.]
// - Note that the bottom of window stack always contains a window called "Debug". // - Note that the bottom of window stack always contains a window called "Debug".
IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
IMGUI_API void End(); IMGUI_API void End();
@ -525,7 +526,14 @@ namespace ImGui
IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). overidde any previous call to SetTooltip(). IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). overidde any previous call to SetTooltip().
IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1);
// Popups // Popups, Modals
// The properties of popups windows are:
// - They block normal mouse hovering detection outside them. (*)
// - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
// - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls.
// User can manipulate the visibility state by calling OpenPopup().
// (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
// Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time.
IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true! IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true!
IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
@ -534,11 +542,11 @@ namespace ImGui
IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside) IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside)
IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true!
IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors). return true when just opened. IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors). return true when just opened.
IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open at the current begin-ed level of the popup stack.
IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup.
// Columns // Columns
// You can also use SameLine(pos_x) for simplified columns. The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) // You can also use SameLine(pos_x) to mimic simplified columns. The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!)
IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true);
IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished
IMGUI_API int GetColumnIndex(); // get current column index IMGUI_API int GetColumnIndex(); // get current column index
@ -570,7 +578,7 @@ namespace ImGui
IMGUI_API bool IsWindowDocked(); // is current window docked into another window? IMGUI_API bool IsWindowDocked(); // is current window docked into another window?
// Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging. // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging.
IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty (stdout)
IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file
IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard
IMGUI_API void LogFinish(); // stop logging (close file, etc.) IMGUI_API void LogFinish(); // stop logging (close file, etc.)

View File

@ -2025,12 +2025,13 @@ static void ShowDemoWindowPopups()
if (!ImGui::CollapsingHeader("Popups & Modal windows")) if (!ImGui::CollapsingHeader("Popups & Modal windows"))
return; return;
// Popups are windows with a few special properties: // The properties of popups windows are:
// - They block normal mouse hovering detection outside them. (*) // - They block normal mouse hovering detection outside them. (*)
// - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
// - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls. // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls.
// User can manipulate the visibility state by calling OpenPopup().
// (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
// Those three properties are intimately connected. The library needs to hold their visibility state because it can close popups at any time. // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time.
// Typical use for regular windows: // Typical use for regular windows:
// bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End();
@ -2159,6 +2160,7 @@ static void ShowDemoWindowPopups()
if (ImGui::Button("Delete..")) if (ImGui::Button("Delete.."))
ImGui::OpenPopup("Delete?"); ImGui::OpenPopup("Delete?");
if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{ {
ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
@ -2191,7 +2193,11 @@ static void ShowDemoWindowPopups()
if (ImGui::Button("Add another modal..")) if (ImGui::Button("Add another modal.."))
ImGui::OpenPopup("Stacked 2"); ImGui::OpenPopup("Stacked 2");
if (ImGui::BeginPopupModal("Stacked 2"))
// Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which will close the popup.
// Note that the visibility state of popups is owned by imgui, so the input value of the bool actually doesn't matter here.
bool dummy_open = true;
if (ImGui::BeginPopupModal("Stacked 2", &dummy_open))
{ {
ImGui::Text("Hello from Stacked The Second!"); ImGui::Text("Hello from Stacked The Second!");
if (ImGui::Button("Close")) if (ImGui::Button("Close"))

View File

@ -876,7 +876,7 @@ struct ImGuiContext
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont() ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont()
ImVector<ImGuiPopupRef> OpenPopupStack; // Which popups are open (persistent) ImVector<ImGuiPopupRef> OpenPopupStack; // Which popups are open (persistent)
ImVector<ImGuiPopupRef> CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) ImVector<ImGuiPopupRef> BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions
ImGuiCond NextTreeNodeOpenCond; ImGuiCond NextTreeNodeOpenCond;
@ -1474,10 +1474,9 @@ namespace ImGui
// Popups, Modals, Tooltips // Popups, Modals, Tooltips
IMGUI_API void OpenPopupEx(ImGuiID id); IMGUI_API void OpenPopupEx(ImGuiID id);
IMGUI_API void ClosePopup(ImGuiID id);
IMGUI_API void ClosePopupToLevel(int remaining); IMGUI_API void ClosePopupToLevel(int remaining);
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window); IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window);
IMGUI_API bool IsPopupOpen(ImGuiID id); IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack!
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true); IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true);
IMGUI_API ImGuiWindow* GetFrontMostPopupModal(); IMGUI_API ImGuiWindow* GetFrontMostPopupModal();
@ -1639,7 +1638,7 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned ch
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
extern void ImGuiTestEngineHook_PreNewFrame(); extern void ImGuiTestEngineHook_PreNewFrame();
extern void ImGuiTestEngineHook_PostNewFrame(); extern void ImGuiTestEngineHook_PostNewFrame();
extern void ImGuiTestEngineHook_ItemAdd(ImGuiID id, const ImRect& bb); extern void ImGuiTestEngineHook_ItemAdd(const ImRect& bb, ImGuiID id);
extern void ImGuiTestEngineHook_ItemInfo(ImGuiID id, const char* label, int flags); extern void ImGuiTestEngineHook_ItemInfo(ImGuiID id, const char* label, int flags);
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(_ID, _LABEL, _FLAGS) // Register status flags #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(_ID, _LABEL, _FLAGS) // Register status flags
#else #else

View File

@ -397,6 +397,11 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if (flatten_hovered_children) if (flatten_hovered_children)
g.HoveredWindow = window; g.HoveredWindow = window;
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (window->DC.LastItemId != id)
ImGuiTestEngineHook_ItemAdd(bb, id);
#endif
bool pressed = false; bool pressed = false;
bool hovered = ItemHoverable(bb, id); bool hovered = ItemHoverable(bb, id);
@ -1363,7 +1368,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
} }
char name[16]; char name[16];
ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
// Peak into expected window size so we can position it // Peak into expected window size so we can position it
if (ImGuiWindow* popup_window = FindWindowByName(name)) if (ImGuiWindow* popup_window = FindWindowByName(name))
@ -5594,7 +5599,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
bool pressed; bool pressed;
bool menu_is_open = IsPopupOpen(id); bool menu_is_open = IsPopupOpen(id);
bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].OpenParentId == window->IDStack.back()); bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back());
ImGuiWindow* backed_nav_window = g.NavWindow; ImGuiWindow* backed_nav_window = g.NavWindow;
if (menuset_is_open) if (menuset_is_open)
g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent)
@ -5635,9 +5640,9 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
{ {
// Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
bool moving_within_opened_triangle = false; bool moving_within_opened_triangle = false;
if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar)) if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar))
{ {
if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window) if (ImGuiWindow* next_window = g.OpenPopupStack[g.BeginPopupStack.Size].Window)
{ {
ImRect next_window_rect = next_window->Rect(); ImRect next_window_rect = next_window->Rect();
ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
@ -5688,11 +5693,11 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }'
want_close = true; want_close = true;
if (want_close && IsPopupOpen(id)) if (want_close && IsPopupOpen(id))
ClosePopupToLevel(g.CurrentPopupStack.Size); ClosePopupToLevel(g.BeginPopupStack.Size);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));
if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size) if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size)
{ {
// Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame.
OpenPopup(label); OpenPopup(label);
@ -5718,14 +5723,14 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
void ImGui::EndMenu() void ImGui::EndMenu()
{ {
// Nav: When a left move request _within our child menu_ failed, close the menu. // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu).
// A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs.
// However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
{ {
ClosePopupToLevel(g.OpenPopupStack.Size - 1); ClosePopupToLevel(g.BeginPopupStack.Size);
NavMoveRequestCancel(); NavMoveRequestCancel();
} }