From fcd08ed8d48da8fd59134a9e45f274928b80cf0a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 May 2015 15:57:02 +0100 Subject: [PATCH 001/127] BeginPopup() API had to be changed! :( Proper support for stacked popups, leading into menus (wip #126) --- imgui.cpp | 170 +++++++++++++++++++++++++++++++++++++----------------- imgui.h | 6 +- 2 files changed, 120 insertions(+), 56 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c70229e3..91c081db 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -136,6 +136,7 @@ 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. + - 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/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 @@ -517,6 +518,7 @@ static void Scrollbar(ImGuiWindow* window); static bool CloseWindowButton(bool* p_opened = NULL); static void FocusWindow(ImGuiWindow* window); static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs); +static void CloseInactivePopups(); // Helpers: String static int ImStricmp(const char* str1, const char* str2); @@ -1013,7 +1015,7 @@ struct ImGuiDrawContext ImVector GroupStack; ImGuiColorEditMode ColorEditMode; 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 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 WindowsSortBuffer; ImGuiWindow* CurrentWindow; // Being drawn into ImVector CurrentWindowStack; - int CurrentPopupStackSize; ImGuiWindow* FocusedWindow; // Will catch keyboard inputs ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) @@ -1142,6 +1143,8 @@ struct ImGuiState ImVector ColorModifiers; ImVector StyleModifiers; ImVector FontStack; + ImVector OpenedPopupStack; // Which popups are open + ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) ImVec2 SetNextWindowPosVal; ImGuiSetCond SetNextWindowPosCond; @@ -1164,7 +1167,7 @@ struct ImGuiState // Widget state ImGuiTextEditState InputTextState; 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; ImVec2 ActiveClickDeltaToCenter; float DragCurrentValue; // current dragged value, always float, not rounded by end-user precision settings @@ -1200,7 +1203,6 @@ struct ImGuiState FrameCount = 0; FrameCountRendered = -1; CurrentWindow = NULL; - CurrentPopupStackSize = 0; FocusedWindow = NULL; HoveredWindow = NULL; HoveredRootWindow = NULL; @@ -1272,6 +1274,7 @@ struct ImGuiWindow bool Accessed; // Set to true when any widget access the current window bool Collapsed; // Set when collapsing window to become only title-bar 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; bool AutoFitOnlyGrows; int AutoPosLastDirection; @@ -1313,7 +1316,7 @@ public: float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } 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())); } - 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(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; } -// FIXME-OPT: Wasting CPU because all SetInt() are preceeded by GetInt() calls so we should have the result from lower_bound already in place. -// However we only use SetInt() on explicit user action (so that's maximum once a frame) so the optimisation isn't much needed. +// 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) void ImGuiStorage::SetInt(ImU32 key, int val) { ImVector::iterator it = LowerBound(Data, key); @@ -1631,6 +1633,7 @@ ImGuiWindow::ImGuiWindow(const char* name) Accessed = false; Collapsed = false; SkipItems = false; + PopupID = 0; AutoFitFrames = -1; AutoFitOnlyGrows = false; AutoPosLastDirection = -1; @@ -2067,12 +2070,37 @@ void ImGui::NewFrame() // 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. 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. ImGui::SetNextWindowSize(ImVec2(400,400), ImGuiSetCond_FirstUseEver); 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. void ImGui::Shutdown() { @@ -2102,6 +2130,8 @@ void ImGui::Shutdown() g.ColorModifiers.clear(); g.StyleModifiers.clear(); g.FontStack.clear(); + g.OpenedPopupStack.clear(); + g.CurrentPopupStack.clear(); for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) g.RenderDrawLists[i].clear(); g.MouseCursorDrawList.ClearFreeMemory(); @@ -2895,30 +2925,65 @@ void ImGui::EndTooltip() ImGui::End(); } -void ImGui::BeginPopup(bool* p_opened) +void ImGui::OpenPopup(const char* str_id) { ImGuiState& g = *GImGui; 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); ImGuiWindowFlags flags = ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; - float alpha = 1.0f; char name[20]; - ImFormatString(name, 20, "##Popup%02d", g.CurrentPopupStackSize++); - ImGui::Begin(name, p_opened, ImVec2(0.0f, 0.0f), alpha, flags); + ImFormatString(name, 20, "##Popup%02d", g.CurrentPopupStack.size()); // Recycle windows based on depth + 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)) GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; + + return opened; } void ImGui::EndPopup() { - ImGuiState& g = *GImGui; IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Popup); - IM_ASSERT(g.CurrentPopupStackSize > 0); - g.CurrentPopupStackSize--; + IM_ASSERT(GImGui->CurrentPopupStack.size() > 0); ImGui::End(); ImGui::PopStyleVar(); } @@ -3153,16 +3218,23 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window_is_new = true; } 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 ImGuiWindow* parent_window = !g.CurrentWindowStack.empty() ? g.CurrentWindowStack.back() : NULL; g.CurrentWindowStack.push_back(window); SetCurrentWindow(window); 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 bool window_pos_set_by_api = false; if (g.SetNextWindowPosCond) @@ -3232,13 +3304,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->AutoPosLastDirection = -1; if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) - { FocusWindow(window); - // Popup first latch mouse position, will position itself when it appears next frame - if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) - window->PosFloat = g.IO.MousePos; - } + // Popup first latch mouse position, will position itself when it appears next frame + if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) + window->PosFloat = g.IO.MousePos; } // Collapse window by double-clicking on title bar @@ -3269,7 +3339,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->SizeContents.y += window->ScrollY; // 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->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); 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() 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(). CheckStacksSize(window, false); g.CurrentWindowStack.pop_back(); + if (window->Flags & ImGuiWindowFlags_Popup) + g.CurrentPopupStack.pop_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); RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max); + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup)) + ImGui::CloseCurrentPopup(); + 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 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 - bool ret = ImGui::Selectable(label, false, ImVec2(w, 0.0f)); + bool pressed = ImGui::Selectable(label, false, ImVec2(w, 0.0f)); if (selected) { @@ -7270,7 +7334,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) RenderCheckMark(pos, window->Color(ImGuiCol_Text)); } - return ret; + return pressed; } 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 popup_open = false; if (ImGui::Button("Select..")) - popup_open = true; + ImGui::OpenPopup("select"); ImGui::SameLine(); ImGui::Text(selected_fish == -1 ? "" : names[selected_fish]); - if (popup_open) + if (ImGui::BeginPopup("select")) { - ImGui::BeginPopup(&popup_open); ImGui::Text("Aquarium"); ImGui::Separator(); for (int i = 0; i < IM_ARRAYSIZE(names); i++) - { if (ImGui::Selectable(names[i])) - { selected_fish = i; - popup_open = false; - } - } ImGui::EndPopup(); } } { - static bool popup_open = false; if (ImGui::Button("Toggle..")) - popup_open = true; - if (popup_open) + ImGui::OpenPopup("toggle"); + if (ImGui::BeginPopup("toggle")) { - ImGui::BeginPopup(&popup_open); for (int i = 0; i < IM_ARRAYSIZE(names); i++) - if (ImGui::MenuItem(names[i], "", &toggles[i])) - popup_open = false; + ImGui::MenuItem(names[i], "", &toggles[i]); ImGui::Separator(); ImGui::Text("Tooltip here"); if (ImGui::IsItemHovered()) 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(); } } diff --git a/imgui.h b/imgui.h index dc435aab..c313e854 100644 --- a/imgui.h +++ b/imgui.h @@ -226,8 +226,10 @@ namespace ImGui IMGUI_API void EndTooltip(); // 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 CloseCurrentPopup(); // Layout IMGUI_API void BeginGroup(); @@ -358,7 +360,7 @@ namespace ImGui IMGUI_API void ListBoxFooter(); // terminate the scrolling region // 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, bool* p_selected); // bool enabled = true From 141ac8beabfcedb5a8b61d3fedf643bc19aa6b65 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 May 2015 18:28:30 +0100 Subject: [PATCH 002/127] Tweaks --- imgui.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 91c081db..ea56eef5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3454,14 +3454,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->ItemWidthDefault = 200.0f; // Prepare for focus requests - if (window->FocusIdxAllRequestNext == IM_INT_MAX || window->FocusIdxAllCounter == -1) - window->FocusIdxAllRequestCurrent = IM_INT_MAX; - else - window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); - if (window->FocusIdxTabRequestNext == IM_INT_MAX || window->FocusIdxTabCounter == -1) - window->FocusIdxTabRequestCurrent = IM_INT_MAX; - else - window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); + window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == IM_INT_MAX || window->FocusIdxAllCounter == -1) ? IM_INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); + window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == IM_INT_MAX || window->FocusIdxTabCounter == -1) ? IM_INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; From 34aad73fd8d513627b0c5cf8f18b6d5c8eb70aa9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 May 2015 19:36:32 +0100 Subject: [PATCH 003/127] Added ImGuiCol_TextDisabled --- imgui.cpp | 2 ++ imgui.h | 1 + 2 files changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index ea56eef5..b3f190c8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -576,6 +576,7 @@ ImGuiStyle::ImGuiStyle() DisplaySafeAreaPadding = ImVec2(4,4); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 0.65f); @@ -3969,6 +3970,7 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) switch (idx) { case ImGuiCol_Text: return "Text"; + case ImGuiCol_TextDisabled: return "TextDisabled"; case ImGuiCol_WindowBg: return "WindowBg"; case ImGuiCol_ChildWindowBg: return "ChildWindowBg"; case ImGuiCol_Border: return "Border"; diff --git a/imgui.h b/imgui.h index c313e854..8adbd44b 100644 --- a/imgui.h +++ b/imgui.h @@ -504,6 +504,7 @@ enum ImGuiKey_ enum ImGuiCol_ { ImGuiCol_Text, + ImGuiCol_TextDisabled, ImGuiCol_WindowBg, ImGuiCol_ChildWindowBg, ImGuiCol_Border, From 79198fd6a5d6f4cffc4904499e3e5c5f4a8242ff Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 May 2015 19:47:01 +0100 Subject: [PATCH 004/127] Default item width for AlwaysAutoResize windows expressed as a factor of font height --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index b3f190c8..333e2335 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3452,7 +3452,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); else - window->ItemWidthDefault = 200.0f; + window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); // Prepare for focus requests window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == IM_INT_MAX || window->FocusIdxAllCounter == -1) ? IM_INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); From 7fb704d308dcf0b99c0492317433513baa54de06 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 May 2015 19:52:02 +0100 Subject: [PATCH 005/127] WIP intermediary branch commit for menus, submenus (some large inconsistencies remaining in API + need cleanup) (#126) May remove the ImGuiWindowFlags_Menu alltogether --- imgui.cpp | 233 +++++++++++++++++++++++++++++++++++++++++++----------- imgui.h | 8 +- 2 files changed, 192 insertions(+), 49 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 333e2335..601618f4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1016,7 +1016,10 @@ struct ImGuiDrawContext ImVector 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,44 +10239,81 @@ 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(); + ImGui::Text(selected_fish == -1 ? "" : names[selected_fish]); + if (ImGui::BeginPopup("select")) { - if (ImGui::Button("Select..")) - ImGui::OpenPopup("select"); - ImGui::SameLine(); - ImGui::Text(selected_fish == -1 ? "" : names[selected_fish]); - if (ImGui::BeginPopup("select")) - { - ImGui::Text("Aquarium"); - ImGui::Separator(); - for (int i = 0; i < IM_ARRAYSIZE(names); i++) - if (ImGui::Selectable(names[i])) - selected_fish = i; - ImGui::EndPopup(); - } + ImGui::Text("Aquarium"); + ImGui::Separator(); + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + if (ImGui::Selectable(names[i])) + selected_fish = i; + ImGui::EndPopup(); } + + if (ImGui::Button("Toggle..")) + ImGui::OpenPopup("toggle"); + if (ImGui::BeginPopup("toggle")) { - if (ImGui::Button("Toggle..")) - ImGui::OpenPopup("toggle"); - if (ImGui::BeginPopup("toggle")) + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + ImGui::MenuItem(names[i], "", &toggles[i]); + + ImGui::Separator(); + ImGui::Text("Tooltip here"); + if (ImGui::IsItemHovered()) + 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::Separator(); - ImGui::Text("Tooltip here"); - if (ImGui::IsItemHovered()) - 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(); + } + + 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(); diff --git a/imgui.h b/imgui.h index 8adbd44b..5a99f728 100644 --- a/imgui.h +++ b/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() From ba7a4fc03406fc3c4acc4f7214ee03bf2ff7489b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 May 2015 20:34:52 +0100 Subject: [PATCH 006/127] WIP Menus: minor cleanup using a ImGuiSimpleColumns helper type (#126) --- imgui.cpp | 73 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 601618f4..ec940482 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -992,6 +992,37 @@ struct ImGuiGroupData float BackupLogLinePosY; }; +// Simple column measurement currently used for menu items +struct ImGuiSimpleColumns +{ + int Count; + float Width; + float Pos[8], NextWidths[8]; + + ImGuiSimpleColumns() { Count = 0; Width = 0.0f; memset(Pos, 0, sizeof(Pos)); memset(NextWidths, 0, sizeof(NextWidths)); } + void Update(int count, float spacing, bool clear) + { + Count = count; + Width = 0.0f; + if (clear) + memset(NextWidths, 0, sizeof(NextWidths)); + for (int i = 0; i < Count; i++) + { + if (i > 0 && NextWidths[i] > 0.0f) + Width += spacing; + Pos[i] = (float)(int)Width; + Width += NextWidths[i]; + NextWidths[i] = 0.0f; + } + } + void Extend(float w0, float w1, float w2) // not using va_arg because they promote float to double + { + NextWidths[0] = ImMax(NextWidths[0], w0); + NextWidths[1] = ImMax(NextWidths[1], w1); + NextWidths[2] = ImMax(NextWidths[2], w2); + } +}; + // Temporary per-window data, reset at the beginning of the frame struct ImGuiDrawContext { @@ -1016,9 +1047,6 @@ struct ImGuiDrawContext ImVector GroupStack; ImGuiColorEditMode ColorEditMode; ImGuiStorage* StateStorage; - 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.) @@ -1044,9 +1072,6 @@ 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; @@ -1296,6 +1321,7 @@ struct ImGuiWindow ImRect ClippedRect; // = ClipRectStack.front() after setup in Begin() int LastFrameDrawn; float ItemWidthDefault; + ImGuiSimpleColumns MenuColumns; // Simplified columns storage for menu items ImGuiStorage StateStorage; float FontWindowScale; // Scale multiplier per-window ImDrawList* DrawList; @@ -3624,18 +3650,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DC.TreeDepth = 0; 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; - } + window->MenuColumns.Update(3, style.ItemInnerSpacing.x, !window_was_visible); if (window->AutoFitFrames > 0) window->AutoFitFrames--; @@ -7364,26 +7379,22 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) ImVec2 pos = ImGui::GetCursorScreenPos(); const ImVec2 label_size = CalcTextSize(label, NULL, true); 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)); + window->MenuColumns.Extend(label_size.x, shortcut_size.x, g.FontSize * 1.20f); // Feedback for next frame 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; + const float w = ImMax(avail_w, window->MenuColumns.Width); // Feedback from previous frame + const float extra_w = w - window->MenuColumns.Width; bool pressed = ImGui::Selectable(label, false, ImVec2(w, 0.0f)); if (shortcut_size.x > 0.0f) { ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); - RenderText(pos + ImVec2(window->DC.MenuColumnsCurr[1] + extra_w, 0.0f), shortcut, NULL, false); + RenderText(pos + ImVec2(window->MenuColumns.Pos[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)); + RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w, 0.0f), window->Color(ImGuiCol_Text)); return pressed; } @@ -7412,13 +7423,11 @@ bool ImGui::BeginMenu(const char* label) const ImVec2 pos = ImGui::GetCursorScreenPos(); const ImVec2 label_size = CalcTextSize(label, NULL, true); + window->MenuColumns.Extend(label_size.x, 0.0f, g.FontSize * 1.20f); // Feedback to next frame - 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)); + const float w = window->MenuColumns.Width; // Feedback from next frame ImGui::Selectable(label, opened, ImVec2(w, 0.0f)); - - RenderCollapseTriangle(pos + ImVec2(window->DC.MenuTotalWidth - g.FontSize, 0.0f), false); + RenderCollapseTriangle(pos + ImVec2(w - g.FontSize, 0.0f), false); bool hovered = ImGui::IsItemHovered(); if (!opened && hovered) From 317744489f0cd8a9a32d0ced75ea2e428f29e47d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 May 2015 20:58:07 +0100 Subject: [PATCH 007/127] WIP Menus: sub-menu arrow alignment take account of extension by other widgets (#126) --- imgui.cpp | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fba539c0..395e3953 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1005,8 +1005,7 @@ struct ImGuiSimpleColumns { Count = count; Width = 0.0f; - if (clear) - memset(NextWidths, 0, sizeof(NextWidths)); + if (clear) memset(NextWidths, 0, sizeof(NextWidths)); for (int i = 0; i < Count; i++) { if (i > 0 && NextWidths[i] > 0.0f) @@ -1022,6 +1021,14 @@ struct ImGuiSimpleColumns NextWidths[1] = ImMax(NextWidths[1], w1); NextWidths[2] = ImMax(NextWidths[2], w2); } + void FillExtraSpace(float avail_w, int column_no) + { + if (Width >= avail_w) return; + float extra_w = avail_w - Width; + Width = avail_w; + for (int i = column_no+1; i < Count; i++) + Pos[i] += extra_w; + } }; // Temporary per-window data, reset at the beginning of the frame @@ -7381,24 +7388,23 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) return false; ImVec2 pos = ImGui::GetCursorScreenPos(); - const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); - window->MenuColumns.Extend(label_size.x, shortcut_size.x, g.FontSize * 1.20f); // Feedback for next frame + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); + window->MenuColumns.Extend(label_size.x, shortcut_size.x, g.FontSize * 1.10f); // Feedback for next frame + window->MenuColumns.FillExtraSpace(window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x, 0); - const float avail_w = window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x; - const float w = ImMax(avail_w, window->MenuColumns.Width); // Feedback from previous frame - const float extra_w = w - window->MenuColumns.Width; + float w = window->MenuColumns.Width; bool pressed = ImGui::Selectable(label, false, ImVec2(w, 0.0f)); if (shortcut_size.x > 0.0f) { ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); - RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); + RenderText(pos + ImVec2(window->MenuColumns.Pos[1], 0.0f), shortcut, NULL, false); ImGui::PopStyleColor(); } if (selected) - RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w, 0.0f), window->Color(ImGuiCol_Text)); + RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + g.FontSize * 0.10f, 0.0f), window->Color(ImGuiCol_Text)); return pressed; } @@ -7425,13 +7431,14 @@ bool ImGui::BeginMenu(const char* label) const ImGuiID id = window->GetID(label); bool opened = IsPopupOpen(id); - const ImVec2 pos = ImGui::GetCursorScreenPos(); - const ImVec2 label_size = CalcTextSize(label, NULL, true); - window->MenuColumns.Extend(label_size.x, 0.0f, g.FontSize * 1.20f); // Feedback to next frame + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 label_size = CalcTextSize(label, NULL, true); + window->MenuColumns.Extend(label_size.x, 0.0f, g.FontSize * 1.10f); // Feedback to next frame + window->MenuColumns.FillExtraSpace(window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x, 0); - const float w = window->MenuColumns.Width; // Feedback from next frame + float w = window->MenuColumns.Width; ImGui::Selectable(label, opened, ImVec2(w, 0.0f)); - RenderCollapseTriangle(pos + ImVec2(w - g.FontSize, 0.0f), false); + RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + g.FontSize * 0.20f, 0.0f), false); bool hovered = ImGui::IsItemHovered(); if (!opened && hovered) @@ -10273,6 +10280,11 @@ void ImGui::ShowTestWindow(bool* opened) { for (int i = 0; i < IM_ARRAYSIZE(names); i++) ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Hello"); + ImGui::EndMenu(); + } ImGui::Separator(); ImGui::Text("Tooltip here"); From 748072c04531d1832f2c346039c0f451c2638fbf Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 May 2015 15:15:17 +0100 Subject: [PATCH 008/127] Popups: identifying popups by their id to avoid conflict when recycling popup durnig same same (CloseCurrentPopup followed by Open+Begin) --- imgui.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b0d68479..6336cda9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3021,8 +3021,11 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags 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 + char name[32]; + if (flags & ImGuiWindowFlags_Menu) + ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.size()); // Recycle windows based on depth + else + ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame float alpha = 1.0f; bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), alpha, flags); IM_ASSERT(opened); @@ -3087,7 +3090,7 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, bool ImGui::BeginChild(ImGuiID id, const ImVec2& size, bool border, ImGuiWindowFlags extra_flags) { char str_id[32]; - ImFormatString(str_id, IM_ARRAYSIZE(str_id), "child_%x", id); + ImFormatString(str_id, IM_ARRAYSIZE(str_id), "child_%08x", id); bool ret = ImGui::BeginChild(str_id, size, border, extra_flags); return ret; } From d9b2a90773a5b22b9ebedb1dd85b9efd291cdf82 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 11:30:51 +0100 Subject: [PATCH 009/127] Popups: fixed child windows within popups vs handling of sub menus. Added examples. --- imgui.cpp | 51 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6336cda9..c5ce7a1f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1149,6 +1149,14 @@ struct ImGuiMouseCursorData ImVec2 TexUvMax[2]; }; +struct ImGuiPopupRef +{ + ImGuiID PopupID; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + + ImGuiPopupRef(ImGuiID id) { PopupID = id; Window = NULL; } +}; + // Main state for ImGui struct ImGuiState { @@ -1183,8 +1191,8 @@ struct ImGuiState ImVector ColorModifiers; ImVector StyleModifiers; ImVector FontStack; - ImVector OpenedPopupStack; // Which popups are open - ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) + ImVector OpenedPopupStack; // Which popups are open + ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) ImVec2 SetNextWindowPosVal; ImGuiSetCond SetNextWindowPosCond; @@ -2132,12 +2140,16 @@ static void CloseInactivePopups() 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) + // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it + IM_ASSERT(g.FocusedWindow->RootWindow->PopupID != 0); + for (int n = 0; n < (int)g.OpenedPopupStack.size()-1; n++) + if (g.OpenedPopupStack[n].PopupID == g.FocusedWindow->RootWindow->PopupID) { - g.OpenedPopupStack.resize(n+1); + // Don't close our own Child Popup windows + while (++n < (int)g.OpenedPopupStack.size()) + if (!g.OpenedPopupStack[n].Window || !(g.OpenedPopupStack[n].Window->Flags & ImGuiWindowFlags_ChildWindow)) + break; + g.OpenedPopupStack.resize(n); return; } } @@ -2975,9 +2987,9 @@ void ImGui::OpenPopup(const char* str_id) // One open popup per level of the popup hierarchy if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size()) - g.OpenedPopupStack.push_back(id); + g.OpenedPopupStack.push_back(ImGuiPopupRef(id)); else if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size() + 1) - g.OpenedPopupStack.back() = id; + g.OpenedPopupStack.back() = ImGuiPopupRef(id); else IM_ASSERT(0); // Invalid state } @@ -2985,9 +2997,9 @@ void ImGui::OpenPopup(const char* str_id) void ImGui::CloseCurrentPopup() { ImGuiState& g = *GImGui; - if (g.CurrentPopupStack.empty() || g.OpenedPopupStack.empty() || g.CurrentPopupStack.back() != g.OpenedPopupStack.back()) + if (g.CurrentPopupStack.empty() || g.OpenedPopupStack.empty() || g.CurrentPopupStack.back().PopupID != g.OpenedPopupStack.back().PopupID) return; - if (g.Windows.back()->PopupID == g.OpenedPopupStack.back() && g.Windows.size() >= 2) + if (g.Windows.back()->PopupID == g.OpenedPopupStack.back().PopupID && g.Windows.size() >= 2) FocusWindow(g.Windows[g.Windows.size()-2]); g.OpenedPopupStack.pop_back(); } @@ -3003,7 +3015,7 @@ static void CloseAllPopups() static bool IsPopupOpen(ImGuiID id) { ImGuiState& g = *GImGui; - const bool opened = g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()] == id; + const bool opened = g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].PopupID == id; return opened; } @@ -3291,10 +3303,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ 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; + ImGuiPopupRef& popup_ref = g.OpenedPopupStack[g.CurrentPopupStack.size()]; + window_was_visible &= (window->PopupID == popup_ref.PopupID); + popup_ref.Window = window; + g.CurrentPopupStack.push_back(popup_ref); + window->PopupID = popup_ref.PopupID; } // Process SetNextWindow***() calls @@ -10237,7 +10250,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::MenuItem(names[i], "", &toggles[i]); if (ImGui::BeginMenu("Sub-menu")) { - ImGui::MenuItem("Hello"); + ImGui::MenuItem("Click me"); ImGui::EndMenu(); } @@ -10284,6 +10297,10 @@ void ImGui::ShowTestWindow(bool* opened) static bool enabled = true; static float f = 0.5f; ImGui::MenuItem("Enabled", "", &enabled); + ImGui::BeginChild("child", ImVec2(0, 60), true); + for (int i = 0; i < 10; i++) + ImGui::Text("Scrolling Text %d", i); + ImGui::EndChild(); ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); ImGui::EndMenu(); } From d9ca8f314501d316e548efb5e8df108180288988 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 12:05:05 +0100 Subject: [PATCH 010/127] Added IO.MetricsAllocs counter (number of memory allocations --- imgui.cpp | 3 +++ imgui.h | 1 + 2 files changed, 4 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index c5ce7a1f..679bfc71 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1787,11 +1787,13 @@ static void AddWindowToRenderList(ImVector& out_render_list, ImGuiW void* ImGui::MemAlloc(size_t sz) { + GImGui->IO.MetricsAllocs++; return GImGui->IO.MemAllocFn(sz); } void ImGui::MemFree(void* ptr) { + GImGui->IO.MetricsAllocs--; return GImGui->IO.MemFreeFn(ptr); } @@ -11039,6 +11041,7 @@ void ImGui::ShowMetricsWindow(bool* opened) ImGui::Text("ImGui %s", ImGui::GetVersion()); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::Text("%d vertices", ImGui::GetIO().MetricsRenderVertices); + ImGui::Text("%d active allocations", ImGui::GetIO().MetricsAllocs); ImGui::Separator(); struct Funcs diff --git a/imgui.h b/imgui.h index 642c02ef..f72c4e7c 100644 --- a/imgui.h +++ b/imgui.h @@ -696,6 +696,7 @@ struct ImGuiIO bool WantCaptureMouse; // Mouse is hovering a window or widget is active (= ImGui will use your mouse input) bool WantCaptureKeyboard; // Widget is active (= ImGui will use your keyboard input) float Framerate; // Framerate estimation, in frame per second. Rolling average estimation based on IO.DeltaTime over 120 frames + int MetricsAllocs; // Number of active memory allocations int MetricsRenderVertices; // Vertices processed during last call to Render() //------------------------------------------------------------------ From 222a9231bb43819a0ea6c05dcb79db29380db7be Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 12:09:34 +0100 Subject: [PATCH 011/127] Examples: Console: example uses standard malloc/free, makes more sense as a copy & pastable example --- imgui.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 679bfc71..edba0908 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11242,13 +11242,13 @@ struct ExampleAppConsole { ClearLog(); for (size_t i = 0; i < Items.size(); i++) - ImGui::MemFree(History[i]); + free(History[i]); } void ClearLog() { for (size_t i = 0; i < Items.size(); i++) - ImGui::MemFree(Items[i]); + free(Items[i]); Items.clear(); ScrollToBottom = true; } @@ -11260,7 +11260,7 @@ struct ExampleAppConsole va_start(args, fmt); ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args); va_end(args); - Items.push_back(ImStrdup(buf)); + Items.push_back(strdup(buf)); ScrollToBottom = true; } @@ -11343,11 +11343,11 @@ struct ExampleAppConsole for (int i = (int)History.size()-1; i >= 0; i--) if (ImStricmp(History[i], command_line) == 0) { - ImGui::MemFree(History[i]); + free(History[i]); History.erase(History.begin() + i); break; } - History.push_back(ImStrdup(command_line)); + History.push_back(strdup(command_line)); // Process command if (ImStricmp(command_line, "CLEAR") == 0) From 900394a61271de11f92980acee1fc5340565a0ee Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 12:24:05 +0100 Subject: [PATCH 012/127] Metrics: metrics window shows popups list --- imgui.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index edba0908..26318ac6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8841,14 +8841,13 @@ bool ImFontAtlas::Build() stbtt_pack_range& range = data.Ranges[i]; for (int char_idx = 0; char_idx < range.num_chars_in_range; char_idx += 1) { - const int codepoint = range.first_unicode_char_in_range + char_idx; const stbtt_packedchar& pc = range.chardata_for_range[char_idx]; if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1) continue; data.OutFont->Glyphs.resize(data.OutFont->Glyphs.size() + 1); ImFont::Glyph& glyph = data.OutFont->Glyphs.back(); - glyph.Codepoint = (ImWchar)codepoint; + glyph.Codepoint = (ImWchar)(range.first_unicode_char_in_range + char_idx); glyph.Width = (signed short)pc.x1 - pc.x0 + 1; glyph.Height = (signed short)pc.y1 - pc.y0 + 1; glyph.XOffset = (signed short)(pc.xoff); @@ -11093,6 +11092,12 @@ void ImGui::ShowMetricsWindow(bool* opened) Funcs::NodeDrawList(g.RenderDrawLists[0][i], "DrawList"); ImGui::TreePop(); } + if (ImGui::TreeNode("Popups", "Opened Popups (%d)", (int)g.OpenedPopupStack.size())) + { + for (int i = 0; i < (int)g.OpenedPopupStack.size(); i++) + ImGui::BulletText("PopupID: %08x, Window: '%s'", g.OpenedPopupStack[i].PopupID, g.OpenedPopupStack[i].Window ? g.OpenedPopupStack[i].Window->Name : "NULL"); + ImGui::TreePop(); + } g.DisableHideTextAfterDoubleHash--; } ImGui::End(); From 1fe29069237a494d8549bd7b0000e600227c2bf1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 12:45:35 +0100 Subject: [PATCH 013/127] Metrics: do not count free(NULL) calls. Settings: contiguous allocations for ImGuiIniData. --- imgui.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 26318ac6..f0854dd4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -384,6 +384,7 @@ - input: rework IO to be able to pass actual events to fix temporal aliasing issues. - input: support track pad style scrolling & slider edit. - portability: big-endian test/support (github issue #81) + - memory: add a way to discard allocs of unused/transient windows. with the current architecture new windows (including popup, opened combos, listbox) perform at least 3 allocs. - misc: mark printf compiler attributes on relevant functions - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? @@ -1135,9 +1136,6 @@ struct ImGuiIniData ImVec2 Pos; ImVec2 Size; bool Collapsed; - - ImGuiIniData() { memset(this, 0, sizeof(*this)); } - ~ImGuiIniData() { if (Name) { ImGui::MemFree(Name); Name = NULL; } } }; struct ImGuiMouseCursorData @@ -1186,7 +1184,7 @@ struct ImGuiState bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction. ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window. float SettingsDirtyTimer; - ImVector Settings; + ImVector Settings; int DisableHideTextAfterDoubleHash; ImVector ColorModifiers; ImVector StyleModifiers; @@ -1793,7 +1791,7 @@ void* ImGui::MemAlloc(size_t sz) void ImGui::MemFree(void* ptr) { - GImGui->IO.MetricsAllocs--; + if (ptr) GImGui->IO.MetricsAllocs--; return GImGui->IO.MemFreeFn(ptr); } @@ -1803,7 +1801,7 @@ static ImGuiIniData* FindWindowSettings(const char* name) ImGuiID id = ImHash(name, 0); for (size_t i = 0; i != g.Settings.size(); i++) { - ImGuiIniData* ini = g.Settings[i]; + ImGuiIniData* ini = &g.Settings[i]; if (ini->ID == id) return ini; } @@ -1812,14 +1810,13 @@ static ImGuiIniData* FindWindowSettings(const char* name) static ImGuiIniData* AddWindowSettings(const char* name) { - ImGuiIniData* ini = (ImGuiIniData*)ImGui::MemAlloc(sizeof(ImGuiIniData)); - new(ini) ImGuiIniData(); + GImGui->Settings.resize(GImGui->Settings.size() + 1); + ImGuiIniData* ini = &GImGui->Settings.back(); ini->Name = ImStrdup(name); ini->ID = ImHash(name, 0); ini->Collapsed = false; ini->Pos = ImVec2(FLT_MAX,FLT_MAX); ini->Size = ImVec2(0,0); - GImGui->Settings.push_back(ini); return ini; } @@ -1897,7 +1894,7 @@ static void SaveSettings() return; for (size_t i = 0; i != g.Settings.size(); i++) { - const ImGuiIniData* settings = g.Settings[i]; + const ImGuiIniData* settings = &g.Settings[i]; if (settings->Pos.x == FLT_MAX) continue; const char* name = settings->Name; @@ -2177,10 +2174,7 @@ void ImGui::Shutdown() g.HoveredWindow = NULL; g.HoveredRootWindow = NULL; for (size_t i = 0; i < g.Settings.size(); i++) - { - g.Settings[i]->~ImGuiIniData(); - ImGui::MemFree(g.Settings[i]); - } + ImGui::MemFree(g.Settings[i].Name); g.Settings.clear(); g.ColorModifiers.clear(); g.StyleModifiers.clear(); From fa0f0f4507efc7b555e2ecaa064b3ef8c64146b6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 13:14:46 +0100 Subject: [PATCH 014/127] ImVector: tweak growth strategy --- imgui.cpp | 2 +- imgui.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f0854dd4..75de808a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11034,7 +11034,7 @@ void ImGui::ShowMetricsWindow(bool* opened) ImGui::Text("ImGui %s", ImGui::GetVersion()); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::Text("%d vertices", ImGui::GetIO().MetricsRenderVertices); - ImGui::Text("%d active allocations", ImGui::GetIO().MetricsAllocs); + ImGui::Text("%d allocations", ImGui::GetIO().MetricsAllocs); ImGui::Separator(); struct Funcs diff --git a/imgui.h b/imgui.h index f72c4e7c..5323223c 100644 --- a/imgui.h +++ b/imgui.h @@ -119,7 +119,9 @@ public: inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size-1]; } inline void swap(ImVector& rhs) { const size_t rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; const size_t rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } - inline void resize(size_t new_size) { if (new_size > Capacity) reserve(new_size); Size = new_size; } + inline size_t _grow_capacity(size_t new_size) { size_t new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > new_size ? new_capacity : new_size; } + + inline void resize(size_t new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } inline void reserve(size_t new_capacity) { if (new_capacity <= Capacity) return; @@ -130,7 +132,7 @@ public: Capacity = new_capacity; } - inline void push_back(const value_type& v) { if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); Data[Size++] = v; } + inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size+1)); Data[Size++] = v; } inline void pop_back() { IM_ASSERT(Size > 0); Size--; } inline iterator erase(const_iterator it) { IM_ASSERT(it >= begin() && it < end()); const ptrdiff_t off = it - begin(); memmove(Data + off, Data + off + 1, (Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; } From 81937d34a8ff54f6784ebfc6106753518aa3590d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 17:29:42 +0100 Subject: [PATCH 015/127] Popups: made OpenPopup()/close loops reclaim focus and update popup position. It is generally a mistake but it's now more easy to understand --- imgui.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 75de808a..d93040e7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2981,11 +2981,14 @@ void ImGui::OpenPopup(const char* str_id) ImGuiWindow* window = GetCurrentWindow(); const ImGuiID id = window->GetID(str_id); - // One open popup per level of the popup hierarchy + // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size()) g.OpenedPopupStack.push_back(ImGuiPopupRef(id)); else if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size() + 1) - g.OpenedPopupStack.back() = ImGuiPopupRef(id); + { + if (g.OpenedPopupStack.back().PopupID != id) + g.OpenedPopupStack.back() = ImGuiPopupRef(id); + } else IM_ASSERT(0); // Invalid state } @@ -2995,7 +2998,7 @@ void ImGui::CloseCurrentPopup() ImGuiState& g = *GImGui; if (g.CurrentPopupStack.empty() || g.OpenedPopupStack.empty() || g.CurrentPopupStack.back().PopupID != g.OpenedPopupStack.back().PopupID) return; - if (g.Windows.back()->PopupID == g.OpenedPopupStack.back().PopupID && g.Windows.size() >= 2) + if (g.CurrentWindow->PopupID == g.OpenedPopupStack.back().PopupID && g.Windows.size() >= 2) FocusWindow(g.Windows[g.Windows.size()-2]); g.OpenedPopupStack.pop_back(); } @@ -3301,6 +3304,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ { ImGuiPopupRef& popup_ref = g.OpenedPopupStack[g.CurrentPopupStack.size()]; window_was_visible &= (window->PopupID == popup_ref.PopupID); + window_was_visible &= (window == popup_ref.Window); popup_ref.Window = window; g.CurrentPopupStack.push_back(popup_ref); window->PopupID = popup_ref.PopupID; From 70f83a3a65353abdcb155f32d742e676a6f6d4e8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 20:35:28 +0100 Subject: [PATCH 016/127] Popups: child popups (menus) hidden on their first frame the same way as regular popup --- imgui.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d93040e7..14b1c5a9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1776,8 +1776,11 @@ static void AddWindowToRenderList(ImVector& out_render_list, ImGuiW for (size_t i = 0; i < window->DC.ChildWindows.size(); i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; - if (child->Active) // clipped children may have been marked not active - AddWindowToRenderList(out_render_list, child); + if (!child->Active) // clipped children may have been marked not active + continue; + if ((child->Flags & ImGuiWindowFlags_Popup) && child->HiddenFrames > 0) + continue; + AddWindowToRenderList(out_render_list, child); } } From c1b55991c07bc10a0dc379ad70cafa4bb8a28428 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 21:40:45 +0100 Subject: [PATCH 017/127] Window: fixed child window sizing lag + minimum size clamping lag --- imgui.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 14b1c5a9..fca2211c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3465,7 +3465,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Minimum window size if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + { window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); + if (!window->Collapsed) + window->Size = window->SizeFull; + } // POSITION @@ -3475,7 +3479,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ 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. + window->Size = 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 From 3115e546aadc791133bec2f3f8315c02a61c72bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 21:55:54 +0100 Subject: [PATCH 018/127] Style editor: fixed slider for indent spacing. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index fca2211c..9b502332 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9862,7 +9862,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); - ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat("ScrollbarWidth", &style.ScrollbarWidth, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); From 79a95256e8020554afb9dc5fd47d1322cc11d7b9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 22:36:31 +0100 Subject: [PATCH 019/127] Window: fixed auto-fit calculation mismatch of whether a scrollbar will be added by maximum height clamping. Also honor NoScrollBar in the case of height clamping, not adding extra horizontal space. --- imgui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9b502332..b97eb136 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3425,15 +3425,16 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Calculate auto-fit size ImVec2 size_auto_fit; + ImVec2 window_padding = window->WindowPadding(); if ((flags & ImGuiWindowFlags_Tooltip) != 0) { // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. - size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); + size_auto_fit = window->SizeContents + window_padding - ImVec2(0.0f, style.ItemSpacing.y); } else { - size_auto_fit = ImClamp(window->SizeContents + style.WindowPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.WindowPadding)); - if (size_auto_fit.y < window->SizeContents.y + style.WindowPadding.y) + size_auto_fit = ImClamp(window->SizeContents + window_padding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - window_padding)); + if (size_auto_fit.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar)) size_auto_fit.x += style.ScrollbarWidth; size_auto_fit.y -= style.ItemSpacing.y; } From 4250357ed2aea8b3b8581c0428087060c14af98c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 22:39:52 +0100 Subject: [PATCH 020/127] Selectable: using window->WindowPadding() to work within non-padded child windows --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b97eb136..339cb7ff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7210,12 +7210,13 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - style.WindowPadding.x - window->DC.CursorPos.x); + const ImVec2 window_padding = window->WindowPadding(); + const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y); ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); if (size_arg.x == 0.0f) - bb.Max.x += style.WindowPadding.x; + bb.Max.x += window_padding.x; // Selectables are meant to be tightly packed together. So for both rendering and collision we extend to compensate for spacing. ImRect bb_with_spacing = bb; From ecda785cbcb5933ae1bf80fb6934e4f52d08faa2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 May 2015 23:57:43 +0100 Subject: [PATCH 021/127] Popups: fix to allow child popups to be opened from a normal window without an intermediate popup window. --- imgui.cpp | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 339cb7ff..6f99f370 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1149,10 +1149,11 @@ struct ImGuiMouseCursorData struct ImGuiPopupRef { - ImGuiID PopupID; // Set on OpenPopup() - ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiID PopupID; // Set on OpenPopup() + ImGuiWindow* ParentWindow; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() - ImGuiPopupRef(ImGuiID id) { PopupID = id; Window = NULL; } + ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window) { PopupID = id; ParentWindow = parent_window; Window = NULL; } }; // Main state for ImGui @@ -2136,24 +2137,36 @@ static void CloseInactivePopups() return; // User has clicked outside of a popup - if (!g.FocusedWindow || !(g.FocusedWindow->RootWindow->Flags & ImGuiWindowFlags_Popup)) + if (!g.FocusedWindow) { g.OpenedPopupStack.resize(0); return; } // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it - IM_ASSERT(g.FocusedWindow->RootWindow->PopupID != 0); - for (int n = 0; n < (int)g.OpenedPopupStack.size()-1; n++) - if (g.OpenedPopupStack[n].PopupID == g.FocusedWindow->RootWindow->PopupID) + // Don't close our own child popup windows + int n; + for (n = 0; n < (int)g.OpenedPopupStack.size(); n++) + { + ImGuiPopupRef& popup = g.OpenedPopupStack[n]; + if (!popup.Window) + continue; + IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); + if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) { - // Don't close our own Child Popup windows - while (++n < (int)g.OpenedPopupStack.size()) - if (!g.OpenedPopupStack[n].Window || !(g.OpenedPopupStack[n].Window->Flags & ImGuiWindowFlags_ChildWindow)) - break; - g.OpenedPopupStack.resize(n); - return; + if (g.FocusedWindow->RootWindow != popup.Window->RootWindow) + break; } + else + { + bool has_focus = false; + for (int m = n; m < (int)g.OpenedPopupStack.size() && !has_focus; m++) + has_focus = (g.OpenedPopupStack[m].Window && g.OpenedPopupStack[m].Window->RootWindow == g.FocusedWindow->RootWindow); + if (!has_focus) + break; + } + } + g.OpenedPopupStack.resize(n); } // NB: behavior of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations. @@ -2985,15 +2998,9 @@ void ImGui::OpenPopup(const char* str_id) const ImGuiID id = window->GetID(str_id); // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) - if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size()) - g.OpenedPopupStack.push_back(ImGuiPopupRef(id)); - else if (g.OpenedPopupStack.size() == g.CurrentPopupStack.size() + 1) - { - if (g.OpenedPopupStack.back().PopupID != id) - g.OpenedPopupStack.back() = ImGuiPopupRef(id); - } - else - IM_ASSERT(0); // Invalid state + g.OpenedPopupStack.resize(g.CurrentPopupStack.size() + 1); + if (g.OpenedPopupStack.back().PopupID != id) + g.OpenedPopupStack.back() = ImGuiPopupRef(id, window); } void ImGui::CloseCurrentPopup() @@ -3032,7 +3039,7 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) 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)) + if ((flags & ImGuiWindowFlags_Menu)) flags |= ImGuiWindowFlags_ChildWindow; char name[32]; From e912bcb36d347bfb36b1a33f6387deeda37e6d23 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 12:10:57 +0100 Subject: [PATCH 022/127] Comments --- imgui.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6f99f370..0877f1fd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7682,7 +7682,7 @@ void ImGui::Spacing() ItemSize(ImVec2(0,0)); } -// Advance cursor given item size. +// Advance cursor given item size for layout. static void ItemSize(ImVec2 size, float text_offset_y) { ImGuiState& g = *GImGui; @@ -7730,6 +7730,9 @@ bool ImGui::IsRectClipped(const ImVec2& size) return IsClippedEx(ImRect(window->DC.CursorPos, window->DC.CursorPos + size), NULL, true); } +// Declare item bounding box for clipping and interaction. +// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface +// declares their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd(). static bool ItemAdd(const ImRect& bb, const ImGuiID* id) { ImGuiWindow* window = GetCurrentWindow(); From f44526cc45b130618b90d0e84dd96a378d54b494 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 13:09:46 +0100 Subject: [PATCH 023/127] Selectable(): horizontal filling not declared to ItemSize() so Selectable(),SameLine() works and we can best auto-fit the window --- imgui.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0877f1fd..3035ab78 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7217,16 +7217,18 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 window_padding = window->WindowPadding(); - const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); - const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y); - ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); + const ImVec2 pos = window->DC.CursorPos; + ImRect bb(pos, pos + size); ItemSize(bb); - if (size_arg.x == 0.0f) - bb.Max.x += window_padding.x; // Selectables are meant to be tightly packed together. So for both rendering and collision we extend to compensate for spacing. - ImRect bb_with_spacing = bb; + const ImVec2 window_padding = window->WindowPadding(); + const float w_full = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); + const ImVec2 size_full(size_arg.x != 0.0f ? size_arg.x : w_full, size_arg.y != 0.0f ? size_arg.y : label_size.y); + ImRect bb_with_spacing(pos, pos + size_full); + if (size_arg.x == 0.0f) + bb_with_spacing.Max.x += window_padding.x; const float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); const float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); const float spacing_R = style.ItemSpacing.x - spacing_L; From 6251d3798777f4047766349767ee928918ae51cc Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 15:48:56 +0100 Subject: [PATCH 024/127] WIP Menus: further fixes for resizing (#126) --- imgui.cpp | 79 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3035ab78..4bf9dbb8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -994,41 +994,44 @@ struct ImGuiGroupData float BackupLogLinePosY; }; -// Simple column measurement currently used for menu items +// Simple column measurement currently used for menu items. This is very short-sighted for now. struct ImGuiSimpleColumns { int Count; - float Width; + float Spacing; + float Width, NextWidth; float Pos[8], NextWidths[8]; - ImGuiSimpleColumns() { Count = 0; Width = 0.0f; memset(Pos, 0, sizeof(Pos)); memset(NextWidths, 0, sizeof(NextWidths)); } + ImGuiSimpleColumns() { Count = 0; Spacing = 0.0f; Width = 0.0f; NextWidth = 0.0f; memset(Pos, 0, sizeof(Pos)); memset(NextWidths, 0, sizeof(NextWidths)); } void Update(int count, float spacing, bool clear) { + IM_ASSERT(Count <= IM_ARRAYSIZE(Pos)); Count = count; - Width = 0.0f; + Width = NextWidth = 0.0f; + Spacing = spacing; if (clear) memset(NextWidths, 0, sizeof(NextWidths)); for (int i = 0; i < Count; i++) { if (i > 0 && NextWidths[i] > 0.0f) - Width += spacing; + Width += Spacing; Pos[i] = (float)(int)Width; Width += NextWidths[i]; NextWidths[i] = 0.0f; } } - void Extend(float w0, float w1, float w2) // not using va_arg because they promote float to double + float DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double { + NextWidth = 0.0f; NextWidths[0] = ImMax(NextWidths[0], w0); NextWidths[1] = ImMax(NextWidths[1], w1); NextWidths[2] = ImMax(NextWidths[2], w2); + for (int i = 0; i < 3; i++) + NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f); + return ImMax(Width, NextWidth); } - void FillExtraSpace(float avail_w, int column_no) + float CalcExtraSpace(float avail_w) { - if (Width >= avail_w) return; - float extra_w = avail_w - Width; - Width = avail_w; - for (int i = column_no+1; i < Count; i++) - Pos[i] += extra_w; + return ImMax(0.0f, avail_w - Width); } }; @@ -7204,9 +7207,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi return value_changed; } -// Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image. -// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID. -bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) +static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -7215,20 +7216,22 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); const ImVec2 pos = window->DC.CursorPos; ImRect bb(pos, pos + size); ItemSize(bb); - // Selectables are meant to be tightly packed together. So for both rendering and collision we extend to compensate for spacing. + // Fill horizontal space. const ImVec2 window_padding = window->WindowPadding(); - const float w_full = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); - const ImVec2 size_full(size_arg.x != 0.0f ? size_arg.x : w_full, size_arg.y != 0.0f ? size_arg.y : label_size.y); - ImRect bb_with_spacing(pos, pos + size_full); - if (size_arg.x == 0.0f) + const float w_draw = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); + const ImVec2 size_draw(size_draw_arg.x != 0.0f ? size_draw_arg.x : w_draw, size_draw_arg.y != 0.0f ? size_draw_arg.y : size.y); + ImRect bb_with_spacing(pos, pos + size_draw); + if (size_draw_arg.x == 0.0f) bb_with_spacing.Max.x += window_padding.x; + + // Selectables are tightly packed together, we extend the box to cover spacing between selectable. const float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); const float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); const float spacing_R = style.ItemSpacing.x - spacing_L; @@ -7261,9 +7264,16 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) return pressed; } +// Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image. +// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID. +bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) +{ + return SelectableEx(label, selected, size_arg, size_arg); +} + bool ImGui::Selectable(const char* label, bool* p_selected, const ImVec2& size_arg) { - if (ImGui::Selectable(label, *p_selected, size_arg)) + if (SelectableEx(label, *p_selected, size_arg, size_arg)) { *p_selected = !*p_selected; return true; @@ -7376,21 +7386,20 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) ImVec2 pos = ImGui::GetCursorScreenPos(); ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); - window->MenuColumns.Extend(label_size.x, shortcut_size.x, g.FontSize * 1.10f); // Feedback for next frame - window->MenuColumns.FillExtraSpace(window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x, 0); + float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame + float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - float w = window->MenuColumns.Width; - bool pressed = ImGui::Selectable(label, false, ImVec2(w, 0.0f)); + bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f)); if (shortcut_size.x > 0.0f) { ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); - RenderText(pos + ImVec2(window->MenuColumns.Pos[1], 0.0f), shortcut, NULL, false); + RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); ImGui::PopStyleColor(); } if (selected) - RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + g.FontSize * 0.10f, 0.0f), window->Color(ImGuiCol_Text)); + RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), window->Color(ImGuiCol_Text)); return pressed; } @@ -7415,16 +7424,15 @@ bool ImGui::BeginMenu(const char* label) return false; const ImGuiID id = window->GetID(label); - bool opened = IsPopupOpen(id); ImVec2 pos = ImGui::GetCursorScreenPos(); ImVec2 label_size = CalcTextSize(label, NULL, true); - window->MenuColumns.Extend(label_size.x, 0.0f, g.FontSize * 1.10f); // Feedback to next frame - window->MenuColumns.FillExtraSpace(window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x, 0); - - float w = window->MenuColumns.Width; - ImGui::Selectable(label, opened, ImVec2(w, 0.0f)); - RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + g.FontSize * 0.20f, 0.0f), false); + float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame + float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); + + bool opened = IsPopupOpen(id); + SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f)); + RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); bool hovered = ImGui::IsItemHovered(); if (!opened && hovered) @@ -10333,7 +10341,6 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::MenuItem("Quit", "Alt+F4"); ImGui::EndPopup(); } - ImGui::TreePop(); } From e0594340ff9794f26a26e27598f8146aa4420bbe Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 16:29:00 +0100 Subject: [PATCH 025/127] Moved internal window flags to higher bit-count --- imgui.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index 5323223c..36ec6e11 100644 --- a/imgui.h +++ b/imgui.h @@ -457,13 +457,13 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_ShowBorders = 1 << 7, // Show borders around windows and items ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file // [Internal] - ImGuiWindowFlags_ChildWindow = 1 << 9, // For internal use by BeginChild() - ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 10, // For internal use by BeginChild() - 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_Menu = 1 << 15 // For internal use by BeginMenu() + ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_ChildWindowAutoFitY = 1 << 22, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_ComboBox = 1 << 23, // Don't use! For internal use by ComboBox() + ImGuiWindowFlags_Tooltip = 1 << 24, // Don't use! For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 25, // Don't use! For internal use by BeginPopup() + ImGuiWindowFlags_Menu = 1 << 26 // Don't use! For internal use by BeginMenu() }; From f2b738648f90cbd97883c7ab24c1bd1a45269bf5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 17:13:45 +0100 Subject: [PATCH 026/127] WIP Menus: menu bars. Still inconsistency with hovering scheme. Will probably follow what Windows does. (#126). --- imgui.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++-------- imgui.h | 4 +++ 2 files changed, 87 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4bf9dbb8..9831015c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -588,6 +588,7 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f); Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); + Colors[ImGuiCol_MenuBarBg] = ImVec4(0.35f, 0.35f, 0.45f, 0.55f); Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.40f, 0.80f, 0.15f); Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); @@ -1052,6 +1053,8 @@ struct ImGuiDrawContext ImRect LastItemRect; bool LastItemHoveredAndUsable; bool LastItemHoveredRect; + bool MenuBarAppending; + float MenuBarOffsetX; ImVector ChildWindows; ImVector AllowKeyboardFocus; ImVector ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window @@ -1082,6 +1085,8 @@ struct ImGuiDrawContext LastItemID = 0; LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f); LastItemHoveredAndUsable = LastItemHoveredRect = false; + MenuBarAppending = false; + MenuBarOffsetX = 0.0f; ColorEditMode = ImGuiColorEditMode_RGB; StateStorage = NULL; memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); @@ -1181,6 +1186,7 @@ struct ImGuiState ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) ImGuiID HoveredId; // Hovered widget + ImGuiID HoveredIdPreviousFrame; ImGuiID ActiveId; // Active widget ImGuiID ActiveIdPreviousFrame; bool ActiveIdIsAlive; @@ -1257,6 +1263,7 @@ struct ImGuiState HoveredWindow = NULL; HoveredRootWindow = NULL; HoveredId = 0; + HoveredIdPreviousFrame = 0; ActiveId = 0; ActiveIdPreviousFrame = 0; ActiveIdIsAlive = false; @@ -1365,8 +1372,10 @@ public: ImRect Rect() const { return ImRect(Pos, Pos+Size); } 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.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } + float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } + ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } 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(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } @@ -2031,6 +2040,7 @@ void ImGui::NewFrame() g.IO.Framerate = 1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame)); // Clear reference to active widget if the widget isn't alive anymore + g.HoveredIdPreviousFrame = g.HoveredId; g.HoveredId = 0; if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) SetActiveId(0); @@ -3497,7 +3507,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ 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) + ImRect rect_to_avoid; + if (parent_window->DC.MenuBarAppending) + rect_to_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); + else + 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) @@ -3635,6 +3649,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (!(flags & ImGuiWindowFlags_NoTitleBar)) window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBg), window_rounding, 1|2); + // Menu bar + if (flags & ImGuiWindowFlags_MenuBar) + { + ImRect menu_bar_rect = window->MenuBarRect(); + window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), window->Color(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, 1|2); + } + // Borders if (flags & ImGuiWindowFlags_ShowBorders) { @@ -3671,12 +3692,14 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Setup drawing context window->DC.ColumnsStartX = window->WindowPadding().x; window->DC.ColumnsOffsetX = 0.0f; - window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->WindowPadding().y) - ImVec2(0.0f, window->ScrollY); + window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding().y) - ImVec2(0.0f, window->ScrollY); window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPosPrevLine = window->DC.CursorPos; window->DC.CursorMaxPos = window->DC.CursorStartPos; window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f; window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.MenuBarAppending = false; + window->DC.MenuBarOffsetX = window->DC.ColumnsStartX; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); window->DC.ItemWidth.resize(0); @@ -4094,6 +4117,7 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_FrameBgActive: return "FrameBgActive"; case ImGuiCol_TitleBg: return "TitleBg"; case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; + case ImGuiCol_MenuBarBg: return "MenuBarBg"; case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; @@ -4327,7 +4351,7 @@ ImVec2 ImGui::GetContentRegionMax() ImVec2 ImGui::GetWindowContentRegionMin() { ImGuiWindow* window = GetCurrentWindow(); - return ImVec2(0, window->TitleBarHeight()) + window->WindowPadding(); + return ImVec2(0, window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding(); } ImVec2 ImGui::GetWindowContentRegionMax() @@ -7415,6 +7439,32 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected) return false; } +bool ImGui::BeginMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(!window->DC.MenuBarAppending); + window->DC.MenuBarAppending = true; + ImGui::PushID("##menubar"); + + return true; +} + +void ImGui::EndMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); + window->DC.MenuBarAppending = false; + ImGui::PopID(); +} + // FIXME-WIP: v1.39 in development, API *WILL* change! bool ImGui::BeginMenu(const char* label) { @@ -7423,16 +7473,36 @@ bool ImGui::BeginMenu(const char* label) if (window->SkipItems) return false; + const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - - ImVec2 pos = ImGui::GetCursorScreenPos(); - ImVec2 label_size = CalcTextSize(label, NULL, true); - float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame - float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - bool opened = IsPopupOpen(id); - SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f)); - RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); + + ImVec2 pos; + ImVec2 popup_pos; + ImVec2 backup_pos = window->DC.CursorPos; + ImVec2 label_size = CalcTextSize(label, NULL, true); + + if (window->DC.MenuBarAppending) + { + // FIXME: Should be moved at a lower-level once we have horizontal layout (#97) + pos = window->DC.CursorPos = ImVec2(window->Pos.x + window->DC.MenuBarOffsetX, window->Pos.y + window->TitleBarHeight() + style.FramePadding.y); + popup_pos = ImVec2(pos.x - style.ItemSpacing.x, pos.y); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); + float w = label_size.x; + SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f)); + window->DC.MenuBarOffsetX += (label_size.x + style.ItemSpacing.x); + window->DC.CursorPos = backup_pos; + ImGui::PopStyleVar(); + } + else + { + pos = window->DC.CursorPos; + popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); + float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame + float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); + SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f)); + RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); + } bool hovered = ImGui::IsItemHovered(); if (!opened && hovered) @@ -7447,7 +7517,7 @@ bool ImGui::BeginMenu(const char* label) } if (opened) { - ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y - g.Style.WindowPadding.y), ImGuiSetCond_Always); + ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always); bool popup_opened = BeginPopupEx(label, ImGuiWindowFlags_Menu); IM_ASSERT(opened == popup_opened); } diff --git a/imgui.h b/imgui.h index 36ec6e11..44bb87dd 100644 --- a/imgui.h +++ b/imgui.h @@ -363,6 +363,8 @@ namespace ImGui // Widgets: Menus // FIXME-WIP: v1.39 in development, API *WILL* change + IMGUI_API bool BeginMenuBar(); + IMGUI_API void EndMenuBar(); IMGUI_API bool BeginMenu(const char* label); IMGUI_API void EndMenu(); IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false); // bool enabled = true @@ -456,6 +458,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame ImGuiWindowFlags_ShowBorders = 1 << 7, // Show borders around windows and items ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file + ImGuiWindowFlags_MenuBar = 1 << 9, // Has a menubar // [Internal] ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild() @@ -520,6 +523,7 @@ enum ImGuiCol_ ImGuiCol_FrameBgActive, ImGuiCol_TitleBg, ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, ImGuiCol_ScrollbarBg, ImGuiCol_ScrollbarGrab, ImGuiCol_ScrollbarGrabHovered, From 88d7b3de23bf522fcf62e5e72988f70a27b0b73d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 17:21:49 +0100 Subject: [PATCH 027/127] WIP Menus: fixed hovering handling of menus from menu bars (#126) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9831015c..a2510c9d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4707,7 +4707,7 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window) static bool IsHovered(const ImRect& bb, ImGuiID id) { ImGuiState& g = *GImGui; - if (g.HoveredId == 0) + if (g.HoveredId == 0 || g.HoveredId == id) { ImGuiWindow* window = GetCurrentWindow(); if (g.HoveredRootWindow == window->RootWindow) @@ -7504,7 +7504,7 @@ bool ImGui::BeginMenu(const char* label) RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); } - bool hovered = ImGui::IsItemHovered(); + bool hovered = IsHovered(window->DC.LastItemRect, id); if (!opened && hovered) { ImGui::OpenPopup(label); From 7f3f3891c04d36dfa5ea86db975863e46c48cd8a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 22:15:40 +0100 Subject: [PATCH 028/127] WIP Menus: fixed case where zero-sized display (e.g. minimised window) clips popups/menus and asserted (#126) --- imgui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a2510c9d..b3dcda0d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3062,11 +3062,13 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame 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)) GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; + if (!opened) // opened can be 'false' when the popup is completely clipped (e.g. zero size display) + ImGui::EndPopup(); + return opened; } @@ -7518,8 +7520,7 @@ bool ImGui::BeginMenu(const char* label) if (opened) { ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always); - bool popup_opened = BeginPopupEx(label, ImGuiWindowFlags_Menu); - IM_ASSERT(opened == popup_opened); + opened = BeginPopupEx(label, ImGuiWindowFlags_Menu); // opened can be 'false' when the popup is completely clipped (e.g. zero size display) } return opened; From 4bd43bdb352f6ac88033eefbb10c260aa6a2c69f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 22:28:57 +0100 Subject: [PATCH 029/127] Renamed ImGuiWindowFlags_Menu to ImGuiWindowFlags_ChildMenu --- imgui.cpp | 10 +++++----- imgui.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b3dcda0d..c840ba73 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3052,11 +3052,11 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) 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)) + if ((flags & ImGuiWindowFlags_ChildMenu)) flags |= ImGuiWindowFlags_ChildWindow; char name[32]; - if (flags & ImGuiWindowFlags_Menu) + if (flags & ImGuiWindowFlags_ChildMenu) ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.size()); // Recycle windows based on depth else ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame @@ -3506,7 +3506,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Position popup - if (flags & ImGuiWindowFlags_Menu) + if (flags & ImGuiWindowFlags_ChildMenu) { IM_ASSERT(window_pos_set_by_api); ImRect rect_to_avoid; @@ -7283,7 +7283,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_Menu)) + if (pressed && (window->Flags & ImGuiWindowFlags_ChildMenu)) CloseAllPopups(); else if (pressed && (window->Flags & ImGuiWindowFlags_Popup)) ImGui::CloseCurrentPopup(); @@ -7520,7 +7520,7 @@ bool ImGui::BeginMenu(const char* label) if (opened) { ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always); - opened = BeginPopupEx(label, ImGuiWindowFlags_Menu); // opened can be 'false' when the popup is completely clipped (e.g. zero size display) + opened = BeginPopupEx(label, ImGuiWindowFlags_ChildMenu); // opened can be 'false' when the popup is completely clipped (e.g. zero size display) } return opened; diff --git a/imgui.h b/imgui.h index 44bb87dd..ea344f02 100644 --- a/imgui.h +++ b/imgui.h @@ -466,7 +466,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_ComboBox = 1 << 23, // Don't use! For internal use by ComboBox() ImGuiWindowFlags_Tooltip = 1 << 24, // Don't use! For internal use by BeginTooltip() ImGuiWindowFlags_Popup = 1 << 25, // Don't use! For internal use by BeginPopup() - ImGuiWindowFlags_Menu = 1 << 26 // Don't use! For internal use by BeginMenu() + ImGuiWindowFlags_ChildMenu = 1 << 26 // Don't use! For internal use by BeginMenu() }; From 09abf11e56198bad20a0be8992ea00920e777122 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 23:13:53 +0100 Subject: [PATCH 030/127] WIP Menus: BeginMenuBar() return false on window without a menu bar (#126) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index c840ba73..abc8a55f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7446,8 +7446,9 @@ bool ImGui::BeginMenuBar() ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; + if (!(window->Flags & ImGuiWindowFlags_MenuBar)) + return false; - IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); IM_ASSERT(!window->DC.MenuBarAppending); window->DC.MenuBarAppending = true; ImGui::PushID("##menubar"); From a17c930d1fefd787808184ac92a467a4f63fc0ab Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 May 2015 23:19:05 +0100 Subject: [PATCH 031/127] WIP Menus: Added example menu, move app examples to a sub-menu (#126) NB: menus do not react on click yet, with popup-style blocking of other inputs yet --- imgui.cpp | 117 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index abc8a55f..dd3e23f6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10032,6 +10032,7 @@ static void ShowExampleAppAutoResize(bool* opened); static void ShowExampleAppFixedOverlay(bool* opened); static void ShowExampleAppManipulatingWindowTitle(bool* opened); static void ShowExampleAppCustomRendering(bool* opened); +static void ShowExampleMenuFile(); // Demonstrate ImGui features (unfortunately this makes this function a little bloated!) void ImGui::ShowTestWindow(bool* opened) @@ -10065,6 +10066,7 @@ void ImGui::ShowTestWindow(bool* opened) static bool no_move = false; static bool no_scrollbar = false; static bool no_collapse = false; + static bool no_menu = false; static float bg_alpha = 0.65f; // Demonstrate the various window flags. Typically you would just use the default. @@ -10075,6 +10077,7 @@ void ImGui::ShowTestWindow(bool* opened) if (no_move) window_flags |= ImGuiWindowFlags_NoMove; if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; + if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; if (!ImGui::Begin("ImGui Test", opened, ImVec2(550,680), bg_alpha, window_flags)) { // Early out if the window is collapsed, as an optimization. @@ -10092,6 +10095,28 @@ void ImGui::ShowTestWindow(bool* opened) //ImGui::Text("WantCaptureMouse: %d", ImGui::GetIO().WantCaptureMouse); //ImGui::Text("WantCaptureKeyboard: %d", ImGui::GetIO().WantCaptureKeyboard); + // Menu + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Examples")) + { + ImGui::MenuItem("Metrics", NULL, &show_app_metrics); + ImGui::MenuItem("Console", NULL, &show_app_console); + ImGui::MenuItem("Long text display", NULL, &show_app_long_text); + ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); + ImGui::MenuItem("Simple overlay", NULL, &show_app_fixed_overlay); + ImGui::MenuItem("Manipulating window title", NULL, &show_app_manipulating_window_title); + ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Spacing(); if (ImGui::CollapsingHeader("Help")) { @@ -10107,6 +10132,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Checkbox("no move", &no_move); ImGui::SameLine(150); ImGui::Checkbox("no scrollbar", &no_scrollbar); ImGui::SameLine(300); ImGui::Checkbox("no collapse", &no_collapse); + ImGui::Checkbox("no menu", &no_menu); ImGui::SliderFloat("bg alpha", &bg_alpha, 0.0f, 1.0f); if (ImGui::TreeNode("Style")) @@ -10374,43 +10400,7 @@ void ImGui::ShowTestWindow(bool* opened) 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::BeginChild("child", ImVec2(0, 60), true); - for (int i = 0; i < 10; i++) - ImGui::Text("Scrolling Text %d", i); - ImGui::EndChild(); - 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"); + ShowExampleMenuFile(); ImGui::EndPopup(); } ImGui::TreePop(); @@ -11117,17 +11107,6 @@ void ImGui::ShowTestWindow(bool* opened) } } - if (ImGui::CollapsingHeader("App Examples")) - { - ImGui::Checkbox("Metrics", &show_app_metrics); - ImGui::Checkbox("Console", &show_app_console); - ImGui::Checkbox("Long text display", &show_app_long_text); - ImGui::Checkbox("Auto-resizing window", &show_app_auto_resize); - ImGui::Checkbox("Simple overlay", &show_app_fixed_overlay); - ImGui::Checkbox("Manipulating window title", &show_app_manipulating_window_title); - ImGui::Checkbox("Custom rendering", &show_app_custom_rendering); - } - ImGui::End(); } @@ -11201,6 +11180,48 @@ void ImGui::ShowMetricsWindow(bool* opened) ImGui::End(); } +static void ShowExampleMenuFile() +{ + ImGui::TextColored(ImGui::GetStyle().Colors[ImGuiCol_TextDisabled], "(dummy 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; + ImGui::MenuItem("Enabled", "", &enabled); + ImGui::BeginChild("child", ImVec2(0, 60), true); + for (int i = 0; i < 10; i++) + ImGui::Text("Scrolling Text %d", i); + ImGui::EndChild(); + static float f = 0.5f; + 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"); +} + static void ShowExampleAppAutoResize(bool* opened) { if (!ImGui::Begin("Example: Auto-Resizing Window", opened, ImGuiWindowFlags_AlwaysAutoResize)) From 7184de24b87eec694d7807a45562a67e83d205d9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 May 2015 15:54:56 +0100 Subject: [PATCH 032/127] WIP Menus: scrolling section of the window is clipped by the menu bar (#126) --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index dd3e23f6..14ae546a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3759,7 +3759,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior. const ImRect title_bar_rect = window->TitleBarRect(); - ImVec4 clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_rect.Max.y+0.5f, window->Rect().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Rect().Max.y-1.5f); + ImVec4 clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_rect.Max.y+window->MenuBarHeight()+0.5f, window->Rect().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Rect().Max.y-1.5f); if (window->ScrollbarY) clip_rect.z -= style.ScrollbarWidth; PushClipRect(clip_rect); @@ -7452,7 +7452,8 @@ bool ImGui::BeginMenuBar() IM_ASSERT(!window->DC.MenuBarAppending); window->DC.MenuBarAppending = true; ImGui::PushID("##menubar"); - + ImRect rect = window->MenuBarRect(); + PushClipRect(ImVec4(rect.Min.x+0.5f, rect.Min.y-0.5f, rect.Max.x+0.5f, rect.Max.y-1.5f), false); return true; } @@ -7465,6 +7466,7 @@ void ImGui::EndMenuBar() IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); IM_ASSERT(window->DC.MenuBarAppending); window->DC.MenuBarAppending = false; + PopClipRect(); ImGui::PopID(); } From 75ec4841df68c724652f1f1f99e4339cb3a9880c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 May 2015 18:44:15 +0100 Subject: [PATCH 033/127] WIP Menus: menu opens on press (not release), uses popup style hovering, allow switch between menus at parent site (#126) --- imgui.cpp | 61 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9a1728ab..1d91db3e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1170,10 +1170,11 @@ struct ImGuiMouseCursorData struct ImGuiPopupRef { ImGuiID PopupID; // Set on OpenPopup() - ImGuiWindow* ParentWindow; // Set on OpenPopup() ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiWindow* ParentWindow; // Set on OpenPopup() + ImGuiID ParentMenuSet; // Set on OpenPopup() - ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window) { PopupID = id; ParentWindow = parent_window; Window = NULL; } + ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set) { PopupID = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; } }; // Main state for ImGui @@ -3026,7 +3027,7 @@ void ImGui::OpenPopup(const char* str_id) // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) g.OpenedPopupStack.resize(g.CurrentPopupStack.size() + 1); if (g.OpenedPopupStack.back().PopupID != id) - g.OpenedPopupStack.back() = ImGuiPopupRef(id, window); + g.OpenedPopupStack.back() = ImGuiPopupRef(id, window, window->GetID("##menus")); } void ImGui::CloseCurrentPopup() @@ -3063,10 +3064,7 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) return false; 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_ChildMenu)) - flags |= ImGuiWindowFlags_ChildWindow; + ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; char name[32]; if (flags & ImGuiWindowFlags_ChildMenu) @@ -7249,7 +7247,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi return value_changed; } -static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg) +static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, bool menu_item = false) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -7286,7 +7284,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar return false; bool hovered, held; - bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true); + bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, menu_item ? (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_FlattenChilds) : 0); // Render if (hovered || selected) @@ -7431,7 +7429,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f)); + bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true); if (shortcut_size.x > 0.0f) { @@ -7503,14 +7501,24 @@ bool ImGui::BeginMenu(const char* label) ImVec2 backup_pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); + bool pressed; + bool active_menuset = false; + ImGuiWindow* focused_window_backup = g.FocusedWindow; + if (window->DC.MenuBarAppending) { // FIXME: Should be moved at a lower-level once we have horizontal layout (#97) pos = window->DC.CursorPos = ImVec2(window->Pos.x + window->DC.MenuBarOffsetX, window->Pos.y + window->TitleBarHeight() + style.FramePadding.y); popup_pos = ImVec2(pos.x - style.ItemSpacing.x, pos.y); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); + + active_menuset = (g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].ParentMenuSet == window->GetID("##menus")); + if (active_menuset) + g.FocusedWindow = NULL; + float w = label_size.x; - SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f)); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true); + window->DC.MenuBarOffsetX += (label_size.x + style.ItemSpacing.x); window->DC.CursorPos = backup_pos; ImGui::PopStyleVar(); @@ -7521,25 +7529,40 @@ bool ImGui::BeginMenu(const char* label) popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f)); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true); RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); } bool hovered = IsHovered(window->DC.LastItemRect, id); - if (!opened && hovered) + if (active_menuset) + g.FocusedWindow = focused_window_backup; + + if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) { - ImGui::OpenPopup(label); - opened = true; + if (!opened && hovered) + { + ImGui::OpenPopup(label); + opened = true; + } } - else if (opened && !hovered && g.HoveredWindow == window) + else { - g.OpenedPopupStack.pop_back(); - opened = false; + if (active_menuset) + pressed |= hovered; + else + pressed |= (hovered && !g.OpenedPopupStack.empty() && g.OpenedPopupStack.back().PopupID != id && g.OpenedPopupStack.back().ParentWindow == window); + if (pressed) + { + ImGui::OpenPopup(label); // FIXME-MENUS: toggle + opened = true; + } } + if (opened) { ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always); - opened = BeginPopupEx(label, ImGuiWindowFlags_ChildMenu); // opened can be 'false' when the popup is completely clipped (e.g. zero size display) + ImGuiWindowFlags flags = (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu; + opened = BeginPopupEx(label, flags); // opened can be 'false' when the popup is completely clipped (e.g. zero size display) } return opened; From 9bdacaf08dcf4201837930a1b38e815a2ac24cf9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 May 2015 19:12:36 +0100 Subject: [PATCH 034/127] WIP Menus: click again to toggle + allow hovering in same menuset even outside of a menubar (#126) --- imgui.cpp | 57 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1d91db3e..aed20983 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3018,18 +3018,33 @@ void ImGui::EndTooltip() ImGui::End(); } +static bool IsPopupOpen(ImGuiID id) +{ + ImGuiState& g = *GImGui; + const bool opened = g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].PopupID == id; + return opened; +} + +// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) void ImGui::OpenPopup(const char* str_id) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); const ImGuiID id = window->GetID(str_id); - - // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) g.OpenedPopupStack.resize(g.CurrentPopupStack.size() + 1); if (g.OpenedPopupStack.back().PopupID != id) g.OpenedPopupStack.back() = ImGuiPopupRef(id, window, window->GetID("##menus")); } +static void ClosePopup(const char* str_id) // not exposed because 'id' scope is misleading +{ + ImGuiState& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + const ImGuiID id = window->GetID(str_id); + if (IsPopupOpen(id)) + g.OpenedPopupStack.resize(g.CurrentPopupStack.size()); +} + void ImGui::CloseCurrentPopup() { ImGuiState& g = *GImGui; @@ -3048,13 +3063,6 @@ static void CloseAllPopups() g.OpenedPopupStack.resize(0); } -static bool IsPopupOpen(ImGuiID id) -{ - ImGuiState& g = *GImGui; - const bool opened = g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].PopupID == id; - return opened; -} - static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; @@ -3072,11 +3080,10 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) else ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame float alpha = 1.0f; - bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), alpha, flags); + bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), alpha, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; - if (!opened) // opened can be 'false' when the popup is completely clipped (e.g. zero size display) ImGui::EndPopup(); @@ -7484,7 +7491,6 @@ void ImGui::EndMenuBar() ImGui::PopID(); } -// FIXME-WIP: v1.39 in development, API *WILL* change! bool ImGui::BeginMenu(const char* label) { ImGuiState& g = *GImGui; @@ -7494,16 +7500,18 @@ bool ImGui::BeginMenu(const char* label) const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - bool opened = IsPopupOpen(id); ImVec2 pos; ImVec2 popup_pos; - ImVec2 backup_pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 backup_pos = window->DC.CursorPos; + ImGuiWindow* backed_focused_window = g.FocusedWindow; bool pressed; - bool active_menuset = false; - ImGuiWindow* focused_window_backup = g.FocusedWindow; + bool opened = IsPopupOpen(id); + bool menuset_opened = (g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].ParentMenuSet == window->GetID("##menus")); + if (menuset_opened) + g.FocusedWindow = window; if (window->DC.MenuBarAppending) { @@ -7511,14 +7519,8 @@ bool ImGui::BeginMenu(const char* label) pos = window->DC.CursorPos = ImVec2(window->Pos.x + window->DC.MenuBarOffsetX, window->Pos.y + window->TitleBarHeight() + style.FramePadding.y); popup_pos = ImVec2(pos.x - style.ItemSpacing.x, pos.y); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); - - active_menuset = (g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].ParentMenuSet == window->GetID("##menus")); - if (active_menuset) - g.FocusedWindow = NULL; - float w = label_size.x; pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true); - window->DC.MenuBarOffsetX += (label_size.x + style.ItemSpacing.x); window->DC.CursorPos = backup_pos; ImGui::PopStyleVar(); @@ -7534,8 +7536,8 @@ bool ImGui::BeginMenu(const char* label) } bool hovered = IsHovered(window->DC.LastItemRect, id); - if (active_menuset) - g.FocusedWindow = focused_window_backup; + if (menuset_opened) + g.FocusedWindow = backed_focused_window; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) { @@ -7547,7 +7549,12 @@ bool ImGui::BeginMenu(const char* label) } else { - if (active_menuset) + if (menuset_opened && pressed) + { + ClosePopup(label); + opened = pressed = false; + } + else if (menuset_opened) pressed |= hovered; else pressed |= (hovered && !g.OpenedPopupStack.empty() && g.OpenedPopupStack.back().PopupID != id && g.OpenedPopupStack.back().ParentWindow == window); From 6da8a77fa3d39782d9ffd284ed537afb748b4998 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 May 2015 19:41:02 +0100 Subject: [PATCH 035/127] WIP Menus: tidying up, fixed hovering in parent popup menu item from child popup (individual popups acts as hovering barrier) (#126) --- imgui.cpp | 75 ++++++++++++++++++++++--------------------------------- imgui.h | 2 +- 2 files changed, 31 insertions(+), 46 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index aed20983..79d33ff1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7262,27 +7262,26 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar return false; const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); - const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); - - const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); - const ImVec2 pos = window->DC.CursorPos; + ImGuiID id = window->GetID(label); + ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); + ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); + ImVec2 pos = window->DC.CursorPos; ImRect bb(pos, pos + size); ItemSize(bb); // Fill horizontal space. - const ImVec2 window_padding = window->WindowPadding(); - const float w_draw = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); - const ImVec2 size_draw(size_draw_arg.x != 0.0f ? size_draw_arg.x : w_draw, size_draw_arg.y != 0.0f ? size_draw_arg.y : size.y); + ImVec2 window_padding = window->WindowPadding(); + float w_draw = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window_padding.x - window->DC.CursorPos.x); + ImVec2 size_draw(size_draw_arg.x != 0.0f ? size_draw_arg.x : w_draw, size_draw_arg.y != 0.0f ? size_draw_arg.y : size.y); ImRect bb_with_spacing(pos, pos + size_draw); if (size_draw_arg.x == 0.0f) bb_with_spacing.Max.x += window_padding.x; // Selectables are tightly packed together, we extend the box to cover spacing between selectable. - const float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); - const float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); - const float spacing_R = style.ItemSpacing.x - spacing_L; - const float spacing_D = style.ItemSpacing.y - spacing_U; + float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); + float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); + float spacing_R = style.ItemSpacing.x - spacing_L; + float spacing_D = style.ItemSpacing.y - spacing_U; bb_with_spacing.Min.x -= spacing_L; bb_with_spacing.Min.y -= spacing_U; bb_with_spacing.Max.x += spacing_R; @@ -7291,7 +7290,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar return false; bool hovered, held; - bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, menu_item ? (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_FlattenChilds) : 0); + bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, menu_item ? ImGuiButtonFlags_PressedOnClick : 0); // Render if (hovered || selected) @@ -7299,8 +7298,6 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar const ImU32 col = window->Color((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, style.FrameRounding); } - - //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); // Automatically close popups @@ -7342,9 +7339,9 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) ImVec2 size; size.x = (size_arg.x != 0.0f) ? (size_arg.x) : ImGui::CalcItemWidth() + style.FramePadding.x * 2.0f; size.y = (size_arg.y != 0.0f) ? (size_arg.y) : ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y; - const ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); - const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); - const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); + ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); window->DC.LastItemRect = bb; ImGui::BeginGroup(); @@ -7437,7 +7434,6 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true); - if (shortcut_size.x > 0.0f) { ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); @@ -7501,15 +7497,13 @@ bool ImGui::BeginMenu(const char* label) const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - ImVec2 pos; - ImVec2 popup_pos; + ImVec2 pos, popup_pos, backup_pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); - ImVec2 backup_pos = window->DC.CursorPos; ImGuiWindow* backed_focused_window = g.FocusedWindow; bool pressed; bool opened = IsPopupOpen(id); - bool menuset_opened = (g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].ParentMenuSet == window->GetID("##menus")); + bool menuset_opened = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].ParentMenuSet == window->GetID("##menus")); if (menuset_opened) g.FocusedWindow = window; @@ -7539,31 +7533,22 @@ bool ImGui::BeginMenu(const char* label) if (menuset_opened) g.FocusedWindow = backed_focused_window; + bool want_open = false; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) + want_open = (!opened && hovered); + else if (pressed && menuset_opened) { - if (!opened && hovered) - { - ImGui::OpenPopup(label); - opened = true; - } - } - else - { - if (menuset_opened && pressed) - { - ClosePopup(label); - opened = pressed = false; - } - else if (menuset_opened) - pressed |= hovered; - else - pressed |= (hovered && !g.OpenedPopupStack.empty() && g.OpenedPopupStack.back().PopupID != id && g.OpenedPopupStack.back().ParentWindow == window); - if (pressed) - { - ImGui::OpenPopup(label); // FIXME-MENUS: toggle - opened = true; - } + ClosePopup(label); // click again to toggle + want_open = opened = false; } + else if (pressed) + want_open = true; + else if (hovered && menuset_opened) + want_open = true; + + opened |= want_open; + if (want_open) + ImGui::OpenPopup(label); if (opened) { diff --git a/imgui.h b/imgui.h index a5b0e043..eb982fd6 100644 --- a/imgui.h +++ b/imgui.h @@ -232,7 +232,7 @@ namespace ImGui IMGUI_API void EndTooltip(); // Popup - 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 void OpenPopup(const char* str_id); // mark popup as open. close childs popups if any. will close popup 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 CloseCurrentPopup(); From 0cdd050cd79e7ca96886b7c1f4cbbdce55fcd1e9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 May 2015 21:26:46 +0100 Subject: [PATCH 036/127] WIP Menus: fixed recycling menu level during the same frame (#126) We could also enforce "clearing" the window and recycle immediate which sort of work, but it would be a less tested code path. --- imgui.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 79d33ff1..8d9123b6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7536,16 +7536,23 @@ bool ImGui::BeginMenu(const char* label) bool want_open = false; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) want_open = (!opened && hovered); - else if (pressed && menuset_opened) + else if (opened && pressed && menuset_opened) { ClosePopup(label); // click again to toggle want_open = opened = false; } else if (pressed) want_open = true; - else if (hovered && menuset_opened) + else if (hovered && menuset_opened && !opened) want_open = true; + if (!opened && want_open && g.OpenedPopupStack.size() > g.CurrentPopupStack.size()) + { + // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. + ImGui::OpenPopup(label); + return false; + } + opened |= want_open; if (want_open) ImGui::OpenPopup(label); From e7097d6176ebcce93ec5fbef17578bdf03097ca4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 May 2015 13:03:09 +0100 Subject: [PATCH 037/127] WIP Menus: menus now affected by WindowMinSize (#126) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index fbe0592c..f0208b79 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3510,7 +3510,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Minimum window size - if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip))) { window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); if (!window->Collapsed) From e6b1e39847fc7c7e0a1ca425936bc7b053749df4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 May 2015 13:43:13 +0100 Subject: [PATCH 038/127] WIP Menus: don't clamp windows within display when a position has been explicitly set by user. Menu item spacing uses ItemSpacing. (#126) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f0208b79..44ef159b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3577,7 +3577,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Clamp into display if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { - if (window->AutoFitFrames <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + if (!window_pos_set_by_api && window->AutoFitFrames <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. { ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); window->PosFloat = ImMax(window->PosFloat + window->Size, padding) - window->Size; @@ -3741,7 +3741,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DC.TreeDepth = 0; window->DC.StateStorage = &window->StateStorage; window->DC.GroupStack.resize(0); - window->MenuColumns.Update(3, style.ItemInnerSpacing.x, !window_was_visible); + window->MenuColumns.Update(3, style.ItemSpacing.x, !window_was_visible); if (window->AutoFitFrames > 0) window->AutoFitFrames--; From 485832fe06cc2cc4da1aee88c18dcbf4bda5e23c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 May 2015 13:43:45 +0100 Subject: [PATCH 039/127] WIP Menus: Added BeginMainMenuBar()/EndMainMenuBar() helpers. Added to examples. --- imgui.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++----------- imgui.h | 5 +++- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 44ef159b..59b528e8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4072,6 +4072,7 @@ static ImVec2* GetStyleVarVec2Addr(ImGuiStyleVar idx) switch (idx) { case ImGuiStyleVar_WindowPadding: return &g.Style.WindowPadding; + case ImGuiStyleVar_WindowMinSize: return &g.Style.WindowMinSize; case ImGuiStyleVar_FramePadding: return &g.Style.FramePadding; case ImGuiStyleVar_ItemSpacing: return &g.Style.ItemSpacing; case ImGuiStyleVar_ItemInnerSpacing: return &g.Style.ItemInnerSpacing; @@ -7452,6 +7453,30 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected) return false; } +bool ImGui::BeginMainMenuBar() +{ + ImGuiState& g = *GImGui; + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.FontBaseSize + g.Style.FramePadding.y * 2.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0)); + if (!ImGui::Begin("##MainMenuBar", NULL, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_MenuBar) + || !ImGui::BeginMenuBar()) + { + ImGui::End(); + ImGui::PopStyleVar(2); + return false; + } + return true; +} + +void ImGui::EndMainMenuBar() +{ + ImGui::EndMenuBar(); + ImGui::End(); + ImGui::PopStyleVar(2); +} + bool ImGui::BeginMenuBar() { ImGuiWindow* window = GetCurrentWindow(); @@ -10075,33 +10100,29 @@ static void ShowExampleAppAutoResize(bool* opened); static void ShowExampleAppFixedOverlay(bool* opened); static void ShowExampleAppManipulatingWindowTitle(bool* opened); static void ShowExampleAppCustomRendering(bool* opened); +static void ShowExampleAppMainMenuBar(); static void ShowExampleMenuFile(); -// Demonstrate ImGui features (unfortunately this makes this function a little bloated!) +// Demonstrate most ImGui features (big function!) void ImGui::ShowTestWindow(bool* opened) { // Examples apps static bool show_app_metrics = false; + static bool show_app_main_menu_bar = false; static bool show_app_console = false; static bool show_app_long_text = false; static bool show_app_auto_resize = false; static bool show_app_fixed_overlay = false; static bool show_app_custom_rendering = false; static bool show_app_manipulating_window_title = false; - if (show_app_metrics) - ImGui::ShowMetricsWindow(&show_app_metrics); - if (show_app_console) - ShowExampleAppConsole(&show_app_console); - if (show_app_long_text) - ShowExampleAppLongText(&show_app_long_text); - if (show_app_auto_resize) - ShowExampleAppAutoResize(&show_app_auto_resize); - if (show_app_fixed_overlay) - ShowExampleAppFixedOverlay(&show_app_fixed_overlay); - if (show_app_manipulating_window_title) - ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title); - if (show_app_custom_rendering) - ShowExampleAppCustomRendering(&show_app_custom_rendering); + if (show_app_metrics) ImGui::ShowMetricsWindow(&show_app_metrics); + if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); + if (show_app_console) ShowExampleAppConsole(&show_app_console); + if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); + if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); + if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay); + if (show_app_manipulating_window_title) ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title); + if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); static bool no_titlebar = false; static bool no_border = true; @@ -10149,6 +10170,7 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::BeginMenu("Examples")) { ImGui::MenuItem("Metrics", NULL, &show_app_metrics); + ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); ImGui::MenuItem("Console", NULL, &show_app_console); ImGui::MenuItem("Long text display", NULL, &show_app_long_text); ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); @@ -11223,6 +11245,29 @@ void ImGui::ShowMetricsWindow(bool* opened) ImGui::End(); } +static void ShowExampleAppMainMenuBar() +{ + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Edit")) + { + if (ImGui::MenuItem("Undo", "CTRL+Z")) {} + if (ImGui::MenuItem("Redo", "CTRL+Y")) {} + ImGui::Separator(); + if (ImGui::MenuItem("Cut", "CTRL+X")) {} + if (ImGui::MenuItem("Copy", "CTRL+C")) {} + if (ImGui::MenuItem("Paste", "CTRL+V")) {} + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); + } +} + static void ShowExampleMenuFile() { ImGui::TextColored(ImGui::GetStyle().Colors[ImGuiCol_TextDisabled], "(dummy menu)"); diff --git a/imgui.h b/imgui.h index 1aefd98c..2ba8e332 100644 --- a/imgui.h +++ b/imgui.h @@ -300,7 +300,9 @@ namespace ImGui // Widgets: Menus // FIXME-WIP: v1.39 in development, API *WILL* change - IMGUI_API bool BeginMenuBar(); + IMGUI_API bool BeginMainMenuBar(); // create and append to a fullscreen menu-bar + IMGUI_API void EndMainMenuBar(); + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window IMGUI_API void EndMenuBar(); IMGUI_API bool BeginMenu(const char* label); IMGUI_API void EndMenu(); @@ -504,6 +506,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_Alpha, // float ImGuiStyleVar_WindowPadding, // ImVec2 ImGuiStyleVar_WindowRounding, // float + ImGuiStyleVar_WindowMinSize, // ImVec2 ImGuiStyleVar_ChildWindowRounding, // float ImGuiStyleVar_FramePadding, // ImVec2 ImGuiStyleVar_FrameRounding, // float From 89d1340225309f24c569a9b9df7981b523acdfa8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 May 2015 13:54:57 +0100 Subject: [PATCH 040/127] WIP Menus: Added Enabled/Disabled option for MenuItem() (#126) --- imgui.cpp | 29 ++++++++++++++++++++--------- imgui.h | 4 ++-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 59b528e8..402f524b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -948,7 +948,8 @@ enum ImGuiButtonFlags_ { ImGuiButtonFlags_Repeat = (1 << 0), ImGuiButtonFlags_PressedOnClick = (1 << 1), - ImGuiButtonFlags_FlattenChilds = (1 << 2) + ImGuiButtonFlags_FlattenChilds = (1 << 2), + ImGuiButtonFlags_Disabled = (1 << 3) }; struct ImGuiColMod // Color modifier, backup of modified data so we can restore it @@ -4741,6 +4742,14 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); + if (flags & ImGuiButtonFlags_Disabled) + { + if (out_hovered) *out_hovered = false; + if (out_held) *out_held = false; + if (g.ActiveId == id) SetActiveId(0); + return false; + } + bool pressed = false; const bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0); if (hovered) @@ -7249,7 +7258,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi return value_changed; } -static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, bool menu_item = false) +static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, bool menu_item = false, bool enabled = true) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -7285,7 +7294,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar return false; bool hovered, held; - bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, menu_item ? ImGuiButtonFlags_PressedOnClick : 0); + bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, (menu_item ? ImGuiButtonFlags_PressedOnClick : 0) | (enabled ? 0 : ImGuiButtonFlags_Disabled)); // Render if (hovered || selected) @@ -7293,7 +7302,9 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar const ImU32 col = window->Color((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, style.FrameRounding); } + if (!enabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max); + if (!enabled) ImGui::PopStyleColor(); // Automatically close popups if (pressed && (window->Flags & ImGuiWindowFlags_ChildMenu)) @@ -7415,7 +7426,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v return value_changed; } -bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) +bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -7428,7 +7439,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true); + bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true, enabled); if (shortcut_size.x > 0.0f) { ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); @@ -7442,9 +7453,9 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected) 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, bool enabled) { - if (ImGui::MenuItem(label, shortcut, p_selected ? *p_selected : false)) + if (ImGui::MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) { if (p_selected) *p_selected = !*p_selected; @@ -11257,7 +11268,7 @@ static void ShowExampleAppMainMenuBar() if (ImGui::BeginMenu("Edit")) { if (ImGui::MenuItem("Undo", "CTRL+Z")) {} - if (ImGui::MenuItem("Redo", "CTRL+Y")) {} + if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item ImGui::Separator(); if (ImGui::MenuItem("Cut", "CTRL+X")) {} if (ImGui::MenuItem("Copy", "CTRL+C")) {} @@ -11270,7 +11281,7 @@ static void ShowExampleAppMainMenuBar() static void ShowExampleMenuFile() { - ImGui::TextColored(ImGui::GetStyle().Colors[ImGuiCol_TextDisabled], "(dummy menu)"); + ImGui::MenuItem("(dummy menu)", NULL, false, false); ImGui::MenuItem("New"); ImGui::MenuItem("Open", "Ctrl+O"); if (ImGui::BeginMenu("Open Recent")) diff --git a/imgui.h b/imgui.h index 2ba8e332..56a30779 100644 --- a/imgui.h +++ b/imgui.h @@ -306,8 +306,8 @@ namespace ImGui IMGUI_API void EndMenuBar(); IMGUI_API bool BeginMenu(const char* label); IMGUI_API void EndMenu(); - IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false); // 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 = NULL, bool selected = false, bool enabled = true); + IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare your own within the ImGui namespace!) IMGUI_API void Value(const char* prefix, bool b); From 8cfae350426bd437d9417ce04c9a2c910f85bd5f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 17:30:59 +0100 Subject: [PATCH 041/127] Added Dummy() helper --- imgui.cpp | 16 ++++++++++++++-- imgui.h | 5 +++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b405e529..de8a71d9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7472,16 +7472,22 @@ void ImGui::Separator() } } -// A little vertical spacing. void ImGui::Spacing() { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - ItemSize(ImVec2(0,0)); } +void ImGui::Dummy(const ImVec2& size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ItemSize(size); +} + // Advance cursor given item size. static void ItemSize(ImVec2 size, float text_offset_y) { @@ -10463,6 +10469,12 @@ void ImGui::ShowTestWindow(bool* opened) } ImGui::PopItemWidth(); + // Dummy + ImVec2 sz(30,30); + ImGui::Button("A", sz); ImGui::SameLine(); + ImGui::Dummy(sz); ImGui::SameLine(); + ImGui::Button("B", sz); + ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index 8331d747..8432862b 100644 --- a/imgui.h +++ b/imgui.h @@ -169,11 +169,12 @@ namespace ImGui IMGUI_API void EndPopup(); // Layout - IMGUI_API void BeginGroup(); + IMGUI_API void BeginGroup(); // once closing a group it is seen as a single item (so you can use IsItemHovered() on a group, SameLine() between groups, etc. IMGUI_API void EndGroup(); IMGUI_API void Separator(); // horizontal line IMGUI_API void SameLine(int column_x = 0, int spacing_w = -1); // call between widgets or groups to layout them horizontally - IMGUI_API void Spacing(); // add vertical spacing + IMGUI_API void Spacing(); // add spacing + IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border=true); // setup number of columns. use an identifier to distinguish multiple column sets. close with Columns(1). From 292f08b11e6c62a453d447231b9ca155a06e03f3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 21:11:11 +0100 Subject: [PATCH 042/127] WIP Menus: Fixed some alignment issues with non standard styles. Tweaked menu-bar color (#126) --- imgui.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 47c750dd..42292d28 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -597,7 +597,7 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f); Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); - Colors[ImGuiCol_MenuBarBg] = ImVec4(0.35f, 0.35f, 0.45f, 0.55f); + Colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.60f); Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.40f, 0.80f, 0.15f); Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); @@ -3480,9 +3480,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ else { size_auto_fit = ImClamp(window->SizeContents + window_padding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - window_padding)); - if (size_auto_fit.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar)) + if (size_auto_fit.y + style.ItemSpacing.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar)) size_auto_fit.x += style.ScrollbarWidth; - size_auto_fit.y -= style.ItemSpacing.y; + size_auto_fit.y = ImMax(size_auto_fit.y - style.ItemSpacing.y, 0.0f); } // Handle automatic resize @@ -3654,7 +3654,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Scrollbar - window->ScrollbarY = (window->SizeContents.y > window->Size.y) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarY = (window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar); // Window background if (bg_alpha > 0.0f) @@ -3725,7 +3725,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f; window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.MenuBarAppending = false; - window->DC.MenuBarOffsetX = window->DC.ColumnsStartX; + window->DC.MenuBarOffsetX = ImMax(window->DC.ColumnsStartX, style.ItemSpacing.x); window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); window->DC.ItemWidth.resize(0); @@ -7478,6 +7478,7 @@ bool ImGui::BeginMainMenuBar() ImGui::PopStyleVar(2); return false; } + g.CurrentWindow->DC.MenuBarOffsetX += g.Style.DisplaySafeAreaPadding.x; return true; } @@ -7541,7 +7542,7 @@ bool ImGui::BeginMenu(const char* label) { // FIXME: Should be moved at a lower-level once we have horizontal layout (#97) pos = window->DC.CursorPos = ImVec2(window->Pos.x + window->DC.MenuBarOffsetX, window->Pos.y + window->TitleBarHeight() + style.FramePadding.y); - popup_pos = ImVec2(pos.x - style.ItemSpacing.x, pos.y); + popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true); From 53892ab8936eca92de9c2847cfa3d86128976fec Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 21:20:10 +0100 Subject: [PATCH 043/127] WIP Menus: Fixed manually closing submenu affecting position of the following window (#126) --- imgui.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 42292d28..4b4f5b2c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3071,13 +3071,22 @@ static void CloseAllPopups() g.OpenedPopupStack.resize(0); } +static void ClearSetNextWindowData() +{ + ImGuiState& g = *GImGui; + g.SetNextWindowPosCond = g.SetNextWindowSizeCond = g.SetNextWindowCollapsedCond = g.SetNextWindowFocus = 0; +} + static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); const ImGuiID id = window->GetID(str_id); if (!IsPopupOpen(id)) + { + ClearSetNextWindowData(); // We behave like Begin() and need to consume those values return false; + } ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; From 3498617a3c5648b2d96643cc3c16d5aa2e6e668c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 22:16:34 +0100 Subject: [PATCH 044/127] Comments. --- imgui.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index a7da1c51..d5f88ee2 100644 --- a/imgui.h +++ b/imgui.h @@ -168,7 +168,7 @@ namespace ImGui IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. close childs popups if any. will close popup 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 CloseCurrentPopup(); + IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into // Layout IMGUI_API void BeginGroup(); // once closing a group it is seen as a single item (so you can use IsItemHovered() on a group, SameLine() between groups, etc. @@ -301,11 +301,11 @@ namespace ImGui // Widgets: Menus // FIXME-WIP: v1.39 in development, API *WILL* change - IMGUI_API bool BeginMainMenuBar(); // create and append to a fullscreen menu-bar + IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. only call EndMainMenuBar() if this returns true! IMGUI_API void EndMainMenuBar(); - IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window. only call EndMenuBar() if this returns true! IMGUI_API void EndMenuBar(); - IMGUI_API bool BeginMenu(const char* label); + IMGUI_API bool BeginMenu(const char* label); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); @@ -411,7 +411,6 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_Tooltip = 1 << 24, // Don't use! For internal use by BeginTooltip() ImGuiWindowFlags_Popup = 1 << 25, // Don't use! For internal use by BeginPopup() ImGuiWindowFlags_ChildMenu = 1 << 26 // Don't use! For internal use by BeginMenu() - }; // Flags for ImGui::InputText() From 48ede93a58a8be2dd08c845f7ba005bbaf121e12 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 22:30:48 +0100 Subject: [PATCH 045/127] WIP Menus: Fixed closing popup on menu item activation when a child menu is open from the popup (#126) --- imgui.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4b4f5b2c..fd2b63f3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3056,14 +3056,15 @@ static void ClosePopup(const char* str_id) // not exposed because 'id' scope is void ImGui::CloseCurrentPopup() { ImGuiState& g = *GImGui; - if (g.CurrentPopupStack.empty() || g.OpenedPopupStack.empty() || g.CurrentPopupStack.back().PopupID != g.OpenedPopupStack.back().PopupID) + int popup_idx = (int)g.CurrentPopupStack.size() - 1; + if (popup_idx < 0 || popup_idx > (int)g.OpenedPopupStack.size() || g.CurrentPopupStack[popup_idx].PopupID != g.OpenedPopupStack[popup_idx].PopupID) return; - if (g.CurrentWindow->PopupID == g.OpenedPopupStack.back().PopupID && g.Windows.size() >= 2) + if (g.CurrentWindow->PopupID == g.OpenedPopupStack[popup_idx].PopupID && g.Windows.size() > 1) FocusWindow(g.Windows[g.Windows.size()-2]); - g.OpenedPopupStack.pop_back(); + g.OpenedPopupStack.resize(popup_idx); } -static void CloseAllPopups() +static void CloseCurrentMenus() { // Close all popups // FIXME-MENUS: invalid for popup->menus with current BeginMenu() scheme @@ -7317,7 +7318,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar // Automatically close popups if (pressed && (window->Flags & ImGuiWindowFlags_ChildMenu)) - CloseAllPopups(); + CloseCurrentMenus(); else if (pressed && (window->Flags & ImGuiWindowFlags_Popup)) ImGui::CloseCurrentPopup(); return pressed; From 1ab17128492fa7ac4f5c21ab92fcb917553d18d4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 22:33:04 +0100 Subject: [PATCH 046/127] WIP Menus: Clicking the label of an already open sub-menu doesn't close it unless from a menu-bar (match Windows behavior) (#126) Argh, --- imgui.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fd2b63f3..d072a6f5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7268,7 +7268,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi return value_changed; } -static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, bool menu_item = false, bool enabled = true) +static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, bool menu_item = false, bool enabled = true, bool close_popups = true) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -7317,9 +7317,9 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar if (!enabled) ImGui::PopStyleColor(); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_ChildMenu)) + if (close_popups && pressed && (window->Flags & ImGuiWindowFlags_ChildMenu)) CloseCurrentMenus(); - else if (pressed && (window->Flags & ImGuiWindowFlags_Popup)) + else if (close_popups && pressed && (window->Flags & ImGuiWindowFlags_Popup)) ImGui::CloseCurrentPopup(); return pressed; } @@ -7555,7 +7555,7 @@ bool ImGui::BeginMenu(const char* label) popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; - pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true, true, false); window->DC.MenuBarOffsetX += (label_size.x + style.ItemSpacing.x); window->DC.CursorPos = backup_pos; ImGui::PopStyleVar(); @@ -7566,7 +7566,7 @@ bool ImGui::BeginMenu(const char* label) popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true, true, false); RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); } From 8c1d7daef8af0b9ba0857ca85dc3c0b5e054c3a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 23:17:06 +0100 Subject: [PATCH 047/127] WIP Menus: Fixed repositioning of menus when there's no room in the 4 quadrants., we still keep them within the visible display area (#126) vs popup which prefer to stay away from the mouse cursor --- imgui.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d072a6f5..0783ebe8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3227,14 +3227,14 @@ static void CheckStacksSize(ImGuiWindow* window, bool write) IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); } -static ImVec2 FindBestWindowPos(const ImVec2& mouse_pos, const ImVec2& size, int* last_dir, const ImRect& r_inner) +static ImVec2 FindBestWindowPos(const ImVec2& base_pos, const ImVec2& size, ImGuiWindowFlags flags, int* last_dir, const ImRect& r_inner) { const ImGuiStyle& style = GImGui->Style; // Clamp into visible area while not overlapping the cursor ImRect r_outer(GetVisibleRect()); r_outer.Reduce(style.DisplaySafeAreaPadding); - ImVec2 mouse_pos_clamped = ImClamp(mouse_pos, r_outer.Min, r_outer.Max - size); + ImVec2 base_pos_clamped = ImClamp(base_pos, r_outer.Min, r_outer.Max - size); for (int n = (*last_dir != -1) ? -1 : 0; n < 4; n++) // Right, down, up, left. Favor last used direction. { @@ -3243,12 +3243,19 @@ static ImVec2 FindBestWindowPos(const ImVec2& mouse_pos, const ImVec2& size, int if (rect.GetWidth() < size.x || rect.GetHeight() < size.y) continue; *last_dir = dir; - return ImVec2(dir == 0 ? r_inner.Max.x : dir == 3 ? r_inner.Min.x - size.x : mouse_pos_clamped.x, dir == 1 ? r_inner.Max.y : dir == 2 ? r_inner.Min.y - size.y : mouse_pos_clamped.y); + return ImVec2(dir == 0 ? r_inner.Max.x : dir == 3 ? r_inner.Min.x - size.x : base_pos_clamped.x, dir == 1 ? r_inner.Max.y : dir == 2 ? r_inner.Min.y - size.y : base_pos_clamped.y); } // Fallback *last_dir = -1; - return mouse_pos + ImVec2(2,2); + if (flags & ImGuiWindowFlags_Tooltip) // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. + return base_pos + ImVec2(2,2); + + // Otherwise try to keep within display + ImVec2 pos = base_pos; + pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); + pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); + return pos; } static ImGuiWindow* FindWindowByName(const char* name) @@ -3548,19 +3555,19 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ rect_to_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); else 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); + window->PosFloat = FindBestWindowPos(window->PosFloat, window->Size, flags, &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); + window->PosFloat = FindBestWindowPos(window->PosFloat, window->Size, flags, &window->AutoPosLastDirection, rect_to_avoid); } // Position tooltip (always follows mouse) if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api) { ImRect rect_to_avoid(g.IO.MousePos.x - 16, g.IO.MousePos.y - 8, g.IO.MousePos.x + 24, g.IO.MousePos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead? - window->PosFloat = FindBestWindowPos(g.IO.MousePos, window->Size, &window->AutoPosLastDirection, rect_to_avoid); + window->PosFloat = FindBestWindowPos(g.IO.MousePos, window->Size, flags, &window->AutoPosLastDirection, rect_to_avoid); } // User moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. @@ -3585,7 +3592,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } } - // Clamp into display + // Clamp position so it stays visible if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { if (!window_pos_set_by_api && window->AutoFitFrames <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. @@ -7552,7 +7559,7 @@ bool ImGui::BeginMenu(const char* label) { // FIXME: Should be moved at a lower-level once we have horizontal layout (#97) pos = window->DC.CursorPos = ImVec2(window->Pos.x + window->DC.MenuBarOffsetX, window->Pos.y + window->TitleBarHeight() + style.FramePadding.y); - popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y); + popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y - style.FramePadding.y + window->MenuBarHeight()); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true, true, false); From 63aa035f591eea5b06ad05e4d2ede19c35412ffb Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 23:25:57 +0100 Subject: [PATCH 048/127] WIP Menus: Fixed estimation of scrollbar width (broke in 292f08b11e6c62a453d447231b9ca155a06e03f3) (#126) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 0783ebe8..866dffa3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3497,7 +3497,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ else { size_auto_fit = ImClamp(window->SizeContents + window_padding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - window_padding)); - if (size_auto_fit.y + style.ItemSpacing.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar)) + if (size_auto_fit.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar)) size_auto_fit.x += style.ScrollbarWidth; size_auto_fit.y = ImMax(size_auto_fit.y - style.ItemSpacing.y, 0.0f); } From 9abcbf73cbe75c6948a97865f372d06a86b58084 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 23:37:47 +0100 Subject: [PATCH 049/127] WIP Menus: Sub-menus appears over the parent-menu scrollbar if there is one (unsure about that) (#126) --- imgui.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 866dffa3..9add2701 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1396,8 +1396,9 @@ public: float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } - ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } + ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & (ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : GImGui->Style.WindowPadding; } + float ScrollbarWidth() const { return ScrollbarY ? GImGui->Style.ScrollbarWidth : 0.0f; } 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); } }; @@ -3554,7 +3555,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (parent_window->DC.MenuBarAppending) rect_to_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); else - 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) + rect_to_avoid = ImRect(parent_window->Pos.x + 4.0f, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - 4.0f - parent_window->ScrollbarWidth(), 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, flags, &window->AutoPosLastDirection, rect_to_avoid); } else if ((flags & ImGuiWindowFlags_Popup) != 0 && window_appearing_after_being_hidden && !window_pos_set_by_api) @@ -3683,7 +3684,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ 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)); + window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarWidth(),0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF)); else window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_WindowBg, bg_alpha), window_rounding); } @@ -4379,8 +4380,7 @@ ImVec2 ImGui::GetContentRegionMax() } else { - if (window->ScrollbarY) - mx.x -= GImGui->Style.ScrollbarWidth; + mx.x -= window->ScrollbarWidth(); } return mx; } @@ -4395,8 +4395,7 @@ ImVec2 ImGui::GetWindowContentRegionMax() { ImGuiWindow* window = GetCurrentWindow(); ImVec2 m = window->Size - window->WindowPadding(); - if (window->ScrollbarY) - m.x -= GImGui->Style.ScrollbarWidth; + m.x -= window->ScrollbarWidth(); return m; } From 6c749934ec70244bcf6854a1c02238ad757d08a9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 23:45:44 +0100 Subject: [PATCH 050/127] Combo: empty label doesn't add ItemInnerSpacing alignment, matching other widgets --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index de8a71d9..e2f7988b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6970,7 +6970,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); - const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(style.ItemInnerSpacing.x + label_size.x,0)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, &id)) return false; @@ -9714,7 +9714,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) } ImGui::LogFinish(); } - ImGui::SameLine(); ImGui::PushItemWidth(150); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY"); ImGui::PopItemWidth(); + ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY"); ImGui::PopItemWidth(); ImGui::SameLine(); ImGui::Checkbox("Only Modified Fields", &output_only_modified); static ImGuiColorEditMode edit_mode = ImGuiColorEditMode_RGB; From 0836f69d9b27c6858b33bea9672f77dc700ec75b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 23:56:29 +0100 Subject: [PATCH 051/127] WIP Menus: Fixed style.WindowPadding == 0 leading to zero-sized initial clipping rectangle leading to self-collapsing childs (#126) --- imgui.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9add2701..f1d211dc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3821,8 +3821,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); window->Collapsed = parent_window && parent_window->Collapsed; - const ImVec4 clip_rect_t = window->ClipRectStack.back(); - window->Collapsed |= (clip_rect_t.x >= clip_rect_t.z || clip_rect_t.y >= clip_rect_t.w); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFrames <= 0) + { + const ImVec4 clip_rect_t = window->ClipRectStack.back(); + window->Collapsed |= (clip_rect_t.x >= clip_rect_t.z || clip_rect_t.y >= clip_rect_t.w); + } // We also hide the window from rendering because we've already added its border to the command list. // (we could perform the check earlier in the function but it is simpler at this point) From 44ed5640d3badb43f691c7487dbdf63d22d58635 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 May 2015 23:58:40 +0100 Subject: [PATCH 052/127] WIP Menus: Sub-menu overlapping amount not hardcoded (#126) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index f1d211dc..a89b6cf3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3555,7 +3555,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (parent_window->DC.MenuBarAppending) rect_to_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight()); else - rect_to_avoid = ImRect(parent_window->Pos.x + 4.0f, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - 4.0f - parent_window->ScrollbarWidth(), FLT_MAX); // We want some overlap to convey the relative depth of each popup (here hard-coded to 4) + rect_to_avoid = ImRect(parent_window->Pos.x + style.ItemSpacing.x, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - style.ItemSpacing.x - parent_window->ScrollbarWidth(), 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, flags, &window->AutoPosLastDirection, rect_to_avoid); } else if ((flags & ImGuiWindowFlags_Popup) != 0 && window_appearing_after_being_hidden && !window_pos_set_by_api) From 83cb040d203e3964bcbb672f4e5357232b4006b0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 25 May 2015 23:03:16 +0100 Subject: [PATCH 053/127] Selectable: text baseline alignment for line that aren't of text height. --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index a89b6cf3..b3cbd2c3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7289,6 +7289,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrentLineTextBaseOffset; ImRect bb(pos, pos + size); ItemSize(bb); From bb8cdcb91649e816e96138fb9230a626846abc09 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 25 May 2015 23:08:22 +0100 Subject: [PATCH 054/127] WIP Menus: Layout in menu-bar more standard, allows mixing different widgets in menubar. (#126) Still some minor spacing bugs. --- imgui.cpp | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b3cbd2c3..6cfc0ccd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -501,6 +501,7 @@ struct ImGuiTextEditState; struct ImGuiIniData; struct ImGuiState; struct ImGuiWindow; +typedef int ImGuiLayoutType; // enum ImGuiLayoutType_ typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags = 0); @@ -944,6 +945,12 @@ static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, //----------------------------------------------------------------------------- +enum ImGuiLayoutType_ +{ + ImGuiLayoutType_Vertical, + ImGuiLayoutType_Horizontal +}; + enum ImGuiButtonFlags_ { ImGuiButtonFlags_Repeat = (1 << 0), @@ -1012,6 +1019,7 @@ struct ImGuiGroupData float BackupCurrentLineHeight; float BackupCurrentLineTextBaseOffset; float BackupLogLinePosY; + bool AdvanceCursor; }; // Simple column measurement currently used for menu items. This is very short-sighted for now. @@ -1075,6 +1083,7 @@ struct ImGuiDrawContext bool MenuBarAppending; float MenuBarOffsetX; ImVector ChildWindows; + ImGuiLayoutType LayoutType; ImVector AllowKeyboardFocus; ImVector ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window ImVector TextWrapPos; @@ -1106,6 +1115,7 @@ struct ImGuiDrawContext LastItemHoveredAndUsable = LastItemHoveredRect = false; MenuBarAppending = false; MenuBarOffsetX = 0.0f; + LayoutType = ImGuiLayoutType_Vertical; ColorEditMode = ImGuiColorEditMode_RGB; StateStorage = NULL; memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); @@ -3748,6 +3758,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DC.ChildWindows.resize(0); window->DC.ItemWidth.resize(0); window->DC.ItemWidth.push_back(window->ItemWidthDefault); + window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.AllowKeyboardFocus.resize(0); window->DC.AllowKeyboardFocus.push_back(true); window->DC.TextWrapPos.resize(0); @@ -7518,10 +7529,14 @@ bool ImGui::BeginMenuBar() return false; IM_ASSERT(!window->DC.MenuBarAppending); - window->DC.MenuBarAppending = true; + ImGui::BeginGroup(); // Save position ImGui::PushID("##menubar"); ImRect rect = window->MenuBarRect(); PushClipRect(ImVec4(rect.Min.x+0.5f, rect.Min.y-0.5f, rect.Max.x+0.5f, rect.Max.y-1.5f), false); + window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y); + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.MenuBarAppending = true; + ImGui::AlignFirstTextHeightToWidgets(); return true; } @@ -7533,22 +7548,25 @@ void ImGui::EndMenuBar() IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); IM_ASSERT(window->DC.MenuBarAppending); - window->DC.MenuBarAppending = false; PopClipRect(); ImGui::PopID(); + window->DC.MenuBarOffsetX = window->DC.CursorPos.x - window->MenuBarRect().Min.x; + window->DC.GroupStack.back().AdvanceCursor = false; + ImGui::EndGroup(); + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.MenuBarAppending = false; } bool ImGui::BeginMenu(const char* label) { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; + ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - ImVec2 pos, popup_pos, backup_pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); ImGuiWindow* backed_focused_window = g.FocusedWindow; @@ -7558,21 +7576,18 @@ bool ImGui::BeginMenu(const char* label) if (menuset_opened) g.FocusedWindow = window; - if (window->DC.MenuBarAppending) + ImVec2 popup_pos, pos = window->DC.CursorPos; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { - // FIXME: Should be moved at a lower-level once we have horizontal layout (#97) - pos = window->DC.CursorPos = ImVec2(window->Pos.x + window->DC.MenuBarOffsetX, window->Pos.y + window->TitleBarHeight() + style.FramePadding.y); popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y - style.FramePadding.y + window->MenuBarHeight()); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true, true, false); - window->DC.MenuBarOffsetX += (label_size.x + style.ItemSpacing.x); - window->DC.CursorPos = backup_pos; + ImGui::SameLine(); ImGui::PopStyleVar(); } else { - pos = window->DC.CursorPos; popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); @@ -7956,6 +7971,7 @@ void ImGui::BeginGroup() group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupLogLinePosY = window->DC.LogLinePosY; + group_data.AdvanceCursor = true; window->DC.ColumnsStartX = window->DC.CursorPos.x - window->Pos.x; window->DC.CursorMaxPos = window->DC.CursorPos; @@ -7983,8 +7999,11 @@ void ImGui::EndGroup() window->DC.ColumnsStartX = group_data.BackupColumnsStartX; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; - ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset); - ItemAdd(group_bb, NULL); + if (group_data.AdvanceCursor) + { + ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset); + ItemAdd(group_bb, NULL); + } window->DC.GroupStack.pop_back(); From 98540370a0fec1c0b27b9daae21c73abb504fdd0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 25 May 2015 23:15:00 +0100 Subject: [PATCH 055/127] WIP Menus: Layout in menu-bar tweaks to lay better when mixed widgets (#126) --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6cfc0ccd..1c203dca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7580,11 +7580,13 @@ bool ImGui::BeginMenu(const char* label) if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y - style.FramePadding.y + window->MenuBarHeight()); + window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true, true, false); - ImGui::SameLine(); ImGui::PopStyleVar(); + ImGui::SameLine(); + window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); } else { From fd0108dbef1b76474dd594a5c5e989a411b5a64f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 25 May 2015 23:37:08 +0100 Subject: [PATCH 056/127] Comments --- imgui.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index d5f88ee2..3b479fed 100644 --- a/imgui.h +++ b/imgui.h @@ -300,14 +300,13 @@ namespace ImGui IMGUI_API void ListBoxFooter(); // terminate the scrolling region // Widgets: Menus - // FIXME-WIP: v1.39 in development, API *WILL* change IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. only call EndMainMenuBar() if this returns true! IMGUI_API void EndMainMenuBar(); IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window. only call EndMenuBar() if this returns true! IMGUI_API void EndMenuBar(); IMGUI_API bool BeginMenu(const char* label); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); - IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // shortcuts are displayed for convenience but not processed by ImGui IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare your own within the ImGui namespace!) From 83b10f77a9bf573d56edfe67bdeedd49d4e35c16 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 25 May 2015 23:47:59 +0100 Subject: [PATCH 057/127] Comments --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 1c203dca..94d9b072 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -136,7 +136,7 @@ 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. - - 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/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. BeginPopup() returns true if the popup is opened. - 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/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API From 4eeba016f620cd2aac3e4a3eab4dc526397597dc Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 15:01:04 +0100 Subject: [PATCH 058/127] WIP Menus: Closing sub-menu when hovering something else in the same parent window (#126) Immediate open/close is error-prone --- imgui.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 94d9b072..2e284d3d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7603,15 +7603,17 @@ bool ImGui::BeginMenu(const char* label) bool want_open = false; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) - want_open = (!opened && hovered); - else if (opened && pressed && menuset_opened) { - ClosePopup(label); // click again to toggle + if (opened && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id) + ClosePopup(label); + want_open = (!opened && hovered); + } + else if (opened && pressed && menuset_opened) // menu-bar: click open menu to close + { + ClosePopup(label); want_open = opened = false; } - else if (pressed) - want_open = true; - else if (hovered && menuset_opened && !opened) + else if (pressed || (hovered && menuset_opened && !opened)) // menu-bar: first click to open, then hover to open others want_open = true; if (!opened && want_open && g.OpenedPopupStack.size() > g.CurrentPopupStack.size()) From cdb5e16f70f852680f5c05b4b6c0729b25874709 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 16:12:40 +0100 Subject: [PATCH 059/127] SelectableEx: use flags internally (similar to ButtonBehavior) --- imgui.cpp | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2e284d3d..782d10f8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -501,8 +501,9 @@ struct ImGuiTextEditState; struct ImGuiIniData; struct ImGuiState; struct ImGuiWindow; -typedef int ImGuiLayoutType; // enum ImGuiLayoutType_ -typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_ +typedef int ImGuiLayoutType; // enum ImGuiLayoutType_ +typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_ +typedef int ImGuiSelectableFlags; // enum ImGuiSelectableFlags_ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags = 0); static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL); @@ -959,6 +960,14 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_Disabled = (1 << 3) }; +enum ImGuiSelectableFlags_ +{ + ImGuiSelectableFlags_MenuItem = (1 << 0), + ImGuiSelectableFlags_DontClosePopups = (1 << 1), + ImGuiSelectableFlags_Disabled = (1 << 2) +}; + + struct ImGuiColMod // Color modifier, backup of modified data so we can restore it { ImGuiCol Col; @@ -7288,7 +7297,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi return value_changed; } -static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, bool menu_item = false, bool enabled = true, bool close_popups = true) +static bool SelectableEx(const char* label, bool selected, const ImVec2& size_arg, const ImVec2 size_draw_arg, ImGuiSelectableFlags flags) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -7325,7 +7334,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar return false; bool hovered, held; - bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, (menu_item ? ImGuiButtonFlags_PressedOnClick : 0) | (enabled ? 0 : ImGuiButtonFlags_Disabled)); + bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, ((flags & ImGuiSelectableFlags_MenuItem) ? ImGuiButtonFlags_PressedOnClick : 0) | ((flags & ImGuiSelectableFlags_Disabled) ? ImGuiButtonFlags_Disabled : 0)); // Render if (hovered || selected) @@ -7333,14 +7342,14 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar const ImU32 col = window->Color((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, style.FrameRounding); } - if (!enabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + if (flags & ImGuiSelectableFlags_Disabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max); - if (!enabled) ImGui::PopStyleColor(); + if (flags & ImGuiSelectableFlags_Disabled) ImGui::PopStyleColor(); // Automatically close popups - if (close_popups && pressed && (window->Flags & ImGuiWindowFlags_ChildMenu)) + if (pressed && (window->Flags & ImGuiWindowFlags_ChildMenu) && !(flags & ImGuiSelectableFlags_DontClosePopups)) CloseCurrentMenus(); - else if (close_popups && pressed && (window->Flags & ImGuiWindowFlags_Popup)) + else if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups)) ImGui::CloseCurrentPopup(); return pressed; } @@ -7349,12 +7358,12 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID. bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) { - return SelectableEx(label, selected, size_arg, size_arg); + return SelectableEx(label, selected, size_arg, size_arg, 0); } bool ImGui::Selectable(const char* label, bool* p_selected, const ImVec2& size_arg) { - if (SelectableEx(label, *p_selected, size_arg, size_arg)) + if (SelectableEx(label, *p_selected, size_arg, size_arg, 0)) { *p_selected = !*p_selected; return true; @@ -7470,7 +7479,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true, enabled); + bool pressed = SelectableEx(label, false, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), ImGuiSelectableFlags_MenuItem | (!enabled ? ImGuiSelectableFlags_Disabled : 0)); if (shortcut_size.x > 0.0f) { ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); @@ -7583,7 +7592,7 @@ bool ImGui::BeginMenu(const char* label) window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; - pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), true, true, false); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups); ImGui::PopStyleVar(); ImGui::SameLine(); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); @@ -7593,7 +7602,7 @@ bool ImGui::BeginMenu(const char* label) popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), true, true, false); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups); RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); } From 63a39dd08e2a3e34760e7a7115be7a41185cc008 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 16:14:51 +0100 Subject: [PATCH 060/127] WIP Menus: Recursive menu demo (#126). Actually useful to test sub-menu positioning. --- imgui.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 782d10f8..727776e4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11358,6 +11358,11 @@ static void ShowExampleMenuFile() { ImGui::MenuItem("Hello"); ImGui::MenuItem("Sailor"); + if (ImGui::BeginMenu("Recurse..")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } ImGui::EndMenu(); } ImGui::EndMenu(); From d009a85de4c30e14105cded25d419639c9a03694 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 17:09:21 +0100 Subject: [PATCH 061/127] WIP Menus: Implement amazon's dropdown-like triangle test for navigating sub-menus (#126) --- imgui.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 727776e4..a956b459 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -729,6 +729,14 @@ static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } +static bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c) +{ + bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; + bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; + bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; + return ((b1 == b2) && (b2 == b3)); +} + static int ImStricmp(const char* str1, const char* str2) { int d; @@ -7613,9 +7621,28 @@ bool ImGui::BeginMenu(const char* label) bool want_open = false; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) { - if (opened && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id) + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers so menus feel more reactive. + bool moving_within_opened_triangle = false; + if (g.HoveredWindow == window && g.OpenedPopupStack.size() > g.CurrentPopupStack.size() && g.OpenedPopupStack[g.CurrentPopupStack.size()].ParentWindow == window) + { + if (ImGuiWindow* next_window = g.OpenedPopupStack[g.CurrentPopupStack.size()].Window) + { + ImRect next_window_rect = next_window->Rect(); + ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; + ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); + ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); + float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. all sizes are hard-coded in pixels, need some sort of pixel-to-window-size ratio for retina-like displays. + ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus + tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); + moving_within_opened_triangle = ImIsPointInTriangle(g.IO.MousePos, ta, tb, tc); + //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? 0x80008000 : 0x80000080); window->DrawList->PopClipRect(); // Debug + } + } + + if (opened && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle) ClosePopup(label); - want_open = (!opened && hovered); + want_open = (!opened && hovered && !moving_within_opened_triangle) || (!opened && hovered && pressed); } else if (opened && pressed && menuset_opened) // menu-bar: click open menu to close { From fdce095101a763f1d35835bb1e6a2d434c936087 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 17:27:35 +0100 Subject: [PATCH 062/127] Comments --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a956b459..edaec412 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7631,7 +7631,7 @@ bool ImGui::BeginMenu(const char* label) ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); - float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. all sizes are hard-coded in pixels, need some sort of pixel-to-window-size ratio for retina-like displays. + float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); From 0db122bc3b323921d44a84284d30564b3a95e433 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 17:48:28 +0100 Subject: [PATCH 063/127] Comments. Examples: added empty if (MenuItem()) {} statements in more places to better document the typical use cases (#126) --- imgui.cpp | 10 +++++----- imgui.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index edaec412..3825607f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11374,8 +11374,8 @@ static void ShowExampleAppMainMenuBar() static void ShowExampleMenuFile() { ImGui::MenuItem("(dummy menu)", NULL, false, false); - ImGui::MenuItem("New"); - ImGui::MenuItem("Open", "Ctrl+O"); + if (ImGui::MenuItem("New")) {} + if (ImGui::MenuItem("Open", "Ctrl+O")) {} if (ImGui::BeginMenu("Open Recent")) { ImGui::MenuItem("fish_hat.c"); @@ -11394,8 +11394,8 @@ static void ShowExampleMenuFile() } ImGui::EndMenu(); } - ImGui::MenuItem("Save", "Ctrl+S"); - ImGui::MenuItem("Save As.."); + if (ImGui::MenuItem("Save", "Ctrl+S")) {} + if (ImGui::MenuItem("Save As..")) {} ImGui::Separator(); if (ImGui::BeginMenu("Options")) { @@ -11415,7 +11415,7 @@ static void ShowExampleMenuFile() ImGui::MenuItem(ImGui::GetStyleColName((ImGuiCol)i)); ImGui::EndMenu(); } - ImGui::MenuItem("Quit", "Alt+F4"); + if (ImGui::MenuItem("Quit", "Alt+F4")) {} } static void ShowExampleAppAutoResize(bool* opened) diff --git a/imgui.h b/imgui.h index 3b479fed..b3a5b9d0 100644 --- a/imgui.h +++ b/imgui.h @@ -300,14 +300,14 @@ namespace ImGui IMGUI_API void ListBoxFooter(); // terminate the scrolling region // Widgets: Menus - IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. only call EndMainMenuBar() if this returns true! + IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. only call EndMainMenuBar() if this returns true! IMGUI_API void EndMainMenuBar(); - IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window. only call EndMenuBar() if this returns true! + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window. only call EndMenuBar() if this returns true! IMGUI_API void EndMenuBar(); - IMGUI_API bool BeginMenu(const char* label); // create a sub-menu entry. only call EndMenu() if this returns true! + IMGUI_API bool BeginMenu(const char* label); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); - IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // shortcuts are displayed for convenience but not processed by ImGui - 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 = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui + IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare your own within the ImGui namespace!) IMGUI_API void Value(const char* prefix, bool b); From 6b3ccd3edfcd0ff9fb44060bea092f91b1522795 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 18:02:42 +0100 Subject: [PATCH 064/127] WIP Menus: Added support for disabled sub-menu (#126) --- imgui.cpp | 16 ++++++++++++---- imgui.h | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3825607f..8bd96200 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7343,6 +7343,8 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar bool hovered, held; bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, ((flags & ImGuiSelectableFlags_MenuItem) ? ImGuiButtonFlags_PressedOnClick : 0) | ((flags & ImGuiSelectableFlags_Disabled) ? ImGuiButtonFlags_Disabled : 0)); + if (flags & ImGuiSelectableFlags_Disabled) + selected = false; // Render if (hovered || selected) @@ -7574,7 +7576,7 @@ void ImGui::EndMenuBar() window->DC.MenuBarAppending = false; } -bool ImGui::BeginMenu(const char* label) +bool ImGui::BeginMenu(const char* label, bool enabled) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -7600,7 +7602,7 @@ bool ImGui::BeginMenu(const char* label) window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; - pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(w, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0)); ImGui::PopStyleVar(); ImGui::SameLine(); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); @@ -7610,11 +7612,13 @@ bool ImGui::BeginMenu(const char* label) popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame float extra_w = ImMax(0.0f, window->Pos.x + ImGui::GetContentRegionMax().x - pos.x - w); - pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups); + pressed = SelectableEx(label, opened, ImVec2(w, 0.0f), ImVec2(0.0f, 0.0f), ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0)); + if (!enabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); + if (!enabled) ImGui::PopStyleColor(); } - bool hovered = IsHovered(window->DC.LastItemRect, id); + bool hovered = enabled && IsHovered(window->DC.LastItemRect, id); if (menuset_opened) g.FocusedWindow = backed_focused_window; @@ -11415,6 +11419,10 @@ static void ShowExampleMenuFile() ImGui::MenuItem(ImGui::GetStyleColName((ImGuiCol)i)); ImGui::EndMenu(); } + if (ImGui::BeginMenu("Disabled", false)) // Disabled + { + IM_ASSERT(0); + } if (ImGui::MenuItem("Quit", "Alt+F4")) {} } diff --git a/imgui.h b/imgui.h index b3a5b9d0..9c828a5c 100644 --- a/imgui.h +++ b/imgui.h @@ -304,7 +304,7 @@ namespace ImGui IMGUI_API void EndMainMenuBar(); IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window. only call EndMenuBar() if this returns true! IMGUI_API void EndMenuBar(); - IMGUI_API bool BeginMenu(const char* label); // create a sub-menu entry. only call EndMenu() if this returns true! + IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL From 3a6e6645e61cdaacc4c38ed0ec96116a736cfd07 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 20:33:48 +0100 Subject: [PATCH 065/127] WIP Menus: Fixed remaining inconsistency with stacks of popups. Activating/closing a menu close the parent popup. Added test case. (#126) --- imgui.cpp | 36 +++++++++++++++++++++--------------- imgui.h | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ee42ebf8..6d98c693 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3072,32 +3072,35 @@ void ImGui::OpenPopup(const char* str_id) g.OpenedPopupStack.back() = ImGuiPopupRef(id, window, window->GetID("##menus")); } +static void ClosePopupToLevel(int remaining) +{ + ImGuiState& g = *GImGui; + if (remaining > 0) + FocusWindow(g.OpenedPopupStack[remaining-1].Window); + else + FocusWindow(g.OpenedPopupStack[0].ParentWindow); + g.OpenedPopupStack.resize(remaining); +} + static void ClosePopup(const char* str_id) // not exposed because 'id' scope is misleading { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); const ImGuiID id = window->GetID(str_id); if (IsPopupOpen(id)) - g.OpenedPopupStack.resize(g.CurrentPopupStack.size()); + ClosePopupToLevel((int)g.CurrentPopupStack.size()); } +// Close the popup we have begin-ed into. void ImGui::CloseCurrentPopup() { ImGuiState& g = *GImGui; int popup_idx = (int)g.CurrentPopupStack.size() - 1; if (popup_idx < 0 || popup_idx > (int)g.OpenedPopupStack.size() || g.CurrentPopupStack[popup_idx].PopupID != g.OpenedPopupStack[popup_idx].PopupID) return; - if (g.CurrentWindow->PopupID == g.OpenedPopupStack[popup_idx].PopupID && g.Windows.size() > 1) - FocusWindow(g.Windows[g.Windows.size()-2]); - g.OpenedPopupStack.resize(popup_idx); -} - -static void CloseCurrentMenus() -{ - // Close all popups - // FIXME-MENUS: invalid for popup->menus with current BeginMenu() scheme - ImGuiState& g = *GImGui; - g.OpenedPopupStack.resize(0); + while (popup_idx > 0 && g.OpenedPopupStack[popup_idx].Window && (g.OpenedPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) + popup_idx--; + ClosePopupToLevel(popup_idx); } static void ClearSetNextWindowData() @@ -7357,9 +7360,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar if (flags & ImGuiSelectableFlags_Disabled) ImGui::PopStyleColor(); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_ChildMenu) && !(flags & ImGuiSelectableFlags_DontClosePopups)) - CloseCurrentMenus(); - else if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups)) + if (pressed && !(flags & ImGuiSelectableFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) ImGui::CloseCurrentPopup(); return pressed; } @@ -10557,6 +10558,11 @@ void ImGui::ShowTestWindow(bool* opened) { for (int i = 0; i < IM_ARRAYSIZE(names); i++) ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Click me"); + ImGui::EndMenu(); + } ImGui::EndPopup(); } ImGui::EndPopup(); diff --git a/imgui.h b/imgui.h index 9c828a5c..cac50660 100644 --- a/imgui.h +++ b/imgui.h @@ -168,7 +168,7 @@ namespace ImGui IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. close childs popups if any. will close popup 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 CloseCurrentPopup(); // close the popup we have begin-ed into + IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. // Layout IMGUI_API void BeginGroup(); // once closing a group it is seen as a single item (so you can use IsItemHovered() on a group, SameLine() between groups, etc. From 15113f682ec6597d4b466bf03db1e4e3eba9af08 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 21:10:16 +0100 Subject: [PATCH 066/127] Added TextDisabled(), TextDisabledV() helpers. --- imgui.cpp | 18 +++++++++++++++++- imgui.h | 2 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6d98c693..d4cf0747 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4593,6 +4593,21 @@ void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) va_end(args); } +void ImGui::TextDisabledV(const char* fmt, va_list args) +{ + ImGui::PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]); + TextV(fmt, args); + ImGui::PopStyleColor(); +} + +void ImGui::TextDisabled(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextDisabledV(fmt, args); + va_end(args); +} + void ImGui::TextWrappedV(const char* fmt, va_list args) { ImGui::PushTextWrapPos(0.0f); @@ -10382,6 +10397,7 @@ void ImGui::ShowTestWindow(bool* opened) // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. ImGui::TextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink"); ImGui::TextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow"); + ImGui::TextDisabled("Disabled"); ImGui::TreePop(); } @@ -10663,7 +10679,7 @@ void ImGui::ShowTestWindow(bool* opened) static int i2=42; ImGui::DragInt("drag int", &i1, 1); ImGui::SameLine(); - ImGui::TextColored(ImColor(170,170,170,255), "(?)"); + ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input text"); diff --git a/imgui.h b/imgui.h index cac50660..7be8a99e 100644 --- a/imgui.h +++ b/imgui.h @@ -215,6 +215,8 @@ namespace ImGui IMGUI_API void TextV(const char* fmt, va_list args); IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args); + IMGUI_API void TextDisabled(const char* fmt, ...); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextDisabledV(const char* fmt, va_list args); IMGUI_API void TextWrapped(const char* fmt, ...); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos(); IMGUI_API void TextWrappedV(const char* fmt, va_list args); IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, recommended for long chunks of text From 6f32684f15749e3b732f86187704faf3b97b4460 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 21:36:44 +0100 Subject: [PATCH 067/127] Examples: various usage comments. --- imgui.cpp | 34 +++++++++++++++++++++------------- imgui.h | 2 +- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d4cf0747..489dcb8c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -54,7 +54,7 @@ - TAB/SHIFT+TAB to cycle through keyboard editable fields - use mouse wheel to scroll - use CTRL+mouse wheel to zoom window contents (if IO.FontAllowScaling is true) - - CTRL+Click on a slider to input value as text + - CTRL+Click on a slider or drag box to input value as text - text editor: - Hold SHIFT or use mouse to select text. - CTRL+Left/Right to word jump @@ -373,6 +373,7 @@ - text edit: field resize behavior - field could stretch when being edited? hover tooltip shows more text? - text edit: add multi-line text edit - tree: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings + - tooltip: figure out a way to use TextWrapped() in a tooltip. - settings: write more decent code to allow saving/loading new fields - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file ! style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost. @@ -10099,12 +10100,12 @@ void ImGui::ShowUserGuide() if (g.IO.FontAllowUserScaling) ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); - ImGui::BulletText("CTRL+Click on a slider to input text."); + ImGui::BulletText("CTRL+Click on a slider or drag box to input text."); ImGui::BulletText( "While editing text:\n" "- Hold SHIFT or use mouse to select text\n" "- CTRL+Left/Right to word jump\n" - "- CTRL+A select all\n" + "- CTRL+A or double-click to select all\n" "- CTRL+X,CTRL+C,CTRL+V clipboard\n" "- CTRL+Z,CTRL+Y undo/redo\n" "- ESCAPE to revert\n" @@ -10351,6 +10352,7 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::TreeNode("Logging")) { + ImGui::TextWrapped("The logging API redirects all text output of ImGui so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded. You can also call ImGui::LogText() to output directly to the log without a visual output."); ImGui::LogButtons(); ImGui::TreePop(); } @@ -10387,8 +10389,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::BulletText("Bullet point 1"); ImGui::BulletText("Bullet point 2\nOn multiple lines"); ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); - ImGui::Bullet(); ImGui::SmallButton("Button 1"); - ImGui::Bullet(); ImGui::SmallButton("Button 2"); + ImGui::Bullet(); ImGui::SmallButton("Button"); ImGui::TreePop(); } @@ -10404,7 +10405,7 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::TreeNode("Word Wrapping")) { // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. - ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules that works for English and possibly other languages."); + ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages."); ImGui::Spacing(); static float wrap_width = 200.0f; @@ -10449,7 +10450,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text if it won't fit in its frame."); ImGui::SliderFloat2("size", (float*)&size, 5.0f, 200.0f); ImGui::Button("Line 1 hello\nLine 2 clip me!", size); - ImGui::TextWrapped("Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and rendering cost."); + ImGui::TextWrapped("Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost."); ImGui::TreePop(); } @@ -10533,6 +10534,8 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::TreeNode("Popup, Menus")) { + ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it."); + static int selected_fish = -1; const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; static bool toggles[] = { true, false, false, false, false }; @@ -10667,7 +10670,11 @@ void ImGui::ShowTestWindow(bool* opened) static int i0=123; static float f0=0.001f; ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); + ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Hold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n"); + ImGui::InputInt("input int", &i0); + ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; @@ -10678,10 +10685,7 @@ void ImGui::ShowTestWindow(bool* opened) static int i1=50; static int i2=42; ImGui::DragInt("drag int", &i1, 1); - ImGui::SameLine(); - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input text"); + ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input text."); ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%"); @@ -10694,7 +10698,9 @@ void ImGui::ShowTestWindow(bool* opened) { static int i1=0; //static int i2=42; - ImGui::SliderInt("slider int 0..3", &i1, 0, 3); + ImGui::SliderInt("slider int", &i1, 0, 3); + ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("CTRL+click to input value."); + //ImGui::SliderInt("slider int -100..100", &i2, -100, 100); static float f1=0.123f; @@ -10708,6 +10714,8 @@ void ImGui::ShowTestWindow(bool* opened) static float col1[3] = { 1.0f,0.0f,0.2f }; static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; ImGui::ColorEdit3("color 1", col1); + ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Click on the colored square to change edit mode. CTRL+click on individual component to input value.\n"); + ImGui::ColorEdit4("color 2", col2); const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; @@ -11286,7 +11294,7 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::TreeNode("Mouse cursors")) { - ImGui::TextWrapped("(Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. You can also set io.MouseDrawCursor to ask ImGui to render the cursor for you in software)"); + ImGui::TextWrapped("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. You can also set io.MouseDrawCursor to ask ImGui to render the cursor for you in software."); ImGui::Checkbox("io.MouseDrawCursor", &ImGui::GetIO().MouseDrawCursor); ImGui::Text("Hover to see mouse cursors:"); for (int i = 0; i < ImGuiMouseCursor_Count_; i++) diff --git a/imgui.h b/imgui.h index 7be8a99e..f2d62c6c 100644 --- a/imgui.h +++ b/imgui.h @@ -217,7 +217,7 @@ namespace ImGui IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args); IMGUI_API void TextDisabled(const char* fmt, ...); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); IMGUI_API void TextDisabledV(const char* fmt, va_list args); - IMGUI_API void TextWrapped(const char* fmt, ...); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos(); + IMGUI_API void TextWrapped(const char* fmt, ...); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). IMGUI_API void TextWrappedV(const char* fmt, va_list args); IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, recommended for long chunks of text IMGUI_API void LabelText(const char* label, const char* fmt, ...); // display text+label aligned the same way as value+label widgets From 7b8b5754bc7f53ba3cfccb167e2e8c08fa94d0b0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 22:13:07 +0100 Subject: [PATCH 068/127] EndGroup() carries on the text base offset from the last line of the group (sort of incorrect but better than nothing) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 489dcb8c..fda0051a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8056,12 +8056,13 @@ void ImGui::EndGroup() window->DC.CursorPos = group_data.BackupCursorPos; window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; - window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; // FIXME: Ideally we'll grab the base offset from the first line of the group. + window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; window->DC.ColumnsStartX = group_data.BackupColumnsStartX; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; if (group_data.AdvanceCursor) { + window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset); ItemAdd(group_bb, NULL); } From 843219daeca79cfb7faf72c7fae7b3809549131f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 May 2015 22:14:07 +0100 Subject: [PATCH 069/127] Spacing + untabify --- imgui.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fda0051a..671900cf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3125,10 +3125,10 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_ShowBorders|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; char name[32]; - if (flags & ImGuiWindowFlags_ChildMenu) - ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.size()); // Recycle windows based on depth - else - ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame + if (flags & ImGuiWindowFlags_ChildMenu) + ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.size()); // Recycle windows based on depth + else + ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame float alpha = 1.0f; bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), alpha, flags); @@ -6633,7 +6633,6 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, value_changed = true; } } - ImGui::PopID(); if (label_size.x > 0) @@ -6642,7 +6641,6 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label); ItemSize(label_size, style.FramePadding.y); } - ImGui::EndGroup(); return value_changed; @@ -7615,7 +7613,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) ImVec2 popup_pos, pos = window->DC.CursorPos; if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { - popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y - style.FramePadding.y + window->MenuBarHeight()); + popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y - style.FramePadding.y + window->MenuBarHeight()); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; @@ -10741,6 +10739,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::InputInt2("input int2", vec4i); ImGui::SliderInt2("slider int2", vec4i, 0, 255); + ImGui::Spacing(); ImGui::InputFloat3("input float3", vec4f); ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); @@ -10748,6 +10747,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::InputInt3("input int3", vec4i); ImGui::SliderInt3("slider int3", vec4i, 0, 255); + ImGui::Spacing(); ImGui::InputFloat4("input float4", vec4f); ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); From b8ee48a74bd120e5ef6e0fe1f234d4b19a66a9d9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 09:18:04 +0100 Subject: [PATCH 070/127] OpenPopup() Comments --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index f2d62c6c..e7bc298f 100644 --- a/imgui.h +++ b/imgui.h @@ -165,7 +165,7 @@ namespace ImGui IMGUI_API void EndTooltip(); // Popup - IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. close childs popups if any. will close popup when user click outside, or activate menu items, or CloseCurrentPopup() is called within a BeginPopup/EndPopup block. + IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). close childs popups if any. will close popup when user click outside, or activate a pressable item, 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 CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. From e6ac9e88aadec6a02c75d6eb42b0bdbb3595cf08 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 09:22:30 +0100 Subject: [PATCH 071/127] Refactor Button() and SmallButton() into a shared function ButtonEx() --- imgui.cpp | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 671900cf..aca72005 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4864,16 +4864,16 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool return pressed; } -bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_held) +static bool ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; + ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : (label_size.x + style.FramePadding.x*2), size_arg.y != 0.0f ? size_arg.y : (label_size.y + style.FramePadding.y*2)); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); @@ -4882,45 +4882,35 @@ bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_h return false; bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, repeat_when_held ? ImGuiButtonFlags_Repeat : 0); + bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, flags); // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); const ImVec2 off = ImVec2(ImMax(0.0f, size.x - label_size.x) * 0.5f, ImMax(0.0f, size.y - label_size.y) * 0.5f); // Center (only applies if we explicitly gave a size bigger than the text size, which isn't the common path) - RenderTextClipped(bb.Min + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't the commmon path) + RenderTextClipped(bb.Min + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't common) return pressed; } -// Small buttons fits within text without additional spacing. +bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_held) +{ + return ButtonEx(label, size_arg, repeat_when_held ? ImGuiButtonFlags_Repeat : 0); +} + +// Small buttons fits within text without additional vertical spacing. bool ImGui::SmallButton(const char* label) { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); - const ImVec2 label_size = CalcTextSize(label, NULL, true); - - ImVec2 text_pos = window->DC.CursorPos; - text_pos.y += window->DC.CurrentLineTextBaseOffset; - ImRect bb(text_pos, text_pos + label_size + ImVec2(style.FramePadding.x*2,0)); - ItemSize(bb); - if (!ItemAdd(bb, &id)) - return false; - - bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held, true); - - // Render - const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); - RenderFrame(bb.Min, bb.Max, col); - RenderText(bb.Min + ImVec2(style.FramePadding.x,0), label); - + ImGuiState& g = *GImGui; + float backup_padding_y = g.Style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + bool pressed = ButtonEx(label, ImVec2(0,0), 0); + g.Style.FramePadding.y = backup_padding_y; return pressed; } From f26de4635066950da80a174f276b668d4cb336a2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 09:28:44 +0100 Subject: [PATCH 072/127] Button() closes active popup (#126) unsure about that --- imgui.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index aca72005..4e322040 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -963,10 +963,11 @@ enum ImGuiLayoutType_ enum ImGuiButtonFlags_ { - ImGuiButtonFlags_Repeat = (1 << 0), - ImGuiButtonFlags_PressedOnClick = (1 << 1), - ImGuiButtonFlags_FlattenChilds = (1 << 2), - ImGuiButtonFlags_Disabled = (1 << 3) + ImGuiButtonFlags_Repeat = (1 << 0), + ImGuiButtonFlags_PressedOnClick = (1 << 1), + ImGuiButtonFlags_FlattenChilds = (1 << 2), + ImGuiButtonFlags_DontClosePopups = (1 << 3), + ImGuiButtonFlags_Disabled = (1 << 4) }; enum ImGuiSelectableFlags_ @@ -4891,6 +4892,10 @@ static bool ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags const ImVec2 off = ImVec2(ImMax(0.0f, size.x - label_size.x) * 0.5f, ImMax(0.0f, size.y - label_size.y) * 0.5f); // Center (only applies if we explicitly gave a size bigger than the text size, which isn't the common path) RenderTextClipped(bb.Min + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't common) + // Automatically close popups + if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + ImGui::CloseCurrentPopup(); + return pressed; } @@ -6611,13 +6616,13 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, { ImGui::PopItemWidth(); ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - if (ImGui::Button("-", button_sz, true)) + if (ButtonEx("-", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { *v -= g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; value_changed = true; } ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - if (ImGui::Button("+", button_sz, true)) + if (ButtonEx("+", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { *v += g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; value_changed = true; @@ -7834,7 +7839,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) { ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); const char* button_titles[3] = { "RGB", "HSV", "HEX" }; - if (ImGui::Button(button_titles[edit_mode])) + if (ButtonEx(button_titles[edit_mode], ImVec2(0,0), ImGuiButtonFlags_DontClosePopups)) g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! ImGui::SameLine(); } @@ -11432,6 +11437,8 @@ static void ShowExampleMenuFile() ImGui::EndChild(); static float f = 0.5f; ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); + ImGui::InputFloat("Input", &f, 0.1f); + ImGui::Button("Button"); ImGui::EndMenu(); } if (ImGui::BeginMenu("Colors")) From f841097e992c78d790aed77dd1a07902650f9aad Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 14:20:50 +0100 Subject: [PATCH 073/127] Button centering left to RenderTextClipped function. --- imgui.cpp | 5 ++--- imgui.h | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4e322040..3cc63371 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2643,6 +2643,7 @@ static void RenderTextClipped(ImVec2 pos, const char* text, const char* text_end // Align if (align & ImGuiAlign_Center) pos.x = ImMax(pos.x, (pos.x + pos_max.x - text_size.x) * 0.5f); else if (align & ImGuiAlign_Right) pos.x = ImMax(pos.x, pos_max.x - text_size.x); + if (align & ImGuiAlign_VCenter) pos.y = ImMax(pos.y, (pos.y + pos_max.y - text_size.y) * 0.5f); // Render window->DrawList->AddText(g.Font, g.FontSize, pos, window->Color(ImGuiCol_Text), text, text_display_end, 0.0f, need_clipping ? clip_max : NULL); @@ -4888,9 +4889,7 @@ static bool ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - - const ImVec2 off = ImVec2(ImMax(0.0f, size.x - label_size.x) * 0.5f, ImMax(0.0f, size.y - label_size.y) * 0.5f); // Center (only applies if we explicitly gave a size bigger than the text size, which isn't the common path) - RenderTextClipped(bb.Min + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't common) + RenderTextClipped(bb.Min, label, NULL, &label_size, bb.Max, NULL, ImGuiAlign_Center | ImGuiAlign_VCenter); // Automatically close popups if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) diff --git a/imgui.h b/imgui.h index e7bc298f..79fd4597 100644 --- a/imgui.h +++ b/imgui.h @@ -522,7 +522,9 @@ enum ImGuiAlign_ ImGuiAlign_Left = 1 << 0, ImGuiAlign_Center = 1 << 1, ImGuiAlign_Right = 1 << 2, - ImGuiAlign_Default = ImGuiAlign_Left, + ImGuiAlign_Top = 1 << 3, + ImGuiAlign_VCenter = 1 << 4, + ImGuiAlign_Default = ImGuiAlign_Left | ImGuiAlign_Top, }; // Enumeration for ColorEditMode() From 3c264827fd31ba88ee485209df128c7dd8a01449 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 14:24:52 +0100 Subject: [PATCH 074/127] Reordering parameters of internal RenderTextClipped() --- imgui.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3cc63371..a3f93373 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -511,7 +511,7 @@ static void LogText(const ImVec2& ref_pos, const char* text, const char* static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); static void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); -static void RenderTextClipped(ImVec2 pos, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& pos_max, const ImVec2* clip_max = NULL, ImGuiAlign align = ImGuiAlign_Default); +static void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2* clip_max = NULL, ImGuiAlign align = ImGuiAlign_Default); static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); static void RenderCheckMark(ImVec2 pos, ImU32 col); @@ -2624,7 +2624,7 @@ static void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end } } -static void RenderTextClipped(ImVec2 pos, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& pos_max, const ImVec2* clip_max, ImGuiAlign align) +static void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2* clip_max, ImGuiAlign align) { // Hide anything after a '##' string const char* text_display_end = FindTextDisplayEnd(text, text_end); @@ -2636,6 +2636,7 @@ static void RenderTextClipped(ImVec2 pos, const char* text, const char* text_end ImGuiWindow* window = GetCurrentWindow(); // Perform CPU side clipping for single clipped element to avoid using scissor state + ImVec2 pos = pos_min; const ImVec2 text_size = text_size_if_known ? *text_size_if_known : ImGui::CalcTextSize(text, text_display_end, false, 0.0f); if (!clip_max) clip_max = &pos_max; const bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); @@ -3817,7 +3818,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left; if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x; - RenderTextClipped(text_min, name, NULL, &text_size, text_max, &clip_max, style.WindowTitleAlign); + RenderTextClipped(text_min, text_max, name, NULL, &text_size, &clip_max, style.WindowTitleAlign); } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() @@ -4767,7 +4768,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) return; // Render - RenderTextClipped(ImVec2(value_bb.Min.x, value_bb.Min.y + style.FramePadding.y), value_text_begin, value_text_end, NULL, value_bb.Max); + RenderTextClipped(ImVec2(value_bb.Min.x, value_bb.Min.y + style.FramePadding.y), value_bb.Max, value_text_begin, value_text_end, NULL); RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } @@ -4889,7 +4890,7 @@ static bool ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderTextClipped(bb.Min, label, NULL, &label_size, bb.Max, NULL, ImGuiAlign_Center | ImGuiAlign_VCenter); + RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, NULL, ImGuiAlign_Center | ImGuiAlign_VCenter); // Automatically close popups if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) @@ -5742,7 +5743,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, frame_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); + RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, frame_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, &value_text_size); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -5791,7 +5792,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float char value_buf[64]; char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x, frame_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); + RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x, frame_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, &value_text_size); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6047,7 +6048,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, f char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); + RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, &value_text_size); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); @@ -6247,7 +6248,7 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // Text overlay if (overlay_text) - RenderTextClipped(ImVec2(ImMax(inner_bb.Min.x, inner_bb.GetCenter().x - ImGui::CalcTextSize(overlay_text, NULL, true).x*0.5f), frame_bb.Min.y + style.FramePadding.y), overlay_text, NULL, NULL, frame_bb.Max); + RenderTextClipped(ImVec2(ImMax(inner_bb.Min.x, inner_bb.GetCenter().x - ImGui::CalcTextSize(overlay_text, NULL, true).x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); } @@ -7243,7 +7244,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi { const char* item_text; if (items_getter(data, *current_item, &item_text)) - RenderTextClipped(frame_bb.Min + style.FramePadding, item_text, NULL, NULL, value_bb.Max); + RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, item_text, NULL, NULL); } if (label_size.x > 0) @@ -7364,7 +7365,7 @@ static bool SelectableEx(const char* label, bool selected, const ImVec2& size_ar RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, style.FrameRounding); } if (flags & ImGuiSelectableFlags_Disabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); - RenderTextClipped(bb.Min, label, NULL, &label_size, bb_with_spacing.Max); + RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size); if (flags & ImGuiSelectableFlags_Disabled) ImGui::PopStyleColor(); // Automatically close popups From 904e187f70e82d1a758ec6c14e7d1ed79a85bdc7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 14:39:41 +0100 Subject: [PATCH 075/127] Simplified some widget code, moving alignment to RenderTextClipped() --- imgui.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a3f93373..2e56ad7e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2636,9 +2636,9 @@ static void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons ImGuiWindow* window = GetCurrentWindow(); // Perform CPU side clipping for single clipped element to avoid using scissor state + if (!clip_max) clip_max = &pos_max; ImVec2 pos = pos_min; const ImVec2 text_size = text_size_if_known ? *text_size_if_known : ImGui::CalcTextSize(text, text_display_end, false, 0.0f); - if (!clip_max) clip_max = &pos_max; const bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); // Align @@ -4757,9 +4757,6 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) const ImGuiStyle& style = g.Style; const float w = ImGui::CalcItemWidth(); - const char* value_text_begin = &g.TempBuffer[0]; - const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2, label_size.y + style.FramePadding.y*2)); const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2 + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size); @@ -4768,7 +4765,9 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) return; // Render - RenderTextClipped(ImVec2(value_bb.Min.x, value_bb.Min.y + style.FramePadding.y), value_bb.Max, value_text_begin, value_text_end, NULL); + const char* value_text_begin = &g.TempBuffer[0]; + const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, NULL, ImGuiAlign_VCenter); RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } @@ -5742,8 +5741,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, frame_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, &value_text_size); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -5791,8 +5789,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float // For the vertical slider we allow centered text to overlap the frame padding char value_buf[64]; char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x, frame_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, &value_text_size); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, NULL, ImGuiAlign_Center); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6047,8 +6044,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, f // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, &value_text_size); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); @@ -6248,7 +6244,7 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // Text overlay if (overlay_text) - RenderTextClipped(ImVec2(ImMax(inner_bb.Min.x, inner_bb.GetCenter().x - ImGui::CalcTextSize(overlay_text, NULL, true).x*0.5f), frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, NULL, ImGuiAlign_Center); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); } From d69f2f57eed1c3d7fc10b030ad3c5e126ca6f64d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 15:17:44 +0100 Subject: [PATCH 076/127] Added configurable io.KeyRepeatDelay, io.KeyRepeatRate --- imgui.cpp | 22 ++++++++++++---------- imgui.h | 2 ++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2e56ad7e..15907308 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -653,6 +653,8 @@ ImGuiIO::ImGuiIO() MouseDoubleClickTime = 0.30f; MouseDoubleClickMaxDist = 6.0f; MouseDragThreshold = 6.0f; + KeyRepeatDelay = 0.250f; + KeyRepeatRate = 0.020f; UserData = NULL; // User functions @@ -2864,12 +2866,12 @@ bool ImGui::IsKeyPressed(int key_index, bool repeat) if (t == 0.0f) return true; - // FIXME: Repeat rate should be provided elsewhere? - const float KEY_REPEAT_DELAY = 0.250f; - const float KEY_REPEAT_RATE = 0.020f; - if (repeat && t > KEY_REPEAT_DELAY) - if ((fmodf(t - KEY_REPEAT_DELAY, KEY_REPEAT_RATE) > KEY_REPEAT_RATE*0.5f) != (fmodf(t - KEY_REPEAT_DELAY - g.IO.DeltaTime, KEY_REPEAT_RATE) > KEY_REPEAT_RATE*0.5f)) + if (repeat && t > g.IO.KeyRepeatDelay) + { + float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate; + if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f)) return true; + } return false; } @@ -2889,12 +2891,12 @@ bool ImGui::IsMouseClicked(int button, bool repeat) if (t == 0.0f) return true; - // FIXME: Repeat rate should be provided elsewhere? - const float MOUSE_REPEAT_DELAY = 0.250f; - const float MOUSE_REPEAT_RATE = 0.020f; - if (repeat && t > MOUSE_REPEAT_DELAY) - if ((fmodf(t - MOUSE_REPEAT_DELAY, MOUSE_REPEAT_RATE) > MOUSE_REPEAT_RATE*0.5f) != (fmodf(t - MOUSE_REPEAT_DELAY - g.IO.DeltaTime, MOUSE_REPEAT_RATE) > MOUSE_REPEAT_RATE*0.5f)) + if (repeat && t > g.IO.KeyRepeatDelay) + { + float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate; + if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f)) return true; + } return false; } diff --git a/imgui.h b/imgui.h index 79fd4597..c3071368 100644 --- a/imgui.h +++ b/imgui.h @@ -603,6 +603,8 @@ struct ImGuiIO float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array + float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds. (for actions where 'repeat' is active) + float KeyRepeatRate; // = 0.020f // When holding a key/button, rate at which it repeats, in seconds. void* UserData; // = NULL // Store your own data for retrieval by callbacks. ImFontAtlas* Fonts; // // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array. From 3d36c81241d66526c345a6795da12a77adc908dc Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 15:22:09 +0100 Subject: [PATCH 077/127] Added PushButtonRepeat() / PopButtonRepeat(). REMOVED third 'repeat_if_held' parameter of Button() ! --- imgui.cpp | 37 +++++++++++++++++++++++++++---------- imgui.h | 4 +++- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 15907308..01c7db7a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -136,6 +136,7 @@ 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. + - 2015/05/27 (1.39) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. - 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. BeginPopup() returns true if the popup is opened. - 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). @@ -1104,13 +1105,16 @@ struct ImGuiDrawContext bool MenuBarAppending; float MenuBarOffsetX; ImVector ChildWindows; + ImGuiStorage* StateStorage; ImGuiLayoutType LayoutType; + + bool ButtonRepeat; // == ButtonRepeatStack.back() [false] + ImVector ButtonRepeatStack; ImVector AllowKeyboardFocus; ImVector ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window ImVector TextWrapPos; ImVector GroupStack; ImGuiColorEditMode ColorEditMode; - ImGuiStorage* StateStorage; int StackSizesBackup[6]; // Store size of various stacks for asserting float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) @@ -1136,9 +1140,9 @@ struct ImGuiDrawContext LastItemHoveredAndUsable = LastItemHoveredRect = false; MenuBarAppending = false; MenuBarOffsetX = 0.0f; + StateStorage = NULL; LayoutType = ImGuiLayoutType_Vertical; ColorEditMode = ImGuiColorEditMode_RGB; - StateStorage = NULL; memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); ColumnsStartX = 0.0f; @@ -3785,6 +3789,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DC.ItemWidth.resize(0); window->DC.ItemWidth.push_back(window->ItemWidthDefault); window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.ButtonRepeat = false; + window->DC.ButtonRepeatStack.resize(0); window->DC.AllowKeyboardFocus.resize(0); window->DC.AllowKeyboardFocus.push_back(true); window->DC.TextWrapPos.resize(0); @@ -4076,6 +4082,20 @@ void ImGui::PopAllowKeyboardFocus() window->DC.AllowKeyboardFocus.pop_back(); } +void ImGui::PushButtonRepeat(bool repeat) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ButtonRepeat = repeat; + window->DC.ButtonRepeatStack.push_back(repeat); +} + +void ImGui::PopButtonRepeat() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ButtonRepeatStack.pop_back(); + window->DC.ButtonRepeat = window->DC.ButtonRepeatStack.empty() ? false : window->DC.ButtonRepeatStack.back(); +} + void ImGui::PushTextWrapPos(float wrap_x) { ImGuiWindow* window = GetCurrentWindow(); @@ -4868,7 +4888,7 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool return pressed; } -static bool ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) +static bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -4885,6 +4905,7 @@ static bool ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags if (!ItemAdd(bb, &id)) return false; + if (window->DC.ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, flags); @@ -4900,22 +4921,18 @@ static bool ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags return pressed; } -bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_held) +bool ImGui::Button(const char* label, const ImVec2& size_arg) { - return ButtonEx(label, size_arg, repeat_when_held ? ImGuiButtonFlags_Repeat : 0); + return ButtonEx(label, size_arg, 0); } // Small buttons fits within text without additional vertical spacing. bool ImGui::SmallButton(const char* label) { - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; - ImGuiState& g = *GImGui; float backup_padding_y = g.Style.FramePadding.y; g.Style.FramePadding.y = 0.0f; - bool pressed = ButtonEx(label, ImVec2(0,0), 0); + bool pressed = ButtonEx(label); g.Style.FramePadding.y = backup_padding_y; return pressed; } diff --git a/imgui.h b/imgui.h index c3071368..0522b0c7 100644 --- a/imgui.h +++ b/imgui.h @@ -157,6 +157,8 @@ namespace ImGui IMGUI_API void PopAllowKeyboardFocus(); IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space IMGUI_API void PopTextWrapPos(); + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return true multiple times as you hold them (uses io.KeyRepeatDelay/io.KeyRepeatRate for now) + IMGUI_API void PopButtonRepeat(); // Tooltip IMGUI_API void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins @@ -225,7 +227,7 @@ namespace ImGui IMGUI_API void Bullet(); IMGUI_API void BulletText(const char* fmt, ...); IMGUI_API void BulletTextV(const char* fmt, va_list args); - IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0), bool repeat_when_held = false); + IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); IMGUI_API bool SmallButton(const char* label); IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); From 0a7024c198f3bd02ba8da1385977856b50d2efe9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 15:35:49 +0100 Subject: [PATCH 078/127] Store common stacked settings contiguously in memory to reduce cache misses & unnecessary heap allocations --- imgui.cpp | 70 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 01c7db7a..b7abfb11 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1091,7 +1091,7 @@ struct ImGuiDrawContext ImVec2 CursorPos; ImVec2 CursorPosPrevLine; ImVec2 CursorStartPos; - ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame + ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame float CurrentLineHeight; float CurrentLineTextBaseOffset; float PrevLineHeight; @@ -1108,17 +1108,21 @@ struct ImGuiDrawContext ImGuiStorage* StateStorage; ImGuiLayoutType LayoutType; - bool ButtonRepeat; // == ButtonRepeatStack.back() [false] + // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. + bool ButtonRepeat; // == ButtonRepeatStack.back() [empty == false] + bool AllowKeyboardFocus; // == AllowKeyboardFocusStack.back() [empty == true] + float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window + float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] ImVector ButtonRepeatStack; - ImVector AllowKeyboardFocus; - ImVector ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window - ImVector TextWrapPos; - ImVector GroupStack; + ImVector AllowKeyboardFocusStack; + ImVector ItemWidthStack; + ImVector TextWrapPosStack; + ImVectorGroupStack; ImGuiColorEditMode ColorEditMode; - int StackSizesBackup[6]; // Store size of various stacks for asserting + 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. + 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. int ColumnsCurrent; int ColumnsCount; ImVec2 ColumnsStartPos; @@ -1126,7 +1130,7 @@ struct ImGuiDrawContext float ColumnsCellMaxY; bool ColumnsShowBorders; ImGuiID ColumnsSetID; - ImVector ColumnsOffsetsT; // Columns offset normalized 0.0 (far left) -> 1.0 (far right) + ImVector ColumnsOffsetsT; // Columns offset normalized 0.0 (far left) -> 1.0 (far right) ImGuiDrawContext() { @@ -1801,7 +1805,7 @@ bool ImGuiWindow::FocusItemRegister(bool is_active, bool tab_stop) ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus.back(); + const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus; FocusIdxAllCounter++; if (allow_keyboard_focus) FocusIdxTabCounter++; @@ -3256,7 +3260,7 @@ void ImGui::EndChildFrame() // Save and compare stack sizes on Begin()/End() to detect usage errors static void CheckStacksSize(ImGuiWindow* window, bool write) { - // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) ImGuiState& g = *GImGui; 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() @@ -3786,15 +3790,16 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DC.MenuBarOffsetX = ImMax(window->DC.ColumnsStartX, style.ItemSpacing.x); window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); - window->DC.ItemWidth.resize(0); - window->DC.ItemWidth.push_back(window->ItemWidthDefault); window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.ItemWidthStack.resize(0); + window->DC.ItemWidthStack.push_back(window->ItemWidthDefault); + window->DC.ItemWidth = window->ItemWidthDefault; window->DC.ButtonRepeat = false; window->DC.ButtonRepeatStack.resize(0); - window->DC.AllowKeyboardFocus.resize(0); - window->DC.AllowKeyboardFocus.push_back(true); - window->DC.TextWrapPos.resize(0); - window->DC.TextWrapPos.push_back(-1.0f); // disabled + window->DC.AllowKeyboardFocus = true; + window->DC.AllowKeyboardFocusStack.resize(0); + window->DC.TextWrapPos = -1.0f; // disabled + window->DC.TextWrapPosStack.resize(0); window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect; window->DC.ColumnsCurrent = 0; window->DC.ColumnsCount = 1; @@ -4004,7 +4009,8 @@ static void FocusWindow(ImGuiWindow* window) void ImGui::PushItemWidth(float item_width) { ImGuiWindow* window = GetCurrentWindow(); - window->DC.ItemWidth.push_back(item_width == 0.0f ? window->ItemWidthDefault : item_width); + window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); } static void PushMultiItemsWidths(int components, float w_full = 0.0f) @@ -4015,21 +4021,23 @@ static void PushMultiItemsWidths(int components, float w_full = 0.0f) w_full = ImGui::CalcItemWidth(); const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)) / (float)components)); const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1))); - window->DC.ItemWidth.push_back(w_item_last); + window->DC.ItemWidthStack.push_back(w_item_last); for (int i = 0; i < components-1; i++) - window->DC.ItemWidth.push_back(w_item_one); + window->DC.ItemWidthStack.push_back(w_item_one); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); } void ImGui::PopItemWidth() { ImGuiWindow* window = GetCurrentWindow(); - window->DC.ItemWidth.pop_back(); + window->DC.ItemWidthStack.pop_back(); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); } float ImGui::CalcItemWidth() { ImGuiWindow* window = GetCurrentWindow(); - float w = window->DC.ItemWidth.back(); + float w = window->DC.ItemWidth; if (w < 0.0f) { // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well. @@ -4073,13 +4081,15 @@ void ImGui::PopFont() void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) { ImGuiWindow* window = GetCurrentWindow(); - window->DC.AllowKeyboardFocus.push_back(allow_keyboard_focus); + window->DC.AllowKeyboardFocus = allow_keyboard_focus; + window->DC.AllowKeyboardFocusStack.push_back(allow_keyboard_focus); } void ImGui::PopAllowKeyboardFocus() { ImGuiWindow* window = GetCurrentWindow(); - window->DC.AllowKeyboardFocus.pop_back(); + window->DC.AllowKeyboardFocusStack.pop_back(); + window->DC.AllowKeyboardFocus = window->DC.AllowKeyboardFocusStack.empty() ? true : window->DC.AllowKeyboardFocusStack.back(); } void ImGui::PushButtonRepeat(bool repeat) @@ -4096,16 +4106,18 @@ void ImGui::PopButtonRepeat() window->DC.ButtonRepeat = window->DC.ButtonRepeatStack.empty() ? false : window->DC.ButtonRepeatStack.back(); } -void ImGui::PushTextWrapPos(float wrap_x) +void ImGui::PushTextWrapPos(float wrap_pos_x) { ImGuiWindow* window = GetCurrentWindow(); - window->DC.TextWrapPos.push_back(wrap_x); + window->DC.TextWrapPos = wrap_pos_x; + window->DC.TextWrapPosStack.push_back(wrap_pos_x); } void ImGui::PopTextWrapPos() { ImGuiWindow* window = GetCurrentWindow(); - window->DC.TextWrapPos.pop_back(); + window->DC.TextWrapPosStack.pop_back(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); } void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) @@ -4661,7 +4673,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) if (text_end == NULL) text_end = text + strlen(text); // FIXME-OPT - const float wrap_pos_x = window->DC.TextWrapPos.back(); + const float wrap_pos_x = window->DC.TextWrapPos; const bool wrap_enabled = wrap_pos_x >= 0.0f; if (text_end - text > 2000 && !wrap_enabled) { From 405785ea62b20929e76a01b7f7443d6bb48a6960 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 15:42:29 +0100 Subject: [PATCH 079/127] ItemWidthStack can be empty, to remove one allocation per window --- imgui.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b7abfb11..93960eec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3791,9 +3791,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); window->DC.LayoutType = ImGuiLayoutType_Vertical; - window->DC.ItemWidthStack.resize(0); - window->DC.ItemWidthStack.push_back(window->ItemWidthDefault); window->DC.ItemWidth = window->ItemWidthDefault; + window->DC.ItemWidthStack.resize(0); window->DC.ButtonRepeat = false; window->DC.ButtonRepeatStack.resize(0); window->DC.AllowKeyboardFocus = true; @@ -4031,7 +4030,7 @@ void ImGui::PopItemWidth() { ImGuiWindow* window = GetCurrentWindow(); window->DC.ItemWidthStack.pop_back(); - window->DC.ItemWidth = window->DC.ItemWidthStack.back(); + window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); } float ImGui::CalcItemWidth() From d05c1d58c3a84fd9a614c3adfa64bcae4241ca74 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 15:44:07 +0100 Subject: [PATCH 080/127] Oops --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 93960eec..d595cf8f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4116,7 +4116,7 @@ void ImGui::PopTextWrapPos() { ImGuiWindow* window = GetCurrentWindow(); window->DC.TextWrapPosStack.pop_back(); - window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); } void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) From 7d28fe59156dc9fd8e1ee2dc6bbae0be4e7ef9bb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 15:51:50 +0100 Subject: [PATCH 081/127] WIP Menus: Reverted f26de4635066950da80a174f276b668d4cb336a2 for now (#126) --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d595cf8f..a6101fb0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -357,7 +357,8 @@ - combo/listbox: keyboard control. need inputtext like non-active focus + key handling. considering keybord for custom listbox (see github pr #203) - listbox: multiple selection - listbox: user may want to initial scroll to focus on the one selected value? - ! menubar, menus (github issue #126) + - menus: local shortcuts, global shortcuts + - menus: icons - tabs - gauge: various forms of gauge/loading bars widgets - color: better color editor. @@ -4926,8 +4927,8 @@ static bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), Im RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, NULL, ImGuiAlign_Center | ImGuiAlign_VCenter); // Automatically close popups - if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) - ImGui::CloseCurrentPopup(); + //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + // ImGui::CloseCurrentPopup(); return pressed; } @@ -11464,7 +11465,6 @@ static void ShowExampleMenuFile() static float f = 0.5f; ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); ImGui::InputFloat("Input", &f, 0.1f); - ImGui::Button("Button"); ImGui::EndMenu(); } if (ImGui::BeginMenu("Colors")) From 487500d291ec9cea1fa322a00e7c81521a807063 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 16:03:44 +0100 Subject: [PATCH 082/127] Tweaks --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a6101fb0..788e01ca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -357,7 +357,7 @@ - combo/listbox: keyboard control. need inputtext like non-active focus + key handling. considering keybord for custom listbox (see github pr #203) - listbox: multiple selection - listbox: user may want to initial scroll to focus on the one selected value? - - menus: local shortcuts, global shortcuts + - menus: local shortcuts, global shortcuts (github issue #126) - menus: icons - tabs - gauge: various forms of gauge/loading bars widgets @@ -11477,6 +11477,7 @@ static void ShowExampleMenuFile() { IM_ASSERT(0); } + if (ImGui::MenuItem("Checked", NULL, true)) {} if (ImGui::MenuItem("Quit", "Alt+F4")) {} } From 90db64d4e3a434a2796844827e09dc5aea9f1d34 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 21:39:41 +0100 Subject: [PATCH 083/127] Added context menu example on a DragFloat widget --- imgui.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 788e01ca..039bf1ce 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10609,12 +10609,25 @@ void ImGui::ShowTestWindow(bool* opened) } if (ImGui::Button("Popup Menu..")) - ImGui::OpenPopup("context menu"); - if (ImGui::BeginPopup("context menu")) + ImGui::OpenPopup("popup from button"); + if (ImGui::BeginPopup("popup from button")) { ShowExampleMenuFile(); ImGui::EndPopup(); } + + static float value = 0.5f; + ImGui::PushItemWidth(100); ImGui::DragFloat("Context Menu", &value); ImGui::PopItemWidth(); + if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1)) + ImGui::OpenPopup("context menu"); + ImGui::SameLine(); ImGui::Text("<-- right-click"); + if (ImGui::BeginPopup("context menu")) + { + if (ImGui::Selectable("Set to zero")) value = 0.0f; + if (ImGui::Selectable("Set to PI")) value = PI; + ImGui::EndPopup(); + } + ImGui::TreePop(); } From 99ff45ad2e33d44934ddbda1a9a7da44d1a18b11 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 21:42:16 +0100 Subject: [PATCH 084/127] Tweak context menu example --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 039bf1ce..bc86d29a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10617,7 +10617,7 @@ void ImGui::ShowTestWindow(bool* opened) } static float value = 0.5f; - ImGui::PushItemWidth(100); ImGui::DragFloat("Context Menu", &value); ImGui::PopItemWidth(); + ImGui::Text("Value = %.3f", value); if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1)) ImGui::OpenPopup("context menu"); ImGui::SameLine(); ImGui::Text("<-- right-click"); From 70f2ff0e5a8ddd4d53a9ef72f8456f58b6f939b5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 21:59:02 +0100 Subject: [PATCH 085/127] No minimum size for popups --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index bc86d29a..83026cfb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3574,7 +3574,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Minimum window size - if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip))) + if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip))) { window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); if (!window->Collapsed) From 8c4c421f74bc38a8cccf26412f802bb1a7d6c29a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 22:02:12 +0100 Subject: [PATCH 086/127] Added IsAnyItemHovered() public helper. --- imgui.cpp | 8 ++++++-- imgui.h | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 83026cfb..9bbc60cf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2984,10 +2984,14 @@ bool ImGui::IsItemActive() return false; } +bool ImGui::IsAnyItemHovered() +{ + return GImGui->HoveredId != 0 || GImGui->HoveredIdPreviousFrame != 0; +} + bool ImGui::IsAnyItemActive() { - ImGuiState& g = *GImGui; - return g.ActiveId != 0; + return GImGui->ActiveId != 0; } bool ImGui::IsItemVisible() diff --git a/imgui.h b/imgui.h index 0522b0c7..9e280841 100644 --- a/imgui.h +++ b/imgui.h @@ -333,8 +333,9 @@ namespace ImGui IMGUI_API bool IsItemHovered(); // was the last item hovered by mouse? IMGUI_API bool IsItemHoveredRect(); // was the last item hovered by mouse? even if another item is active while we are hovering this IMGUI_API bool IsItemActive(); // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) - IMGUI_API bool IsAnyItemActive(); // IMGUI_API bool IsItemVisible(); + IMGUI_API bool IsAnyItemHovered(); // + IMGUI_API bool IsAnyItemActive(); // IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item in screen space IMGUI_API ImVec2 GetItemRectMax(); // " IMGUI_API ImVec2 GetItemRectSize(); // " From 5b0861768e30b17369bd6db8173251bf6aa015ca Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 22:26:03 +0100 Subject: [PATCH 087/127] Fixed GetId()/BeginPopup() accessing current window in "append" mode --- imgui.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9bbc60cf..b5e5c5e1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3131,7 +3131,7 @@ static void ClearSetNextWindowData() static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = g.CurrentWindow; const ImGuiID id = window->GetID(str_id); if (!IsPopupOpen(id)) { @@ -5454,20 +5454,17 @@ void ImGui::PopID() ImGuiID ImGui::GetID(const char* str_id) { - ImGuiWindow* window = GetCurrentWindow(); - return window->GetID(str_id); + return GImGui->CurrentWindow->GetID(str_id); } ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) { - ImGuiWindow* window = GetCurrentWindow(); - return window->GetID(str_id_begin, str_id_end); + return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end); } ImGuiID ImGui::GetID(const void* ptr_id) { - ImGuiWindow* window = GetCurrentWindow(); - return window->GetID(ptr_id); + return GImGui->CurrentWindow->GetID(ptr_id); } // User can input math operators (e.g. +100) to edit a numerical values. From 938528e5ee851cb3edd4737aa56b969ca4d838a1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 22:36:23 +0100 Subject: [PATCH 088/127] Added BeginPopupContextItem() / BeginPopupContextWindow() (#126) --- imgui.cpp | 20 ++++++++++++++++++++ imgui.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index b5e5c5e1..ea70d592 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3171,6 +3171,21 @@ void ImGui::EndPopup() ImGui::PopStyleVar(); } +bool ImGui::BeginPopupContextItem(const char* str_id, int button) +{ + if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(button)) + ImGui::OpenPopup(str_id); + return ImGui::BeginPopup(str_id); +} + +bool ImGui::BeginPopupContextWindow(const char* str_id, bool void_only, int button) +{ + if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(button)) + if (!void_only || !ImGui::IsAnyItemHovered()) + ImGui::OpenPopup(str_id); + return ImGui::BeginPopup(str_id); +} + bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; @@ -11694,6 +11709,11 @@ struct ExampleAppConsole // NB- if you have thousands of entries this approach may be too inefficient. You can seek and display only the lines that are visible - CalcListClipping() is a helper to compute this information. // If your items are of variable size you may want to implement code similar to what CalcListClipping() does. Or split your data into fixed height items to allow random-seeking into your list. ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetTextLineHeightWithSpacing()*2)); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) ClearLog(); + ImGui::EndPopup(); + } ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing for (size_t i = 0; i < Items.size(); i++) { diff --git a/imgui.h b/imgui.h index 9e280841..0cb0ad5a 100644 --- a/imgui.h +++ b/imgui.h @@ -169,6 +169,8 @@ namespace ImGui // Popup IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). close childs popups if any. will close popup when user click outside, or activate a pressable item, 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 bool BeginPopupContextItem(const char* str_id, int button = 1); // open popup when clicked on last item + IMGUI_API bool BeginPopupContextWindow(const char* str_id = "window_context_menu", bool void_only = false, int button = 1); // open popup when clicked on current window IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. From f8b7d5c76d114dc86366200199d6b48bbfe98316 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 22:53:43 +0100 Subject: [PATCH 089/127] Tracking ActiveIdWindow along with ActiveId --- imgui.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ea70d592..fe182ea2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1250,8 +1250,9 @@ struct ImGuiState ImGuiID ActiveId; // Active widget ImGuiID ActiveIdPreviousFrame; bool ActiveIdIsAlive; - bool ActiveIdIsJustActivated; // Set when - bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction. + bool ActiveIdIsJustActivated; // Set at the time of activation for one frame + bool ActiveIdIsFocusedOnly; // Set only by active widget. Denote focus but no active interaction + ImGuiWindow* ActiveIdWindow; ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window. float SettingsDirtyTimer; ImVector Settings; @@ -1466,12 +1467,13 @@ static inline ImGuiWindow* GetParentWindow() return g.CurrentWindowStack[g.CurrentWindowStack.size() - 2]; } -static void SetActiveId(ImGuiID id) +static void SetActiveId(ImGuiID id, ImGuiWindow* window = NULL) { ImGuiState& g = *GImGui; g.ActiveId = id; g.ActiveIdIsFocusedOnly = false; g.ActiveIdIsJustActivated = true; + g.ActiveIdWindow = window; } static void RegisterAliveId(ImGuiID id) @@ -2379,7 +2381,7 @@ void ImGui::Render() { IM_ASSERT(g.MovedWindow == NULL); g.MovedWindow = g.HoveredWindow; - SetActiveId(g.HoveredRootWindow->MoveID); + SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); } else if (g.FocusedWindow != NULL) { @@ -4887,7 +4889,7 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } else { - SetActiveId(id); + SetActiveId(id, window); } FocusWindow(window); } @@ -5537,7 +5539,7 @@ static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int char text_buf[64]; ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v); - SetActiveId(g.ScalarAsInputTextId); + SetActiveId(g.ScalarAsInputTextId, window); g.HoveredId = 0; // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen) @@ -5767,7 +5769,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id); if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) { - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); const bool is_ctrl_down = g.IO.KeyCtrl; @@ -5825,7 +5827,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float if (hovered && g.IO.MouseClicked[0]) { - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); } @@ -6071,7 +6073,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, f const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id); if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] | g.IO.MouseDoubleClicked[0]))) { - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0]) @@ -6855,16 +6857,14 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (focus_requested_by_tab || (user_clicked && is_ctrl_down)) select_all = true; } - SetActiveId(id); + SetActiveId(id, window); FocusWindow(window); } else if (io.MouseClicked[0]) { // Release focus when we click outside if (g.ActiveId == id) - { SetActiveId(0); - } } // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. From b0a9bbf6f6aaa6ee47d9db0d5290812c3d9efd07 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 22:58:49 +0100 Subject: [PATCH 090/127] Popup taking focus deactivate focused widget of other window (#126) e.g. focus InputText(), open contextual popup, input text used to stay focused --- imgui.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index fe182ea2..56242512 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4015,6 +4015,11 @@ static void FocusWindow(ImGuiWindow* window) if (window->RootWindow) window = window->RootWindow; + // Steal focus on active widgets + if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) + SetActiveId(0); + if (g.Windows.back() == window) return; @@ -6786,11 +6791,11 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // Edit a string of text bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; + ImGuiState& g = *GImGui; const ImGuiIO& io = g.IO; const ImGuiStyle& style = g.Style; From 1cb6a294b0cda721121a4cf3e3242241427d015c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 23:07:24 +0100 Subject: [PATCH 091/127] BeginPopupContextWindow() rearranged and clarified parameters (#126) --- imgui.cpp | 5 +++-- imgui.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 56242512..96920a33 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3180,10 +3180,11 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int button) return ImGui::BeginPopup(str_id); } -bool ImGui::BeginPopupContextWindow(const char* str_id, bool void_only, int button) +bool ImGui::BeginPopupContextWindow(bool in_empty_space_only, const char* str_id, int button) { + if (str_id == NULL) str_id = "window_context_menu"; if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(button)) - if (!void_only || !ImGui::IsAnyItemHovered()) + if (!in_empty_space_only || !ImGui::IsAnyItemHovered()) ImGui::OpenPopup(str_id); return ImGui::BeginPopup(str_id); } diff --git a/imgui.h b/imgui.h index 0cb0ad5a..a36f6167 100644 --- a/imgui.h +++ b/imgui.h @@ -170,7 +170,7 @@ namespace ImGui IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). close childs popups if any. will close popup when user click outside, or activate a pressable item, 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 bool BeginPopupContextItem(const char* str_id, int button = 1); // open popup when clicked on last item - IMGUI_API bool BeginPopupContextWindow(const char* str_id = "window_context_menu", bool void_only = false, int button = 1); // open popup when clicked on current window + IMGUI_API bool BeginPopupContextWindow(bool in_void_only = false, const char* str_id = "window_context_menu", int button = 1); // open popup when clicked on current window IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. From 235cca4f971cda95d2b14c2d599e98aac6a0ca5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 23:24:39 +0100 Subject: [PATCH 092/127] Fix to allow opening popup from a left-click on void or another window (because left-click would normally override focus immediately) (#126) Neither appears to be really useful frankly. --- imgui.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 96920a33..735b5d33 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2377,16 +2377,19 @@ void ImGui::Render() // Click to focus window and start moving (after we're done with all our widgets) if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) { - if (g.HoveredRootWindow != NULL) + if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear { - IM_ASSERT(g.MovedWindow == NULL); - g.MovedWindow = g.HoveredWindow; - SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); - } - else if (g.FocusedWindow != NULL) - { - // Clicking on void disable focus - FocusWindow(NULL); + if (g.HoveredRootWindow != NULL) + { + IM_ASSERT(g.MovedWindow == NULL); + g.MovedWindow = g.HoveredWindow; + SetActiveId(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); + } + else if (g.FocusedWindow != NULL) + { + // Clicking on void disable focus + FocusWindow(NULL); + } } } From dcc7df2b216091a2ed238cac1c071dcd48ca0463 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 May 2015 23:28:53 +0100 Subject: [PATCH 093/127] Added BeginPopupContextVoid() helper for completeness (#126) --- imgui.cpp | 10 +++++++++- imgui.h | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 735b5d33..26d91908 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3185,13 +3185,21 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int button) bool ImGui::BeginPopupContextWindow(bool in_empty_space_only, const char* str_id, int button) { - if (str_id == NULL) str_id = "window_context_menu"; + if (!str_id) str_id = "window_context_menu"; if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(button)) if (!in_empty_space_only || !ImGui::IsAnyItemHovered()) ImGui::OpenPopup(str_id); return ImGui::BeginPopup(str_id); } +bool ImGui::BeginPopupContextVoid(const char* str_id, int button) +{ + if (!str_id) str_id = "void_context_menu"; + if (!ImGui::IsMouseHoveringAnyWindow() && ImGui::IsMouseClicked(button)) + ImGui::OpenPopup(str_id); + return ImGui::BeginPopup(str_id); +} + bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; diff --git a/imgui.h b/imgui.h index a36f6167..3be321d1 100644 --- a/imgui.h +++ b/imgui.h @@ -170,7 +170,8 @@ namespace ImGui IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). close childs popups if any. will close popup when user click outside, or activate a pressable item, 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 bool BeginPopupContextItem(const char* str_id, int button = 1); // open popup when clicked on last item - IMGUI_API bool BeginPopupContextWindow(bool in_void_only = false, const char* str_id = "window_context_menu", int button = 1); // open popup when clicked on current window + IMGUI_API bool BeginPopupContextWindow(bool in_empty_space_only = false, const char* str_id = "window_context_menu", int button = 1); // open popup when clicked on current window + IMGUI_API bool BeginPopupContextVoid(const char* str_id = "void_context_menu", int button = 1); // open popup when clicked in void (no window) IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. From cd9244ab158c8f73b76351b4963e6ebd176cff57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Wed, 27 May 2015 16:12:52 -0700 Subject: [PATCH 094/127] Define STBTT_DEF extern when STBTT not compiled with ImGui. --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index ea70d592..3b1e4dca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -474,6 +474,8 @@ namespace IMGUI_STB_NAMESPACE #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION +#else +#define STBTT_DEF extern #endif #include "stb_truetype.h" From 95e2afcad61979410d568e4a8e6b87d5ada5981f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 May 2015 09:38:00 +0100 Subject: [PATCH 095/127] Updated to stb_truetype 1.05 --- stb_truetype.h | 78 +++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 3c5d6f30..3317e39f 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,7 +1,7 @@ -// [ImGui] this is a slightly modified version of stb_truetype.h 1.02 +// [ImGui] this is a slightly modified version of stb_truetype.h 1.05 // [ImGui] we added stbtt_PackFontRangesGatherRects() and stbtt_PackFontRangesRenderIntoRects() and modified stbtt_PackBegin() -// stb_truetype.h - v1.02 - public domain +// stb_truetype.h - v1.05 - public domain // authored from 2009-2014 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: @@ -37,12 +37,20 @@ // Johan Duparc // Hou Qiming // Fabian "ryg" Giesen +// Martins Mozeiko +// Cap Petschulat +// Omar Cornut +// github:aloucks +// Peter LaValle // // Misc other: // Ryan Gordon // // VERSION HISTORY // +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes // 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ // 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match // non-oversampled; STBTT_POINT_SIZE for packed case only @@ -86,6 +94,9 @@ // before the #include of this file. This expands out the actual // implementation into that C/C++ file. // +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// // Simple 3D API (don't ship this, but it's fine for tools and quick start) // stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture // stbtt_GetBakedQuad() -- compute quad to draw for a given char @@ -225,16 +236,16 @@ #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" -char ttf_buffer[1<<20]; +unsigned char ttf_buffer[1<<20]; unsigned char temp_bitmap[512*512]; stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs -GLstbtt_uint ftex; +GLuint ftex; void my_stbtt_initfont(void) { fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); - stbtt_BakeFontBitmap(data,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! + stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! // can free ttf_buffer at this point glGenTextures(1, &ftex); glBindTexture(GL_TEXTURE_2D, ftex); @@ -246,6 +257,7 @@ void my_stbtt_initfont(void) void my_stbtt_print(float x, float y, char *text) { // assume orthographic projection with units = screen pixels, origin at top left + glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, ftex); glBegin(GL_QUADS); while (*text) { @@ -379,12 +391,6 @@ int main(int arg, char **argv) typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - #ifdef STBTT_STATIC - #define STBTT_DEF static - #else - #define STBTT_DEF extern - #endif - // #define your own STBTT_sort() to override this to avoid qsort #ifndef STBTT_sort #include @@ -437,6 +443,12 @@ int main(int arg, char **argv) #ifndef __STB_INCLUDE_STB_TRUETYPE_H__ #define __STB_INCLUDE_STB_TRUETYPE_H__ +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + #ifdef __cplusplus extern "C" { #endif @@ -1059,7 +1071,6 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - stbtt_uint16 item, offset, start, end; // do a binary search of the segments stbtt_uint32 endCount = index_map + 14; @@ -1076,8 +1087,8 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep // now decrement to bias correctly to find smallest search -= 2; while (entrySelector) { + stbtt_uint16 end; searchRange >>= 1; - start = ttUSHORT(data + search + searchRange*2 + segcount*2 + 2); end = ttUSHORT(data + search + searchRange*2); if (unicode_codepoint > end) search += searchRange*2; @@ -1085,19 +1096,21 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep } search += 2; - item = (stbtt_uint16) ((search - endCount) >> 1); + { + stbtt_uint16 offset, start; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - end = ttUSHORT(data + index_map + 14 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; + STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + if (unicode_codepoint < start) + return 0; - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } } else if (format == 12 || format == 13) { stbtt_uint32 ngroups = ttULONG(data+index_map+12); stbtt_int32 low,high; @@ -2054,8 +2067,8 @@ STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int float d3d_bias = opengl_fillrule ? 0 : -0.5f; float ipw = 1.0f / pw, iph = 1.0f / ph; stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5); + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); q->x0 = round_x + d3d_bias; q->y0 = round_y + d3d_bias; @@ -2209,7 +2222,7 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i for (j=0; j < h; ++j) { int i; unsigned int total; - memset(buffer, 0, kernel_width); + STBTT_memset(buffer, 0, kernel_width); total = 0; @@ -2263,7 +2276,7 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i for (j=0; j < w; ++j) { int i; unsigned int total; - memset(buffer, 0, kernel_width); + STBTT_memset(buffer, 0, kernel_width); total = 0; @@ -2333,7 +2346,7 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fon for (j=0; j < ranges[i].num_chars_in_range; ++j) { int x0,y0,x1,y1; int glyph = stbtt_FindGlyphIndex(info,ranges[i].first_unicode_char_in_range + j); - if (glyph) { + if (glyph) { stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, scale * spc->h_oversample, scale * spc->v_oversample, @@ -2341,10 +2354,10 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fon &x0,&y0,&x1,&y1); rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); - } else { + } else { rects[k].w = rects[k].h = 1; } - ++k; + ++k; } } @@ -2453,6 +2466,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + STBTT_free(rects, spc->user_allocator_context); return return_value; } @@ -2473,8 +2487,8 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, i stbtt_packedchar *b = chardata + char_index; if (align_to_integer) { - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5); - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5); + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); q->x0 = x; q->y0 = y; q->x1 = x + b->xoff2 - b->xoff; From 733e079081030fc19fc279627a24927539b54443 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 May 2015 23:04:29 +0100 Subject: [PATCH 096/127] Moved CloseInactivePopups() and tweaked. --- imgui.cpp | 76 ++++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4b4ca3a6..e00b1eaa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2209,45 +2209,6 @@ void ImGui::NewFrame() 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.OpenedPopupStack.resize(0); - 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; - for (n = 0; n < (int)g.OpenedPopupStack.size(); n++) - { - ImGuiPopupRef& popup = g.OpenedPopupStack[n]; - if (!popup.Window) - continue; - IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); - if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) - { - if (g.FocusedWindow->RootWindow != popup.Window->RootWindow) - break; - } - else - { - bool has_focus = false; - for (int m = n; m < (int)g.OpenedPopupStack.size() && !has_focus; m++) - has_focus = (g.OpenedPopupStack[m].Window && g.OpenedPopupStack[m].Window->RootWindow == g.FocusedWindow->RootWindow); - if (!has_focus) - break; - } - } - g.OpenedPopupStack.resize(n); -} - // 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() { @@ -3098,6 +3059,41 @@ void ImGui::OpenPopup(const char* str_id) g.OpenedPopupStack.back() = ImGuiPopupRef(id, window, window->GetID("##menus")); } +static void CloseInactivePopups() +{ + ImGuiState& g = *GImGui; + if (g.OpenedPopupStack.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 (g.FocusedWindow) + { + for (n = 0; n < (int)g.OpenedPopupStack.size(); n++) + { + ImGuiPopupRef& popup = g.OpenedPopupStack[n]; + if (!popup.Window) + continue; + IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); + if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) + { + if (g.FocusedWindow->RootWindow != popup.Window->RootWindow) + break; + } + else + { + bool has_focus = false; + for (int m = n; m < (int)g.OpenedPopupStack.size() && !has_focus; m++) + has_focus = (g.OpenedPopupStack[m].Window && g.OpenedPopupStack[m].Window->RootWindow == g.FocusedWindow->RootWindow); + if (!has_focus) + break; + } + } + } + g.OpenedPopupStack.resize(n); +} + static void ClosePopupToLevel(int remaining) { ImGuiState& g = *GImGui; @@ -3411,9 +3407,9 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl } // Push a new ImGui window to add widgets to. -// - 'size' for a regular window denote the initial size for first-time creation (no saved data) and isn't that useful. Use SetNextWindowSize() prior to calling Begin() for more flexible window manipulation. // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. // - Begin/End can be called multiple times during the frame with the same window name to append content. +// - 'size_on_first_use' for a regular window denote the initial size for first-time creation (no saved data) and isn't that useful. Use SetNextWindowSize() prior to calling Begin() for more flexible window manipulation. // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). // You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. From 7847100ad857a8ee90aaec1f6b1ed2ff57e64047 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 May 2015 23:14:25 +0100 Subject: [PATCH 097/127] Tweak BeginMenu() code --- imgui.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e00b1eaa..8696e243 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3104,15 +3104,6 @@ static void ClosePopupToLevel(int remaining) g.OpenedPopupStack.resize(remaining); } -static void ClosePopup(const char* str_id) // not exposed because 'id' scope is misleading -{ - ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - const ImGuiID id = window->GetID(str_id); - if (IsPopupOpen(id)) - ClosePopupToLevel((int)g.CurrentPopupStack.size()); -} - // Close the popup we have begin-ed into. void ImGui::CloseCurrentPopup() { @@ -7690,7 +7681,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (menuset_opened) g.FocusedWindow = backed_focused_window; - bool want_open = false; + bool want_open = false, want_close = false; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) { // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers so menus feel more reactive. @@ -7712,18 +7703,20 @@ bool ImGui::BeginMenu(const char* label, bool enabled) } } - if (opened && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle) - ClosePopup(label); + want_close = (opened && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle); want_open = (!opened && hovered && !moving_within_opened_triangle) || (!opened && hovered && pressed); } else if (opened && pressed && menuset_opened) // menu-bar: click open menu to close { - ClosePopup(label); + want_close = true; want_open = opened = false; } else if (pressed || (hovered && menuset_opened && !opened)) // menu-bar: first click to open, then hover to open others want_open = true; + if (want_close && IsPopupOpen(id)) + ClosePopupToLevel((int)GImGui->CurrentPopupStack.size()); + if (!opened && want_open && g.OpenedPopupStack.size() > g.CurrentPopupStack.size()) { // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. From 78dc54ab3d227ef8059ab7d306ee96d55c7914f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 May 2015 23:37:11 +0100 Subject: [PATCH 098/127] Popups: calling OpenPopup() on already open popup doesn't close it's child (#126) It think it makes more sense? Maybe? Note that calling OpenPopup() every frame probably doesn't make sense. --- imgui.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8696e243..930075f5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3054,9 +3054,12 @@ void ImGui::OpenPopup(const char* str_id) ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); const ImGuiID id = window->GetID(str_id); - g.OpenedPopupStack.resize(g.CurrentPopupStack.size() + 1); - if (g.OpenedPopupStack.back().PopupID != id) - g.OpenedPopupStack.back() = ImGuiPopupRef(id, window, window->GetID("##menus")); + size_t current_stack_size = g.CurrentPopupStack.size(); + ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus")); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here) + if (g.OpenedPopupStack.size() < current_stack_size + 1) + g.OpenedPopupStack.push_back(popup_ref); + else if (g.OpenedPopupStack[current_stack_size].PopupID != id) + g.OpenedPopupStack[current_stack_size] = popup_ref; } static void CloseInactivePopups() From aaefe462bbc10641067fdc0d69fed90bdfca6107 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 May 2015 23:47:01 +0100 Subject: [PATCH 099/127] Popups: calling OpenPopup() on already open popup doesn't close it's child (#126) Fixed previous commit. --- imgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 930075f5..99007c79 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3059,7 +3059,10 @@ void ImGui::OpenPopup(const char* str_id) if (g.OpenedPopupStack.size() < current_stack_size + 1) g.OpenedPopupStack.push_back(popup_ref); else if (g.OpenedPopupStack[current_stack_size].PopupID != id) + { + g.OpenedPopupStack.resize(current_stack_size+1); g.OpenedPopupStack[current_stack_size] = popup_ref; + } } static void CloseInactivePopups() From f0781d3a24dfe9276c84e8105827366c47f6639b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 09:00:34 +0100 Subject: [PATCH 100/127] Added GetItemsLineHeightWithSpacing() helper. --- imgui.cpp | 8 +++++++- imgui.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 99007c79..4ff8fef1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4516,6 +4516,12 @@ float ImGui::GetTextLineHeightWithSpacing() return g.FontSize + g.Style.ItemSpacing.y; } +float ImGui::GetItemsLineHeightWithSpacing() +{ + ImGuiState& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; +} + ImDrawList* ImGui::GetWindowDrawList() { ImGuiWindow* window = GetCurrentWindow(); @@ -11722,7 +11728,7 @@ struct ExampleAppConsole // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); // NB- if you have thousands of entries this approach may be too inefficient. You can seek and display only the lines that are visible - CalcListClipping() is a helper to compute this information. // If your items are of variable size you may want to implement code similar to what CalcListClipping() does. Or split your data into fixed height items to allow random-seeking into your list. - ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetTextLineHeightWithSpacing()*2)); + ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetItemsLineHeightWithSpacing())); if (ImGui::BeginPopupContextWindow()) { if (ImGui::Selectable("Clear")) ClearLog(); diff --git a/imgui.h b/imgui.h index 3be321d1..fad89849 100644 --- a/imgui.h +++ b/imgui.h @@ -202,6 +202,7 @@ namespace ImGui IMGUI_API void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match subsequent (bigger) widgets IMGUI_API float GetTextLineHeight(); // height of font == GetWindowFontSize() IMGUI_API float GetTextLineHeightWithSpacing(); // spacing (in pixels) between 2 consecutive lines of text == GetWindowFontSize() + GetStyle().ItemSpacing.y + IMGUI_API float GetItemsLineHeightWithSpacing(); // ID scopes // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them From 15a26a479bba924ff3ec0a7c992dfc6d585925c1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 10:24:03 +0100 Subject: [PATCH 101/127] Fixed auto-filling child window using WindowMinSize at their minimum size, irrelevant. Using an arbitrary small number instead. --- imgui.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4ff8fef1..a2873af9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -360,6 +360,7 @@ - menus: local shortcuts, global shortcuts (github issue #126) - menus: icons - tabs + - separator: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y) - gauge: various forms of gauge/loading bars widgets - color: better color editor. - plot: make it easier for user to draw extra stuff into the graph (e.g: draw basis, highlight certain points, 2d plots, multiple plots) @@ -3197,7 +3198,6 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int button) bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { - ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; @@ -3209,13 +3209,13 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, { if (size.x == 0.0f) flags |= ImGuiWindowFlags_ChildWindowAutoFitX; - size.x = ImMax(content_max.x - cursor_pos.x, g.Style.WindowMinSize.x) - fabsf(size.x); + size.x = ImMax(content_max.x - cursor_pos.x, 4.0f) - fabsf(size.x); // Arbitrary minimum zeroish child size of 4.0f } if (size.y <= 0.0f) { if (size.y == 0.0f) flags |= ImGuiWindowFlags_ChildWindowAutoFitY; - size.y = ImMax(content_max.y - cursor_pos.y, g.Style.WindowMinSize.y) - fabsf(size.y); + size.y = ImMax(content_max.y - cursor_pos.y, 4.0f) - fabsf(size.y); } if (border) flags |= ImGuiWindowFlags_ShowBorders; @@ -3255,10 +3255,10 @@ void ImGui::EndChild() // When using auto-filling child window, we don't provide full width/height to ItemSize so that it doesn't feed back into automatic size-fitting. ImGuiState& g = *GImGui; ImVec2 sz = ImGui::GetWindowSize(); - if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitX) - sz.x = ImMax(g.Style.WindowMinSize.x, sz.x - g.Style.WindowPadding.x); + if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitX) // Arbitrary minimum zeroish child size of 4.0f + sz.x = ImMax(4.0f, sz.x - g.Style.WindowPadding.x); if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitY) - sz.y = ImMax(g.Style.WindowMinSize.y, sz.y - g.Style.WindowPadding.y); + sz.y = ImMax(4.0f, sz.y - g.Style.WindowPadding.y); ImGui::End(); From 4144c59ce4d03cb13d3220d3872323b5efa1619c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 10:29:26 +0100 Subject: [PATCH 102/127] Added Simple Layout example applet --- imgui.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index a2873af9..a79debc9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10270,6 +10270,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) //----------------------------------------------------------------------------- static void ShowExampleAppConsole(bool* opened); +static void ShowExampleAppLayout(bool* opened); static void ShowExampleAppLongText(bool* opened); static void ShowExampleAppAutoResize(bool* opened); static void ShowExampleAppFixedOverlay(bool* opened); @@ -10285,6 +10286,7 @@ void ImGui::ShowTestWindow(bool* opened) static bool show_app_metrics = false; static bool show_app_main_menu_bar = false; static bool show_app_console = false; + static bool show_app_layout = true; static bool show_app_long_text = false; static bool show_app_auto_resize = false; static bool show_app_fixed_overlay = false; @@ -10293,6 +10295,7 @@ void ImGui::ShowTestWindow(bool* opened) if (show_app_metrics) ImGui::ShowMetricsWindow(&show_app_metrics); if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); if (show_app_console) ShowExampleAppConsole(&show_app_console); + if (show_app_layout) ShowExampleAppLayout(&show_app_layout); if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay); @@ -10347,6 +10350,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::MenuItem("Metrics", NULL, &show_app_metrics); ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); ImGui::MenuItem("Console", NULL, &show_app_console); + ImGui::MenuItem("Simple layout", NULL, &show_app_layout); ImGui::MenuItem("Long text display", NULL, &show_app_long_text); ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); ImGui::MenuItem("Simple overlay", NULL, &show_app_fixed_overlay); @@ -11921,6 +11925,51 @@ static void ShowExampleAppConsole(bool* opened) console.Run("Example: Console", opened); } +static void ShowExampleAppLayout(bool* opened) +{ + ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiSetCond_FirstUseEver); + if (ImGui::Begin("Example: Layout", opened, ImGuiWindowFlags_MenuBar)) + { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Close")) *opened = false; + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // left + static int selected = 0; + ImGui::BeginChild("left pane", ImVec2(150, 0), true); + for (int i = 0; i < 100; i++) + { + char label[128]; + sprintf(label, "MyObject %d", i); + if (ImGui::Selectable(label, selected == i)) + selected = i; + } + ImGui::EndChild(); + ImGui::SameLine(); + + // right + ImGui::BeginGroup(); + ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetItemsLineHeightWithSpacing())); // Leave room for 1 line below us + ImGui::Text("MyObject: %d", selected); + ImGui::Separator(); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + ImGui::EndChild(); + ImGui::BeginChild("buttons"); + if (ImGui::Button("Revert")) {} + ImGui::SameLine(); + if (ImGui::Button("Save")) {} + ImGui::EndChild(); + ImGui::EndGroup(); + } + ImGui::End(); +} + static void ShowExampleAppLongText(bool* opened) { ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); From d86785ac98e9084b109ee0a2d5b5c6df8486dec5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 10:36:33 +0100 Subject: [PATCH 103/127] Examples: Fixed Simple Layout example always showing. Using BeginPopupContextItem(). --- imgui.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a79debc9..a4fea11b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10286,7 +10286,7 @@ void ImGui::ShowTestWindow(bool* opened) static bool show_app_metrics = false; static bool show_app_main_menu_bar = false; static bool show_app_console = false; - static bool show_app_layout = true; + static bool show_app_layout = false; static bool show_app_long_text = false; static bool show_app_auto_resize = false; static bool show_app_fixed_overlay = false; @@ -10543,7 +10543,7 @@ void ImGui::ShowTestWindow(bool* opened) if (i > 0) ImGui::SameLine(); ImGui::PushID(i); - int frame_padding = -1 + i; // -1 padding uses default padding + int frame_padding = -1 + i; // -1 = uses default padding if (ImGui::ImageButton(tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/tex_w,32/tex_h), frame_padding)) pressed_count += 1; ImGui::PopID(); @@ -10657,11 +10657,8 @@ void ImGui::ShowTestWindow(bool* opened) } static float value = 0.5f; - ImGui::Text("Value = %.3f", value); - if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1)) - ImGui::OpenPopup("context menu"); - ImGui::SameLine(); ImGui::Text("<-- right-click"); - if (ImGui::BeginPopup("context menu")) + ImGui::Text("Value = %.3f (Right-click here)", value); + if (ImGui::BeginPopupContextItem("item context menu")) { if (ImGui::Selectable("Set to zero")) value = 0.0f; if (ImGui::Selectable("Set to PI")) value = PI; From 616a7e6c6121f6c40c0658edc28a59099f4944ff Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 10:44:30 +0100 Subject: [PATCH 104/127] Examples: Using a helper function for ? markers --- imgui.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a4fea11b..ba03b518 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -965,7 +965,7 @@ static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, enum ImGuiLayoutType_ { ImGuiLayoutType_Vertical, - ImGuiLayoutType_Horizontal + ImGuiLayoutType_Horizontal // FIXME: this is in development, not exposed/functional as a generic feature yet. }; enum ImGuiButtonFlags_ @@ -10279,6 +10279,13 @@ static void ShowExampleAppCustomRendering(bool* opened); static void ShowExampleAppMainMenuBar(); static void ShowExampleMenuFile(); +static void ShowHelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(desc); +} + // Demonstrate most ImGui features (big function!) void ImGui::ShowTestWindow(bool* opened) { @@ -10657,7 +10664,7 @@ void ImGui::ShowTestWindow(bool* opened) } static float value = 0.5f; - ImGui::Text("Value = %.3f (Right-click here)", value); + ImGui::Text("Value = %.3f (Context menu, right-click here)", value); if (ImGui::BeginPopupContextItem("item context menu")) { if (ImGui::Selectable("Set to zero")) value = 0.0f; @@ -10730,21 +10737,21 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::LabelText("label", "Value"); static int item = 1; - ImGui::Combo("combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + ImGui::Combo("combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); // Combo using values packed in a single constant string (for really quick combo) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK" }; static int item2 = -1; - ImGui::Combo("combo scroll", &item2, items, IM_ARRAYSIZE(items)); + ImGui::Combo("combo scroll", &item2, items, IM_ARRAYSIZE(items)); // Combo using proper array. You can also pass a callback to retrieve array value, no need to create/copy an array just for that. { static char str0[128] = "Hello, world!"; static int i0=123; static float f0=0.001f; ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); - ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Hold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n"); + ImGui::SameLine(); ShowHelpMarker("Hold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n"); ImGui::InputInt("input int", &i0); - ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); + ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); @@ -10756,7 +10763,7 @@ void ImGui::ShowTestWindow(bool* opened) static int i1=50; static int i2=42; ImGui::DragInt("drag int", &i1, 1); - ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input text."); + ImGui::SameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input text."); ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%"); @@ -10770,7 +10777,7 @@ void ImGui::ShowTestWindow(bool* opened) static int i1=0; //static int i2=42; ImGui::SliderInt("slider int", &i1, 0, 3); - ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("CTRL+click to input value."); + ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value."); //ImGui::SliderInt("slider int -100..100", &i2, -100, 100); @@ -10785,7 +10792,7 @@ void ImGui::ShowTestWindow(bool* opened) static float col1[3] = { 1.0f,0.0f,0.2f }; static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; ImGui::ColorEdit3("color 1", col1); - ImGui::SameLine(); ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Click on the colored square to change edit mode. CTRL+click on individual component to input value.\n"); + ImGui::SameLine(); ShowHelpMarker("Click on the colored square to change edit mode. CTRL+click on individual component to input value.\n"); ImGui::ColorEdit4("color 2", col2); @@ -11330,7 +11337,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); ImGui::PushAllowKeyboardFocus(false); ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); - //ImGui::SameLine(); ImGui::Text("(?)"); if (ImGui::IsHovered()) ImGui::SetTooltip("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); + //ImGui::SameLine(); ShowHelperMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); ImGui::PopAllowKeyboardFocus(); ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); ImGui::TreePop(); From 9ace617e7e29fba03a0931de26abaff89e7b633b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 10:52:45 +0100 Subject: [PATCH 105/127] Examples: Tiding up. Moved Dragging example higher up. --- imgui.cpp | 53 ++++++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ba03b518..86ce6a98 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10687,6 +10687,25 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TreePop(); } + if (ImGui::TreeNode("Dragging")) + { + ImGui::TextWrapped("You can use ImGui::GetItemActiveDragDelta() to query for the dragged amount on any widget."); + ImGui::Button("Drag Me"); + if (ImGui::IsItemActive()) + { + // Draw a line between the button and the mouse cursor + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->PushClipRectFullScreen(); + draw_list->AddLine(ImGui::CalcItemRectClosestPoint(ImGui::GetIO().MousePos, true, -2.0f), ImGui::GetIO().MousePos, ImColor(ImGui::GetStyle().Colors[ImGuiCol_Button]), 4.0f); + draw_list->PopClipRect(); + ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); + ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); + ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y); + } + + ImGui::TreePop(); + } + static bool check = true; ImGui::Checkbox("checkbox", &check); @@ -10760,29 +10779,23 @@ void ImGui::ShowTestWindow(bool* opened) } { - static int i1=50; - static int i2=42; + static int i1=50, i2=42; ImGui::DragInt("drag int", &i1, 1); ImGui::SameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input text."); ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%"); - static float f1=1.00f; - static float f2=0.0067f; + static float f1=1.00f, f2=0.0067f; ImGui::DragFloat("drag float", &f1, 1.0f); ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); } { static int i1=0; - //static int i2=42; ImGui::SliderInt("slider int", &i1, 0, 3); ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value."); - //ImGui::SliderInt("slider int -100..100", &i2, -100, 100); - - static float f1=0.123f; - static float f2=0.0f; + static float f1=0.123f, f2=0.0f; ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f); static float angle = 0.0f; @@ -10905,28 +10918,6 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Indent(); ImGui::TreePop(); } - - if (ImGui::TreeNode("Dragging")) - { - // You can use ImGui::GetItemActiveDragDelta() to query for the dragged amount on any widget. - static ImVec2 value_raw(0.0f, 0.0f); - static ImVec2 value_with_lock_threshold(0.0f, 0.0f); - ImGui::Button("Drag Me"); - if (ImGui::IsItemActive()) - { - value_raw = ImGui::GetMouseDragDelta(0, 0.0f); - value_with_lock_threshold = ImGui::GetMouseDragDelta(0); - //ImGui::SetTooltip("Delta: %.1f, %.1f", value.x, value.y); - - // Draw a line between the button and the mouse cursor - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - draw_list->PushClipRectFullScreen(); - draw_list->AddLine(ImGui::CalcItemRectClosestPoint(ImGui::GetIO().MousePos, true, -2.0f), ImGui::GetIO().MousePos, ImColor(ImGui::GetStyle().Colors[ImGuiCol_Button]), 4.0f); - draw_list->PopClipRect(); - } - ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y); - ImGui::TreePop(); - } } if (ImGui::CollapsingHeader("Graphs widgets")) From 0db6bac5900edc5613bbab41bedba2264cca67f6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 11:01:53 +0100 Subject: [PATCH 106/127] Examples: Tweaks, demo code creating graph data actually creates data at the correct rate. --- imgui.cpp | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 86ce6a98..02308796 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10929,12 +10929,10 @@ void ImGui::ShowTestWindow(bool* opened) static ImVector values; if (values.empty()) { values.resize(90); memset(&values.front(), 0, values.size()*sizeof(float)); } static size_t values_offset = 0; if (!pause) - { - // create dummy data at fixed 60 hz rate - static float refresh_time = -1.0f; - if (ImGui::GetTime() > refresh_time + 1.0f/60.0f) + { + static float refresh_time = ImGui::GetTime(); // Create dummy data at fixed 60 hz rate for the demo + for (; ImGui::GetTime() > refresh_time + 1.0f/60.0f; refresh_time += 1.0f/60.0f) { - refresh_time = ImGui::GetTime(); static float phase = 0.0f; values[values_offset] = cosf(phase); values_offset = (values_offset+1)%values.size(); @@ -10978,13 +10976,11 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceeding item)"); // Text - ImGui::Text("Two items: Hello"); - ImGui::SameLine(); + ImGui::Text("Two items: Hello"); ImGui::SameLine(); ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); // Adjust spacing - ImGui::Text("More spacing: Hello"); - ImGui::SameLine(0, 20); + ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); // Button @@ -11050,8 +11046,6 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::TreeNode("Groups")) { ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items)"); - - ImVec2 size; ImGui::BeginGroup(); { ImGui::BeginGroup(); @@ -11068,12 +11062,12 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::SameLine(); ImGui::Button("EEE"); ImGui::EndGroup(); - - // Capture the group size and create widgets using the same size - size = ImGui::GetItemRectSize(); - const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; - ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); } + // Capture the group size and create widgets using the same size + ImVec2 size = ImGui::GetItemRectSize(); + const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; + ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); + ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f,size.y)); ImGui::SameLine(); ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f,size.y)); From 83770e5e406b5bba186dde66cd2f57182df34a1a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 11:05:17 +0100 Subject: [PATCH 107/127] Examples: Tweaks. Usnig sprintf() in user-copiable code. --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 02308796..ed595394 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11151,7 +11151,7 @@ void ImGui::ShowTestWindow(bool* opened) if (i == 50) ImGui::NextColumn(); char buf[32]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "%08x", i*5731); + sprintf(buf, "%08x", i*5731); ImGui::Button(buf); } ImGui::EndChild(); @@ -11169,8 +11169,8 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Text("Path"); ImGui::NextColumn(); ImGui::Text("Flags"); ImGui::NextColumn(); ImGui::Separator(); - const char* names[3] = { "Robert", "Stephanie", "C64" }; - const char* paths[3] = { "/path/robert", "/path/stephanie", "/path/computer" }; + const char* names[3] = { "One", "Two", "Three" }; + const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; for (int i = 0; i < 3; i++) { ImGui::Text("%04d", i); ImGui::NextColumn(); @@ -11315,7 +11315,7 @@ void ImGui::ShowTestWindow(bool* opened) { if (ImGui::TreeNode("Tabbing")) { - ImGui::Text("Use TAB/SHIFT+TAB to cycle thru keyboard editable fields."); + ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); static char buf[32] = "dummy"; ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); From 448b262b37ac1586a92e9b230086e2f0c900b842 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 11:11:50 +0100 Subject: [PATCH 108/127] Examples: Comments. --- imgui.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ed595394..33894e3b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11536,7 +11536,6 @@ static void ShowExampleAppAutoResize(bool* opened) ImGui::SliderInt("Number of lines", &lines, 1, 20); for (int i = 0; i < lines; i++) ImGui::Text("%*sThis is line %d", i*4, "", i); // Pad with space to extend size horizontally - ImGui::End(); } @@ -11548,11 +11547,9 @@ static void ShowExampleAppFixedOverlay(bool* opened) ImGui::End(); return; } - ImGui::Text("Simple overlay\non the top-left side of the screen."); ImGui::Separator(); ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); - ImGui::End(); } @@ -11645,6 +11642,7 @@ static void ShowExampleAppCustomRendering(bool* opened) ImGui::End(); } +// For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions. struct ExampleAppConsole { char InputBuf[256]; @@ -11701,8 +11699,7 @@ struct ExampleAppConsole ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc."); ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); - // TODO: display from bottom - // TODO: clip manually + // TODO: display items starting from the bottom if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.size()); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); if (ImGui::SmallButton("Add Dummy Error")) AddLog("[error] something went wrong"); ImGui::SameLine(); @@ -11714,7 +11711,6 @@ struct ExampleAppConsole ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0)); static ImGuiTextFilter filter; filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); - //if (ImGui::IsItemHovered()) ImGui::SetKeyboardFocusHere(-1); // Auto focus on hover ImGui::PopStyleVar(); ImGui::Separator(); @@ -11801,7 +11797,7 @@ struct ExampleAppConsole } } - static int TextEditCallbackStub(ImGuiTextEditCallbackData* data) + static int TextEditCallbackStub(ImGuiTextEditCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks { ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; return console->TextEditCallback(data); @@ -12001,7 +11997,7 @@ static void ShowExampleAppLongText(bool* opened) ImGui::PopStyleVar(); break; case 2: - // Multiple calls to Text(), not clipped + // Multiple calls to Text(), not clipped (slow) ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); for (int i = 0; i < lines; i++) ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i); From 73d1126bf423a2dc376452ac33a570ecb59bec71 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 11:15:24 +0100 Subject: [PATCH 109/127] Examples: OCD tweaks, a sign that we are near the release! --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 33894e3b..df51220e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11525,7 +11525,7 @@ static void ShowExampleMenuFile() static void ShowExampleAppAutoResize(bool* opened) { - if (!ImGui::Begin("Example: Auto-Resizing Window", opened, ImGuiWindowFlags_AlwaysAutoResize)) + if (!ImGui::Begin("Example: Auto-resizing window", opened, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::End(); return; @@ -11583,7 +11583,7 @@ static void ShowExampleAppManipulatingWindowTitle(bool* opened) static void ShowExampleAppCustomRendering(bool* opened) { ImGui::SetNextWindowSize(ImVec2(300,350), ImGuiSetCond_FirstUseEver); - if (!ImGui::Begin("Example: Custom Rendering", opened)) + if (!ImGui::Begin("Example: Custom rendering", opened)) { ImGui::End(); return; From f1f3424cdd99f88dbbbe26f4807109a4ecacd2b3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 11:42:35 +0100 Subject: [PATCH 110/127] Popups WantCaptureMouse active when popups/menus are active + using tracked mouse button ownership when mouse down (#126) --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index df51220e..0ac82810 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2135,16 +2135,18 @@ void ImGui::NewFrame() // Are we using inputs? Tell user so they can capture/discard the inputs away from the rest of their application. // When clicking outside of a window we assume the click is owned by the application and won't request capture. int mouse_earliest_button_down = -1; + bool mouse_any_down = false; for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) { if (g.IO.MouseClicked[i]) - g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL); + g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenedPopupStack.empty()); + mouse_any_down |= g.IO.MouseDown[i]; if (g.IO.MouseDown[i]) if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[mouse_earliest_button_down] > g.IO.MouseClickedTime[i]) mouse_earliest_button_down = i; } bool mouse_owned_by_application = mouse_earliest_button_down != -1 && !g.IO.MouseDownOwned[mouse_earliest_button_down]; - g.IO.WantCaptureMouse = (!mouse_owned_by_application && g.HoveredWindow != NULL) || (g.ActiveId != 0); + g.IO.WantCaptureMouse = (!mouse_owned_by_application && g.HoveredWindow != NULL) || (!mouse_owned_by_application && mouse_any_down) || (g.ActiveId != 0) || (!g.OpenedPopupStack.empty()); g.IO.WantCaptureKeyboard = (g.ActiveId != 0); g.MouseCursor = ImGuiMouseCursor_Arrow; From 5ea23977f7464dbdfbf0a50a50d1da82ea7db578 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 May 2015 14:54:33 +0100 Subject: [PATCH 111/127] Fixed uninitialized fields in constructor - wouldn't have caused a problem (thanks Coverity!) --- imgui.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0ac82810..db77e160 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1150,6 +1150,10 @@ struct ImGuiDrawContext MenuBarOffsetX = 0.0f; StateStorage = NULL; LayoutType = ImGuiLayoutType_Vertical; + ItemWidth = 0.0f; + ButtonRepeat = false; + AllowKeyboardFocus = true; + TextWrapPos = 1.0f; ColorEditMode = ImGuiColorEditMode_RGB; memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); @@ -1333,6 +1337,7 @@ struct ImGuiState ActiveIdIsAlive = false; ActiveIdIsJustActivated = false; ActiveIdIsFocusedOnly = false; + ActiveIdWindow = NULL; MovedWindow = NULL; SettingsDirtyTimer = 0.0f; DisableHideTextAfterDoubleHash = 0; @@ -3201,7 +3206,6 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int button) bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { ImGuiWindow* window = GetCurrentWindow(); - ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; const ImVec2 content_max = window->Pos + ImGui::GetContentRegionMax(); @@ -3441,6 +3445,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ g.CurrentWindowStack.push_back(window); SetCurrentWindow(window); CheckStacksSize(window, true); + IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); 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 @@ -10243,7 +10248,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) filter.Draw("Filter colors", 200); ImGui::BeginChild("#colors", ImVec2(0, 300), true); - ImGui::ColorEditMode(edit_mode); for (int i = 0; i < ImGuiCol_COUNT; i++) { From abd0e85fc61d8e85165c5deb8aa319c912b36564 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 29 May 2015 15:42:15 +0100 Subject: [PATCH 112/127] Update README.md - supporters --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f8ef61d4..3053610b 100644 --- a/README.md +++ b/README.md @@ -127,13 +127,13 @@ Embeds [stb_textedit.h, stb_truetype.h, stb_rectpack.h](https://github.com/nothi Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. And everybody posting feedback, questions and patches on the GitHub. -ImGui is financially supported on [**Patreon**](http://www.patreon.com/imgui). +ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). -Special supporters -- Jetha Chan, Mārtiņš Možeiko, Alex Evans, Pastagames, Wild Sheep Studio +Special supporters: +- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano. -And -- Dale Kim, Michel Courtine, Paul Patrashcu, Rui Figueira +And: +- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly. And other supporters; thanks! From 9417df2a26081957e8eb46f3950d1f94eb2e0f5b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 09:12:07 +0100 Subject: [PATCH 113/127] Renamed IsRectClipped to IsRectVisible for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete) --- imgui.cpp | 6 ++++-- imgui.h | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index db77e160..28a8f5c0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -136,6 +136,7 @@ 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. + - 2015/05/31 (1.39) - renamed IsRectClipped to IsRectVisible for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). - 2015/05/27 (1.39) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. - 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. BeginPopup() returns true if the popup is opened. - 2015/05/03 (1.39) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). @@ -8042,10 +8043,11 @@ static bool IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when return false; } -bool ImGui::IsRectClipped(const ImVec2& size) +bool ImGui::IsRectVisible(const ImVec2& size) { ImGuiWindow* window = GetCurrentWindow(); - return IsClippedEx(ImRect(window->DC.CursorPos, window->DC.CursorPos + size), NULL, true); + ImRect r(window->ClipRectStack.back()); + return r.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); } // Declare item bounding box for clipping and interaction. diff --git a/imgui.h b/imgui.h index fad89849..3ddb05a7 100644 --- a/imgui.h +++ b/imgui.h @@ -344,9 +344,9 @@ namespace ImGui IMGUI_API ImVec2 GetItemRectMax(); // " IMGUI_API ImVec2 GetItemRectSize(); // " IMGUI_API bool IsWindowFocused(); // is current window focused (differentiate child windows from each others) - IMGUI_API bool IsRootWindowFocused(); // is current root window focused + IMGUI_API bool IsRootWindowFocused(); // is current root window focused (top parent window in case of child windows) IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused - IMGUI_API bool IsRectClipped(const ImVec2& size); // test if rectangle of given size starting from cursor pos is out of clipping region. to perform coarse clipping on user's side (as an optimization) + IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle of given size starting from cursor pos is visible (not clipped). to perform coarse clipping on user's side (as an optimization) IMGUI_API bool IsKeyDown(int key_index); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // " IMGUI_API bool IsMouseDown(int button); @@ -392,7 +392,8 @@ namespace ImGui static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE - static inline bool IsClipped(const ImVec2& size) { return IsRectClipped(size); } // OBSOLETE + static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE + static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE } // namespace ImGui From c4cb76843224cbac94e6f31dff57ae05857e3000 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 10:53:42 +0100 Subject: [PATCH 114/127] Comments --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 3ddb05a7..65da75d2 100644 --- a/imgui.h +++ b/imgui.h @@ -201,8 +201,8 @@ namespace ImGui IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] IMGUI_API void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match subsequent (bigger) widgets IMGUI_API float GetTextLineHeight(); // height of font == GetWindowFontSize() - IMGUI_API float GetTextLineHeightWithSpacing(); // spacing (in pixels) between 2 consecutive lines of text == GetWindowFontSize() + GetStyle().ItemSpacing.y - IMGUI_API float GetItemsLineHeightWithSpacing(); + IMGUI_API float GetTextLineHeightWithSpacing(); // distance (in pixels) between 2 consecutive lines of text == GetWindowFontSize() + GetStyle().ItemSpacing.y + IMGUI_API float GetItemsLineHeightWithSpacing(); // distance (in pixels) between 2 consecutive lines of standard height widgets == GetWindowFontSize() + GetStyle().FramePadding.y*2 + GetStyle().ItemSpacing.y // ID scopes // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them From 03ff2faacb6eb8501d2073568c313f0eff2bad42 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 11:01:22 +0100 Subject: [PATCH 115/127] Comments --- imgui.cpp | 2 +- imgui.h | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 28a8f5c0..dbf7d506 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -144,7 +144,7 @@ - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. - - 2015/03/17 (1.36) - renamed GetItemRectMin()/GetItemRectMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete). + - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete). - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete). - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth diff --git a/imgui.h b/imgui.h index 65da75d2..4b8e1612 100644 --- a/imgui.h +++ b/imgui.h @@ -310,14 +310,14 @@ namespace ImGui // Widgets: Menus IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. only call EndMainMenuBar() if this returns true! IMGUI_API void EndMainMenuBar(); - IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window. only call EndMenuBar() if this returns true! + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set). only call EndMenuBar() if this returns true! IMGUI_API void EndMenuBar(); IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL - // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare your own within the ImGui namespace!) + // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) IMGUI_API void Value(const char* prefix, bool b); IMGUI_API void Value(const char* prefix, int v); IMGUI_API void Value(const char* prefix, unsigned int v); @@ -338,8 +338,8 @@ namespace ImGui IMGUI_API bool IsItemHoveredRect(); // was the last item hovered by mouse? even if another item is active while we are hovering this IMGUI_API bool IsItemActive(); // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) IMGUI_API bool IsItemVisible(); - IMGUI_API bool IsAnyItemHovered(); // - IMGUI_API bool IsAnyItemActive(); // + IMGUI_API bool IsAnyItemHovered(); + IMGUI_API bool IsAnyItemActive(); IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item in screen space IMGUI_API ImVec2 GetItemRectMax(); // " IMGUI_API ImVec2 GetItemRectSize(); // " @@ -367,7 +367,7 @@ namespace ImGui IMGUI_API const char* GetStyleColName(ImGuiCol idx); IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); - IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of items. see comments in implementation + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of evenly sized items. see comments in implementation IMGUI_API void BeginChildFrame(ImGuiID id, const ImVec2& size); // helper to create a child window / scrolling region that looks like a normal widget frame IMGUI_API void EndChildFrame(); @@ -376,25 +376,25 @@ namespace ImGui IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); - // Proxy functions to access the MemAllocFn/MemFreeFn pointers in ImGui::GetIO() + // Helpers functions to access the MemAllocFn/MemFreeFn pointers in ImGui::GetIO() IMGUI_API void* MemAlloc(size_t sz); IMGUI_API void MemFree(void* ptr); - // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself + // Internal state/context access - if you want to use multiple ImGui context, or share context between modules (e.g. DLL), or allocate the memory yourself IMGUI_API const char* GetVersion(); IMGUI_API void* GetInternalState(); IMGUI_API size_t GetInternalStateSize(); IMGUI_API void SetInternalState(void* state, bool construct = false); // Obsolete (will be removed) - IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); // OBSOLETE - static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE - static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE - static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE - static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE - static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE - static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE - static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE + IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); // OBSOLETE 1.30+ + static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE 1.34+ + static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+ + static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE 1.36+ + static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE 1.36+ + static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.38+ + static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+ + static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE 1.36+ } // namespace ImGui @@ -411,7 +411,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame ImGuiWindowFlags_ShowBorders = 1 << 7, // Show borders around windows and items ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file - ImGuiWindowFlags_MenuBar = 1 << 9, // Has a menubar + ImGuiWindowFlags_MenuBar = 1 << 9, // Has a menu-bar // [Internal] ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild() From 475498f2ebd80e988bfc1470e776cdfe93da6d06 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 11:12:29 +0100 Subject: [PATCH 116/127] Comments, moved Sliders below Drag & Input in imgui.h --- imgui.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/imgui.h b/imgui.h index 4b8e1612..8afa0c6c 100644 --- a/imgui.h +++ b/imgui.h @@ -175,7 +175,7 @@ namespace ImGui IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. - // Layout + // Cursor / Layout IMGUI_API void BeginGroup(); // once closing a group it is seen as a single item (so you can use IsItemHovered() on a group, SameLine() between groups, etc. IMGUI_API void EndGroup(); IMGUI_API void Separator(); // horizontal line @@ -253,19 +253,6 @@ namespace ImGui IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float)); IMGUI_API void PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); - // Widgets: Sliders (tip: ctrl+click on a slider to input text) - IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); // adjust display_format to decorate the value with a prefix or a suffix. Use power!=1.0 for logarithmic sliders - IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); - IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); - IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f"); - IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format = "%.0f"); - IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format = "%.0f"); - IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format = "%.0f"); - IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); - IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); - // Widgets: Drags (tip: ctrl+click on a drag box to input text) IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); @@ -287,6 +274,19 @@ namespace ImGui IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags = 0); + // Widgets: Sliders (tip: ctrl+click on a slider to input text) + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); // adjust display_format to decorate the value with a prefix or a suffix. Use power!=1.0 for logarithmic sliders + IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format = "%.0f"); + IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); + // Widgets: Trees IMGUI_API bool TreeNode(const char* str_label_id); // if returning 'true' the node is open and the user is responsible for calling TreePop IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...); // " From 0539be7067cfe83b9113f17d316ca63ac3ec7334 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 11:17:58 +0100 Subject: [PATCH 117/127] Added IMGUI_DISABLE_OBSOLETE_FUNCTIONS --- imconfig.h | 3 +++ imgui.cpp | 2 ++ imgui.h | 2 ++ 3 files changed, 7 insertions(+) diff --git a/imconfig.h b/imconfig.h index 24d61148..8573ebd5 100644 --- a/imconfig.h +++ b/imconfig.h @@ -31,6 +31,9 @@ //---- Don't implement help and test window functionality (ShowUserGuide()/ShowStyleEditor()/ShowTestWindow() methods will be empty) //#define IMGUI_DISABLE_TEST_WINDOWS +//---- Don't define obsolete functions names +//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS + //---- Implement STB libraries in a namespace to avoid conflicts //#define IMGUI_STB_NAMESPACE ImStb diff --git a/imgui.cpp b/imgui.cpp index dbf7d506..7325fe1d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8940,6 +8940,7 @@ void ImFontAtlas::Clear() ClearFonts(); } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS void ImGui::GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size) { printf("GetDefaultFontData() is obsoleted in ImGui 1.30.\n"); @@ -8950,6 +8951,7 @@ void ImGui::GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, co if (png_size) *png_size = 0; IM_ASSERT(false); } +#endif void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) { diff --git a/imgui.h b/imgui.h index 8afa0c6c..821e6de3 100644 --- a/imgui.h +++ b/imgui.h @@ -387,6 +387,7 @@ namespace ImGui IMGUI_API void SetInternalState(void* state, bool construct = false); // Obsolete (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); // OBSOLETE 1.30+ static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE 1.34+ static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+ @@ -395,6 +396,7 @@ namespace ImGui static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.38+ static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+ static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE 1.36+ +#endif } // namespace ImGui From df37df821e5042bbd54cfa563445cbb9b06b452d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 11:52:57 +0100 Subject: [PATCH 118/127] RetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline indirection. --- imgui.cpp | 6 +++--- imgui.h | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7325fe1d..a3cf1697 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -136,6 +136,7 @@ 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. + - 2015/05/31 (1.39) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). - 2015/05/31 (1.39) - renamed IsRectClipped to IsRectVisible for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). - 2015/05/27 (1.39) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. - 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. BeginPopup() returns true if the popup is opened. @@ -4421,10 +4422,9 @@ void ImGui::SetWindowCollapsed(bool collapsed, ImGuiSetCond cond) SetWindowCollapsed(window, collapsed, cond); } -bool ImGui::GetWindowCollapsed() +bool ImGui::IsWindowCollapsed() { - ImGuiWindow* window = GetCurrentWindow(); - return window->Collapsed; + return GImGui->CurrentWindow->Collapsed; } void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond) diff --git a/imgui.h b/imgui.h index 821e6de3..90a103f9 100644 --- a/imgui.h +++ b/imgui.h @@ -115,10 +115,10 @@ namespace ImGui IMGUI_API ImFont* GetWindowFont(); IMGUI_API float GetWindowFontSize(); // size (also height in pixels) of current font with current scale applied IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows - IMGUI_API ImVec2 GetWindowPos(); // you should rarely need/care about the window position, but it can be useful if you want to do your own drawing - IMGUI_API ImVec2 GetWindowSize(); // get current window position + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList api) + IMGUI_API ImVec2 GetWindowSize(); // get current window size IMGUI_API float GetWindowWidth(); - IMGUI_API bool GetWindowCollapsed(); + IMGUI_API bool IsWindowCollapsed(); IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position - call before Begin() IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set to ImVec2(0,0) to force an auto-fit @@ -389,12 +389,13 @@ namespace ImGui // Obsolete (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); // OBSOLETE 1.30+ - static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE 1.34+ - static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+ - static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE 1.36+ - static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE 1.36+ - static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.38+ - static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+ + static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE 1.34+ + static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+ + static inline bool GetWindowCollapsed() { return ImGui::IsWindowCollapsed(); } // OBSOLETE 1.39+ + static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE 1.36+ + static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE 1.36+ + static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.38+ + static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+ static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE 1.36+ #endif From 446d8abfb07f8fae596d5ba322a5787b2f57fcb8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 11:54:00 +0100 Subject: [PATCH 119/127] ListBoxHeader() can return false. Also made ListBox() only use public API. --- imgui.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a3cf1697..49c56aea 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7465,6 +7465,8 @@ bool ImGui::Selectable(const char* label, bool* p_selected, const ImVec2& size_a bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) { ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; const ImGuiStyle& style = ImGui::GetStyle(); const ImGuiID id = ImGui::GetID(label); @@ -7527,10 +7529,6 @@ bool ImGui::ListBox(const char* label, int* current_item, const char** items, in bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) { - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; - if (!ImGui::ListBoxHeader(label, items_count, height_in_items)) return false; From eb4ffd5dbd7f6f9f4260e5d66df2347e7ef12270 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 12:33:24 +0100 Subject: [PATCH 120/127] Added ImGuiListClipper helper to avoid using CalcListClipping() directly. --- imgui.cpp | 3 +-- imgui.h | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 49c56aea..8d4507cd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2730,6 +2730,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex } // Helper to calculate coarse clipping of large list of evenly sized items. +// NB: Prefer using the ImGuiListClipper higher-level helper if you can! // If you are displaying thousands of items and you have a random access to the list, you can perform clipping yourself to save on CPU. // { // float item_height = ImGui::GetTextLineHeightWithSpacing(); @@ -2744,7 +2745,6 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - if (g.LogEnabled) { // If logging is active, do not perform any clipping @@ -2762,7 +2762,6 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items int end = (int)((clip_y2 - pos.y) / items_height); start = ImClamp(start, 0, items_count); end = ImClamp(end + 1, start, items_count); - *out_items_display_start = start; *out_items_display_end = end; } diff --git a/imgui.h b/imgui.h index 90a103f9..617ec6f0 100644 --- a/imgui.h +++ b/imgui.h @@ -80,6 +80,7 @@ struct ImVec4 // - struct ImGuiTextBuffer // Text buffer for logging/accumulating text // - struct ImGuiStorage // Custom key value storage (if you need to alter open/close states manually) // - struct ImGuiTextEditCallbackData // Shared state of ImGui::InputText() when using custom callbacks +// - struct ImGuiListClipper // Helper to manually clip large list of items. // - struct ImColor // Helper functions to created packed 32-bit RGBA color values // - struct ImDrawList // Draw command list // - struct ImFontAtlas // Bake multiple fonts into a single texture, TTF font loader, bake glyphs into bitmap @@ -367,7 +368,7 @@ namespace ImGui IMGUI_API const char* GetStyleColName(ImGuiCol idx); IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); - IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of evenly sized items. see comments in implementation + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can. IMGUI_API void BeginChildFrame(ImGuiID id, const ImVec2& size); // helper to create a child window / scrolling region that looks like a normal widget frame IMGUI_API void EndChildFrame(); @@ -903,6 +904,38 @@ struct ImColor static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r,g,b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r,g,b,a); } }; +// Helper: Manually clip large list of items. +// If you are displaying thousands of even spaced items and you have a random access to the list, you can perform clipping yourself to save on CPU. +// Usage: +// ImGuiListClipper clipper(count, ImGui::GetTextLineHeightWithSpacing()); +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) // display only visible items +// ImGui::Text("line number %d", i); +// clipper.End(); +struct ImGuiListClipper +{ + float ItemsHeight; + int ItemsCount, DisplayStart, DisplayEnd; + + ImGuiListClipper() { ItemsHeight = 0.0f; ItemsCount = DisplayStart = DisplayEnd = -1; } + ImGuiListClipper(int count, float height) { ItemsCount = -1; Begin(count, height); } + ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); } // user forgot to call End() + + void Begin(int count, float height) // items_height: generally pass GetTextLineHeightWithSpacing() or GetItemsLineHeightWithSpacing() + { + IM_ASSERT(ItemsCount == -1); + ItemsCount = count; + ItemsHeight = height; + ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + DisplayStart * ItemsHeight); // advance cursor + } + void End() + { + IM_ASSERT(ItemsCount >= 0); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ItemsCount - DisplayEnd) * ItemsHeight); // advance cursor + ItemsCount = -1; + } +}; + //----------------------------------------------------------------------------- // Draw List // Hold a series of drawing commands. The user provides a renderer for ImDrawList. From bda0269133b42b16612a079bbf9348329504994e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 12:35:21 +0100 Subject: [PATCH 121/127] ListBox() uses ImGuiListClipper helper, faster for large lists, assume evenly sized items. --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8d4507cd..90983bc6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7531,8 +7531,10 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v if (!ImGui::ListBoxHeader(label, items_count, height_in_items)) return false; + // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. bool value_changed = false; - for (int i = 0; i < items_count; i++) + ImGuiListClipper clipper(items_count, ImGui::GetTextLineHeightWithSpacing()); + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { const bool item_selected = (i == *current_item); const char* item_text; @@ -7547,7 +7549,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v } ImGui::PopID(); } - + clipper.End(); ImGui::ListBoxFooter(); return value_changed; } From 374d160234a5dd433f133cd9c32566b251d96f34 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 12:55:12 +0100 Subject: [PATCH 122/127] BeginPopupContextWindow() in_empty_space_only -> !also_over_items (#126)+ comments Sorry if you used this parameter already. --- imgui.cpp | 14 +++++++------- imgui.h | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 90983bc6..faa55c33 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3180,26 +3180,26 @@ void ImGui::EndPopup() ImGui::PopStyleVar(); } -bool ImGui::BeginPopupContextItem(const char* str_id, int button) +bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) { - if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(button)) + if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(mouse_button)) ImGui::OpenPopup(str_id); return ImGui::BeginPopup(str_id); } -bool ImGui::BeginPopupContextWindow(bool in_empty_space_only, const char* str_id, int button) +bool ImGui::BeginPopupContextWindow(bool also_over_items, const char* str_id, int mouse_button) { if (!str_id) str_id = "window_context_menu"; - if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(button)) - if (!in_empty_space_only || !ImGui::IsAnyItemHovered()) + if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(mouse_button)) + if (also_over_items || !ImGui::IsAnyItemHovered()) ImGui::OpenPopup(str_id); return ImGui::BeginPopup(str_id); } -bool ImGui::BeginPopupContextVoid(const char* str_id, int button) +bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) { if (!str_id) str_id = "void_context_menu"; - if (!ImGui::IsMouseHoveringAnyWindow() && ImGui::IsMouseClicked(button)) + if (!ImGui::IsMouseHoveringAnyWindow() && ImGui::IsMouseClicked(mouse_button)) ImGui::OpenPopup(str_id); return ImGui::BeginPopup(str_id); } diff --git a/imgui.h b/imgui.h index 617ec6f0..9326956c 100644 --- a/imgui.h +++ b/imgui.h @@ -170,9 +170,9 @@ namespace ImGui // Popup IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). close childs popups if any. will close popup when user click outside, or activate a pressable item, 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 bool BeginPopupContextItem(const char* str_id, int button = 1); // open popup when clicked on last item - IMGUI_API bool BeginPopupContextWindow(bool in_empty_space_only = false, const char* str_id = "window_context_menu", int button = 1); // open popup when clicked on current window - IMGUI_API bool BeginPopupContextVoid(const char* str_id = "void_context_menu", int button = 1); // open popup when clicked in void (no window) + IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // open and begin popup when clicked on last item + IMGUI_API bool BeginPopupContextWindow(bool also_over_items = true, const char* str_id = NULL, int mouse_button = 1); // open and begin popup when clicked on current window + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // open and begin popup when clicked in void (no window) IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. @@ -315,7 +315,7 @@ namespace ImGui IMGUI_API void EndMenuBar(); IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); - IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) From 04e91500c585a43f6c2ab7b7b83f790749e61238 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 14:03:07 +0100 Subject: [PATCH 123/127] Comments --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index faa55c33..a6bde9ba 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -137,7 +137,7 @@ 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/31 (1.39) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). - - 2015/05/31 (1.39) - renamed IsRectClipped to IsRectVisible for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). + - 2015/05/31 (1.39) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). - 2015/05/27 (1.39) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. - 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. BeginPopup() returns true if the popup is opened. - 2015/05/03 (1.39) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). From b5b165b9890e67f19a9fd5ea977e24158465a833 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 14:44:47 +0100 Subject: [PATCH 124/127] Web: Added screenshots --- README.md | 4 +++- web/examples_03.png | Bin 0 -> 23423 bytes web/test_window_05_menus.png | Bin 0 -> 3278 bytes 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 web/examples_03.png create mode 100644 web/test_window_05_menus.png diff --git a/README.md b/README.md index 3053610b..0de22f7d 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,9 @@ Gallery ![screenshot 2](/web/test_window_02.png?raw=true) ![screenshot 3](/web/test_window_03.png?raw=true) ![screenshot 4](/web/test_window_04.png?raw=true) -![screenshot 4](/web/examples_02.png?raw=true) +![screenshot 5](/web/test_window_05_menus.png?raw=true) +![screenshot 6](/web/examples_03.png?raw=true) +![screenshot 7](/web/examples_02.png?raw=true) ImGui can load TTF fonts. UTF-8 is supported for text display and input. Here using Arial Unicode font to display Japanese. Initialize custom font with: ``` diff --git a/web/examples_03.png b/web/examples_03.png new file mode 100644 index 0000000000000000000000000000000000000000..3b95c7c08f209069ee3077a3f57c6ab93af7c412 GIT binary patch literal 23423 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 U$R)+2zYr2+$i}pa^hfOf0^*e=Qvd(} literal 0 HcmV?d00001 From 1c2dac2a9006add109bdff5f0878da53cdacb3aa Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 14:46:28 +0100 Subject: [PATCH 125/127] Version increased to 1.40 WIP makes more sense than 1.39 (changelog is huge) --- imgui.cpp | 2 +- imgui.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a6bde9ba..0cf63cd7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.39 WIP +// ImGui library v1.40 WIP // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui diff --git a/imgui.h b/imgui.h index 9326956c..e1a1117e 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.39 WIP +// ImGui library v1.40 WIP // See .cpp file for documentation. // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. @@ -13,7 +13,7 @@ #include // NULL, malloc, free, qsort, atoi #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.39 WIP" +#define IMGUI_VERSION "1.40 WIP" // Define assertion handler. #ifndef IM_ASSERT From b148f70f83d6c3a5c01a53617a8a43f3df843bc9 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 31 May 2015 14:51:35 +0100 Subject: [PATCH 126/127] Update README.md - new demo binaries --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0de22f7d..3b87cb4e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Demo ---- You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download binaries of the demo app here. -- [imgui-demo-binaries-20150321.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20150321.zip) (Windows binaries, ImGui 1.37 WIP 2015/03/31, 4 executables, 391 KB) +- [imgui-demo-binaries-20150531.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20150531.zip) (Windows binaries, ImGui 1.40 WIP 2015/05/31, 4 executables, 432 KB) Gallery From 8738147aee1f91256f1b68b8e8e467cedfcb21f3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 May 2015 15:55:32 +0100 Subject: [PATCH 127/127] Windows: pragma link with user32.lib if we are using native clipboard function (unless IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS) #238 --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index 0cf63cd7..3e6a09e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10043,6 +10043,7 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re #define WIN32_LEAN_AND_MEAN #include #endif +#pragma comment(lib, "user32") // Win32 API clipboard implementation static const char* GetClipboardTextFn_DefaultImpl()