mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-15 01:17:00 +00:00
WIP intermediary branch commit for menus, submenus (some large inconsistencies remaining in API + need cleanup) (#126)
May remove the ImGuiWindowFlags_Menu alltogether
This commit is contained in:
parent
79198fd6a5
commit
7fb704d308
179
imgui.cpp
179
imgui.cpp
@ -1016,7 +1016,10 @@ struct ImGuiDrawContext
|
||||
ImVector<ImGuiGroupData> GroupStack;
|
||||
ImGuiColorEditMode ColorEditMode;
|
||||
ImGuiStorage* StateStorage;
|
||||
int StackSizesBackup[5]; // Store size of various stacks for asserting
|
||||
float MenuTotalWidth; // Simplified columns storage for menu items
|
||||
float MenuColumnsCurr[3];
|
||||
float MenuColumnsNextWidth[3];
|
||||
int StackSizesBackup[6]; // Store size of various stacks for asserting
|
||||
|
||||
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.
|
||||
@ -1041,6 +1044,9 @@ struct ImGuiDrawContext
|
||||
LastItemHoveredAndUsable = LastItemHoveredRect = false;
|
||||
ColorEditMode = ImGuiColorEditMode_RGB;
|
||||
StateStorage = NULL;
|
||||
MenuTotalWidth = 0.0f;
|
||||
memset(MenuColumnsCurr, 0, sizeof(MenuColumnsCurr));
|
||||
memset(MenuColumnsNextWidth, 0, sizeof(MenuColumnsNextWidth));
|
||||
memset(StackSizesBackup, 0, sizeof(StackSizesBackup));
|
||||
|
||||
ColumnsStartX = 0.0f;
|
||||
@ -2944,13 +2950,21 @@ void ImGui::OpenPopup(const char* str_id)
|
||||
void ImGui::CloseCurrentPopup()
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
if (g.CurrentPopupStack.back() != g.OpenedPopupStack.back())
|
||||
if (g.CurrentPopupStack.empty() || g.OpenedPopupStack.empty() || 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 void CloseAllPopups()
|
||||
{
|
||||
// Close all popups
|
||||
// FIXME-MENUS: invalid for popup->menus with current BeginMenu() scheme
|
||||
ImGuiState& g = *GImGui;
|
||||
g.OpenedPopupStack.resize(0);
|
||||
}
|
||||
|
||||
static bool IsPopupOpen(ImGuiID id)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
@ -2958,7 +2972,7 @@ static bool IsPopupOpen(ImGuiID id)
|
||||
return opened;
|
||||
}
|
||||
|
||||
bool ImGui::BeginPopup(const char* str_id)
|
||||
static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
@ -2968,6 +2982,9 @@ bool ImGui::BeginPopup(const char* str_id)
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize;
|
||||
flags |= extra_flags;
|
||||
if ((flags & ImGuiWindowFlags_Menu) && (window->Flags & ImGuiWindowFlags_Popup))
|
||||
flags |= ImGuiWindowFlags_ChildWindow;
|
||||
|
||||
char name[20];
|
||||
ImFormatString(name, 20, "##Popup%02d", g.CurrentPopupStack.size()); // Recycle windows based on depth
|
||||
@ -2981,6 +2998,11 @@ bool ImGui::BeginPopup(const char* str_id)
|
||||
return opened;
|
||||
}
|
||||
|
||||
bool ImGui::BeginPopup(const char* str_id)
|
||||
{
|
||||
return BeginPopupEx(str_id, 0);
|
||||
}
|
||||
|
||||
void ImGui::EndPopup()
|
||||
{
|
||||
IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Popup);
|
||||
@ -3088,6 +3110,7 @@ static void CheckStacksSize(ImGuiWindow* window, bool write)
|
||||
int* p_backup = &window->DC.StackSizesBackup[0];
|
||||
{ int current = (int)window->IDStack.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopID()
|
||||
{ int current = (int)window->DC.GroupStack.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot EndGroup()
|
||||
{ int current = (int)g.CurrentPopupStack.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot EndPopup()/EndMenu()
|
||||
{ int current = (int)g.ColorModifiers.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopStyleColor()
|
||||
{ int current = (int)g.StyleModifiers.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopStyleVar()
|
||||
{ int current = (int)g.FontStack.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopFont()
|
||||
@ -3292,7 +3315,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
|
||||
// Setup texture, outer clipping rectangle
|
||||
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
|
||||
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
|
||||
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ComboBox|ImGuiWindowFlags_Popup)))
|
||||
PushClipRect(parent_window->ClipRectStack.back());
|
||||
else
|
||||
PushClipRect(GetVisibleRect());
|
||||
@ -3304,7 +3327,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
{
|
||||
window->AutoPosLastDirection = -1;
|
||||
|
||||
if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
|
||||
if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
|
||||
FocusWindow(window);
|
||||
|
||||
// Popup first latch mouse position, will position itself when it appears next frame
|
||||
@ -3394,14 +3417,21 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
|
||||
// Position child window
|
||||
if (flags & ImGuiWindowFlags_ChildWindow)
|
||||
{
|
||||
parent_window->DC.ChildWindows.push_back(window);
|
||||
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup))
|
||||
{
|
||||
window->Pos = window->PosFloat = parent_window->DC.CursorPos;
|
||||
window->SizeFull = size_on_first_use; // NB: argument name 'size_on_first_use' misleading here, it's really just 'size' as provided by user.
|
||||
}
|
||||
|
||||
// Position popup
|
||||
if ((flags & ImGuiWindowFlags_Popup) != 0 && window_appearing_after_being_hidden && !window_pos_set_by_api)
|
||||
if (flags & ImGuiWindowFlags_Menu)
|
||||
{
|
||||
IM_ASSERT(window_pos_set_by_api);
|
||||
ImRect rect_to_avoid = ImRect(parent_window->Pos.x + 4.0f, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - 4.0f, FLT_MAX); // We want some overlap to convey the relative depth of each popup (here hard-coded to 4)
|
||||
window->PosFloat = FindBestWindowPos(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
|
||||
}
|
||||
else if ((flags & ImGuiWindowFlags_Popup) != 0 && window_appearing_after_being_hidden && !window_pos_set_by_api)
|
||||
{
|
||||
ImRect rect_to_avoid(window->PosFloat.x - 1, window->PosFloat.y - 1, window->PosFloat.x + 1, window->PosFloat.y + 1);
|
||||
window->PosFloat = FindBestWindowPos(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
|
||||
@ -3524,6 +3554,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_ComboBg, bg_alpha), window_rounding);
|
||||
else if ((flags & ImGuiWindowFlags_Tooltip) != 0)
|
||||
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_TooltipBg, bg_alpha), window_rounding);
|
||||
else if ((flags & ImGuiWindowFlags_Popup) != 0)
|
||||
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_WindowBg, bg_alpha), window_rounding);
|
||||
else if ((flags & ImGuiWindowFlags_ChildWindow) != 0)
|
||||
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarY?style.ScrollbarWidth:0.0f,0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF));
|
||||
else
|
||||
@ -3593,6 +3625,18 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
|
||||
window->DC.StateStorage = &window->StateStorage;
|
||||
window->DC.GroupStack.resize(0);
|
||||
|
||||
window->DC.MenuTotalWidth = 0.0f;
|
||||
for (size_t n = 0; n < IM_ARRAYSIZE(window->DC.MenuColumnsCurr); n++)
|
||||
{
|
||||
if (!window_was_visible)
|
||||
window->DC.MenuColumnsNextWidth[n] = 0.0f;
|
||||
if (n > 0 && window->DC.MenuColumnsNextWidth[n] > 0.0f)
|
||||
window->DC.MenuTotalWidth += style.ItemInnerSpacing.x;
|
||||
window->DC.MenuColumnsCurr[n] = window->DC.MenuTotalWidth;
|
||||
window->DC.MenuTotalWidth += window->DC.MenuColumnsNextWidth[n];
|
||||
window->DC.MenuColumnsNextWidth[n] = 0.0f;
|
||||
}
|
||||
|
||||
if (window->AutoFitFrames > 0)
|
||||
window->AutoFitFrames--;
|
||||
|
||||
@ -3680,10 +3724,10 @@ void ImGui::End()
|
||||
|
||||
// Pop
|
||||
// NB: we don't clear 'window->RootWindow'. The pointer is allowed to live until the next call to Begin().
|
||||
CheckStacksSize(window, false);
|
||||
g.CurrentWindowStack.pop_back();
|
||||
if (window->Flags & ImGuiWindowFlags_Popup)
|
||||
g.CurrentPopupStack.pop_back();
|
||||
CheckStacksSize(window, false);
|
||||
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
|
||||
}
|
||||
|
||||
@ -7198,9 +7242,10 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg)
|
||||
RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max);
|
||||
|
||||
// Automatically close popups
|
||||
if (pressed && (window->Flags & ImGuiWindowFlags_Popup))
|
||||
if (pressed && (window->Flags & ImGuiWindowFlags_Menu))
|
||||
CloseAllPopups();
|
||||
else if (pressed && (window->Flags & ImGuiWindowFlags_Popup))
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
@ -7311,8 +7356,6 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
|
||||
|
||||
bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected)
|
||||
{
|
||||
(void)shortcut; // FIXME-MENU: Shortcut are not supported yet. Argument is reserved.
|
||||
|
||||
ImGuiState& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
@ -7320,16 +7363,28 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected)
|
||||
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
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 ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f);
|
||||
|
||||
window->DC.MenuColumnsNextWidth[0] = ImMax(window->DC.MenuColumnsNextWidth[0], label_size.x + (shortcut_size.x > 0.0f ? g.FontSize : 0.0f)); // Feedback to next frame
|
||||
window->DC.MenuColumnsNextWidth[1] = ImMax(window->DC.MenuColumnsNextWidth[1], shortcut_size.x);
|
||||
window->DC.MenuColumnsNextWidth[2] = ImMax(window->DC.MenuColumnsNextWidth[2], (float)(int)(g.FontSize * 1.20f + 0.5f));
|
||||
|
||||
const float avail_w = window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x;
|
||||
const float menu_w = window->DC.MenuTotalWidth; // Feedback from previous frame
|
||||
const float w = ImMax(avail_w, menu_w);
|
||||
const float extra_w = w - menu_w;
|
||||
bool pressed = ImGui::Selectable(label, false, ImVec2(w, 0.0f));
|
||||
|
||||
if (selected)
|
||||
if (shortcut_size.x > 0.0f)
|
||||
{
|
||||
pos.x = window->Pos.x + ImGui::GetContentRegionMax().x - g.FontSize;
|
||||
RenderCheckMark(pos, window->Color(ImGuiCol_Text));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
|
||||
RenderText(pos + ImVec2(window->DC.MenuColumnsCurr[1] + extra_w, 0.0f), shortcut, NULL, false);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
if (selected)
|
||||
RenderCheckMark(pos + ImVec2(window->DC.MenuColumnsCurr[2] + extra_w, 0.0f), window->Color(ImGuiCol_Text));
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
@ -7344,6 +7399,53 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected)
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME-WIP: v1.39 in development, API *WILL* change!
|
||||
bool ImGui::BeginMenu(const char* label)
|
||||
{
|
||||
ImGuiState& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
const ImGuiID id = window->GetID(label);
|
||||
bool opened = IsPopupOpen(id);
|
||||
|
||||
const ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
|
||||
const float w = window->DC.MenuTotalWidth; // Feedback from next frame
|
||||
window->DC.MenuColumnsNextWidth[0] = ImMax(window->DC.MenuColumnsNextWidth[0], label_size.x); // Feedback to next frame
|
||||
window->DC.MenuColumnsNextWidth[2] = ImMax(window->DC.MenuColumnsNextWidth[2], (float)(int)(g.FontSize * 1.20f + 0.5f));
|
||||
ImGui::Selectable(label, opened, ImVec2(w, 0.0f));
|
||||
|
||||
RenderCollapseTriangle(pos + ImVec2(window->DC.MenuTotalWidth - g.FontSize, 0.0f), false);
|
||||
|
||||
bool hovered = ImGui::IsItemHovered();
|
||||
if (!opened && hovered)
|
||||
{
|
||||
ImGui::OpenPopup(label);
|
||||
opened = true;
|
||||
}
|
||||
else if (opened && !hovered && g.HoveredWindow == window)
|
||||
{
|
||||
g.OpenedPopupStack.pop_back();
|
||||
opened = false;
|
||||
}
|
||||
if (opened)
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y - g.Style.WindowPadding.y), ImGuiSetCond_Always);
|
||||
bool popup_opened = BeginPopupEx(label, ImGuiWindowFlags_Menu);
|
||||
IM_ASSERT(opened == popup_opened);
|
||||
}
|
||||
|
||||
return opened;
|
||||
}
|
||||
|
||||
void ImGui::EndMenu()
|
||||
{
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// A little colored square. Return true when clicked.
|
||||
bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_border)
|
||||
{
|
||||
@ -10137,7 +10239,6 @@ void ImGui::ShowTestWindow(bool* opened)
|
||||
const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
|
||||
static bool toggles[] = { true, false, false, false, false };
|
||||
|
||||
{
|
||||
if (ImGui::Button("Select.."))
|
||||
ImGui::OpenPopup("select");
|
||||
ImGui::SameLine();
|
||||
@ -10151,8 +10252,7 @@ void ImGui::ShowTestWindow(bool* opened)
|
||||
selected_fish = i;
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
if (ImGui::Button("Toggle.."))
|
||||
ImGui::OpenPopup("toggle");
|
||||
if (ImGui::BeginPopup("toggle"))
|
||||
@ -10175,6 +10275,45 @@ void ImGui::ShowTestWindow(bool* opened)
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Popup Menu.."))
|
||||
ImGui::OpenPopup("context menu");
|
||||
if (ImGui::BeginPopup("context menu"))
|
||||
{
|
||||
ImGui::MenuItem("New");
|
||||
ImGui::MenuItem("Open", "Ctrl+O");
|
||||
if (ImGui::BeginMenu("Open Recent"))
|
||||
{
|
||||
ImGui::MenuItem("fish_hat.c");
|
||||
ImGui::MenuItem("fish_hat.inl");
|
||||
ImGui::MenuItem("fish_hat.h");
|
||||
if (ImGui::BeginMenu("More.."))
|
||||
{
|
||||
ImGui::MenuItem("Hello");
|
||||
ImGui::MenuItem("Sailor");
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::MenuItem("Save", "Ctrl+S");
|
||||
ImGui::MenuItem("Save As..");
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginMenu("Options"))
|
||||
{
|
||||
static bool enabled = true;
|
||||
static float f = 0.5f;
|
||||
ImGui::MenuItem("Enabled", "", &enabled);
|
||||
ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Colors"))
|
||||
{
|
||||
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
||||
ImGui::MenuItem(ImGui::GetStyleColName((ImGuiCol)i));
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::MenuItem("Quit", "Alt+F4");
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
|
8
imgui.h
8
imgui.h
@ -360,7 +360,9 @@ namespace ImGui
|
||||
IMGUI_API void ListBoxFooter(); // terminate the scrolling region
|
||||
|
||||
// Widgets: Menus
|
||||
// FIXME-WIP: v1.39 in development, API may change
|
||||
// FIXME-WIP: v1.39 in development, API *WILL* change
|
||||
IMGUI_API bool BeginMenu(const char* label);
|
||||
IMGUI_API void EndMenu();
|
||||
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
|
||||
|
||||
@ -458,7 +460,9 @@ enum ImGuiWindowFlags_
|
||||
ImGuiWindowFlags_ChildWindowAutoFitY = 1 << 11, // For internal use by BeginChild()
|
||||
ImGuiWindowFlags_ComboBox = 1 << 12, // For internal use by ComboBox()
|
||||
ImGuiWindowFlags_Tooltip = 1 << 13, // For internal use by BeginTooltip()
|
||||
ImGuiWindowFlags_Popup = 1 << 14 // For internal use by BeginPopup()
|
||||
ImGuiWindowFlags_Popup = 1 << 14, // For internal use by BeginPopup()
|
||||
ImGuiWindowFlags_Menu = 1 << 15 // For internal use by BeginMenu()
|
||||
|
||||
};
|
||||
|
||||
// Flags for ImGui::InputText()
|
||||
|
Loading…
Reference in New Issue
Block a user