BeginPopup() API had to be changed! :( Proper support for stacked popups, leading into menus (wip #126)

This commit is contained in:
ocornut 2015-05-11 15:57:02 +01:00
parent d23709ce35
commit fcd08ed8d4
2 changed files with 120 additions and 56 deletions

162
imgui.cpp
View File

@ -136,6 +136,7 @@
Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
- 2015/05/11 (1.39) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "opened" state of a popup.
- 2015/05/03 (1.39) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). - 2015/05/03 (1.39) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
- 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete). - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete).
- 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
@ -517,6 +518,7 @@ static void Scrollbar(ImGuiWindow* window);
static bool CloseWindowButton(bool* p_opened = NULL); static bool CloseWindowButton(bool* p_opened = NULL);
static void FocusWindow(ImGuiWindow* window); static void FocusWindow(ImGuiWindow* window);
static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs); static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
static void CloseInactivePopups();
// Helpers: String // Helpers: String
static int ImStricmp(const char* str1, const char* str2); static int ImStricmp(const char* str1, const char* str2);
@ -1013,7 +1015,7 @@ struct ImGuiDrawContext
ImVector<ImGuiGroupData> GroupStack; ImVector<ImGuiGroupData> GroupStack;
ImGuiColorEditMode ColorEditMode; ImGuiColorEditMode ColorEditMode;
ImGuiStorage* StateStorage; ImGuiStorage* StateStorage;
int StackSizesBackup[5]; // store size of various stacks for asserting int StackSizesBackup[5]; // Store size of various stacks for asserting
float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
@ -1125,7 +1127,6 @@ struct ImGuiState
ImVector<ImGuiWindow*> WindowsSortBuffer; ImVector<ImGuiWindow*> WindowsSortBuffer;
ImGuiWindow* CurrentWindow; // Being drawn into ImGuiWindow* CurrentWindow; // Being drawn into
ImVector<ImGuiWindow*> CurrentWindowStack; ImVector<ImGuiWindow*> CurrentWindowStack;
int CurrentPopupStackSize;
ImGuiWindow* FocusedWindow; // Will catch keyboard inputs ImGuiWindow* FocusedWindow; // Will catch keyboard inputs
ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredWindow; // Will catch mouse inputs
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
@ -1142,6 +1143,8 @@ struct ImGuiState
ImVector<ImGuiColMod> ColorModifiers; ImVector<ImGuiColMod> ColorModifiers;
ImVector<ImGuiStyleMod> StyleModifiers; ImVector<ImGuiStyleMod> StyleModifiers;
ImVector<ImFont*> FontStack; ImVector<ImFont*> FontStack;
ImVector<ImGuiID> OpenedPopupStack; // Which popups are open
ImVector<ImGuiID> CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame)
ImVec2 SetNextWindowPosVal; ImVec2 SetNextWindowPosVal;
ImGuiSetCond SetNextWindowPosCond; ImGuiSetCond SetNextWindowPosCond;
@ -1164,7 +1167,7 @@ struct ImGuiState
// Widget state // Widget state
ImGuiTextEditState InputTextState; ImGuiTextEditState InputTextState;
ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
ImGuiStorage ColorEditModeStorage; // for user selection ImGuiStorage ColorEditModeStorage; // Store user selection of color edit mode
ImGuiID ActiveComboID; ImGuiID ActiveComboID;
ImVec2 ActiveClickDeltaToCenter; ImVec2 ActiveClickDeltaToCenter;
float DragCurrentValue; // current dragged value, always float, not rounded by end-user precision settings float DragCurrentValue; // current dragged value, always float, not rounded by end-user precision settings
@ -1200,7 +1203,6 @@ struct ImGuiState
FrameCount = 0; FrameCount = 0;
FrameCountRendered = -1; FrameCountRendered = -1;
CurrentWindow = NULL; CurrentWindow = NULL;
CurrentPopupStackSize = 0;
FocusedWindow = NULL; FocusedWindow = NULL;
HoveredWindow = NULL; HoveredWindow = NULL;
HoveredRootWindow = NULL; HoveredRootWindow = NULL;
@ -1272,6 +1274,7 @@ struct ImGuiWindow
bool Accessed; // Set to true when any widget access the current window bool Accessed; // Set to true when any widget access the current window
bool Collapsed; // Set when collapsing window to become only title-bar bool Collapsed; // Set when collapsing window to become only title-bar
bool SkipItems; // == Visible && !Collapsed bool SkipItems; // == Visible && !Collapsed
ImGuiID PopupID; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
int AutoFitFrames; int AutoFitFrames;
bool AutoFitOnlyGrows; bool AutoFitOnlyGrows;
int AutoPosLastDirection; int AutoPosLastDirection;
@ -1313,7 +1316,7 @@ public:
float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; }
float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; }
ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); }
ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders) && !(Flags & ImGuiWindowFlags_ComboBox)) ? ImVec2(0,0) : GImGui->Style.WindowPadding; } ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & (ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : GImGui->Style.WindowPadding; }
ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); } ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); }
ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }
}; };
@ -1436,8 +1439,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
return &it->val_p; return &it->val_p;
} }
// FIXME-OPT: Wasting CPU because all SetInt() are preceeded by GetInt() calls so we should have the result from lower_bound already in place. // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
// However we only use SetInt() on explicit user action (so that's maximum once a frame) so the optimisation isn't much needed.
void ImGuiStorage::SetInt(ImU32 key, int val) void ImGuiStorage::SetInt(ImU32 key, int val)
{ {
ImVector<Pair>::iterator it = LowerBound(Data, key); ImVector<Pair>::iterator it = LowerBound(Data, key);
@ -1631,6 +1633,7 @@ ImGuiWindow::ImGuiWindow(const char* name)
Accessed = false; Accessed = false;
Collapsed = false; Collapsed = false;
SkipItems = false; SkipItems = false;
PopupID = 0;
AutoFitFrames = -1; AutoFitFrames = -1;
AutoFitOnlyGrows = false; AutoFitOnlyGrows = false;
AutoPosLastDirection = -1; AutoPosLastDirection = -1;
@ -2067,12 +2070,37 @@ 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);
CloseInactivePopups();
// Create implicit window - we will only render it if the user has added something to it. // Create implicit window - we will only render it if the user has added something to it.
ImGui::SetNextWindowSize(ImVec2(400,400), ImGuiSetCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(400,400), ImGuiSetCond_FirstUseEver);
ImGui::Begin("Debug"); ImGui::Begin("Debug");
} }
static void CloseInactivePopups()
{
ImGuiState& g = *GImGui;
if (g.OpenedPopupStack.empty())
return;
// User has clicked outside of a popup
if (!g.FocusedWindow || !(g.FocusedWindow->RootWindow->Flags & ImGuiWindowFlags_Popup))
{
g.OpenedPopupStack.resize(0);
return;
}
// When popups are stacked, clicking on a lower level popups puts focus back to it and close its child
IM_ASSERT(g.FocusedWindow->PopupID != 0);
for (size_t n = 0; n < g.OpenedPopupStack.size(); n++)
if (g.OpenedPopupStack[n] == g.FocusedWindow->PopupID)
{
g.OpenedPopupStack.resize(n+1);
return;
}
}
// NB: behavior of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations. // NB: behavior of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations.
void ImGui::Shutdown() void ImGui::Shutdown()
{ {
@ -2102,6 +2130,8 @@ void ImGui::Shutdown()
g.ColorModifiers.clear(); g.ColorModifiers.clear();
g.StyleModifiers.clear(); g.StyleModifiers.clear();
g.FontStack.clear(); g.FontStack.clear();
g.OpenedPopupStack.clear();
g.CurrentPopupStack.clear();
for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
g.RenderDrawLists[i].clear(); g.RenderDrawLists[i].clear();
g.MouseCursorDrawList.ClearFreeMemory(); g.MouseCursorDrawList.ClearFreeMemory();
@ -2895,30 +2925,65 @@ void ImGui::EndTooltip()
ImGui::End(); ImGui::End();
} }
void ImGui::BeginPopup(bool* p_opened) void ImGui::OpenPopup(const char* str_id)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(p_opened != NULL); // Must provide a bool at the moment const ImGuiID id = window->GetID(str_id);
// One open popup per level of the popup hierarchy
if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size())
g.OpenedPopupStack.push_back(id);
else if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size() + 1)
g.OpenedPopupStack.back() = id;
else
IM_ASSERT(0); // Invalid state
}
void ImGui::CloseCurrentPopup()
{
ImGuiState& g = *GImGui;
if (g.CurrentPopupStack.back() != g.OpenedPopupStack.back())
return;
if (g.Windows.back()->PopupID == g.OpenedPopupStack.back() && g.Windows.size() >= 2)
FocusWindow(g.Windows[g.Windows.size()-2]);
g.OpenedPopupStack.pop_back();
}
static bool IsPopupOpen(ImGuiID id)
{
ImGuiState& g = *GImGui;
const bool opened = g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()] == id;
return opened;
}
bool ImGui::BeginPopup(const char* str_id)
{
ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
const ImGuiID id = window->GetID(str_id);
if (!IsPopupOpen(id))
return false;
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGuiWindowFlags flags = ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; ImGuiWindowFlags flags = ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize;
float alpha = 1.0f;
char name[20]; char name[20];
ImFormatString(name, 20, "##Popup%02d", g.CurrentPopupStackSize++); ImFormatString(name, 20, "##Popup%02d", g.CurrentPopupStack.size()); // Recycle windows based on depth
ImGui::Begin(name, p_opened, ImVec2(0.0f, 0.0f), alpha, flags); float alpha = 1.0f;
bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), alpha, flags);
IM_ASSERT(opened);
if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) if (!(window->Flags & ImGuiWindowFlags_ShowBorders))
GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders;
return opened;
} }
void ImGui::EndPopup() void ImGui::EndPopup()
{ {
ImGuiState& g = *GImGui;
IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Popup); IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Popup);
IM_ASSERT(g.CurrentPopupStackSize > 0); IM_ASSERT(GImGui->CurrentPopupStack.size() > 0);
g.CurrentPopupStackSize--;
ImGui::End(); ImGui::End();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
} }
@ -3154,15 +3219,22 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
} }
window->Flags = (ImGuiWindowFlags)flags; window->Flags = (ImGuiWindowFlags)flags;
const int current_frame = ImGui::GetFrameCount();
const bool window_was_visible = (window->LastFrameDrawn == current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
// Add to stack // Add to stack
ImGuiWindow* parent_window = !g.CurrentWindowStack.empty() ? g.CurrentWindowStack.back() : NULL; ImGuiWindow* parent_window = !g.CurrentWindowStack.empty() ? g.CurrentWindowStack.back() : NULL;
g.CurrentWindowStack.push_back(window); g.CurrentWindowStack.push_back(window);
SetCurrentWindow(window); SetCurrentWindow(window);
CheckStacksSize(window, true); CheckStacksSize(window, true);
const int current_frame = ImGui::GetFrameCount();
bool window_was_visible = (window->LastFrameDrawn == current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
if (flags & ImGuiWindowFlags_Popup)
{
const ImGuiID popup_id = g.OpenedPopupStack[g.CurrentPopupStack.size()];
g.CurrentPopupStack.push_back(popup_id);
window_was_visible &= (window->PopupID == popup_id);
window->PopupID = popup_id;
}
// Process SetNextWindow***() calls // Process SetNextWindow***() calls
bool window_pos_set_by_api = false; bool window_pos_set_by_api = false;
if (g.SetNextWindowPosCond) if (g.SetNextWindowPosCond)
@ -3232,14 +3304,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->AutoPosLastDirection = -1; window->AutoPosLastDirection = -1;
if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
{
FocusWindow(window); FocusWindow(window);
// Popup first latch mouse position, will position itself when it appears next frame // Popup first latch mouse position, will position itself when it appears next frame
if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
window->PosFloat = g.IO.MousePos; window->PosFloat = g.IO.MousePos;
} }
}
// Collapse window by double-clicking on title bar // Collapse window by double-clicking on title bar
// At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
@ -3269,7 +3339,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->SizeContents.y += window->ScrollY; window->SizeContents.y += window->ScrollY;
// Hide popup/tooltip window when first appearing while we measure size (because we recycle them) // Hide popup/tooltip window when first appearing while we measure size (because we recycle them)
if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window->WasActive) if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window_was_visible)
{ {
window->HiddenFrames = 1; window->HiddenFrames = 1;
window->Size = window->SizeFull = window->SizeContents = ImVec2(0.f, 0.f); // TODO: We don't support SetNextWindowSize() for tooltips or popups yet window->Size = window->SizeFull = window->SizeContents = ImVec2(0.f, 0.f); // TODO: We don't support SetNextWindowSize() for tooltips or popups yet
@ -3548,18 +3618,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_rect.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y); const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_rect.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y);
RenderTextClipped(text_min, name, NULL, &text_size, text_max); RenderTextClipped(text_min, name, NULL, &text_size, text_max);
} }
if (flags & ImGuiWindowFlags_Popup)
{
if (p_opened)
{
if (g.IO.MouseClicked[0] && (!g.HoveredWindow || g.HoveredWindow->RootWindow != window))
*p_opened = false;
else if (!g.FocusedWindow)
*p_opened = false;
else if (g.FocusedWindow->RootWindow != window)// && !(g.FocusedWindow->RootWindow->Flags & ImGuiWindowFlags_Tooltip))
*p_opened = false;
}
}
// Save clipped aabb so we can access it in constant-time in FindHoveredWindow() // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
window->ClippedRect = window->Rect(); window->ClippedRect = window->Rect();
@ -3629,6 +3687,8 @@ void ImGui::End()
// NB: we don't clear 'window->RootWindow'. The pointer is allowed to live until the next call to Begin(). // NB: we don't clear 'window->RootWindow'. The pointer is allowed to live until the next call to Begin().
CheckStacksSize(window, false); CheckStacksSize(window, false);
g.CurrentWindowStack.pop_back(); g.CurrentWindowStack.pop_back();
if (window->Flags & ImGuiWindowFlags_Popup)
g.CurrentPopupStack.pop_back();
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
} }
@ -7141,6 +7201,10 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg)
//const ImVec2 off = ImVec2(ImMax(0.0f, size.x - text_size.x) * 0.5f, ImMax(0.0f, size.y - text_size.y) * 0.5f); //const ImVec2 off = ImVec2(ImMax(0.0f, size.x - text_size.x) * 0.5f, ImMax(0.0f, size.y - text_size.y) * 0.5f);
RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max); RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max);
// Automatically close popups
if (pressed && (window->Flags & ImGuiWindowFlags_Popup))
ImGui::CloseCurrentPopup();
return pressed; return pressed;
} }
@ -7262,7 +7326,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected)
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
const float symbol_spacing = (float)(int)(g.FontSize * 1.50f + 0.5f); const float symbol_spacing = (float)(int)(g.FontSize * 1.50f + 0.5f);
const float w = ImMax(label_size.x + symbol_spacing, window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x); // Feedback to next frame const float w = ImMax(label_size.x + symbol_spacing, window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x); // Feedback to next frame
bool ret = ImGui::Selectable(label, false, ImVec2(w, 0.0f)); bool pressed = ImGui::Selectable(label, false, ImVec2(w, 0.0f));
if (selected) if (selected)
{ {
@ -7270,7 +7334,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected)
RenderCheckMark(pos, window->Color(ImGuiCol_Text)); RenderCheckMark(pos, window->Color(ImGuiCol_Text));
} }
return ret; return pressed;
} }
bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected) bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected)
@ -10078,43 +10142,41 @@ void ImGui::ShowTestWindow(bool* opened)
static bool toggles[] = { true, false, false, false, false }; static bool toggles[] = { true, false, false, false, false };
{ {
static bool popup_open = false;
if (ImGui::Button("Select..")) if (ImGui::Button("Select.."))
popup_open = true; ImGui::OpenPopup("select");
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text(selected_fish == -1 ? "<None>" : names[selected_fish]); ImGui::Text(selected_fish == -1 ? "<None>" : names[selected_fish]);
if (popup_open) if (ImGui::BeginPopup("select"))
{ {
ImGui::BeginPopup(&popup_open);
ImGui::Text("Aquarium"); ImGui::Text("Aquarium");
ImGui::Separator(); ImGui::Separator();
for (int i = 0; i < IM_ARRAYSIZE(names); i++) for (int i = 0; i < IM_ARRAYSIZE(names); i++)
{
if (ImGui::Selectable(names[i])) if (ImGui::Selectable(names[i]))
{
selected_fish = i; selected_fish = i;
popup_open = false;
}
}
ImGui::EndPopup(); ImGui::EndPopup();
} }
} }
{ {
static bool popup_open = false;
if (ImGui::Button("Toggle..")) if (ImGui::Button("Toggle.."))
popup_open = true; ImGui::OpenPopup("toggle");
if (popup_open) if (ImGui::BeginPopup("toggle"))
{ {
ImGui::BeginPopup(&popup_open);
for (int i = 0; i < IM_ARRAYSIZE(names); i++) for (int i = 0; i < IM_ARRAYSIZE(names); i++)
if (ImGui::MenuItem(names[i], "", &toggles[i])) ImGui::MenuItem(names[i], "", &toggles[i]);
popup_open = false;
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Tooltip here"); ImGui::Text("Tooltip here");
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip over a popup"); ImGui::SetTooltip("I am a tooltip over a popup");
if (ImGui::Button("Stacked Popup"))
ImGui::OpenPopup("another popup");
if (ImGui::BeginPopup("another popup"))
{
for (int i = 0; i < IM_ARRAYSIZE(names); i++)
ImGui::MenuItem(names[i], "", &toggles[i]);
ImGui::EndPopup();
}
ImGui::EndPopup(); ImGui::EndPopup();
} }
} }

View File

@ -226,8 +226,10 @@ namespace ImGui
IMGUI_API void EndTooltip(); IMGUI_API void EndTooltip();
// Popup // Popup
IMGUI_API void BeginPopup(bool* p_opened); IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. will close when user click outside, or activate menu items, or CloseCurrentPopup() is called within a BeginPopup/EndPopup block.
IMGUI_API bool BeginPopup(const char* str_id); // return true if popup if opened and start outputting to it. only call EndPopup() if BeginPopup() returned true!
IMGUI_API void EndPopup(); IMGUI_API void EndPopup();
IMGUI_API void CloseCurrentPopup();
// Layout // Layout
IMGUI_API void BeginGroup(); IMGUI_API void BeginGroup();
@ -358,7 +360,7 @@ namespace ImGui
IMGUI_API void ListBoxFooter(); // terminate the scrolling region IMGUI_API void ListBoxFooter(); // terminate the scrolling region
// Widgets: Menus // Widgets: Menus
// FIXME-WIP: v1.39 in development // FIXME-WIP: v1.39 in development, API may change
IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = NULL); // bool enabled = true IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = NULL); // bool enabled = true
IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected); // bool enabled = true IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected); // bool enabled = true