From ade2acfd1ddef8a45424d128d3e80bf13b948bcc Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Oct 2023 14:44:24 +0200 Subject: [PATCH 01/13] Inputs: Added IsKeyChordPressed() public helper function. Amend 99913b5 --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 6 ++++++ imgui.h | 1 + 3 files changed, 9 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b63338bf..7f71aca3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -141,6 +141,8 @@ Other changes: - Ensure calling AddFontXXX function doesn't invalidates ImFont's ConfigData pointers prior to building again. (#6825) - imgui_freetype: Fixed a warning and leak in IMGUI_ENABLE_FREETYPE_LUNASVG support. (#6842, #6591) +- Inputs: Added IsKeyChordPressed() helper function e.g. IsKeyChordPressed(ImGuiMod_Ctrl | ImGuiKey_S). + (Note that ImGuiMod_Shortcut may be used as an alias for Cmd on OSX and Ctrl on other systems). - Misc: Most text functions also treat "%.*s" (along with "%s") specially to avoid formatting. (#3466, #6846) - IO: Add extra keys to ImGuiKey enum: ImGuiKey_F13 to ImGuiKey_F24. (#6891, #4921) - IO: Add extra keys to ImGuiKey enum: ImGuiKey_AppBack, ImGuiKey_AppForward. (#4921) diff --git a/imgui.cpp b/imgui.cpp index b753b61d..adb0b1b1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9136,6 +9136,12 @@ void ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags) } } +// This is the only public API until we expose owner_id versions of the API as replacements. +bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord) +{ + return IsKeyChordPressed(key_chord, 0, ImGuiInputFlags_None); +} + // This is equivalent to comparing KeyMods + doing a IsKeyPressed() bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) { diff --git a/imgui.h b/imgui.h index be5283c0..2c691aec 100644 --- a/imgui.h +++ b/imgui.h @@ -913,6 +913,7 @@ namespace ImGui IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? + IMGUI_API bool IsKeyChordPressed(ImGuiKeyChord key_chord); // was key chord (mods + key) pressed, e.g. you can pass 'ImGuiMod_Ctrl | ImGuiKey_S' as a key-chord. This doesn't do any routing or focus check, please consider using Shortcut() function instead. IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared. IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call. From c95fbb44642da914d78ce3f1e15a53ea54ae60f0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Oct 2023 16:06:07 +0200 Subject: [PATCH 02/13] Windows: Double-clicking bottom or right window border auto-resize on a singles axis. --- docs/CHANGELOG.txt | 3 +- imgui.cpp | 88 ++++++++++++++++++++++++++++------------------ imgui_internal.h | 1 - 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7f71aca3..c0039a88 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -73,7 +73,8 @@ Other changes: - Windows: - 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) - - Can also auto-resize by double-clicking lower-left resize grip (not only lower-right one). + - Double-clicking lower-left resize grip auto-resize (like lower-rightone). + - Double-clicking bottom or right window border auto-resize on a singles axis. - Separators: - Altered end-points to use more standard boundaries. (#205, #4787, #1643) Left position is always current cursor X position. diff --git a/imgui.cpp b/imgui.cpp index adb0b1b1..76af94a6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1098,9 +1098,9 @@ static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); // Misc static void UpdateSettings(); -static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); -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 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 RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); static void RenderDimmedBackgrounds(); @@ -5838,7 +5838,7 @@ ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir) // Handle resize for: Resize Grips, Borders, Gamepad // Return true when using auto-fit (double-click on resize grip) -static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect) +static int ImGui::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) { ImGuiContext& g = *GImGui; ImGuiWindowFlags flags = window->Flags; @@ -5848,8 +5848,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s if (window->WasActive == false) // Early out to avoid running this code for e.g. a hidden implicit/fallback Debug window. return false; - bool ret_auto_fit = false; - const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; + int ret_auto_fit_mask = 0x00; const float grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); const float grip_hover_inner_size = IM_TRUNC(grip_draw_size * 0.75f); const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f; @@ -5884,11 +5883,11 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s if (hovered || held) g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; - if (held && g.IO.MouseClickedCount[0] == 2) + if (held && g.IO.MouseDoubleClicked[0]) { - // Manual auto-fit when double-clicking + // Auto-fit when double-clicking size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); - ret_auto_fit = true; + ret_auto_fit_mask = 0x03; // Both axises ClearActiveID(); } else if (held) @@ -5906,8 +5905,12 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s if (resize_grip_n == 0 || held || hovered) resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); } - for (int border_n = 0; border_n < resize_border_count; border_n++) + + const int resize_border_mask = g.IO.ConfigWindowsResizeFromEdges ? 0x0F : 0x00; + for (int border_n = 0; border_n < 4; border_n++) { + if ((resize_border_mask & (1 << border_n)) == 0) + continue; const ImGuiResizeBorderDef& def = resize_border_def[border_n]; const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; @@ -5920,10 +5923,23 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) { g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + if (hovered) + *border_hovered = border_n; if (held) *border_held = border_n; } - if (held) + if (held && g.IO.MouseDoubleClicked[0]) + { + // Double-clicking bottom or right border auto-fit on this axis + // FIXME: Support top and right borders: rework CalcResizePosSizeFromAnyCorner() to be reusable in both cases. + if (border_n == 1 || border_n == 3) // Right and bottom border + { + size_target[axis] = CalcWindowSizeAfterConstraint(window, size_auto_fit)[axis]; + ret_auto_fit_mask |= (1 << axis); + } + ClearActiveID(); + } + else if (held) { 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); @@ -5969,18 +5985,17 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s // Apply back modified position/size to window if (size_target.x != FLT_MAX) - { - window->SizeFull = size_target; - MarkIniSettingsDirty(window); - } + window->Size.x = window->SizeFull.x = size_target.x; + if (size_target.y != FLT_MAX) + window->Size.y = window->SizeFull.y = size_target.y; if (pos_target.x != FLT_MAX) - { - window->Pos = ImTrunc(pos_target); - MarkIniSettingsDirty(window); - } + window->Pos.x = ImTrunc(pos_target.x); + if (pos_target.y != FLT_MAX) + window->Pos.y = ImTrunc(pos_target.y); + if (size_target.x != FLT_MAX || size_target.y != FLT_MAX || pos_target.x != FLT_MAX|| pos_target.y != FLT_MAX) + MarkIniSettingsDirty(window); - window->Size = window->SizeFull; - return ret_auto_fit; + return ret_auto_fit_mask; } static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_rect) @@ -5992,7 +6007,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) +static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window, int border_hovered, int border_held) { ImGuiContext& g = *GImGui; float rounding = window->WindowRounding; @@ -6000,14 +6015,15 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) 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); - int border_held = window->ResizeBorderHeld; - if (border_held != -1) + if (border_hovered != -1 || border_held != -1) { - const ImGuiResizeBorderDef& def = resize_border_def[border_held]; - ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); + const int border_n = (border_held != -1) ? border_held : border_hovered; + 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); 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(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual + window->DrawList->PathStroke(border_col, 0, ImMax(2.0f, border_size)); // Thicker than usual } if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) { @@ -6018,7 +6034,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) // 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) +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) { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; @@ -6101,7 +6117,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar // Borders if (handle_borders_and_resize_grips) - RenderWindowOuterBorders(window); + RenderWindowOuterBorders(window, border_hovered, border_held); } } @@ -6627,14 +6643,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) #endif // Handle manual resize: Resize Grips, Borders, Gamepad - int border_held = -1; + int border_hovered = -1, border_held = -1; ImU32 resize_grip_col[4] = {}; const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); if (!window->Collapsed) - if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) - use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; - window->ResizeBorderHeld = (signed char)border_held; + if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) + { + if (auto_fit_mask & (1 << ImGuiAxis_X)) + use_current_size_for_scrollbar_x = true; + if (auto_fit_mask & (1 << ImGuiAxis_Y)) + use_current_size_for_scrollbar_y = true; + } // SCROLLBAR VISIBILITY @@ -6749,7 +6769,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); + 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); if (render_decorations_in_parent) window->DrawList = &window->DrawListInst; diff --git a/imgui_internal.h b/imgui_internal.h index 16532fb4..3f493f7e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2428,7 +2428,6 @@ 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 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 e2035a514cab4fcbfbe2bc3148ac770882aa2a1d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Oct 2023 17:28:16 +0200 Subject: [PATCH 03/13] Windows: shared code for CalcWindowMinSize(). + Don't apply WindowMinSize during auto-fit of child windows (not exercised yet). --- imgui.cpp | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 76af94a6..d0fea68a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5646,6 +5646,24 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) return window; } +static inline ImVec2 CalcWindowMinSize(ImGuiWindow* window) +{ + // Popups, menus and childs bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) + ImGuiContext& g = *GImGui; + ImVec2 size_min; + if (window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_ChildWindow)) + { + size_min = ImVec2(4.0f, 4.0f); + } + else + { + ImGuiWindow* window_for_height = window; + size_min = g.Style.WindowMinSize; + size_min.y = ImMax(size_min.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows + } + return size_min; +} + static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired) { ImGuiContext& g = *GImGui; @@ -5671,14 +5689,8 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& s } // Minimum size - if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) - { - ImGuiWindow* window_for_height = window; - new_size = ImMax(new_size, g.Style.WindowMinSize); - const float minimum_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f); - new_size.y = ImMax(new_size.y, minimum_height); // Reduce artifacts with very small windows - } - return new_size; + ImVec2 size_min = CalcWindowMinSize(window); + return ImMax(new_size, size_min); } static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal) @@ -5717,12 +5729,7 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont else { // Maximum window size is determined by the viewport size or monitor size - const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0; - const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0; - ImVec2 size_min = style.WindowMinSize; - if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) - size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); - + ImVec2 size_min = CalcWindowMinSize(window); ImVec2 avail_size = ImGui::GetMainViewport()->WorkSize; ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - style.DisplaySafeAreaPadding * 2.0f)); From bc3c6e74e6644d074d37e7d5c7fbc3ac3d77689e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Oct 2023 17:40:32 +0200 Subject: [PATCH 04/13] Windows: fixed double-clicked border from showing highlighted at the new position. Amend c95fbb4 + misc tidying up, comments of grip/border resizing struct. --- imgui.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d0fea68a..99063e1c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5779,7 +5779,7 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co *out_size = size_constrained; } -// Data for resizing from corner +// Data for resizing from resize grip / corner struct ImGuiResizeGripDef { ImVec2 CornerPosN; @@ -5797,9 +5797,9 @@ static const ImGuiResizeGripDef resize_grip_def[4] = // Data for resizing from borders struct ImGuiResizeBorderDef { - ImVec2 InnerDir; - ImVec2 SegmentN1, SegmentN2; - float OuterAngle; + ImVec2 InnerDir; // Normal toward inside + ImVec2 SegmentN1, SegmentN2; // End positions, normalized (0,0: upper left) + float OuterAngle; // Angle toward outside }; static const ImGuiResizeBorderDef resize_border_def[4] = { @@ -5927,14 +5927,10 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si ItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav); ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); - if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) - { + if (hovered && g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) + hovered = false; + if (hovered || held) g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; - if (hovered) - *border_hovered = border_n; - if (held) - *border_held = border_n; - } if (held && g.IO.MouseDoubleClicked[0]) { // Double-clicking bottom or right border auto-fit on this axis @@ -5943,6 +5939,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si { size_target[axis] = CalcWindowSizeAfterConstraint(window, size_auto_fit)[axis]; ret_auto_fit_mask |= (1 << axis); + hovered = held = false; // So border doesn't show highlighted at new position } ClearActiveID(); } @@ -5955,6 +5952,10 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si border_target = ImClamp(border_target, clamp_min, clamp_max); CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); } + if (hovered) + *border_hovered = border_n; + if (held) + *border_held = border_n; } PopID(); @@ -5999,8 +6000,8 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si window->Pos.x = ImTrunc(pos_target.x); if (pos_target.y != FLT_MAX) window->Pos.y = ImTrunc(pos_target.y); - if (size_target.x != FLT_MAX || size_target.y != FLT_MAX || pos_target.x != FLT_MAX|| pos_target.y != FLT_MAX) - MarkIniSettingsDirty(window); + if (size_target.x != FLT_MAX || size_target.y != FLT_MAX || pos_target.x != FLT_MAX || pos_target.y != FLT_MAX) + MarkIniSettingsDirty(window); return ret_auto_fit_mask; } From 4e4042bc335b28ae6027ed17ed46784d66a19399 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Oct 2023 15:12:29 +0200 Subject: [PATCH 05/13] Windows: tidying up skipitems logic at end of Begin(), normally should be no meaningful side-effect. --- imgui.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 99063e1c..772d0a17 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6915,18 +6915,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Update visibility if (first_begin_of_the_frame) { - if (flags & ImGuiWindowFlags_ChildWindow) + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ChildMenu)) { // Child window can be out of sight and have "negative" clip windows. // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); - if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) // FIXME: Doesn't make sense for ChildWindow?? - { - 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; - } + 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; // Hide along with parent or if parent is collapsed if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) From 8ee85137d886c3bbe2dbe38eb24d65178c3994e0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Oct 2023 15:27:25 +0200 Subject: [PATCH 06/13] 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. # Conflicts: # docs/CHANGELOG.txt # imgui.h --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 4 +++- imgui.h | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c0039a88..aa0dcd1f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,9 @@ Other changes: Previously was inconsistent and only enabled when stepping through a non-input item. (#6802, #3092, #5759, #787) - Windows: + - 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. - 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). diff --git a/imgui.cpp b/imgui.cpp index 772d0a17..a11f2281 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5444,7 +5444,9 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b // 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. const char* temp_window_name; - if (name) + if (name && parent_window->IDStack.back() == parent_window->ID) + ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s", parent_window->Name, name); // May omit ID if in root of ID stack + else if (name) ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s_%08X", parent_window->Name, name, id); else ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id); diff --git a/imgui.h b/imgui.h index 2c691aec..4fbce76a 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 18995 +#define IMGUI_VERSION_NUM 18996 #define IMGUI_HAS_TABLE /* From 313676d200f093e2694b5cfca574f72a2b116c85 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Oct 2023 17:04:51 +0200 Subject: [PATCH 07/13] Settings: omit outputing Collapsed=0 in .ini file. Changelog + docs tweaks --- docs/CHANGELOG.txt | 28 ++++++++++++++-------------- docs/README.md | 14 +++++++------- imgui.cpp | 3 ++- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index aa0dcd1f..2623b63e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,9 +67,6 @@ Breaking changes: Other changes: -- Nav: Tabbing always enable nav highlight when ImGuiConfigFlags_NavEnableKeyboard is set. - Previously was inconsistent and only enabled when stepping through a non-input item. - (#6802, #3092, #5759, #787) - Windows: - 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 @@ -80,9 +77,8 @@ Other changes: - Double-clicking bottom or right window border auto-resize on a singles axis. - Separators: - Altered end-points to use more standard boundaries. (#205, #4787, #1643) - Left position is always current cursor X position. - Right position is always work-rect rightmost edge. - - Effectively means that: + Left position is always current cursor X position, right position is always work-rect + rightmost edge. It effectively means that: - A separator in the root of a window will end up a little more distant from edges than previously (essentially following WindowPadding instead of clipping edges). - A separator inside a table cell end up a little distance from edges instead of @@ -100,8 +96,8 @@ Other changes: - Made is possible to combine ImGuiHoveredFlags_ForTooltip with a ImGuiHoveredFlags_DelayXXX override. (#1485) - Drag and Drop: - - Reworked drop target highlight: reduce rectangle to its visible portion, and - then expand slightly. A full rectangle is always visible and it may protrude slightly. (#4281, #3272) + - Reworked drop target highlight: reduce rectangle to its visible portion, and then expand + slightly. A full rectangle is always visible and it may protrude slightly. (#4281, #3272) - Fixed submitting a tooltip from drop target location when using AcceptDragDropPayload() with ImGuiDragDropFlags_AcceptNoPreviewTooltip and submitting a tooltip manually. - Tables: @@ -126,19 +122,23 @@ Other changes: - MenuBar: Fixed an issue where layouting an item in the menu-bar would erroneously register contents size in a way that would affect the scrolling layer. Was most often noticable when using an horizontal scrollbar. (#6789) +- InputText: + - InputTextMultiline: Fixed a crash pressing Down on last empty line of a multiline buffer. + (regression from 1.89.2, only happened in some states). (#6783, #6000) + - InputTextMultiline: Fixed Tabbing cycle leading to a situation where Enter key wouldn't + be accepted by the widget when navigation highlight is visible. (#6802, #3092, #5759, #787) +- Nav: Tabbing always enable nav highlight when ImGuiConfigFlags_NavEnableKeyboard is set. + Previously was inconsistent and only enabled when stepping through a non-input item. + (#6802, #3092, #5759, #787) - TreeNode: Added ImGuiTreeNodeFlags_SpanAllColumns for use in tables. (#3151, #3565, #2451, #2438) - TabBar: Fixed position of unsaved document marker (ImGuiTabItemFlags_UnsavedDocument) which was accidentally offset in 1.89.9. (#6862) [@alektron] -- InputTextMultiline: Fixed a crash pressing Down on last empty line of a multiline buffer. - (regression from 1.89.2, only happened in some states). (#6783, #6000) -- InputTextMultiline: Fixed Tabbing cycle leading to a situation where Enter key wouldn't - be accepted by the widget when navigation highlight is visible. (#6802, #3092, #5759, #787) - BeginGroup(): Fixed a bug pushing line lower extent too far down when called after a call to SameLine() followed by manual cursor manipulation. - BeginCombo(): Added ImGuiComboFlags_WidthFitPreview flag. (#6881) [@mpv-enjoyer] - BeginListBox(): Fixed not consuming SetNextWindowXXX data when returning false. - Fonts: - - Arument 'float size_pixels' passed to AddFontXXX() functions is now rounded to lowest integer. + - Argument 'float size_pixels' passed to AddFontXXX() functions is now rounded to lowest integer. This is because our layout/font system currently doesn't fully support non-integer sizes. Until it does, this has been a common pitfall leading to more or less subtle issues. (#3164, #3309, #6800) - Better assert during load when passing truncated font data or wrong data size. (#6822) @@ -146,7 +146,7 @@ Other changes: prior to building again. (#6825) - imgui_freetype: Fixed a warning and leak in IMGUI_ENABLE_FREETYPE_LUNASVG support. (#6842, #6591) - Inputs: Added IsKeyChordPressed() helper function e.g. IsKeyChordPressed(ImGuiMod_Ctrl | ImGuiKey_S). - (Note that ImGuiMod_Shortcut may be used as an alias for Cmd on OSX and Ctrl on other systems). + (note that ImGuiMod_Shortcut may be used as an alias for Cmd on OSX and Ctrl on other systems). - Misc: Most text functions also treat "%.*s" (along with "%s") specially to avoid formatting. (#3466, #6846) - IO: Add extra keys to ImGuiKey enum: ImGuiKey_F13 to ImGuiKey_F24. (#6891, #4921) - IO: Add extra keys to ImGuiKey enum: ImGuiKey_AppBack, ImGuiKey_AppForward. (#4921) diff --git a/docs/README.md b/docs/README.md index bd7ee8dd..d4240905 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,7 +27,7 @@ Dear ImGui is designed to **enable fast iterations** and to **empower programmer Dear ImGui is particularly suited to integration in game engines (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on console platforms where operating system features are non-standard. - Minimize state synchronization. - - Minimize state storage on user side. + - Minimize UI-related state storage on user side. - Minimize setup and maintenance. - Easy to use to create dynamic UI which are the reflection of a dynamic data set. - Easy to use to create code-driven and data-driven tools. @@ -133,7 +133,7 @@ Officially maintained backends/bindings (in repository): - Many bindings are auto-generated (by good old [cimgui](https://github.com/cimgui/cimgui) or newer/experimental [dear_bindings](https://github.com/dearimgui/dear_bindings)), you can use their metadata output to generate bindings for other languages. [Useful Extensions/Widgets](https://github.com/ocornut/imgui/wiki/Useful-Extensions) wiki page: -- Automation/testing, Text editors, node editors, timeline editors, plotting, software renderers, remote network access, memory editors, gizmos, etc. One of the most notable and well supported extension is [ImPlot](https://github.com/epezent/implot). +- Automation/testing, Text editors, node editors, timeline editors, plotting, software renderers, remote network access, memory editors, gizmos, etc. Notable and well supported extensions include [ImPlot](https://github.com/epezent/implot) and [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine). Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas. @@ -160,7 +160,7 @@ See: [Upcoming Changes](https://github.com/ocornut/imgui/wiki/Upcoming-Changes). See: [Dear ImGui Test Engine + Test Suite](https://github.com/ocornut/imgui_test_engine) for Automation & Testing. -Getting started? For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions). For other questions, bug reports, requests, feedback, you may post on [GitHub Issues](https://github.com/ocornut/imgui/issues). Please read and fill the New Issue template carefully. +Getting started? For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions). For ANY other questions, bug reports, requests, feedback, please post on [GitHub Issues](https://github.com/ocornut/imgui/issues). Please read and fill the New Issue template carefully. Private support is available for paying business customers (E-mail: _contact @ dearimgui dot com_). @@ -177,10 +177,10 @@ How to help **How can I help?** -- See [GitHub Forum/Issues](https://github.com/ocornut/imgui/issues) and [GitHub Discussions](https://github.com/ocornut/imgui/discussions). +- See [GitHub Forum/Issues](https://github.com/ocornut/imgui/issues). - You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it. - See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the [Wiki](https://github.com/ocornut/imgui/wiki/) for some more ideas. -- Have your company financially support this project with invoiced sponsoring/support contracts or by buying a license for [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine) (please reach out: omar AT dearimgui DOT com). +- Be a [sponsor](https://github.com/ocornut/imgui/wiki/Sponsors)! Have your company financially support this project via invoiced sponsors/maintenance or by buying a license for [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine) (please reach out: omar AT dearimgui DOT com). Sponsors -------- @@ -201,9 +201,9 @@ Credits Developed by [Omar Cornut](https://www.miracleworld.net) and every direct or indirect [contributors](https://github.com/ocornut/imgui/graphs/contributors) to the GitHub. The early version of this library was developed with the support of [Media Molecule](https://www.mediamolecule.com) and first used internally on the game [Tearaway](https://tearaway.mediamolecule.com) (PS Vita). -Recurring contributors (2022): Omar Cornut [@ocornut](https://github.com/ocornut), Rokas Kupstys [@rokups](https://github.com/rokups) (a good portion of work on automation system and regression tests now available in [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine)). +Recurring contributors include Rokas Kupstys [@rokups](https://github.com/rokups) (2020-2022): a good portion of work on automation system and regression tests now available in [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine). -Sponsoring, support contracts and other B2B transactions are hosted and handled by [Disco Hello](https://www.discohello.com). +Sponsoring, maintenance/support contracts and other B2B transactions are hosted and handled by [Disco Hello](https://www.discohello.com). Omar: "I first discovered the IMGUI paradigm at [Q-Games](https://www.q-games.com) where Atman Binstock had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating and improving it." diff --git a/imgui.cpp b/imgui.cpp index a11f2281..fcd52327 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13351,7 +13351,8 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); - buf->appendf("Collapsed=%d\n", settings->Collapsed); + if (settings->Collapsed) + buf->appendf("Collapsed=1\n"); buf->append("\n"); } } From 88fec097158867edf7753fe0d842d23d67e7966d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Oct 2023 15:45:45 +0200 Subject: [PATCH 08/13] ColorPicker4(): Fixed ImGuiColorEditFlags_NoTooltip when ImGuiColorEditFlags_NoSidePreview is also set. (#6957) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2623b63e..9dec2217 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -133,6 +133,8 @@ Other changes: - TreeNode: Added ImGuiTreeNodeFlags_SpanAllColumns for use in tables. (#3151, #3565, #2451, #2438) - TabBar: Fixed position of unsaved document marker (ImGuiTabItemFlags_UnsavedDocument) which was accidentally offset in 1.89.9. (#6862) [@alektron] +- ColorPicker4(): Fixed ImGuiColorEditFlags_NoTooltip not being forwarded to individual DragFloat3 + sub-widgets which have a visible color preview when ImGuiColorEditFlags_NoSidePreview is set. (#6957) - BeginGroup(): Fixed a bug pushing line lower extent too far down when called after a call to SameLine() followed by manual cursor manipulation. - BeginCombo(): Added ImGuiComboFlags_WidthFitPreview flag. (#6881) [@mpv-enjoyer] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9b2b9707..75a8922e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5609,7 +5609,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoInputs) == 0) { PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) From 7713c2925846856c25abda8fe2ba2ff3684282ba Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Oct 2023 18:50:19 +0200 Subject: [PATCH 09/13] BeginChild: Upgraded 'bool border = true' parameter to use a ImGuiChildFlags type and the ImGuiChildFlags_Border value. (toward #1666, #1496, #1395, #1710) --- docs/CHANGELOG.txt | 11 +++++++++++ imgui.cpp | 24 +++++++++++++++--------- imgui.h | 17 ++++++++++++++--- imgui_demo.cpp | 35 ++++++++++++++++++----------------- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 6 files changed, 60 insertions(+), 31 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9dec2217..ff617c46 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -42,6 +42,16 @@ HOW TO UPDATE? Breaking changes: + - BeginChild(): Upgraded 'bool border = false' parameter to 'ImGuiChildFlags flags'. + Added ImGuiChildFlags_Border value. 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. + If you want to neatly transition your call sites: + Before: BeginChild("Name", size, true) + After: BeginChild("Name", size, ImGuiChildFlags_Border) + Before: BeginChild("Name", size, false) + After: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) + Kept inline redirection function with strongly typed bool versions (will obsolete). - 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 @@ -68,6 +78,7 @@ Breaking changes: Other changes: - Windows: + - 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. diff --git a/imgui.cpp b/imgui.cpp index fcd52327..547c17f1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -424,6 +424,11 @@ 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/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) + - old: BeginChild("Name", size, false) + - new: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) - 2023/09/27 (1.90.0) - io: removed io.MetricsActiveAllocations introduced in 1.63. Same as 'g.DebugMemAllocCount - g.DebugMemFreeCount' (still displayed in Metrics, unlikely to be accessed by end-user). - 2023/09/26 (1.90.0) - debug tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIDStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631) - 2023/09/15 (1.90.0) - ListBox, Combo: changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. kept inline redirection function (will obsolete). @@ -5414,22 +5419,23 @@ ImVec2 ImGui::GetItemRectSize() return g.LastItemData.Rect.GetSize(); } -bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) +bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { ImGuiID id = GetCurrentWindow()->GetID(str_id); - return BeginChildEx(str_id, id, size_arg, border, window_flags); + return BeginChildEx(str_id, id, size_arg, child_flags, window_flags); } -bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) +bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { - IM_ASSERT(id != 0); - return BeginChildEx(NULL, id, size_arg, border, window_flags); + return BeginChildEx(NULL, id, size_arg, child_flags, window_flags); } -bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) +bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { ImGuiContext& g = *GImGui; ImGuiWindow* parent_window = g.CurrentWindow; + IM_ASSERT(id != 0); + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow; window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag @@ -5452,7 +5458,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id); const float backup_border_size = g.Style.ChildBorderSize; - if (!border) + if ((child_flags & ImGuiChildFlags_Border) == 0) g.Style.ChildBorderSize = 0.0f; // Begin into window @@ -5532,7 +5538,7 @@ bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags ext PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); - bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); + bool ret = BeginChild(id, size, ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); PopStyleVar(3); PopStyleColor(); return ret; @@ -14787,7 +14793,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) SameLine(); if (SmallButton("Copy")) SetClipboardText(g.DebugLogBuf.c_str()); - BeginChild("##log", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + BeginChild("##log", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); ImGuiListClipper clipper; clipper.Begin(g.DebugLogIndex.size()); diff --git a/imgui.h b/imgui.h index 4fbce76a..f3e6c2de 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 18996 +#define IMGUI_VERSION_NUM 18997 #define IMGUI_HAS_TABLE /* @@ -191,6 +191,7 @@ typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: f typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() +typedef int ImGuiChildFlags; // -> enum ImGuiChildFlags_ // Flags: for BeginChild() typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() @@ -343,8 +344,8 @@ namespace ImGui // [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.] - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags window_flags = 0); - IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags window_flags = 0); + 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(); // Windows Utilities @@ -1010,6 +1011,14 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() }; +// Flags for ImGui::BeginChild() +// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Border to be backward compatible with old API using 'bool border'. +enum ImGuiChildFlags_ +{ + ImGuiChildFlags_None = 0, + ImGuiChildFlags_Border = 1 << 0, // Show an outer border and enable WindowPadding. (Important: this is always == 1 for legacy reason) +}; + // Flags for ImGui::InputText() // (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and io.ConfigInputTextEnterKeepActive) enum ImGuiInputTextFlags_ @@ -3114,6 +3123,8 @@ namespace ImGui namespace ImGui { // OBSOLETED in 1.90.0 (from September 2023) + 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); } IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c213c43e..b1e8236c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2591,7 +2591,7 @@ static void ShowDemoWindowWidgets() static bool embed_all_inside_a_child_window = false; ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); if (embed_all_inside_a_child_window) - ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Border); // Testing IsWindowFocused() function with its various flags. ImGui::BulletText( @@ -2639,7 +2639,7 @@ static void ShowDemoWindowWidgets() ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); - ImGui::BeginChild("child", ImVec2(0, 50), true); + ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Border); ImGui::Text("This is another child window for testing the _ChildWindows flag."); ImGui::EndChild(); if (embed_all_inside_a_child_window) @@ -2723,7 +2723,7 @@ static void ShowDemoWindowLayout() ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; if (disable_mouse_wheel) window_flags |= ImGuiWindowFlags_NoScrollWithMouse; - ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), false, window_flags); + ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags); for (int i = 0; i < 100; i++) ImGui::Text("%04d: scrollable region", i); ImGui::EndChild(); @@ -2739,7 +2739,7 @@ static void ShowDemoWindowLayout() if (!disable_menu) window_flags |= ImGuiWindowFlags_MenuBar; ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); - ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); + ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Border, window_flags); if (!disable_menu && ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("Menu")) @@ -2780,14 +2780,15 @@ static void ShowDemoWindowLayout() ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); - ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); + ImGui::BeginChild("Red", ImVec2(200, 100), ImGuiChildFlags_Border, ImGuiWindowFlags_None); + ImGui::PopStyleColor(); + for (int n = 0; n < 50; n++) ImGui::Text("Some test %d", n); ImGui::EndChild(); bool child_is_hovered = ImGui::IsItemHovered(); ImVec2 child_rect_min = ImGui::GetItemRectMin(); ImVec2 child_rect_max = ImGui::GetItemRectMax(); - ImGui::PopStyleColor(); ImGui::Text("Hovered: %d", child_is_hovered); ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); } @@ -3176,7 +3177,7 @@ static void ShowDemoWindowLayout() const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); + const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Border, child_flags); if (ImGui::BeginMenuBar()) { ImGui::TextUnformatted("abc"); @@ -3223,7 +3224,7 @@ static void ShowDemoWindowLayout() float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); + bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Border, child_flags); if (scroll_to_off) ImGui::SetScrollX(scroll_to_off_px); if (scroll_to_pos) @@ -3265,7 +3266,7 @@ static void ShowDemoWindowLayout() ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); - ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Border, ImGuiWindowFlags_HorizontalScrollbar); for (int line = 0; line < lines; line++) { // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() @@ -3409,7 +3410,7 @@ static void ShowDemoWindowLayout() } if (show_child) { - ImGui::BeginChild("child", ImVec2(0, 0), true); + ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Border); ImGui::EndChild(); } ImGui::End(); @@ -5958,7 +5959,7 @@ static void ShowDemoWindowColumns() { ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); - ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar); ImGui::Columns(10); // Also demonstrate using clipper for large vertical lists @@ -6575,7 +6576,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "Left-click on color square to open color picker,\n" "Right-click to open edit options menu."); - ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); + 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++) { @@ -6802,7 +6803,7 @@ static void ShowExampleMenuFile() { static bool enabled = true; ImGui::MenuItem("Enabled", "", &enabled); - ImGui::BeginChild("child", ImVec2(0, 60), true); + ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Border); for (int i = 0; i < 10; i++) ImGui::Text("Scrolling Text %d", i); ImGui::EndChild(); @@ -6968,7 +6969,7 @@ struct ExampleAppConsole // Reserve enough left-over height for 1 separator + 1 input text const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); - if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar)) + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar)) { if (ImGui::BeginPopupContextWindow()) { @@ -7279,7 +7280,7 @@ struct ExampleAppLog ImGui::Separator(); - if (ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) + if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar)) { if (clear) Clear(); @@ -7398,7 +7399,7 @@ static void ShowExampleAppLayout(bool* p_open) // Left static int selected = 0; { - ImGui::BeginChild("left pane", ImVec2(150, 0), true); + ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Border); for (int i = 0; i < 100; i++) { // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav @@ -7967,7 +7968,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) // To use a child window instead we could use, e.g: // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color - // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove); + // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove); // ImGui::PopStyleColor(); // ImGui::PopStyleVar(); // [...] diff --git a/imgui_internal.h b/imgui_internal.h index 3f493f7e..53f3c672 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3006,7 +3006,7 @@ namespace ImGui IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); // Popups, Modals, Tooltips - IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags); + IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags); IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None); IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup); IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 75a8922e..397300f0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5051,7 +5051,7 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); - if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state + if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), ImGuiChildFlags_Border)) // Visualize undo state { PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); for (int n = 0; n < STB_TEXTEDIT_UNDOSTATECOUNT; n++) From 34a0bc456eb4c8715dad10403bf45ed8185683db Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Oct 2023 19:15:31 +0200 Subject: [PATCH 10/13] BeginChild: Added ImGuiChildFlags_AlwaysUseWindowPadding, obsoleted ImGuiWindowFlags_AlwaysUseWindowPadding. (#462, (toward #1666, #1496, #1395, #1710) (bonus: will also eventually free a window flag) --- docs/CHANGELOG.txt | 9 ++++++++- imgui.cpp | 29 ++++++++++++++++++++++++----- imgui.h | 7 ++++++- imgui_internal.h | 3 +++ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ff617c46..50f27c4d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,7 +51,14 @@ Breaking changes: After: BeginChild("Name", size, ImGuiChildFlags_Border) Before: BeginChild("Name", size, false) After: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) - Kept inline redirection function with strongly typed bool versions (will obsolete). + Kept inline redirection function (will obsolete later) so existing code will work. + - BeginChild(): Added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for + the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense + for use with BeginChild() anyhow, passing it to Begin() had no effect. Now that we accept + child-flags we are moving it there. (#462) + 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. - 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 diff --git a/imgui.cpp b/imgui.cpp index 547c17f1..5694d999 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -429,6 +429,9 @@ CODE - new: BeginChild("Name", size, ImGuiChildFlags_Border) - old: BeginChild("Name", size, false) - new: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) + - 2023/11/02 (1.90.0) - BeginChild: added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for BeginChild() anyhow. + - old: BeginChild("Name", size, 0, ImGuiWindowFlags_AlwaysUseWindowPadding); + - new: BeginChild("Name", size, ImGuiChildFlags_AlwaysUseWindowPadding, 0); - 2023/09/27 (1.90.0) - io: removed io.MetricsActiveAllocations introduced in 1.63. Same as 'g.DebugMemAllocCount - g.DebugMemFreeCount' (still displayed in Metrics, unlikely to be accessed by end-user). - 2023/09/26 (1.90.0) - debug tools: Renamed ShowStackToolWindow() ("Stack Tool") to ShowIDStackToolWindow() ("ID Stack Tool"), as earlier name was misleading. Kept inline redirection function. (#4631) - 2023/09/15 (1.90.0) - ListBox, Combo: changed signature of "name getter" callback in old one-liner ListBox()/Combo() apis. kept inline redirection function (will obsolete). @@ -5419,6 +5422,8 @@ ImVec2 ImGui::GetItemRectSize() return g.LastItemData.Rect.GetSize(); } +// Prior to v1.90 2023/10/16, the BeginChild() function took a 'bool border = false' parameter instead of 'ImGuiChildFlags child_flags = 0'. +// ImGuiChildFlags_Border is defined as always == 1 in order to allow old code passing 'true'. bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { ImGuiID id = GetCurrentWindow()->GetID(str_id); @@ -5436,10 +5441,23 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I ImGuiWindow* parent_window = g.CurrentWindow; IM_ASSERT(id != 0); - window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow; - window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag + // 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; + IM_UNUSED(ImGuiChildFlags_SupportedMask_); + IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?"); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding) + child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding; +#endif + + window_flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag + + // Forward child flags + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags; + g.NextWindowData.ChildFlags = child_flags; - // Size + // Forward size const ImVec2 content_avail = GetContentRegionAvail(); ImVec2 size = ImTrunc(size_arg); if (size.x <= 0.0f) @@ -5538,7 +5556,7 @@ bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags ext PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); - bool ret = BeginChild(id, size, ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); + bool ret = BeginChild(id, size, ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_NoMove | extra_flags); PopStyleVar(3); PopStyleColor(); return ret; @@ -6328,6 +6346,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { UpdateWindowInFocusOrderList(window, window_just_created, flags); window->Flags = (ImGuiWindowFlags)flags; + window->ChildFlags = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : 0; window->LastFrameActive = current_frame; window->LastTimeActive = (float)g.Time; window->BeginOrderWithinParent = 0; @@ -6503,7 +6522,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; window->WindowPadding = style.WindowPadding; - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !(window->ChildFlags & ImGuiChildFlags_AlwaysUseWindowPadding) && window->WindowBorderSize == 0.0f) window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. diff --git a/imgui.h b/imgui.h index f3e6c2de..aa9cfffa 100644 --- a/imgui.h +++ b/imgui.h @@ -994,7 +994,6 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) - ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. @@ -1009,6 +1008,11 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() + + // Obsolete names +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. +#endif }; // Flags for ImGui::BeginChild() @@ -1017,6 +1021,7 @@ enum ImGuiChildFlags_ { ImGuiChildFlags_None = 0, ImGuiChildFlags_Border = 1 << 0, // Show an outer border and enable WindowPadding. (Important: this is always == 1 for legacy reason) + 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) }; // Flags for ImGui::InputText() diff --git a/imgui_internal.h b/imgui_internal.h index 53f3c672..d7363c82 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1161,6 +1161,7 @@ enum ImGuiNextWindowDataFlags_ ImGuiNextWindowDataFlags_HasFocus = 1 << 5, ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, ImGuiNextWindowDataFlags_HasScroll = 1 << 7, + ImGuiNextWindowDataFlags_HasChildFlags = 1 << 8, }; // Storage for SetNexWindow** functions @@ -1175,6 +1176,7 @@ struct ImGuiNextWindowData ImVec2 SizeVal; ImVec2 ContentSizeVal; ImVec2 ScrollVal; + ImGuiChildFlags ChildFlags; bool CollapsedVal; ImRect SizeConstraintRect; ImGuiSizeCallback SizeCallback; @@ -2394,6 +2396,7 @@ struct IMGUI_API ImGuiWindow char* Name; // Window name, owned by the window. ImGuiID ID; // == ImHashStr(Name) ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ + ImGuiChildFlags ChildFlags; // Set when window is a child window. See enum ImGuiChildFlags_ ImGuiViewportP* Viewport; // Always set in Begin(). Inactive windows may have a NULL value here if their viewport was discarded. ImVec2 Pos; // Position (always rounded-up to nearest pixel) ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) From 923535240044ff3470d8dbd051084af770ad93ea Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Oct 2023 18:36:57 +0200 Subject: [PATCH 11/13] BeginChild: Added ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY. (#1710) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 49 +++++++++++++++++++++++++++++++++++----------- imgui.h | 2 ++ imgui_demo.cpp | 27 ++++++++++++++++++++++--- imgui_internal.h | 1 + 5 files changed, 68 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 50f27c4d..f8a81ec0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -85,6 +85,9 @@ Breaking changes: 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) - 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 diff --git a/imgui.cpp b/imgui.cpp index 5694d999..b5127800 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5249,7 +5249,7 @@ static void FindHoveredWindow() continue; // Using the clipped AABB, a child window will typically be clipped by its parent (not always) - ImVec2 hit_padding = (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) ? padding_regular : padding_for_resize; + ImVec2 hit_padding = (window->Flags & (ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) ? padding_regular : padding_for_resize; if (!window->OuterRectClipped.ContainsWithPad(g.IO.MousePos, hit_padding)) continue; @@ -5442,22 +5442,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; + const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; 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."); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding) child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding; #endif - window_flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + window_flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar; window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag + if ((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0) + window_flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + // Forward child flags g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags; g.NextWindowData.ChildFlags = child_flags; // 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) @@ -5679,7 +5686,8 @@ static inline ImVec2 CalcWindowMinSize(ImGuiWindow* window) ImVec2 size_min; if (window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_ChildWindow)) { - size_min = ImVec2(4.0f, 4.0f); + size_min.x = (window->ChildFlags & ImGuiChildFlags_ResizeX) ? g.Style.WindowMinSize.x : 4.0f; + size_min.y = (window->ChildFlags & ImGuiChildFlags_ResizeY) ? g.Style.WindowMinSize.y : 4.0f; } else { @@ -5939,7 +5947,11 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); } - const int resize_border_mask = g.IO.ConfigWindowsResizeFromEdges ? 0x0F : 0x00; + int resize_border_mask = 0x00; + if (window->Flags & ImGuiWindowFlags_ChildWindow) + resize_border_mask |= ((window->ChildFlags & ImGuiChildFlags_ResizeX) ? 0x02 : 0) | ((window->ChildFlags & ImGuiChildFlags_ResizeY) ? 0x08 : 0); + else + resize_border_mask = g.IO.ConfigWindowsResizeFromEdges ? 0x0F : 0x00; for (int border_n = 0; border_n < 4; border_n++) { if ((resize_border_mask & (1 << border_n)) == 0) @@ -5976,6 +5988,8 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si ImVec2 border_target = window->Pos; border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; 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); CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); } if (hovered) @@ -6423,6 +6437,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); + if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && (window->SetWindowSizeAllowFlags & ImGuiCond_FirstUseEver) == 0) // Axis-specific conditions for BeginChild() + g.NextWindowData.SizeVal.x = window->SizeFull.x; + if ((window->ChildFlags & ImGuiChildFlags_ResizeY) && (window->SetWindowSizeAllowFlags & ImGuiCond_FirstUseEver) == 0) + g.NextWindowData.SizeVal.y = window->SizeFull.y; SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); } if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) @@ -6680,7 +6698,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Handle manual resize: Resize Grips, Borders, Gamepad int border_hovered = -1, border_held = -1; ImU32 resize_grip_col[4] = {}; - const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. + const int resize_grip_count = (window->Flags & ImGuiWindowFlags_ChildWindow) ? 0 : g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); if (!window->Collapsed) if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) @@ -13327,6 +13345,7 @@ static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); } else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); } else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); } + else if (sscanf(line, "IsChild=%d", &i) == 1) { settings->IsChild = (i != 0); } } // Apply to existing windows (if any) @@ -13361,7 +13380,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl IM_ASSERT(settings->ID == window->ID); settings->Pos = ImVec2ih(window->Pos); settings->Size = ImVec2ih(window->SizeFull); - + settings->IsChild = (window->Flags & ImGuiWindowFlags_ChildWindow) != 0; settings->Collapsed = window->Collapsed; settings->WantDelete = false; } @@ -13374,10 +13393,18 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl continue; const char* settings_name = settings->GetName(); buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); - buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); - buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); - if (settings->Collapsed) - buf->appendf("Collapsed=1\n"); + if (settings->IsChild) + { + buf->appendf("IsChild=1\n"); + buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); + } + else + { + buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); + buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); + if (settings->Collapsed) + buf->appendf("Collapsed=1\n"); + } buf->append("\n"); } } diff --git a/imgui.h b/imgui.h index aa9cfffa..fa90a8cf 100644 --- a/imgui.h +++ b/imgui.h @@ -1022,6 +1022,8 @@ enum ImGuiChildFlags_ ImGuiChildFlags_None = 0, ImGuiChildFlags_Border = 1 << 0, // Show an outer border and enable WindowPadding. (Important: this is always == 1 for legacy reason) 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). " }; // Flags for ImGui::InputText() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b1e8236c..819838a2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2764,6 +2764,18 @@ static void ShowDemoWindowLayout() ImGui::PopStyleVar(); } + // Child 3: manual-resize + ImGui::SeparatorText("Manual-resize"); + { + 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); + ImGui::PopStyleColor(); + for (int n = 0; n < 10; n++) + ImGui::Text("Line %04d", n); + ImGui::EndChild(); + } + ImGui::SeparatorText("Misc/Advanced"); // Demonstrate a few extra things @@ -2775,13 +2787,22 @@ static void ShowDemoWindowLayout() // the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details. { static int offset_x = 0; + static bool override_bg_color = true; + static ImGuiChildFlags child_flags = ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); + ImGui::Checkbox("Override ChildBg color", &override_bg_color); + ImGui::CheckboxFlags("ImGuiChildFlags_Border", &child_flags, ImGuiChildFlags_Border); + 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::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); - ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); - ImGui::BeginChild("Red", ImVec2(200, 100), ImGuiChildFlags_Border, ImGuiWindowFlags_None); - ImGui::PopStyleColor(); + if (override_bg_color) + ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); + ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None); + if (override_bg_color) + ImGui::PopStyleColor(); for (int n = 0; n < 50; n++) ImGui::Text("Some test %d", n); diff --git a/imgui_internal.h b/imgui_internal.h index d7363c82..cbf1d800 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1712,6 +1712,7 @@ struct ImGuiWindowSettings ImVec2ih Pos; ImVec2ih Size; bool Collapsed; + bool IsChild; bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) bool WantDelete; // Set to invalidate/delete the settings entry From f1d1a8d32b12ca098d45dbac5fd0c5d68497bf3a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 31 Oct 2023 18:37:49 +0100 Subject: [PATCH 12/13] Windows: use relative mouse movement for border resize when the border geometry has moved. (#1710) (e.g. resizing a child window triggering parent scroll) to avoid resizing feedback loop. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 44 ++++++++++++++++++++++++++++++++++++++++---- imgui_internal.h | 6 +++++- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f8a81ec0..f6e77011 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -96,6 +96,9 @@ Other changes: 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 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 + feedback loops. Unless manually mouse-wheeling while border resizing. (#1710) - Separators: - Altered end-points to use more standard boundaries. (#205, #4787, #1643) Left position is always current cursor X position, right position is always work-rect diff --git a/imgui.cpp b/imgui.cpp index b5127800..9e4ffa6d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5964,7 +5964,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID() ItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav); ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); - //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); + //GetForegroundDrawList(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); if (hovered && g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) hovered = false; if (hovered || held) @@ -5983,14 +5983,44 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si } else if (held) { + // Switch to relative resizing mode when border geometry moved (e.g. resizing a child altering parent scroll), in order to avoid resizing feedback loop. + // Currently only using relative mode on resizable child windows, as the problem to solve is more likely noticeable for them, but could apply for all windows eventually. + // FIXME: May want to generalize this idiom at lower-level, so more widgets can use it! + const bool just_scrolled_manually_while_resizing = (g.WheelingWindow != NULL && g.WheelingWindowScrolledFrame == g.FrameCount && IsWindowChildOf(window, g.WheelingWindow, false)); + if (g.ActiveIdIsJustActivated || just_scrolled_manually_while_resizing) + { + g.WindowResizeBorderExpectedRect = border_rect; + g.WindowResizeRelativeMode = false; + } + if ((window->Flags & ImGuiWindowFlags_ChildWindow) && memcmp(&g.WindowResizeBorderExpectedRect, &border_rect, sizeof(ImRect)) != 0) + g.WindowResizeRelativeMode = true; + + const ImVec2 border_curr = (window->Pos + ImMin(def.SegmentN1, def.SegmentN2) * window->Size); + const float border_target_rel_mode_for_axis = border_curr[axis] + g.IO.MouseDelta[axis]; + const float border_target_abs_mode_for_axis = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; // Match ButtonBehavior() padding above. + + // Use absolute mode position + ImVec2 border_target = window->Pos; + border_target[axis] = border_target_abs_mode_for_axis; + + // Use relative mode target for child window, ignore resize when moving back toward the ideal absolute position. + bool ignore_resize = false; + if (g.WindowResizeRelativeMode) + { + //GetForegroundDrawList()->AddText(GetMainViewport()->WorkPos, IM_COL32_WHITE, "Relative Mode"); + border_target[axis] = border_target_rel_mode_for_axis; + if (g.IO.MouseDelta[axis] == 0.0f || (g.IO.MouseDelta[axis] > 0.0f) == (border_target_rel_mode_for_axis > border_target_abs_mode_for_axis)) + ignore_resize = true; + } + + // Clamp, apply 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); - ImVec2 border_target = window->Pos; - border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; 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); - CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); + if (!ignore_resize) + CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); } if (hovered) *border_hovered = border_n; @@ -6043,6 +6073,10 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si if (size_target.x != FLT_MAX || size_target.y != FLT_MAX || pos_target.x != FLT_MAX || pos_target.y != FLT_MAX) MarkIniSettingsDirty(window); + // Recalculate next expected border expected coordinates + if (*border_held != -1) + g.WindowResizeBorderExpectedRect = GetResizeBorderRect(window, *border_held, grip_hover_inner_size, WINDOWS_HOVER_PADDING); + return ret_auto_fit_mask; } @@ -8931,6 +8965,7 @@ void ImGui::UpdateMouseWheel() float max_step = window->InnerRect.GetWidth() * 0.67f; float scroll_step = ImTrunc(ImMin(2 * window->CalcFontSize(), max_step)); SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); + g.WheelingWindowScrolledFrame = g.FrameCount; } if (do_scroll[ImGuiAxis_Y]) { @@ -8938,6 +8973,7 @@ void ImGui::UpdateMouseWheel() float max_step = window->InnerRect.GetHeight() * 0.67f; float scroll_step = ImTrunc(ImMin(5 * window->CalcFontSize(), max_step)); SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); + g.WheelingWindowScrolledFrame = g.FrameCount; } } } diff --git a/imgui_internal.h b/imgui_internal.h index cbf1d800..0b62a036 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1899,6 +1899,7 @@ struct ImGuiContext ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos; int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL + int WheelingWindowScrolledFrame; float WheelingWindowReleaseTimer; ImVec2 WheelingWindowWheelRemainder; ImVec2 WheelingAxisAvg; @@ -2091,6 +2092,8 @@ struct ImGuiContext ImU32 ColorEditSavedColor; // RGB value with alpha set to 0. ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. ImGuiComboPreviewData ComboPreviewData; + ImRect WindowResizeBorderExpectedRect; // Expected border rect, switch to relative edit if moving + bool WindowResizeRelativeMode; float SliderGrabClickOffset; float SliderCurrentAccum; // Accumulated slider delta when using navigation controls. bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it? @@ -2187,7 +2190,7 @@ struct ImGuiContext HoveredWindowUnderMovingWindow = NULL; MovingWindow = NULL; WheelingWindow = NULL; - WheelingWindowStartFrame = -1; + WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1; WheelingWindowReleaseTimer = 0.0f; DebugHookIdInfo = 0; @@ -2289,6 +2292,7 @@ struct ImGuiContext ColorEditCurrentID = ColorEditSavedID = 0; ColorEditSavedHue = ColorEditSavedSat = 0.0f; ColorEditSavedColor = 0; + WindowResizeRelativeMode = false; SliderGrabClickOffset = 0.0f; SliderCurrentAccum = 0.0f; SliderCurrentAccumDirty = false; From c0bc43ccff04b1395b2bbfe0b802f07e2c426f43 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 2 Nov 2023 17:39:32 +0100 Subject: [PATCH 13/13] Offset values for ImGuiWindowFlags_NoNavInputs, ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_UnsavedDocument. (ABI breaking but we technically never supported ABI backward/forward compat, thought it is possible that some generated backends be affected) --- imgui.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index fa90a8cf..f8967455 100644 --- a/imgui.h +++ b/imgui.h @@ -994,9 +994,9 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) - ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window - ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) - ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + ImGuiWindowFlags_NoNavInputs = 1 << 16, // No gamepad/keyboard navigation within the window + ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,