From a2eec8f5b54b50c0ed76aa9115ac41bca23a5270 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 22 May 2019 21:43:42 +0200 Subject: [PATCH 1/3] Fix OuterRectClipped not being clipped correctly, which resulted in child window outside visible bound to not be marked with SkipItems. Broken in b50c61c961498e15b5a4c22c7e7e10df13a64e77. + Comments on InnerClipRect being misleading. Demo: Tweak to sizing of child window in the Layout->Scrolling section. --- imgui.cpp | 19 +++++++++++-------- imgui_demo.cpp | 10 +++++++--- imgui_internal.h | 5 +++-- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1516d259..7baf6d8a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5463,10 +5463,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x + ImMin(window->ScrollbarSizes.x, window->WindowBorderSize))); window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y + ImMin(window->ScrollbarSizes.y, window->WindowBorderSize))); - // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() - window->OuterRectClipped = window->Rect(); - window->OuterRectClipped.ClipWith(window->ClipRect); - // Inner rectangle // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. @@ -5476,13 +5472,23 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize); window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - ImMax(window->ScrollbarSizes.y, window->WindowBorderSize); + // Outer host rectangle for drawing background and borders + ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; + + // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() + window->OuterRectClipped = window->Rect(); + window->OuterRectClipped.ClipWith(host_rect); + // Inner clipping rectangle will extend a little bit outside the work region. // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + // FIXME: This is currently not clipped by the host rectangle, which is misleading because our call to PushClipRect() below will do it anyway. + // If we fix the value in InnerClipRect, which is desirable, we need to fix the two lines of code relying on it. window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + //window->InnerClipRect.ClipWithFull(host_rect); // DRAWING @@ -5490,10 +5496,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList->Clear(); window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) - PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true); - else - PushClipRect(viewport_rect.Min, viewport_rect.Max, true); + PushClipRect(host_rect.Min, host_rect.Max, false); // Draw modal window background (darkens what is behind them, all viewports) const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1bc4a244..af0700c4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2056,14 +2056,17 @@ static void ShowDemoWindowLayout() bool scroll_to = ImGui::Button("Scroll To Pos"); ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %d px"); ImGui::PopItemWidth(); - if (scroll_to) track = false; + if (scroll_to) + track = false; + ImGuiStyle& style = ImGui::GetStyle(); + float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; for (int i = 0; i < 5; i++) { if (i > 0) ImGui::SameLine(); ImGui::BeginGroup(); ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom"); - ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true); + ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true); if (scroll_to) ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f); for (int line = 0; line < 100; line++) @@ -2078,7 +2081,8 @@ static void ShowDemoWindowLayout() ImGui::Text("Line %d", line); } } - float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY(); + float scroll_y = ImGui::GetScrollY(); + float scroll_max_y = ImGui::GetScrollMaxY(); ImGui::EndChild(); ImGui::Text("%.0f/%0.f", scroll_y, scroll_max_y); ImGui::EndGroup(); diff --git a/imgui_internal.h b/imgui_internal.h index 8c4ef1d9..199cda6a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1290,8 +1290,9 @@ struct IMGUI_API ImGuiWindow ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack ImRect ClipRect; // Current clipping rectangle. = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. - ImRect OuterRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window. - ImRect InnerMainRect, InnerClipRect; + ImRect OuterRectClipped; // == WindowRect just after setup in Begin(). == window->Rect() for root window. + ImRect InnerMainRect; // + ImRect InnerClipRect; // == InnerMainRect, minus WindowPadding on each side, clipped within viewport or parent. ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. Maximum visible content position ~~ Pos + (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis int LastFrameActive; // Last frame number the window was Active. float ItemWidthDefault; From b85e97137dfaa07ceed2d804adbb6a6c93182784 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 22 May 2019 23:51:20 +0200 Subject: [PATCH 2/3] Version tag is 1.71 WIP oops --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 77fc9c8a..77fab495 100644 --- a/imgui.h +++ b/imgui.h @@ -46,8 +46,8 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) -#define IMGUI_VERSION "1.71" -#define IMGUI_VERSION_NUM 17001 +#define IMGUI_VERSION "1.71 WIP" +#define IMGUI_VERSION_NUM 17002 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) From 7bc03f7155c67b5081a8e154b3c642fa5db5b33b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 22 May 2019 23:54:32 +0200 Subject: [PATCH 3/3] Internals: Added InnerWorkRect equal to old InnerClipRect, added InnerWorkRectClipped actually clipped. --- imgui.cpp | 28 ++++++++++++++-------------- imgui_internal.h | 3 ++- imgui_widgets.cpp | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7baf6d8a..a8153a23 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5479,16 +5479,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->OuterRectClipped = window->Rect(); window->OuterRectClipped.ClipWith(host_rect); - // Inner clipping rectangle will extend a little bit outside the work region. + // Inner work/clipping rectangle will extend a little bit outside the work region. // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. - // FIXME: This is currently not clipped by the host rectangle, which is misleading because our call to PushClipRect() below will do it anyway. - // If we fix the value in InnerClipRect, which is desirable, we need to fix the two lines of code relying on it. - window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); - window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); - window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); - window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); - //window->InnerClipRect.ClipWithFull(host_rect); + window->InnerWorkRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); + window->InnerWorkRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); + window->InnerWorkRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); + window->InnerWorkRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + window->InnerWorkRectClipped = window->InnerWorkRect; + window->InnerWorkRectClipped.ClipWithFull(host_rect); // DRAWING @@ -5614,7 +5613,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetCurrentWindow(window); } - PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); + PushClipRect(window->InnerWorkRectClipped.Min, window->InnerWorkRectClipped.Max, true); // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) if (first_begin_of_the_frame) @@ -8653,7 +8652,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag window->DC.CurrentColumns = columns; // Set state for first column - const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); + const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerWorkRect.Max.x - window->Pos.x); columns->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range columns->OffMaxX = ImMax(content_region_width - window->Scroll.x, columns->OffMinX + 1.0f); columns->HostCursorPosY = window->DC.CursorPos.y; @@ -9701,10 +9700,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; } - enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerMainRect, RT_InnerClipRect, RT_ContentsRegionRect, RT_ContentsFullRect }; + enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerMainRect, RT_InnerWorkRect, RT_InnerWorkRectClipped, RT_ContentsRegionRect, RT_ContentsFullRect }; static bool show_windows_begin_order = false; static bool show_windows_rects = false; - static int show_windows_rect_type = RT_ContentsRegionRect; + static int show_windows_rect_type = RT_InnerWorkRect; static bool show_drawcmd_clip_rects = true; ImGuiIO& io = ImGui::GetIO(); @@ -9918,7 +9917,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::Checkbox("Show windows rectangles", &show_windows_rects); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12); - show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, "OuterRect\0" "OuterRectClipped\0" "InnerMainRect\0" "InnerClipRect\0" "ContentsRegionRect\0"); + show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, "OuterRect\0" "OuterRectClipped\0" "InnerMainRect\0" "InnerWorkRect\0" "InnerWorkRectClipped\0" "ContentsRegionRect\0"); ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects); ImGui::TreePop(); } @@ -9937,7 +9936,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (show_windows_rect_type == RT_OuterRect) { r = window->Rect(); } else if (show_windows_rect_type == RT_OuterRectClipped) { r = window->OuterRectClipped; } else if (show_windows_rect_type == RT_InnerMainRect) { r = window->InnerMainRect; } - else if (show_windows_rect_type == RT_InnerClipRect) { r = window->InnerClipRect; } + else if (show_windows_rect_type == RT_InnerWorkRect) { r = window->InnerWorkRect; } + else if (show_windows_rect_type == RT_InnerWorkRectClipped) { r = window->InnerWorkRectClipped; } else if (show_windows_rect_type == RT_ContentsRegionRect) { r = window->ContentsRegionRect; } draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); } diff --git a/imgui_internal.h b/imgui_internal.h index 199cda6a..b59844c0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1292,7 +1292,8 @@ struct IMGUI_API ImGuiWindow ImRect ClipRect; // Current clipping rectangle. = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. ImRect OuterRectClipped; // == WindowRect just after setup in Begin(). == window->Rect() for root window. ImRect InnerMainRect; // - ImRect InnerClipRect; // == InnerMainRect, minus WindowPadding on each side, clipped within viewport or parent. + ImRect InnerWorkRect; // == InnerMainRect minus WindowPadding.x + ImRect InnerWorkRectClipped; // == InnerMainRect minus WindowPadding.x, clipped within viewport or parent clip rect. ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. Maximum visible content position ~~ Pos + (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis int LastFrameActive; // Last frame number the window was Active. float ItemWidthDefault; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ab1f657f..30f721b6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6227,7 +6227,7 @@ bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) ImGuiID id = window->GetID(str_id); ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); - ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->InnerClipRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->InnerWorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); tab_bar->ID = id; return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused); }