From 1ab63d925f21e03be7735661500e5b914dd93c19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 2 Nov 2023 18:06:38 +0100 Subject: [PATCH 1/9] Undid some of the changes done by c95fbb4 because they are not compatible with docking code. (Will cherry-pick this from docking to master) # Conflicts: # imgui.cpp --- imgui.cpp | 20 +++++++++++--------- imgui_internal.h | 2 ++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9e4ffa6d8..cb20e5129 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1107,8 +1107,8 @@ static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); // Misc static void UpdateSettings(); static int UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); -static void RenderWindowOuterBorders(ImGuiWindow* window, int border_hovered, int border_held); -static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size, int border_hovered, int border_held); +static void RenderWindowOuterBorders(ImGuiWindow* window); +static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); static void RenderDimmedBackgrounds(); @@ -6089,7 +6089,7 @@ static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_ window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max); } -static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window, int border_hovered, int border_held) +static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) { ImGuiContext& g = *GImGui; float rounding = window->WindowRounding; @@ -6097,12 +6097,12 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window, int border_hove if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); - if (border_hovered != -1 || border_held != -1) + if (window->ResizeBorderHovered != -1 || window->ResizeBorderHeld != -1) { - const int border_n = (border_held != -1) ? border_held : border_hovered; + const int border_n = (window->ResizeBorderHeld != -1) ? window->ResizeBorderHeld : window->ResizeBorderHovered; const ImGuiResizeBorderDef& def = resize_border_def[border_n]; const ImRect border_r = GetResizeBorderRect(window, border_n, rounding, 0.0f); - const ImU32 border_col = GetColorU32((border_held != -1) ? ImGuiCol_SeparatorActive : ImGuiCol_SeparatorHovered); + const ImU32 border_col = GetColorU32((window->ResizeBorderHeld != -1) ? ImGuiCol_SeparatorActive : ImGuiCol_SeparatorHovered); window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle); window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f); window->DrawList->PathStroke(border_col, 0, ImMax(2.0f, border_size)); // Thicker than usual @@ -6116,7 +6116,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window, int border_hove // Draw background and borders // Draw and handle scrollbars -void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size, int border_hovered, int border_held) +void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; @@ -6199,7 +6199,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar // Borders if (handle_borders_and_resize_grips) - RenderWindowOuterBorders(window, border_hovered, border_held); + RenderWindowOuterBorders(window); } } @@ -6742,6 +6742,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (auto_fit_mask & (1 << ImGuiAxis_Y)) use_current_size_for_scrollbar_y = true; } + window->ResizeBorderHovered = (signed char)border_hovered; + window->ResizeBorderHeld = (signed char)border_held; // SCROLLBAR VISIBILITY @@ -6856,7 +6858,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); const bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch. - RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size, border_hovered, border_held); + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size); if (render_decorations_in_parent) window->DrawList = &window->DrawListInst; diff --git a/imgui_internal.h b/imgui_internal.h index 0b62a0364..3671f9cca 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2436,6 +2436,8 @@ struct IMGUI_API ImGuiWindow bool IsFallbackWindow; // Set on the "Debug##Default" window. bool IsExplicitChild; // Set when passed _ChildWindow, left to false by BeginDocked() bool HasCloseButton; // Set when the window has a close button (p_open != NULL) + signed char ResizeBorderHovered; // Current border being hovered for resize (-1: none, otherwise 0-3) + signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) short BeginCountPreviousFrame; // Number of Begin() during the previous frame short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0. From cfc71ab7c5284d4ba4b4fb435129f3e60ca925bf Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Nov 2023 14:00:39 +0100 Subject: [PATCH 2/9] Made ImDrawCallback_ResetRenderState special value -8 instead of -1 so it is pointer aligned (#6969) note https://github.com/dearimgui/dear_bindings/issues/56 may not be of direct use as-i. --- imgui.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index f8967455c..1e32eee2e 100644 --- a/imgui.h +++ b/imgui.h @@ -2540,9 +2540,9 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c // Special Draw callback value to request renderer backend to reset the graphics/render state. // The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address. -// This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored. -// It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call). -#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) +// This is useful, for example, if you submitted callbacks which you know have altered the render state and you want it to be restored. +// Render state is not reset by default because they are many perfectly useful way of altering render state (e.g. changing shader/blending settings before an Image call). +#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) // Typically, 1 command = 1 GPU draw call (unless command is a callback) // - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, From 376035fd01d7b7051af6d63fc6ee206d5fae031f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Nov 2023 14:03:40 +0100 Subject: [PATCH 3/9] Nav: fixed programmatic nav calls (e.g. SetKeyboardFocusHere() from storing io.KeyMods) Note that the g.NavMoveKeyMods -> g.NavJustMovedToKeyMods chain is not used in this branch. Multi-select uses it. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index cb20e5129..ec808425d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11362,7 +11362,7 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM g.NavMoveFlags = move_flags; g.NavMoveScrollFlags = scroll_flags; g.NavMoveForwardToNextFrame = false; - g.NavMoveKeyMods = g.IO.KeyMods; + g.NavMoveKeyMods = (move_flags & ImGuiNavMoveFlags_FocusApi) ? 0 : g.IO.KeyMods; g.NavMoveResultLocal.Clear(); g.NavMoveResultLocalVisible.Clear(); g.NavMoveResultOther.Clear(); From 561af15d67ab70476012de54fd3999699ec1a82d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Nov 2023 14:09:35 +0100 Subject: [PATCH 4/9] Internal: Added owner aware variant of IsMouseDoubleClicked() for consistency. Amend 4448d97. Note that functions entry points will eventually be merged into one, so this is not a problem. --- imgui.cpp | 7 +++++++ imgui_internal.h | 1 + 2 files changed, 8 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index ec808425d..acf6bc699 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8490,6 +8490,13 @@ bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); } +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button, ImGuiID owner_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), owner_id); +} + int ImGui::GetMouseClickedCount(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; diff --git a/imgui_internal.h b/imgui_internal.h index 3671f9cca..83af97330 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3129,6 +3129,7 @@ namespace ImGui IMGUI_API bool IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id); IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags = 0); IMGUI_API bool IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id); + IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button, ImGuiID owner_id); // [EXPERIMENTAL] Shortcut Routing // - ImGuiKeyChord = a ImGuiKey optionally OR-red with ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super. From ab47efd9a074310771a60626857510ee49989f1a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Nov 2023 15:35:31 +0100 Subject: [PATCH 5/9] Bits / comments --- docs/CHANGELOG.txt | 10 ++++++---- imgui.h | 16 ++++++++-------- imgui_demo.cpp | 7 ++++--- imgui_tables.cpp | 2 +- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f6e770110..49a664303 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -87,14 +87,15 @@ Other changes: - Windows: - BeginChild(): Added ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY to allow resizing child windows from the bottom/right border (toward layout direction). Resized child windows - settings are saved and persistent in .ini file. (#1666, #1496, #1395, #1710) + settings are saved and persistent in .ini file. (#1710) - BeginChild(): Added ImGuiChildFlags_Border as a replacement for 'bool border = true' parameter. - BeginChild(): Internal name used by child windows now omits the hash/id if the child - window is submitted in root of id stack of parent window. Makes debugging/metrics easier - and shorter to read in many cases. + window is submitted in root of id stack of parent window. + So "Parent/Child_XXXXXXX" becomes "Parent/Child" when in root of id stack. + Makes debugging/metrics easier and shorter to read in many cases. - Popups: clarified meaning of 'p_open != NULL' in BeginPopupModal() + set back user value to false when popup is closed in ways other than clicking the close button. (#6900) - - Double-clicking lower-left resize grip auto-resize (like lower-rightone). + - Double-clicking lower-left resize grip auto-resize (like lower-right one). - Double-clicking bottom or right window border auto-resize on a singles axis. - Use relative mouse movement for border resize when the border geometry has moved (e.g. resizing a child window triggering parent scroll) in order to avoid resizing @@ -182,6 +183,7 @@ Other changes: - ImDrawList: Added AddEllipse(), AddEllipseFilled(), PathEllipticalArcTo(). (#2743) [@Doohl] - ImVector: Added find_index() helper. - Demo: Added "Drag and Drop -> Tooltip at target location" demo. +- Demo: Added "Layout -> Child Windows -> Manual-resize" demo. (#1710) - Backends: GLFW: Clear emscripten's MouseWheel callback before shutdown. (#6790, #6096, #4019) [@halx99] - Backends: GLFW: Added support for F13 to F24 function keys. (#6891) - Backends: SDL2, SDL3: Added support for F13 to F24 function keys, AppBack, AppForward. (#6891) diff --git a/imgui.h b/imgui.h index 1e32eee2e..06a4b49fa 100644 --- a/imgui.h +++ b/imgui.h @@ -329,9 +329,9 @@ namespace ImGui // Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! - // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, - // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function - // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + // [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions + // such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding + // BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] // - Note that the bottom of window stack always contains a window called "Debug". IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); IMGUI_API void End(); @@ -339,11 +339,11 @@ namespace ImGui // Child Windows // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). - // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. - // Always call a matching EndChild() for each BeginChild() call, regardless of its return value. - // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, - // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function - // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting + // anything to the window. Always call a matching EndChild() for each BeginChild() call, regardless of its return value. + // [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions + // such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding + // BeginXXX function returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), ImGuiChildFlags child_flags = 0, ImGuiWindowFlags window_flags = 0); IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiChildFlags child_flags = 0, ImGuiWindowFlags window_flags = 0); IMGUI_API void EndChild(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 819838a25..a683428f9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2769,10 +2769,10 @@ static void ShowDemoWindowLayout() { HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents."); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg)); - ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY); + if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY)) + for (int n = 0; n < 10; n++) + ImGui::Text("Line %04d", n); ImGui::PopStyleColor(); - for (int n = 0; n < 10; n++) - ImGui::Text("Line %04d", n); ImGui::EndChild(); } @@ -5065,6 +5065,7 @@ static void ShowDemoWindowTables() ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns); + HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns."); if (ImGui::BeginTable("3ways", 3, flags)) { // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 3d8d3cffe..bc54546e2 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -321,7 +321,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG const ImVec2 avail_size = GetContentRegionAvail(); const ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f); const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size); - const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to auto-fitting windows! + const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows! if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size) { ItemSize(outer_rect); From cdbc21a191e4d3622881ed9d9da29e3a463f0a35 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Nov 2023 18:28:03 +0100 Subject: [PATCH 6/9] BeginChild(): Added ImGuiChildFlags_FrameStyle as a replacement for BeginChildFrame(). (#1666, #1496, #1395, #1710, #462, #503, #263) Effectively allows us to avoid extending BeginChildFrame() api to mimic BeginChild() new parameters. --- docs/CHANGELOG.txt | 8 ++++++++ imgui.cpp | 43 ++++++++++++++++++++++--------------------- imgui.h | 7 ++++--- imgui_demo.cpp | 12 ++++++++---- imgui_widgets.cpp | 4 ++-- 5 files changed, 44 insertions(+), 30 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 49a664303..823892d79 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,11 @@ Breaking changes: Before: BeginChild("Name", size, 0, ImGuiWindowFlags_AlwaysUseWindowPadding); After: BeginChild("Name", size, ImGuiChildFlags_AlwaysUseWindowPadding, 0); Kept inline redirection enum (will obsolete later) so existing code will work. + - BeginChildFrame()/EndChildFrame(): removed functions in favor of using BeginChild() with + the ImGuiChildFlags_FrameStyle flag. Kept inline redirection function (will obsolete). + Those functions were merely PushStyle/PopStyle helpers and custom versions are easy to create. + (The removal isn't so much motivated by needing to add the feature in BeginChild(), but by the + necessity to avoid BeginChildFrame() signature mismatching BeginChild() signature and features.) - Debug Tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIDStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631) - IO: Removed io.MetricsActiveAllocations introduced in 1.63, was displayed in Metrics and unlikely to @@ -89,6 +94,9 @@ Other changes: child windows from the bottom/right border (toward layout direction). Resized child windows settings are saved and persistent in .ini file. (#1710) - BeginChild(): Added ImGuiChildFlags_Border as a replacement for 'bool border = true' parameter. + - BeginChild(): Added ImGuiChildFlags_FrameStyle as a replacement for BeginChildFrame(), + use it to make child window use FrameBg, FrameRounding, FrameBorderSize, FramePadding + instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. - BeginChild(): Internal name used by child windows now omits the hash/id if the child window is submitted in root of id stack of parent window. So "Parent/Child_XXXXXXX" becomes "Parent/Child" when in root of id stack. diff --git a/imgui.cpp b/imgui.cpp index acf6bc699..b80499721 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -424,6 +424,8 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2023/11/07 (1.90.0) - removed BeginChildFrame()/EndChildFrame() in favor of using BeginChild() with the ImGuiChildFlags_FrameStyle flag. kept inline redirection function (will obsolete). + those functions were merely PushStyle/PopStyle helpers, the removal isn't so much motivated by needing to add the feature in BeginChild(), but by the necessity to avoid BeginChildFrame() signature mismatching BeginChild() signature and features. - 2023/11/02 (1.90.0) - BeginChild: upgraded 'bool border = true' parameter to 'ImGuiChildFlags flags' type, added ImGuiChildFlags_Border equivalent. As with our prior "bool-to-flags" API updates, the ImGuiChildFlags_Border value is guaranteed to be == true forever to ensure a smoother transition, meaning all existing calls will still work. - old: BeginChild("Name", size, true) - new: BeginChild("Name", size, ImGuiChildFlags_Border) @@ -5442,7 +5444,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I IM_ASSERT(id != 0); // Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument. - const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; + const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_FrameStyle; IM_UNUSED(ImGuiChildFlags_SupportedMask_); IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?"); if (window_flags & ImGuiWindowFlags_AlwaysAutoResize) @@ -5458,6 +5460,17 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I if ((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0) window_flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + // Special framed style + if (child_flags & ImGuiChildFlags_FrameStyle) + { + PushStyleColor(ImGuiCol_ChildBg, g.Style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, g.Style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, g.Style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.FramePadding); + child_flags |= ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding; + window_flags |= ImGuiWindowFlags_NoMove; + } + // Forward child flags g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags; g.NextWindowData.ChildFlags = child_flags; @@ -5482,13 +5495,21 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I else ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id); + // Set style const float backup_border_size = g.Style.ChildBorderSize; if ((child_flags & ImGuiChildFlags_Border) == 0) g.Style.ChildBorderSize = 0.0f; // Begin into window const bool ret = Begin(temp_window_name, NULL, window_flags); + + // Restore style g.Style.ChildBorderSize = backup_border_size; + if (child_flags & ImGuiChildFlags_FrameStyle) + { + PopStyleVar(3); + PopStyleColor(); + } ImGuiWindow* child_window = g.CurrentWindow; child_window->ChildId = id; @@ -5554,26 +5575,6 @@ void ImGui::EndChild() g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } -// Helper to create a child window / scrolling region that looks like a normal widget frame. -bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) -{ - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; - PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); - PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); - PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); - PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); - bool ret = BeginChild(id, size, ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_NoMove | extra_flags); - PopStyleVar(3); - PopStyleColor(); - return ret; -} - -void ImGui::EndChildFrame() -{ - EndChild(); -} - static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) { window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); diff --git a/imgui.h b/imgui.h index 06a4b49fa..869d8d654 100644 --- a/imgui.h +++ b/imgui.h @@ -24,7 +24,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.90 WIP" -#define IMGUI_VERSION_NUM 18997 +#define IMGUI_VERSION_NUM 18998 #define IMGUI_HAS_TABLE /* @@ -894,8 +894,6 @@ namespace ImGui IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) IMGUI_API ImGuiStorage* GetStateStorage(); - IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame - IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) // Text Utilities IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); @@ -1024,6 +1022,7 @@ enum ImGuiChildFlags_ ImGuiChildFlags_AlwaysUseWindowPadding = 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered child windows because it makes more sense) ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless ImGuiWindowFlags_NoSavedSettings passed to window flags) ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). " + ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. }; // Flags for ImGui::InputText() @@ -3130,6 +3129,8 @@ namespace ImGui namespace ImGui { // OBSOLETED in 1.90.0 (from September 2023) + static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } + static inline void EndChildFrame() { EndChild(); } static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) { return BeginChild(str_id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a683428f9..7e0a82fc1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2796,6 +2796,10 @@ static void ShowDemoWindowLayout() ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY); + ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle); + ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding."); + if (child_flags & ImGuiChildFlags_FrameStyle) + override_bg_color = false; ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); if (override_bg_color) @@ -6273,7 +6277,7 @@ void ImGui::ShowAboutWindow(bool* p_open) bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); - ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); + ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle); if (copy_to_clipboard) { ImGui::LogToClipboard(); @@ -6389,7 +6393,7 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::LogText("\n```\n"); ImGui::LogFinish(); } - ImGui::EndChildFrame(); + ImGui::EndChild(); } ImGui::End(); } @@ -8366,13 +8370,13 @@ void ShowExampleAppDocuments(bool* p_open) { ImGui::Text("Save change to the following items?"); float item_height = ImGui::GetTextLineHeightWithSpacing(); - if (ImGui::BeginChildFrame(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height))) + if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle)) { for (int n = 0; n < close_queue.Size; n++) if (close_queue[n]->Dirty) ImGui::Text("%s", close_queue[n]->Name); } - ImGui::EndChildFrame(); + ImGui::EndChild(); ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); if (ImGui::Button("Yes", button_size)) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 397300f0d..dcba6be2a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6901,7 +6901,7 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size); } - BeginChildFrame(id, frame_bb.GetSize()); + BeginChild(id, frame_bb.GetSize(), ImGuiChildFlags_FrameStyle); return true; } @@ -6912,7 +6912,7 @@ void ImGui::EndListBox() IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?"); IM_UNUSED(window); - EndChildFrame(); + EndChild(); EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label } From fa4c49b4a74dff5da56f31a81dccbf01aa043733 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Nov 2023 17:15:57 +0100 Subject: [PATCH 7/9] BeginChild(): resizing is only clamped on axis where there's no scrollbar. Added an extra ResizeX in Demo->Simple Layout. --- imgui.cpp | 9 +++++++-- imgui_demo.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b80499721..c0bb23002 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6018,8 +6018,13 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX); ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX); border_target = ImClamp(border_target, clamp_min, clamp_max); - if (window->Flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent - border_target = ImClamp(border_target, window->ParentWindow->InnerClipRect.Min, window->ParentWindow->InnerClipRect.Max); + if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent + { + if ((flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (flags & ImGuiWindowFlags_NoScrollbar)) + border_target.x = ImClamp(border_target.x, window->ParentWindow->InnerClipRect.Min.x, window->ParentWindow->InnerClipRect.Max.x); + if (flags & ImGuiWindowFlags_NoScrollbar) + border_target.y = ImClamp(border_target.y, window->ParentWindow->InnerClipRect.Min.y, window->ParentWindow->InnerClipRect.Max.y); + } if (!ignore_resize) CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7e0a82fc1..5b0a5ba85 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7425,7 +7425,7 @@ static void ShowExampleAppLayout(bool* p_open) // Left static int selected = 0; { - ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Border); + ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX); for (int i = 0; i < 100; i++) { // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav From 44345c21083b6218d735154670361482e3768780 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Nov 2023 20:14:54 +0100 Subject: [PATCH 8/9] Better documented the difference between BeginListBox() and BeginChild() w/ ImGuiChildFlags_FrameStyle. BeginListBox() can't yet expose child flags because coarse clipping require query of stored size (same issue as with adding resize support to Tables). --- imgui.cpp | 12 ++++-------- imgui.h | 4 ++-- imgui_demo.cpp | 3 +++ imgui_widgets.cpp | 3 ++- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c0bb23002..58c21b314 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14287,8 +14287,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("KEY OWNERS"); { Indent(); - if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) - { + if (BeginChild("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY, ImGuiWindowFlags_NoSavedSettings)) for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); @@ -14298,15 +14297,13 @@ void ImGui::ShowMetricsWindow(bool* p_open) owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : ""); DebugLocateItemOnHover(owner_data->OwnerCurr); } - EndListBox(); - } + EndChild(); Unindent(); } Text("SHORTCUT ROUTING"); { Indent(); - if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) - { + if (BeginChild("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY, ImGuiWindowFlags_NoSavedSettings)) for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; @@ -14320,8 +14317,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) idx = routing_data->NextEntryIndex; } } - EndListBox(); - } + EndChild(); Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); Unindent(); } diff --git a/imgui.h b/imgui.h index 869d8d654..6c9e63fe1 100644 --- a/imgui.h +++ b/imgui.h @@ -635,8 +635,8 @@ namespace ImGui IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. // Widgets: List Boxes - // - This is essentially a thin wrapper to using BeginChild/EndChild with some stylistic changes. - // - The BeginListBox()/EndListBox() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() or any items. + // - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. + // - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items. // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5b0a5ba85..6fffeac2d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1250,6 +1250,9 @@ static void ShowDemoWindowWidgets() IMGUI_DEMO_MARKER("Widgets/List Boxes"); if (ImGui::TreeNode("List boxes")) { + // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. + // You may be tempted to simply use BeginChild() directly, however note that BeginChild() requires EndChild() to always be called (inconsistent with BeginListBox()/EndListBox()). + // Using the generic BeginListBox() API, you have full control over how to display the combo contents. // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dcba6be2a..b597d27de 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6863,6 +6863,7 @@ void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_d // - ListBox() //------------------------------------------------------------------------- +// This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. // Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" // Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) @@ -6892,7 +6893,7 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) return false; } - // FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well. + // FIXME-OPT: We could omit the BeginGroup() if label_size.x == 0.0f but would need to omit the EndGroup() as well. BeginGroup(); if (label_size.x > 0.0f) { From 0d3b468cb35796df9db5f3895931925de07b3a6c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Oct 2023 17:39:56 +0200 Subject: [PATCH 9/9] BeginChild(): added ImGuiChildFlags_AutoResizeX, ImGuiChildFlags_AutoResizeY, ImGuiChildFlags_AlwaysAutoResize + support for SetNextWindowSizeConstraints(). (#1666, #1395, #1496, #1710) + Demo Note that child don't report ideal content size to parent so nesting may be difficult. Note 4e4042b simplified SkipItems logic. Note e2035a5 standardizing WindowMinSize application on child --- docs/CHANGELOG.txt | 16 ++++++++++++++++ imgui.cpp | 42 +++++++++++++++++++++++++++++------------- imgui.h | 17 ++++++++++++++++- imgui_demo.cpp | 18 ++++++++++++++++++ 4 files changed, 79 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 823892d79..a32ce3ca8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -94,6 +94,21 @@ Other changes: child windows from the bottom/right border (toward layout direction). Resized child windows settings are saved and persistent in .ini file. (#1710) - BeginChild(): Added ImGuiChildFlags_Border as a replacement for 'bool border = true' parameter. + - BeginChild(): Added ImGuiChildFlags_AutoResizeX and ImGuiChildFlags_AutoResizeY to auto-resize + on one axis, while generally providing a size on the other axis. (#1666, #1395, #1496, #1710) + e.g. BeginChild("name", {-FLT_MIN, 0.0f}, ImGuiChildFlags_AutoResizeY); + - Size is only reevaluated if the child window is within visible boundaries or just appearing. + This allows coarse clipping to be performed and auto-resizing childs to return false when + hidden because of being scrolled out. + - Combining this with also specifying ImGuiChildFlags_AlwaysAutoResize disables + this optimization, meaning child contents will never be clipped (not recommended). + - Please be considerate that child are full windows and carry significiant overhead: + combining auto-resizing for both axises to create a non-scrolling child to merely draw + a border would be better more optimally using BeginGroup(). + (until we come up with new helpers for framed groups and work-rect adjustments). + - BeginChild(): made it possible to use SetNextWindowSizeConstraints() rectangle, often + useful when ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY. (#1666, #1395, #1496) + Custom constraint callback are not supported with child window. - BeginChild(): Added ImGuiChildFlags_FrameStyle as a replacement for BeginChildFrame(), use it to make child window use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. @@ -192,6 +207,7 @@ Other changes: - ImVector: Added find_index() helper. - Demo: Added "Drag and Drop -> Tooltip at target location" demo. - Demo: Added "Layout -> Child Windows -> Manual-resize" demo. (#1710) +- Demo: Added "Layout -> Child Windows -> Auto-resize with constraints" demo. (#1666, #1395, #1496, #1710) - Backends: GLFW: Clear emscripten's MouseWheel callback before shutdown. (#6790, #6096, #4019) [@halx99] - Backends: GLFW: Added support for F13 to F24 function keys. (#6891) - Backends: SDL2, SDL3: Added support for F13 to F24 function keys, AppBack, AppForward. (#6891) diff --git a/imgui.cpp b/imgui.cpp index 58c21b314..3f32708a2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5444,19 +5444,29 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I IM_ASSERT(id != 0); // Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument. - const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_FrameStyle; + const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle; IM_UNUSED(ImGuiChildFlags_SupportedMask_); IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?"); - if (window_flags & ImGuiWindowFlags_AlwaysAutoResize) - IM_ASSERT((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0 && "Cannot combine ImGuiChildFlags_ResizeX/ImGuiChildFlags_ResizeY with ImGuiWindowFlags_AlwaysAutoResize."); + IM_ASSERT((window_flags & ImGuiWindowFlags_AlwaysAutoResize) == 0 && "Cannot specify ImGuiWindowFlags_AlwaysAutoResize for BeginChild(). Use ImGuiChildFlags_AlwaysAutoResize!"); + if (child_flags & ImGuiChildFlags_AlwaysAutoResize) + { + IM_ASSERT((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0 && "Cannot use ImGuiChildFlags_ResizeX or ImGuiChildFlags_ResizeY with ImGuiChildFlags_AlwaysAutoResize!"); + IM_ASSERT((child_flags & (ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY)) != 0 && "Must use ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY with ImGuiChildFlags_AlwaysAutoResize!"); + } #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding) child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding; #endif + if (child_flags & ImGuiChildFlags_AutoResizeX) + child_flags &= ~ImGuiChildFlags_ResizeX; + if (child_flags & ImGuiChildFlags_AutoResizeY) + child_flags &= ~ImGuiChildFlags_ResizeY; + // Set window flags window_flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar; window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag - + if (child_flags & (ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize)) + window_flags |= ImGuiWindowFlags_AlwaysAutoResize; if ((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0) window_flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; @@ -5478,12 +5488,9 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I // Forward size // Important: Begin() has special processing to switch condition to ImGuiCond_FirstUseEver for a given axis when ImGuiChildFlags_ResizeXXX is set. // (the alternative would to store conditional flags per axis, which is possible but more code) - const ImVec2 content_avail = GetContentRegionAvail(); - ImVec2 size = ImTrunc(size_arg); - if (size.x <= 0.0f) - size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too many issues) - if (size.y <= 0.0f) - size.y = ImMax(content_avail.y + size.y, 4.0f); + const ImVec2 size_avail = GetContentRegionAvail(); + const ImVec2 size_default((child_flags & ImGuiChildFlags_AutoResizeX) ? 0.0f : size_avail.x, (child_flags & ImGuiChildFlags_AutoResizeY) ? 0.0f : size_avail.y); + const ImVec2 size = CalcItemSize(size_arg, size_default.x, size_default.y); SetNextWindowSize(size); // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. @@ -7010,7 +7017,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); if (!g.LogEnabled && !nav_request) if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) - window->HiddenFramesCanSkipItems = 1; + { + if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + window->HiddenFramesCannotSkipItems = 1; + else + window->HiddenFramesCanSkipItems = 1; + } // Hide along with parent or if parent is collapsed if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) @@ -7591,10 +7603,14 @@ void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond con IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + // Enable auto-fit (not done in BeginChild() path unless appearing or combined with ImGuiChildFlags_AlwaysAutoResize) + if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || window->Appearing || (window->ChildFlags & ImGuiChildFlags_AlwaysAutoResize) != 0) + window->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0; + if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || window->Appearing || (window->ChildFlags & ImGuiChildFlags_AlwaysAutoResize) != 0) + window->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0; + // Set ImVec2 old_size = window->SizeFull; - window->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0; - window->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0; if (size.x <= 0.0f) window->AutoFitOnlyGrows = false; else diff --git a/imgui.h b/imgui.h index 6c9e63fe1..06ce5ae17 100644 --- a/imgui.h +++ b/imgui.h @@ -338,7 +338,12 @@ namespace ImGui // Child Windows // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. - // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). + // - Manual sizing (each axis can use a different setting e.g. ImVec2(0.0f, 400.0f)): + // == 0.0f: use remaining parent window size for this axis. + // > 0.0f: use specified size for this axis. + // < 0.0f: right/bottom-align to specified distance from available content boundaries. + // - Specifying ImGuiChildFlags_AutoResizeX or ImGuiChildFlags_AutoResizeY makes the sizing automatic based on child contents. + // Combining both ImGuiChildFlags_AutoResizeX _and_ ImGuiChildFlags_AutoResizeY defeats purpose of a scrolling region and is NOT recommended. // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // anything to the window. Always call a matching EndChild() for each BeginChild() call, regardless of its return value. // [Important: due to legacy reason, Begin/End and BeginChild/EndChild are inconsistent with all other functions @@ -1015,6 +1020,13 @@ enum ImGuiWindowFlags_ // Flags for ImGui::BeginChild() // (Legacy: bit 0 must always correspond to ImGuiChildFlags_Border to be backward compatible with old API using 'bool border'. +// About using AutoResizeX/AutoResizeY flags: +// - May be combined with SetNextWindowSizeConstraints() to set a min/max size for each axis (see "Demo->Child->Auto-resize with Constraints"). +// - Size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing. +// - This allows BeginChild() to return false when not within boundaries (e.g. when scrolling), which is more optimal. BUT it won't update its auto-size while clipped. +// While not perfect, it is a better default behavior as the always-on performance gain is more valuable than the occasional "resizing after becoming visible again" glitch. +// - You may also use ImGuiChildFlags_AlwaysAutoResize to force an update even when child window is not in view. +// HOWEVER PLEASE UNDERSTAND THAT DOING SO WILL PREVENT BeginChild() FROM EVER RETURNING FALSE, disabling benefits of coarse clipping. enum ImGuiChildFlags_ { ImGuiChildFlags_None = 0, @@ -1022,6 +1034,9 @@ enum ImGuiChildFlags_ ImGuiChildFlags_AlwaysUseWindowPadding = 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered child windows because it makes more sense) ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless ImGuiWindowFlags_NoSavedSettings passed to window flags) ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). " + ImGuiChildFlags_AutoResizeX = 1 << 4, // Enable auto-resizing width. Read "IMPORTANT: Size measurement" details above. + ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above. + ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED. ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6fffeac2d..457c61fb9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2779,6 +2779,23 @@ static void ShowDemoWindowLayout() ImGui::EndChild(); } + // Child 4: auto-resizing height with a limit + ImGui::SeparatorText("Auto-resize with constraints"); + { + static int draw_lines = 3; + static int max_height_in_lines = 10; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragInt("Lines Count", &draw_lines, 0.2f); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f); + + ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines)); + if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) + for (int n = 0; n < draw_lines; n++) + ImGui::Text("Line %04d", n); + ImGui::EndChild(); + } + ImGui::SeparatorText("Misc/Advanced"); // Demonstrate a few extra things @@ -6605,6 +6622,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "Left-click on color square to open color picker,\n" "Right-click to open edit options menu."); + ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)); ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); ImGui::PushItemWidth(ImGui::GetFontSize() * -12); for (int i = 0; i < ImGuiCol_COUNT; i++)