From 21ebdcafc957c431d6053e2d3f8680554b7e90b6 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 May 2019 15:54:55 +0200 Subject: [PATCH 1/3] Internals: Window rectangles: Renaming of all rectangles toward their final form. Should be a no-op. Renamed GetWorkRectMax() to GetContentRegionMaxAbs(). Metrics shows SizeContents. --- imgui.cpp | 57 ++++++++++++++++++++++++----------------------- imgui_internal.h | 10 ++++----- imgui_widgets.cpp | 12 +++++----- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 33e53453..bf738ff3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2997,7 +2997,7 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) ImGuiWindow* window = GImGui->CurrentWindow; if (wrap_pos_x == 0.0f) - wrap_pos_x = GetWorkRectMax().x; + wrap_pos_x = GetContentRegionMaxAbs().x; else if (wrap_pos_x > 0.0f) wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space @@ -5517,10 +5517,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // 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. const ImRect title_bar_rect = window->TitleBarRect(); - window->InnerVisibleRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; - window->InnerVisibleRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); - window->InnerVisibleRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize); - window->InnerVisibleRect.Max.y = window->Pos.y + window->Size.y - ImMax(window->ScrollbarSizes.y, window->WindowBorderSize); + window->InnerRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; + window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); + window->InnerRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize); + window->InnerRect.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; @@ -5532,12 +5532,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // 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. - window->InnerWorkRect.Min.x = ImFloor(0.5f + window->InnerVisibleRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); - window->InnerWorkRect.Min.y = ImFloor(0.5f + window->InnerVisibleRect.Min.y); - window->InnerWorkRect.Max.x = ImFloor(0.5f + window->InnerVisibleRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); - window->InnerWorkRect.Max.y = ImFloor(0.5f + window->InnerVisibleRect.Max.y); - window->InnerWorkRectClipped = window->InnerWorkRect; - window->InnerWorkRectClipped.ClipWithFull(host_rect); + window->WorkRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); + window->WorkRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y); + window->WorkRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); + window->WorkRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y); + window->InnerClipRect = window->WorkRect; + window->InnerClipRect.ClipWithFull(host_rect); // DRAWING @@ -5662,7 +5662,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetCurrentWindow(window); } - PushClipRect(window->InnerWorkRectClipped.Min, window->InnerWorkRectClipped.Max, true); + PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.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) @@ -5905,7 +5905,7 @@ float ImGui::CalcItemWidth() w = window->DC.ItemWidth; if (w < 0.0f) { - float region_max_x = GetWorkRectMax().x; + float region_max_x = GetContentRegionMaxAbs().x; w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); } w = (float)(int)w; @@ -5922,7 +5922,7 @@ ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) ImVec2 region_max; if (size.x < 0.0f || size.y < 0.0f) - region_max = GetWorkRectMax(); + region_max = GetContentRegionMaxAbs(); if (size.x == 0.0f) size.x = default_w; @@ -6513,7 +6513,7 @@ ImVec2 ImGui::GetContentRegionMax() } // [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. -ImVec2 ImGui::GetWorkRectMax() +ImVec2 ImGui::GetContentRegionMaxAbs() { ImGuiWindow* window = GImGui->CurrentWindow; ImVec2 mx = window->ContentsRegionRect.Max; @@ -6525,7 +6525,7 @@ ImVec2 ImGui::GetWorkRectMax() ImVec2 ImGui::GetContentRegionAvail() { ImGuiWindow* window = GImGui->CurrentWindow; - return GetWorkRectMax() - window->DC.CursorPos; + return GetContentRegionMaxAbs() - window->DC.CursorPos; } // In window space (not screen space!) @@ -7843,7 +7843,7 @@ ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInput // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated. static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect) { - ImRect window_rect(window->InnerVisibleRect.Min - ImVec2(1, 1), window->InnerVisibleRect.Max + ImVec2(1, 1)); + ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] if (window_rect.Contains(item_rect)) return; @@ -8117,7 +8117,7 @@ static void ImGui::NavUpdate() if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0) { ImGuiWindow* window = g.NavWindow; - ImRect window_rect_rel(window->InnerVisibleRect.Min - window->Pos - ImVec2(1,1), window->InnerVisibleRect.Max - window->Pos + ImVec2(1,1)); + ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1,1), window->InnerRect.Max - window->Pos + ImVec2(1,1)); if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) { float pad = window->CalcFontSize() * 0.5f; @@ -8218,14 +8218,14 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags) { // Fallback manual-scroll when window has no navigable item if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) - SetWindowScrollY(window, window->Scroll.y - window->InnerVisibleRect.GetHeight()); + SetWindowScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) - SetWindowScrollY(window, window->Scroll.y + window->InnerVisibleRect.GetHeight()); + SetWindowScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); } else { const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; - const float page_offset_y = ImMax(0.0f, window->InnerVisibleRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); + const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); float nav_scoring_rect_offset_y = 0.0f; if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) { @@ -8701,7 +8701,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->InnerWorkRect.Max.x - window->Pos.x); + const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->WorkRect.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; @@ -9749,10 +9749,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; } - enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerVisibleRect, RT_InnerWorkRect, RT_InnerWorkRectClipped, RT_ContentsRegionRect, RT_ContentsFullRect }; + enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect }; static bool show_windows_begin_order = false; static bool show_windows_rects = false; - static int show_windows_rect_type = RT_InnerWorkRect; + static int show_windows_rect_type = RT_WorkRect; static bool show_drawcmd_clip_rects = true; ImGuiIO& io = ImGui::GetIO(); @@ -9769,9 +9769,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) { if (rect_type == RT_OuterRect) { return window->Rect(); } else if (rect_type == RT_OuterRectClipped) { return window->OuterRectClipped; } - else if (rect_type == RT_InnerVisibleRect) { return window->InnerVisibleRect; } - else if (rect_type == RT_InnerWorkRect) { return window->InnerWorkRect; } - else if (rect_type == RT_InnerWorkRectClipped) { return window->InnerWorkRectClipped; } + else if (rect_type == RT_InnerRect) { return window->InnerRect; } + else if (rect_type == RT_InnerClipRect) { return window->InnerClipRect; } + else if (rect_type == RT_WorkRect) { return window->WorkRect; } + else if (rect_type == RT_Contents) { return ImRect(window->Pos, window->Pos + window->SizeContents); } else if (rect_type == RT_ContentsRegionRect) { return window->ContentsRegionRect; } IM_ASSERT(0); return ImRect(); @@ -9979,7 +9980,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" "InnerVisibleRect\0" "InnerWorkRect\0" "InnerWorkRectClipped\0" "ContentsRegionRect\0"); + show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, "OuterRect\0" "OuterRectClipped\0" "InnerRect\0" "InnerClipRect\0" "WorkRect\0" "Contents\0" "ContentsRegionRect\0"); if (show_windows_rects && g.NavWindow) { ImRect r = Funcs::GetRect(g.NavWindow, show_windows_rect_type); diff --git a/imgui_internal.h b/imgui_internal.h index 6d396460..0af4a5ed 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1297,9 +1297,9 @@ struct IMGUI_API ImGuiWindow 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 InnerVisibleRect; // Inner visible rectangle - ImRect InnerWorkRect; // == InnerMainRect minus WindowPadding.x - ImRect InnerWorkRectClipped; // == InnerMainRect minus WindowPadding.x, clipped within viewport or parent clip rect. + ImRect InnerRect; // Inner rectangle + ImRect InnerClipRect; // == InnerRect minus WindowPadding.x, clipped within viewport or parent clip rect. + ImRect WorkRect; // == InnerRect minus WindowPadding.x 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; @@ -1501,8 +1501,8 @@ namespace ImGui IMGUI_API void PushMultiItemsWidths(int components, float width_full); IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); IMGUI_API void PopItemFlag(); - IMGUI_API bool IsItemToggledSelection(); // was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) - IMGUI_API ImVec2 GetWorkRectMax(); + IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) + IMGUI_API ImVec2 GetContentRegionMaxAbs(); IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); // Logging/Capture diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e806eec0..08c936fd 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -888,14 +888,14 @@ void ImGui::Scrollbar(ImGuiAxis axis) ImRect bb; if (axis == ImGuiAxis_X) { - bb.Min = ImVec2(window->InnerVisibleRect.Min.x, window->InnerVisibleRect.Max.y); - bb.Max = ImVec2(window->InnerVisibleRect.Max.x, outer_rect.Max.y - window->WindowBorderSize); + bb.Min = ImVec2(window->InnerRect.Min.x, window->InnerRect.Max.y); + bb.Max = ImVec2(window->InnerRect.Max.x, outer_rect.Max.y - window->WindowBorderSize); rounding_corners |= ImDrawCornerFlags_BotLeft; } else { - bb.Min = ImVec2(window->InnerVisibleRect.Max.x, window->InnerVisibleRect.Min.y); - bb.Max = ImVec2(outer_rect.Max.x - window->WindowBorderSize, window->InnerVisibleRect.Max.y); + bb.Min = ImVec2(window->InnerRect.Max.x, window->InnerRect.Min.y); + bb.Max = ImVec2(outer_rect.Max.x - window->WindowBorderSize, window->InnerRect.Max.y); rounding_corners |= ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0; } ScrollbarEx(bb, id, axis, &window->Scroll[axis], window->SizeFull[axis] - other_scrollbar_size, window->SizeContents[axis], rounding_corners); @@ -5127,7 +5127,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // We vertically grow up to current line height up the typical widget height. const float text_base_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); - ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetWorkRectMax().x, window->DC.CursorPos.y + frame_height)); + ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetContentRegionMaxAbs().x, window->DC.CursorPos.y + frame_height)); if (display_frame) { // Framed header expand a little outside the default padding @@ -6281,7 +6281,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->InnerWorkRect.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->WorkRect.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); } From 546b728199f1b41d0bd0fa72e4efdbc7c6a524c8 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 May 2019 16:00:34 +0200 Subject: [PATCH 2/3] Internals: Window rectangles: Fixed ContentsRegion lag by moving back after Scrollbar, fixes b50c61c9. Shuffling setup order and added comments. --- imgui.cpp | 62 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index bf738ff3..e42f3ae0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4996,6 +4996,8 @@ 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, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) { ImGuiContext& g = *GImGui; @@ -5503,39 +5505,46 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. window->SizeFullAtLastBegin = window->SizeFull; - // UPDATE RECTANGLES + // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) + // Update various regions. Variables they depends on should be set above in this function. + // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame. - // Update various regions. Variables they depends on are set above in this function. - // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. - // NB: WindowBorderSize is included in WindowPadding _and_ ScrollbarSizes so we need to cancel one out. - window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; - window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); - 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))); + // Outer rectangle + // Not affected by window border size. Used by: + // - FindHoveredWindow() (w/ extra padding when border resize is enabled) + // - Begin() initial clipping rect for drawing window background and borders. + // - Begin() clipping whole child + ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; + window->OuterRectClipped = window->Rect(); + window->OuterRectClipped.ClipWith(host_rect); // 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. + // Used by: + // - NavScrollToBringItemIntoView() + // - NavUpdatePageUpPageDown() + // - Scrollbar() const ImRect title_bar_rect = window->TitleBarRect(); window->InnerRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize; window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); window->InnerRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize); window->InnerRect.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 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. + // Work rectangle. + // Affected by window padding and border size. Used by: + // - Columns() for right-most edge + // - BeginTabBar() for right-most edge window->WorkRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->WorkRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y); window->WorkRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->WorkRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y); + + // Inner clipping rectangle. + // Will extend a little bit outside the normal 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. + // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. + // Affected by window/frame border size. Used by: + // - Begin() initial clip rect window->InnerClipRect = window->WorkRect; window->InnerClipRect.ClipWithFull(host_rect); @@ -5582,6 +5591,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); } + // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) + + // [LEGACY] Contents Region + // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + // NB: WindowBorderSize is included in WindowPadding _and_ ScrollbarSizes so we need to cancel one out when we have both. + // Used by: + // - Mouse wheel scrolling + // - ... (many things) + window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); + 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))); + // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; From 42c98c5eea852ef134df043f4cc525810c9076ee Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 30 May 2019 18:47:46 +0200 Subject: [PATCH 3/3] ImDrawList: Fix broken channel splitting (broken by d1e8b69) (#2591) --- imgui_draw.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 442c0e18..e4b906ff 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -568,7 +568,10 @@ void ImDrawList::ChannelsMerge() if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0) CmdBuffer.pop_back(); - int new_cmd_buffer_count = 0, new_idx_buffer_count = 0; + // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. + int new_cmd_buffer_count = 0; + int new_idx_buffer_count = 0; + int idx_offset = CmdBuffer.back().IdxOffset + CmdBuffer.back().ElemCount; for (int i = 1; i < _ChannelsCount; i++) { ImDrawChannel& ch = _Channels[i]; @@ -576,10 +579,16 @@ void ImDrawList::ChannelsMerge() ch.CmdBuffer.pop_back(); new_cmd_buffer_count += ch.CmdBuffer.Size; new_idx_buffer_count += ch.IdxBuffer.Size; + for (int cmd_n = 0; cmd_n < ch.CmdBuffer.Size; cmd_n++) + { + ch.CmdBuffer.Data[cmd_n].IdxOffset = idx_offset; + idx_offset += ch.CmdBuffer.Data[cmd_n].ElemCount; + } } CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count); IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count); + // Flatten our N channels at the end of the first one. ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count; _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count; for (int i = 1; i < _ChannelsCount; i++)