From b9874a24233bdc8b7a25c6107a6ae9bffea3477e Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 5 Jun 2019 12:05:53 +0200 Subject: [PATCH 01/12] Comments about obsoleted features version. Todo. Clarify tab bar initial offset (useful if we decide to remove the half-windowpadding clip margin). --- docs/TODO.txt | 2 ++ imgui.h | 20 ++++++++++---------- imgui_widgets.cpp | 7 ++++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index f32c944d..e6e119f1 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -69,6 +69,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - widgets: selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection) - widgets: checkbox: checkbox with custom glyph inside frame. - widgets: coloredit: keep reporting as active when picker is on? + - widgets: group/scalarn functions: expose more per-component information. e.g. store NextItemData.ComponentIdx set by scalarn function, groups can expose them back somehow. - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) @@ -231,6 +232,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - style: a concept of "compact style" that the end-user can easily rely on (e.g. PushStyleCompact()?) that maps to other settings? avoid implementing duplicate helpers such as SmallCheckbox(), etc. - style: try to make PushStyleVar() more robust to incorrect parameters (to be more friendly to edit & continues situation). - style: global scale setting. + - style: FramePadding could be different for up vs down (#584) - style: WindowPadding needs to be EVEN as the 0.5 multiplier used on this value probably have a subtle effect on clip rectangle - style: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438, #707, #1223) - style: gradients fill (#1223) ~ 2 bg colors for each fill? tricky with rounded shapes and using textures for corners. diff --git a/imgui.h b/imgui.h index c9cfcfec..b865679e 100644 --- a/imgui.h +++ b/imgui.h @@ -790,7 +790,7 @@ enum ImGuiTreeNodeFlags_ // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap + , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap // [renamed in 1.53] #endif }; @@ -801,7 +801,7 @@ enum ImGuiSelectableFlags_ ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too - ImGuiSelectableFlags_Disabled = 1 << 3 // Cannot be selected, display greyed out text + ImGuiSelectableFlags_Disabled = 1 << 3 // Cannot be selected, display grayed out text }; // Flags for ImGui::BeginCombo() @@ -1106,7 +1106,8 @@ enum ImGuiStyleVar_ // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT, ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding + , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT // [renamed in 1.60] + , ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding // [renamed in 1.53] #endif }; @@ -1151,7 +1152,7 @@ enum ImGuiColorEditFlags_ // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex + , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] #endif }; @@ -1172,7 +1173,7 @@ enum ImGuiMouseCursor_ // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT + , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT // [renamed in 1.60] #endif }; @@ -1188,7 +1189,7 @@ enum ImGuiCond_ // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiSetCond_Always = ImGuiCond_Always, ImGuiSetCond_Once = ImGuiCond_Once, ImGuiSetCond_FirstUseEver = ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing = ImGuiCond_Appearing + , ImGuiSetCond_Always = ImGuiCond_Always, ImGuiSetCond_Once = ImGuiCond_Once, ImGuiSetCond_FirstUseEver = ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing = ImGuiCond_Appearing // [renamed in 1.51] #endif }; @@ -1535,7 +1536,6 @@ namespace ImGui { // OBSOLETED in 1.71 (from May 2019) static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } - // OBSOLETED in 1.70 (from May 2019) static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // OBSOLETED in 1.69 (from Mar 2019) @@ -1570,7 +1570,7 @@ namespace ImGui static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } } -typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETE in 1.63 (from Aug 2018): made the names consistent +typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; #endif @@ -2153,7 +2153,7 @@ struct ImFontAtlas int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETE 1.67+ + typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ #endif }; @@ -2207,7 +2207,7 @@ struct ImFont IMGUI_API void SetFallbackChar(ImWchar c); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - typedef ImFontGlyph Glyph; // OBSOLETE 1.52+ + typedef ImFontGlyph Glyph; // OBSOLETED in 1.52+ #endif }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 24c7b3e3..aedaa0ef 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6460,7 +6460,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) } // Compute width - const float width_avail = tab_bar->BarRect.GetWidth(); + const float initial_offset_x = 0.0f; // g.Style.ItemInnerSpacing.x; + const float width_avail = ImMax(tab_bar->BarRect.GetWidth() - initial_offset_x, 0.0f); float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f; if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown)) { @@ -6480,7 +6481,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) } // Layout all active tabs - float offset_x = 0.0f; + float offset_x = initial_offset_x; + tab_bar->OffsetNextTab = offset_x; // This is used by non-reorderable tab bar where the submission order is always honored. for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; @@ -6490,7 +6492,6 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) offset_x += tab->Width + g.Style.ItemInnerSpacing.x; } tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f); - tab_bar->OffsetNextTab = 0.0f; // Horizontal scrolling buttons const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll); From 09bcf9fbc54e751aed79ca908811eef4f2b1d700 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 May 2019 16:18:30 +0200 Subject: [PATCH 02/12] Window rectangles: Made InnerRect not affected by window border sizes. its few users shouldn't be meaningfully affected. --- imgui.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 99fb8c2e..652651ab 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5519,15 +5519,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->OuterRectClipped.ClipWith(host_rect); // Inner rectangle - // Used by: + // Not affected by window border size. 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); + window->InnerRect.Min.x = title_bar_rect.Min.x; + window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight(); + window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; + window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; // Work rectangle. // Affected by window padding and border size. Used by: From a0994d74c256aaa582149a174385d2257a55728f Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 3 Jun 2019 15:35:55 +0200 Subject: [PATCH 03/12] Clarified behavior of SetNextWindowContentSize(). Content size is defined as the size available after removal of WindowPadding on each sides. So SetNextWindowContentSize(ImVec2(100,100)) + auto-resize will always allow submitting a 100x100 item without creating a scrollbar, regarding of WindowPadding.The exact meaning of ContentSize for decorated windows was previously ill-defined. --- docs/CHANGELOG.txt | 4 +++ imgui.cpp | 82 ++++++++++++++++++++++------------------------ imgui.h | 2 +- imgui_internal.h | 5 ++- imgui_widgets.cpp | 2 +- 5 files changed, 47 insertions(+), 48 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 09152b43..c0929a07 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,6 +37,10 @@ Breaking Changes: - Renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). Other Changes: +- Window: clarified behavior of SetNextWindowContentSize(). Content size is defined as the size available + after removal of WindowPadding on each sides. So SetNextWindowContentSize(ImVec2(100,100)) + auto-resize + will always allow submitting a 100x100 item without creating a scrollbar, regarding of WindowPadding. + The exact meaning of ContentSize for decorated windows was previously ill-defined. - Columns: Fixed Separator from creating an extraneous draw command. (#125) - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect diff --git a/imgui.cpp b/imgui.cpp index 652651ab..09a81fa9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4637,8 +4637,8 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl if (ImLengthSqr(settings->Size) > 0.00001f) size = ImFloor(settings->Size); } - window->Size = window->SizeFull = window->SizeFullAtLastBegin = ImFloor(size); - window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values + window->Size = window->SizeFull = ImFloor(size); + window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { @@ -4703,19 +4703,22 @@ static ImVec2 CalcSizeContents(ImGuiWindow* window) return window->SizeContents; ImVec2 sz; - sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x)); - sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y)); - return sz + window->WindowPadding; + sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); + sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); + return sz; } static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) { ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; + ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight()); + ImVec2 size_pad = window->WindowPadding * 2.0f; + ImVec2 size_desired = size_contents + size_pad + size_decorations; if (window->Flags & ImGuiWindowFlags_Tooltip) { // Tooltip always resize - return size_contents; + return size_desired; } else { @@ -4725,14 +4728,14 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) 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_auto_fit = ImClamp(size_contents, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); + ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f)); // When the window cannot fit all contents (either because of constraints, either because screen is too small), // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit); - if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) + if (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) size_auto_fit.y += style.ScrollbarSize; - if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) + if (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) size_auto_fit.x += style.ScrollbarSize; return size_auto_fit; } @@ -4746,12 +4749,12 @@ ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) float ImGui::GetWindowScrollMaxX(ImGuiWindow* window) { - return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x)); + return ImMax(0.0f, window->SizeContents.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); } float ImGui::GetWindowScrollMaxY(ImGuiWindow* window) { - return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y)); + return ImMax(0.0f, window->SizeContents.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); } static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) @@ -4761,7 +4764,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s if (window->ScrollTarget.x < FLT_MAX) { float cr_x = window->ScrollTargetCenterRatio.x; - scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); + scroll.x = window->ScrollTarget.x - cr_x * window->InnerRect.GetWidth(); } if (window->ScrollTarget.y < FLT_MAX) { @@ -4770,9 +4773,9 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s float target_y = window->ScrollTarget.y; if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y) target_y = 0.0f; - if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y) - target_y = window->SizeContents.y; - scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y); + if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y + window->WindowPadding.y + g.Style.ItemSpacing.y) + target_y = window->SizeContents.y + window->WindowPadding.y * 2.0f; + scroll.y = target_y - cr_y * window->InnerRect.GetHeight(); } scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); if (!window->Collapsed && !window->SkipItems) @@ -5280,16 +5283,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); } if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) - { - // Adjust passed "client size" to become a "window size" window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal; - if (window->SizeContentsExplicit.y != 0.0f) - window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight(); - } else if (first_begin_of_the_frame) - { window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); - } if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) @@ -5349,9 +5345,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } } + // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style) SetCurrentWindow(window); - // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies) + // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies) + if (flags & ImGuiWindowFlags_ChildWindow) window->WindowBorderSize = style.ChildBorderSize; else @@ -5417,13 +5415,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size). if (!window->Collapsed) { - // When reading the current size we need to read it after size constraints have been applied - float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x; - float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y; - window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); - window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + // When reading the current size we need to read it after size constraints have been applied. + // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. + float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->InnerRect.GetWidth() + window->ScrollbarSizes.x; + float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y - window->TitleBarHeight() - window->MenuBarHeight() : window->InnerRect.GetHeight() + window->ScrollbarSizes.y; + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x + window->WindowPadding.x * 2.0f > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); if (window->ScrollbarX && !window->ScrollbarY) - window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarY = (window->SizeContents.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); } @@ -5502,9 +5501,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); - // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. - window->SizeFullAtLastBegin = window->SizeFull; - // 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. @@ -6325,16 +6321,12 @@ ImVec2 ImGui::GetWindowPos() void ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x) { - window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it. window->Scroll.x = new_scroll_x; - window->DC.CursorMaxPos.x -= window->Scroll.x; } void ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y) { - window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it. window->Scroll.y = new_scroll_y; - window->DC.CursorMaxPos.y -= window->Scroll.y; } void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) @@ -6350,8 +6342,10 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) // Set const ImVec2 old_pos = window->Pos; window->Pos = ImFloor(pos); - window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor - window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected. + ImVec2 offset = window->Pos - old_pos; + window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so SizeContents calculation doesn't get affected. + window->DC.CursorStartPos += offset; } void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond) @@ -6495,11 +6489,13 @@ void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& s g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; } +// Content size = inner scrollable rectangle, padded with WindowPadding. +// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item. void ImGui::SetNextWindowContentSize(const ImVec2& size) { ImGuiContext& g = *GImGui; g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; - g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value. + g.NextWindowData.ContentSizeVal = size; } void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) @@ -6712,7 +6708,7 @@ void ImGui::SetScrollX(float scroll_x) void ImGui::SetScrollY(float scroll_y) { ImGuiWindow* window = GetCurrentWindow(); - window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY + window->ScrollTarget.y = scroll_y; window->ScrollTargetCenterRatio.y = 0.0f; } @@ -7717,7 +7713,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov ImGuiDir clip_dir = g.NavMoveDir; if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) { - bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x) - window->Scroll.x; + bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x + window->WindowPadding.x * 2.0f) - window->Scroll.x; if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; } NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); } @@ -7729,7 +7725,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov } if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) { - bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y) - window->Scroll.y; + bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y + window->WindowPadding.y * 2.0f) - window->Scroll.y; if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; } NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); } @@ -9794,7 +9790,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) 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_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->SizeContents); } else if (rect_type == RT_ContentsRegionRect) { return window->ContentsRegionRect; } IM_ASSERT(0); return ImRect(); diff --git a/imgui.h b/imgui.h index b865679e..394c2842 100644 --- a/imgui.h +++ b/imgui.h @@ -271,7 +271,7 @@ namespace ImGui IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0,0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints. - IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ enforce the range of scrollbars). not including window decorations (title bar, menu bar, etc.). set an axis to 0.0f to leave it automatic. call before Begin() + IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin() IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. diff --git a/imgui_internal.h b/imgui_internal.h index 2ad53b24..c28073ea 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1253,9 +1253,8 @@ struct IMGUI_API ImGuiWindow ImVec2 Pos; // Position (always rounded-up to nearest pixel) ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) ImVec2 SizeFull; // Size when non collapsed - ImVec2 SizeFullAtLastBegin; // Copy of SizeFull at the end of Begin. This is the reference value we'll use on the next frame to decide if we need scrollbars. - ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame. FIXME: Include decoration, window title, border, menu, etc. Ideally should remove them from this value? - ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize(). EXCLUDE decorations. Making this not consistent with the above! + ImVec2 SizeContents; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. + ImVec2 SizeContentsExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). ImVec2 WindowPadding; // Window padding at the time of begin. float WindowRounding; // Window rounding at the time of begin. float WindowBorderSize; // Window border size at the time of begin. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index aedaa0ef..d744d77b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -898,7 +898,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) 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); + ScrollbarEx(bb, id, axis, &window->Scroll[axis], window->InnerRect.Max[axis] - window->InnerRect.Min[axis], window->SizeContents[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners); } void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) From f95c77eeeae70383b3e278a33b511e0d63ee16ac Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 May 2019 21:49:22 +0200 Subject: [PATCH 04/12] Window rectangles: Changed WorkRect to cover the whole region including scrolling (toward obsolete ContentsRegionRect) + using full WindowPadding*1 padding. Tweaked InnerClipRect. TreeNode, CollapsingHeader: Fixed highlight frame not covering horizontal area fully when using horizontal scrolling. (#2211, #2579) TabBar: Fixed BeginTabBar() within a window with horizontal scrolling from creating a feedback loop with the horizontal contents size. Columns: Fixed Columns() within a window with horizontal scrolling from not covering the full horizontal area (previously only worked with an explicit contents size). (#125) Demo: Added demo code to test contentsrect/workrect --- docs/CHANGELOG.txt | 6 +++ imgui.cpp | 44 ++++++++++++---------- imgui_demo.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++-- imgui_internal.h | 16 +++++--- imgui_widgets.cpp | 17 +++++---- 5 files changed, 140 insertions(+), 35 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c0929a07..efbc663e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,12 @@ Other Changes: frame as clearing the focus. This was in most noticeable in back-ends such as Glfw and SDL which emits key release events when focusing another viewport, leading to Alt+clicking on void on another viewport triggering the issue. (#2609) +- TreeNode, CollapsingHeader: Fixed highlight frame not covering horizontal area fully when using + horizontal scrolling. (#2211, #2579) +- TabBar: Fixed BeginTabBar() within a window with horizontal scrolling from creating a feedback + loop with the horizontal contents size. +- Columns: Fixed Columns() within a window with horizontal scrolling from not covering the full + horizontal area (previously only worked with an explicit contents size). (#125) - Style: Added style.WindowMenuButtonPosition (left/right, defaults to ImGuiDir_Left) to move the collapsing/docking button to the other side of the title bar. - Style: Made window close button cross slightly smaller. diff --git a/imgui.cpp b/imgui.cpp index 09a81fa9..8038dfc5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4999,8 +4999,6 @@ 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; @@ -5511,7 +5509,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - 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(); + ImRect outer_rect = window->Rect(); + window->OuterRectClipped = outer_rect; window->OuterRectClipped.ClipWith(host_rect); // Inner rectangle @@ -5525,15 +5524,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; - // 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. @@ -5541,7 +5531,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // 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; + float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); + window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.y * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); window->InnerClipRect.ClipWithFull(host_rect); // DRAWING @@ -5589,12 +5583,25 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) + // Work rectangle. + // Affected by window padding and border size. Used by: + // - Columns() for right-most edge + // - TreeNode(), CollapsingHeader() for right-most edge + // - BeginTabBar() for right-most edge + const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); + const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); + const float work_rect_size_x = (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : ImMax(allow_scrollbar_x ? window->SizeContents.x : 0.0f, window->InnerRect.GetWidth() - window->WindowPadding.x * 2.0f)); + const float work_rect_size_y = (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : ImMax(allow_scrollbar_y ? window->SizeContents.y : 0.0f, window->InnerRect.GetHeight() - window->WindowPadding.y * 2.0f)); + window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); + window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); + window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; + window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; + // [LEGACY] Contents Region - // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + // FIXME-OBSOLETE: 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) + // - Mouse wheel scrolling + many other 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))); @@ -8719,9 +8726,8 @@ 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->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->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x; + columns->OffMaxX = ImMax(window->WorkRect.Max.x - window->Pos.x, columns->OffMinX + 1.0f); columns->HostCursorPosY = window->DC.CursorPos.y; columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; columns->HostClipRect = window->ClipRect; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b38fadc7..294e6f03 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -17,9 +17,18 @@ // In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is // essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data // in the same place, to make the demo source code faster to read, faster to write, and smaller in size. -// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant -// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is -// likely going to be stored outside your functions. +// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be +// reentrant or used in multiple threads. This might be a pattern you will want to use in your code, but most of the real data +// you would be editing is likely going to be stored outside your functions. + +// The Demo code is this file is designed to be easy to copy-and-paste in into your application! +// Because of this: +// - We never omit the ImGui:: namespace when calling functions, even though most of our code is already in the same namespace. +// - We try to declare static variables in the local scope, as close as possible to the code using them. +// - We never use any of the helpers/facilities used internally by dear imgui, unless it has been exposed in the public API (imgui.h). +// - We never use maths operators on ImVec2/ImVec4. For other imgui sources files, they are provided by imgui_internal.h w/ IMGUI_DEFINE_MATH_OPERATORS, +// for your own sources file they are optional and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. +// Because we don't want to assume anything about your support of maths operators, we don't use them in imgui_demo.cpp. /* @@ -2135,6 +2144,83 @@ static void ShowDemoWindowLayout() ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); ImGui::EndChild(); } + ImGui::Spacing(); + + static bool show_horizontal_contents_size_demo_window = false; + ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); + + if (show_horizontal_contents_size_demo_window) + { + static bool show_h_scrollbar = true; + static bool show_button = true; + static bool show_tree_nodes = true; + static bool show_columns = true; + static bool show_tab_bar = true; + static bool explicit_content_size = false; + static float contents_size_x = 300.0f; + if (explicit_content_size) + ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); + ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); + HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); + ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); + ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) + ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width + ImGui::Checkbox("Columns", &show_columns); // Will use contents size + ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size + ImGui::Checkbox("Explicit content size", &explicit_content_size); + if (explicit_content_size) + { + ImGui::SameLine(); + ImGui::SetNextItemWidth(100); + ImGui::DragFloat("##csx", &contents_size_x); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); + ImGui::Dummy(ImVec2(0, 10)); + } + ImGui::PopStyleVar(2); + ImGui::Separator(); + if (show_button) + { + ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); + } + if (show_tree_nodes) + { + bool open = true; + if (ImGui::TreeNode("this is a tree node")) + { + if (ImGui::TreeNode("another one of those tree node...")) + { + ImGui::Text("Some tree contents"); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + ImGui::CollapsingHeader("CollapsingHeader", &open); + } + if (show_columns) + { + ImGui::Columns(4); + for (int n = 0; n < 4; n++) + { + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::NextColumn(); + } + ImGui::Columns(1); + } + if (show_tab_bar && ImGui::BeginTabBar("Hello")) + { + if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } + ImGui::EndTabBar(); + } + ImGui::End(); + } + ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index c28073ea..e360f55a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1294,12 +1294,16 @@ 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 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 + + // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer. + // The main 'OuterRect', omitted as a field, is window->Rect(). + ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. + ImRect InnerRect; // Inner rectangle (omit title bar, menu bar) + ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. + ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentsRegionRect over time (from 1.71+ onward). + ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). + ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. + int LastFrameActive; // Last frame number the window was Active. float ItemWidthDefault; ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d744d77b..0a3c8684 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5127,12 +5127,12 @@ 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(GetContentRegionMaxAbs().x, window->DC.CursorPos.y + frame_height)); + ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->WorkRect.Max.x, window->DC.CursorPos.y + frame_height)); if (display_frame) { // Framed header expand a little outside the default padding - frame_bb.Min.x -= (float)(int)(window->WindowPadding.x * 0.5f) - 1; - frame_bb.Max.x += (float)(int)(window->WindowPadding.x * 0.5f) - 1; + frame_bb.Min.x -= (float)(int)(window->WindowPadding.x * 0.5f - 1.0f); + frame_bb.Max.x += (float)(int)(window->WindowPadding.x * 0.5f - 1.0f); } const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing @@ -6324,15 +6324,15 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG tab_bar->FramePadding = g.Style.FramePadding; // Layout - ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight())); + ItemSize(ImVec2(0.0f /*tab_bar->OffsetMax*/, tab_bar->BarRect.GetHeight())); // Don't feed width back window->DC.CursorPos.x = tab_bar->BarRect.Min.x; // Draw separator const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab); const float y = tab_bar->BarRect.Max.y - 1.0f; { - const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x; - const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x; + const float separator_min_x = tab_bar->BarRect.Min.x - ImFloor(window->WindowPadding.x * 0.5f); + const float separator_max_x = tab_bar->BarRect.Max.x + ImFloor(window->WindowPadding.x * 0.5f); window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); } return true; @@ -6874,7 +6874,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, if (want_clip_rect) PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true); - ItemSize(bb, style.FramePadding.y); + ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; + ItemSize(bb.GetSize(), style.FramePadding.y); + window->DC.CursorMaxPos = backup_cursor_max_pos; + if (!ItemAdd(bb, id)) { if (want_clip_rect) From fe32fde376033916acef02db528de929a69c28c3 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 3 Jun 2019 16:55:48 +0200 Subject: [PATCH 05/12] Internals: Renamed SizeContents to ContentSize, SizeContentsExplicit to ContentSizeExplicit. Tweaked Metrics->Show Rectangles functionality. --- imgui.cpp | 75 ++++++++++++++++++++++++++--------------------- imgui_internal.h | 6 ++-- imgui_widgets.cpp | 4 +-- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8038dfc5..c871445f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2550,7 +2550,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) Flags = ImGuiWindowFlags_None; Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); - SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f); + ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f); WindowPadding = ImVec2(0.0f, 0.0f); WindowRounding = 0.0f; WindowBorderSize = 0.0f; @@ -4638,7 +4638,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl size = ImFloor(settings->Size); } window->Size = window->SizeFull = ImFloor(size); - window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values + window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { @@ -4694,17 +4694,17 @@ static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) return new_size; } -static ImVec2 CalcSizeContents(ImGuiWindow* window) +static ImVec2 CalcContentSize(ImGuiWindow* window) { if (window->Collapsed) if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) - return window->SizeContents; + return window->ContentSize; if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0) - return window->SizeContents; + return window->ContentSize; ImVec2 sz; - sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); - sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); + sz.x = (float)(int)((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); + sz.y = (float)(int)((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); return sz; } @@ -4743,18 +4743,18 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) { - ImVec2 size_contents = CalcSizeContents(window); + ImVec2 size_contents = CalcContentSize(window); return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents)); } float ImGui::GetWindowScrollMaxX(ImGuiWindow* window) { - return ImMax(0.0f, window->SizeContents.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); + return ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); } float ImGui::GetWindowScrollMaxY(ImGuiWindow* window) { - return ImMax(0.0f, window->SizeContents.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); + return ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); } static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) @@ -4773,8 +4773,8 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s float target_y = window->ScrollTarget.y; if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y) target_y = 0.0f; - if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y + window->WindowPadding.y + g.Style.ItemSpacing.y) - target_y = window->SizeContents.y + window->WindowPadding.y * 2.0f; + if (snap_on_edges && cr_y >= 1.0f && target_y >= window->ContentSize.y + window->WindowPadding.y + g.Style.ItemSpacing.y) + target_y = window->ContentSize.y + window->WindowPadding.y * 2.0f; scroll.y = target_y - cr_y * window->InnerRect.GetHeight(); } scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); @@ -5281,9 +5281,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); } if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) - window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal; + window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal; else if (first_begin_of_the_frame) - window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); + window->ContentSizeExplicit = ImVec2(0.0f, 0.0f); if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) @@ -5318,7 +5318,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS // Update contents size from last frame for auto-fitting (or use explicit size) - window->SizeContents = CalcSizeContents(window); + window->ContentSize = CalcContentSize(window); if (window->HiddenFramesCanSkipItems > 0) window->HiddenFramesCanSkipItems--; if (window->HiddenFramesCannotSkipItems > 0) @@ -5329,7 +5329,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->HiddenFramesCannotSkipItems = 1; // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) - // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. + // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) { window->HiddenFramesCannotSkipItems = 1; @@ -5339,7 +5339,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->Size.x = window->SizeFull.x = 0.f; if (!window_size_y_set_by_api) window->Size.y = window->SizeFull.y = 0.f; - window->SizeContents = ImVec2(0.f, 0.f); + window->ContentSize = ImVec2(0.f, 0.f); } } @@ -5382,7 +5382,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // SIZE // Calculate auto-fit size, handle automatic resize - const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents); + const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->ContentSize); ImVec2 size_full_modified(FLT_MAX, FLT_MAX); if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) { @@ -5417,10 +5417,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->InnerRect.GetWidth() + window->ScrollbarSizes.x; float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y - window->TitleBarHeight() - window->MenuBarHeight() : window->InnerRect.GetHeight() + window->ScrollbarSizes.y; - window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); - window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x + window->WindowPadding.x * 2.0f > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->ContentSize.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->ContentSize.x + window->WindowPadding.x * 2.0f > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); if (window->ScrollbarX && !window->ScrollbarY) - window->ScrollbarY = (window->SizeContents.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarY = (window->ContentSize.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); } @@ -5590,8 +5590,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - BeginTabBar() for right-most edge const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); - const float work_rect_size_x = (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : ImMax(allow_scrollbar_x ? window->SizeContents.x : 0.0f, window->InnerRect.GetWidth() - window->WindowPadding.x * 2.0f)); - const float work_rect_size_y = (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : ImMax(allow_scrollbar_y ? window->SizeContents.y : 0.0f, window->InnerRect.GetHeight() - window->WindowPadding.y * 2.0f)); + const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->InnerRect.GetWidth() - window->WindowPadding.x * 2.0f)); + const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->InnerRect.GetHeight() - window->WindowPadding.y * 2.0f)); window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; @@ -5604,8 +5604,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - Mouse wheel scrolling + many other 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))); + window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.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->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.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.) @@ -6351,7 +6351,7 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) window->Pos = ImFloor(pos); ImVec2 offset = window->Pos - old_pos; window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor - window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so SizeContents calculation doesn't get affected. + window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. window->DC.CursorStartPos += offset; } @@ -7720,7 +7720,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov ImGuiDir clip_dir = g.NavMoveDir; if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) { - bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x + window->WindowPadding.x * 2.0f) - window->Scroll.x; + bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x; if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; } NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); } @@ -7732,7 +7732,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov } if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) { - bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y + window->WindowPadding.y * 2.0f) - window->Scroll.y; + bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y; if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; } NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); } @@ -9773,7 +9773,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; } - enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect }; + enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect, RT_Count }; static bool show_windows_begin_order = false; static bool show_windows_rects = false; static int show_windows_rect_type = RT_WorkRect; @@ -9796,7 +9796,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) 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) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->SizeContents); } + else if (rect_type == RT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } else if (rect_type == RT_ContentsRegionRect) { return window->ContentsRegionRect; } IM_ASSERT(0); return ImRect(); @@ -9901,7 +9901,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; ImGuiWindowFlags flags = window->Flags; NodeDrawList(window, window->DrawList, "DrawList"); - ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); + ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y); ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", @@ -10004,11 +10004,18 @@ 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" "InnerRect\0" "InnerClipRect\0" "WorkRect\0" "Contents\0" "ContentsRegionRect\0"); + const char* rects_names[RT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" }; + show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, rects_names, RT_Count); if (show_windows_rects && g.NavWindow) { - ImRect r = Funcs::GetRect(g.NavWindow, show_windows_rect_type); - ImGui::BulletText("'%s': (%.1f,%.1f) (%.1f,%.1f) Size (%.1f,%.1f)", g.NavWindow->Name, r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight()); + ImGui::BulletText("'%s':", g.NavWindow->Name); + ImGui::Indent(); + for (int n = 0; n < RT_Count; n++) + { + ImRect r = Funcs::GetRect(g.NavWindow, n); + ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), rects_names[n]); + } + ImGui::Unindent(); } ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects); ImGui::TreePop(); diff --git a/imgui_internal.h b/imgui_internal.h index e360f55a..87a2598e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1170,7 +1170,7 @@ struct IMGUI_API ImGuiWindowTempData ImVec2 CursorPos; ImVec2 CursorPosPrevLine; ImVec2 CursorStartPos; // Initial position in client area with padding - ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame + ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Used to calculate window->ContentSize at the beginning of next frame ImVec2 CurrLineSize; ImVec2 PrevLineSize; float CurrLineTextBaseOffset; @@ -1253,8 +1253,8 @@ struct IMGUI_API ImGuiWindow ImVec2 Pos; // Position (always rounded-up to nearest pixel) ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) ImVec2 SizeFull; // Size when non collapsed - ImVec2 SizeContents; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. - ImVec2 SizeContentsExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). + ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. + ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). ImVec2 WindowPadding; // Window padding at the time of begin. float WindowRounding; // Window rounding at the time of begin. float WindowBorderSize; // Window border size at the time of begin. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0a3c8684..351a558e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -847,7 +847,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa } // Apply scroll - // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position + // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); *p_scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); @@ -898,7 +898,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) 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->InnerRect.Max[axis] - window->InnerRect.Min[axis], window->SizeContents[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners); + ScrollbarEx(bb, id, axis, &window->Scroll[axis], window->InnerRect.Max[axis] - window->InnerRect.Min[axis], window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners); } void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) From d6df777ff2c52b5afaac2b9837c2ec1b71b6edc6 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 3 Jun 2019 17:07:43 +0200 Subject: [PATCH 06/12] TextWrapped, PushTextWrapPos(0.0f) within a window with horizontal scrolling from not covering the full horizontal area (previously only worked with an explicit contents size). --- imgui.cpp | 2 +- imgui_demo.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index c871445f..4c8812bc 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 = GetContentRegionMaxAbs().x; + wrap_pos_x = window->WorkRect.Max.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 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 294e6f03..c8d7b83f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2154,6 +2154,7 @@ static void ShowDemoWindowLayout() static bool show_h_scrollbar = true; static bool show_button = true; static bool show_tree_nodes = true; + static bool show_text_wrapped = false; static bool show_columns = true; static bool show_tab_bar = true; static bool explicit_content_size = false; @@ -2167,6 +2168,7 @@ static void ShowDemoWindowLayout() ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width + ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size ImGui::Checkbox("Columns", &show_columns); // Will use contents size ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size ImGui::Checkbox("Explicit content size", &explicit_content_size); @@ -2200,6 +2202,10 @@ static void ShowDemoWindowLayout() } ImGui::CollapsingHeader("CollapsingHeader", &open); } + if (show_text_wrapped) + { + ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); + } if (show_columns) { ImGui::Columns(4); From 06f1d2c10152d91a1af6864a22201d9407fdd58b Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 3 Jun 2019 18:51:12 +0200 Subject: [PATCH 07/12] Internals: Storing ScrollMax into a member. Mostly to facilitate debugging. Also locking down window->Scroll slightly lower in the Begin function. --- imgui.cpp | 46 ++++++++++++++++++++++++---------------------- imgui_internal.h | 3 +-- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4c8812bc..3851108a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4747,16 +4747,6 @@ ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents)); } -float ImGui::GetWindowScrollMaxX(ImGuiWindow* window) -{ - return ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); -} - -float ImGui::GetWindowScrollMaxY(ImGuiWindow* window) -{ - return ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); -} - static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) { ImGuiContext& g = *GImGui; @@ -4780,8 +4770,8 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s scroll = ImMax(scroll, ImVec2(0.0f, 0.0f)); if (!window->Collapsed && !window->SkipItems) { - scroll.x = ImMin(scroll.x, ImGui::GetWindowScrollMaxX(window)); - scroll.y = ImMin(scroll.y, ImGui::GetWindowScrollMaxY(window)); + scroll.x = ImMin(scroll.x, window->ScrollMax.x); + scroll.y = ImMin(scroll.y, window->ScrollMax.y); } return scroll; } @@ -5470,10 +5460,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; - // Apply scrolling - window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true); - window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); - // Apply window focus (new and reactivated windows are moved to front) bool want_focus = false; if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) @@ -5538,6 +5524,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); window->InnerClipRect.ClipWithFull(host_rect); + // SCROLLING + + // Lock down maximum scrolling + // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate + // for right/bottom aligned items without creating a scrollbar. + window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); + window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); + + // Apply scrolling + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true); + window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + // DRAWING // Setup draw list and outer clipping rectangle @@ -5619,7 +5617,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.NavHideHighlightOneFrame = false; - window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f); + window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; window->DC.NavLayerActiveMaskNext = 0x00; window->DC.MenuBarAppending = false; @@ -6687,22 +6685,26 @@ void ImGui::SetCursorScreenPos(const ImVec2& pos) float ImGui::GetScrollX() { - return GImGui->CurrentWindow->Scroll.x; + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.x; } float ImGui::GetScrollY() { - return GImGui->CurrentWindow->Scroll.y; + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.y; } float ImGui::GetScrollMaxX() { - return GetWindowScrollMaxX(GImGui->CurrentWindow); + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.x; } float ImGui::GetScrollMaxY() { - return GetWindowScrollMaxY(GImGui->CurrentWindow); + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.y; } void ImGui::SetScrollX(float scroll_x) @@ -9906,7 +9908,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); - ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetWindowScrollMaxX(window), window->Scroll.y, GetWindowScrollMaxY(window)); + ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y); ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); diff --git a/imgui_internal.h b/imgui_internal.h index 87a2598e..8faaa026 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1262,6 +1262,7 @@ struct IMGUI_API ImGuiWindow ImGuiID MoveId; // == window->GetID("#MOVE") ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) ImVec2 Scroll; + ImVec2 ScrollMax; ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered ImVec2 ScrollbarSizes; // Size taken by scrollbars on each axis @@ -1450,8 +1451,6 @@ namespace ImGui IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); IMGUI_API void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x); IMGUI_API void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y); - IMGUI_API float GetWindowScrollMaxX(ImGuiWindow* window); - IMGUI_API float GetWindowScrollMaxY(ImGuiWindow* window); IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window); IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0); IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0); From 4149d22e852a2556865e6ce9cb50a597cc754e14 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 3 Jun 2019 19:25:03 +0200 Subject: [PATCH 08/12] Fixed newly created window (e.g. appearing child window) from having scrollbar active on the first frame. (fix 6e03b27) + reworded code a little. (+1 squashed commits) Fixed auto-resize with AlwaysVerticalScrollbar or AlwaysHorizontalScrollbar flags not taking account of the expect scrollbar sizes. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index efbc663e..1375cb8e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,7 @@ Other Changes: after removal of WindowPadding on each sides. So SetNextWindowContentSize(ImVec2(100,100)) + auto-resize will always allow submitting a 100x100 item without creating a scrollbar, regarding of WindowPadding. The exact meaning of ContentSize for decorated windows was previously ill-defined. +- Window: Fixed auto-resize with AlwaysVerticalScrollbar or AlwaysHorizontalScrollbar flags. - Columns: Fixed Separator from creating an extraneous draw command. (#125) - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect diff --git a/imgui.cpp b/imgui.cpp index 3851108a..e926bf8e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4733,9 +4733,11 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents) // When the window cannot fit all contents (either because of constraints, either because screen is too small), // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit); - if (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + if (will_have_scrollbar_x) size_auto_fit.y += style.ScrollbarSize; - if (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) + if (will_have_scrollbar_y) size_auto_fit.x += style.ScrollbarSize; return size_auto_fit; } @@ -5405,12 +5407,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { // When reading the current size we need to read it after size constraints have been applied. // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. - float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->InnerRect.GetWidth() + window->ScrollbarSizes.x; - float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y - window->TitleBarHeight() - window->MenuBarHeight() : window->InnerRect.GetHeight() + window->ScrollbarSizes.y; - window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->ContentSize.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); - window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->ContentSize.x + window->WindowPadding.x * 2.0f > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - window->TitleBarHeight() - window->MenuBarHeight()); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; + ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0,0) : window->ContentSize + window->WindowPadding * 2.0f; + float size_x_for_scrollbars = (size_full_modified.x != FLT_MAX || window_just_created) ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; + float size_y_for_scrollbars = (size_full_modified.y != FLT_MAX || window_just_created) ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); if (window->ScrollbarX && !window->ScrollbarY) - window->ScrollbarY = (window->ContentSize.y + window->WindowPadding.y * 2.0f > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); } From 15282261ddfd3bdd651a348b2ca8484ae217da26 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 4 Jun 2019 16:22:47 +0200 Subject: [PATCH 09/12] Internals: Minor no-op tidying up toward solving the WindowPadding / WindowBorderSize / ScrollbarSize overlapping mess. + Demo: Use SetScrollY(). --- imgui.cpp | 20 ++++++++++++-------- imgui_demo.cpp | 29 ++++++++++++++++++++--------- imgui_widgets.cpp | 11 +++++++---- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e926bf8e..bc51d8aa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5400,6 +5400,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull); window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; + // Decoration size + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + // SCROLLBAR STATUS // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size). @@ -5407,7 +5410,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { // When reading the current size we need to read it after size constraints have been applied. // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. - ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - window->TitleBarHeight() - window->MenuBarHeight()); + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0,0) : window->ContentSize + window->WindowPadding * 2.0f; float size_x_for_scrollbars = (size_full_modified.x != FLT_MAX || window_just_created) ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; @@ -5499,19 +5502,20 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - 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; - ImRect outer_rect = window->Rect(); + const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; + const ImRect outer_rect = window->Rect(); + const ImRect title_bar_rect = window->TitleBarRect(); window->OuterRectClipped = outer_rect; window->OuterRectClipped.ClipWith(host_rect); // Inner rectangle // Not affected by window border size. Used by: + // - InnerClipRect // - NavScrollToBringItemIntoView() // - NavUpdatePageUpPageDown() // - Scrollbar() - const ImRect title_bar_rect = window->TitleBarRect(); - window->InnerRect.Min.x = title_bar_rect.Min.x; - window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight(); + window->InnerRect.Min.x = window->Pos.x; + window->InnerRect.Min.y = window->Pos.y + decoration_up_height; window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; @@ -5606,7 +5610,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Used by: // - Mouse wheel scrolling + many other 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.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.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->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->ScrollbarSizes.y + ImMin(window->ScrollbarSizes.y, window->WindowBorderSize))); @@ -5615,7 +5619,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; window->DC.GroupOffset.x = 0.0f; window->DC.ColumnsOffset.x = 0.0f; - window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y); + window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y); window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPosPrevLine = window->DC.CursorPos; window->DC.CursorMaxPos = window->DC.CursorStartPos; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c8d7b83f..58f1dbec 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2059,14 +2059,21 @@ static void ShowDemoWindowLayout() HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position."); static bool track = true; - static int track_line = 50, scroll_to_px = 200; + static int track_line = 50; + static float scroll_to_off_px = 0.0f; + static float scroll_to_pos_px = 200.0f; ImGui::Checkbox("Track", &track); ImGui::PushItemWidth(100); - ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d"); - 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::SameLine(140); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d"); + + bool scroll_to_off = ImGui::Button("Scroll Offset"); + ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off_y", &scroll_to_off_px, 1.00f, 0, 9999, "+%.0f px"); + + bool scroll_to_pos = ImGui::Button("Scroll To Pos"); + ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos_y", &scroll_to_pos_px, 1.00f, 0, 9999, "Y = %.0f px"); + ImGui::PopItemWidth(); - if (scroll_to) + if (scroll_to_off || scroll_to_pos) track = false; ImGuiStyle& style = ImGui::GetStyle(); @@ -2076,9 +2083,13 @@ static void ShowDemoWindowLayout() 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(child_w, 200.0f), true); - if (scroll_to) - ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f); + + ImGuiWindowFlags child_flags = ImGuiWindowFlags_MenuBar; + ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags); + if (scroll_to_off) + ImGui::SetScrollY(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); for (int line = 0; line < 100; line++) { if (track && line == track_line) @@ -2094,7 +2105,7 @@ static void ShowDemoWindowLayout() float scroll_y = ImGui::GetScrollY(); float scroll_max_y = ImGui::GetScrollMaxY(); ImGui::EndChild(); - ImGui::Text("%.0f/%0.f", scroll_y, scroll_max_y); + ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); ImGui::EndGroup(); } ImGui::TreePop(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 351a558e..becb5fe9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -883,22 +883,25 @@ void ImGui::Scrollbar(ImGuiAxis axis) // Calculate scrollbar bounding box const ImRect outer_rect = window->Rect(); + const ImRect inner_rect = window->InnerRect; + const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; + IM_ASSERT(scrollbar_size > 0.0f); IM_UNUSED(scrollbar_size); const float other_scrollbar_size = window->ScrollbarSizes[axis]; ImDrawCornerFlags rounding_corners = (other_scrollbar_size <= 0.0f) ? ImDrawCornerFlags_BotRight : 0; ImRect bb; if (axis == ImGuiAxis_X) { - bb.Min = ImVec2(window->InnerRect.Min.x, window->InnerRect.Max.y); - bb.Max = ImVec2(window->InnerRect.Max.x, outer_rect.Max.y - window->WindowBorderSize); + bb.Min = ImVec2(inner_rect.Min.x, inner_rect.Max.y); + bb.Max = ImVec2(inner_rect.Max.x, outer_rect.Max.y - window->WindowBorderSize); rounding_corners |= ImDrawCornerFlags_BotLeft; } else { - bb.Min = ImVec2(window->InnerRect.Max.x, window->InnerRect.Min.y); + bb.Min = ImVec2(inner_rect.Max.x, inner_rect.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->InnerRect.Max[axis] - window->InnerRect.Min[axis], window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners); + ScrollbarEx(bb, id, axis, &window->Scroll[axis], inner_rect.Max[axis] - inner_rect.Min[axis], window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners); } void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) From c1a61d25a71823d21943ff33121f75f344346955 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 5 Jun 2019 15:23:01 +0200 Subject: [PATCH 10/12] Scrollbar overlap an extra WindowBorderSize amount on the left to make all distances consistent. Reverted to BorderSize not affecting work/contents rectangles. Scrollbar, Style: Changed default style.ScrollbarSize from 16 to 14. --- docs/CHANGELOG.txt | 3 ++- imgui.cpp | 45 +++++++++++++++++++++++++++++---------------- imgui_demo.cpp | 8 ++++++++ imgui_widgets.cpp | 11 ++++++----- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1375cb8e..11c98068 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,7 +57,8 @@ Other Changes: - ColorEdit: Fixed the color picker popup only displaying inputs as HSV instead of showing multiple options. (#2587, broken in 1.69 by #2384). - CollapsingHeader: Better clipping when a close button is enabled and it overlaps the label. (#600) -- Scrollbar: Very minor bounding box adjustment to cope with various border size. +- Scrollbar: Minor bounding box adjustment to cope with various border size. +- Scrollbar, Style: Changed default style.ScrollbarSize from 16 to 14. - Combo: Fixed rounding not applying with the ImGuiComboFlags_NoArrowButton flag. (#2607) [@DucaRii] - Nav: Fixed gamepad/keyboard moving of window affecting contents size incorrectly, sometimes leading to scrollbars appearing during the movement. diff --git a/imgui.cpp b/imgui.cpp index bc51d8aa..039f93f6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1146,7 +1146,7 @@ ImGuiStyle::ImGuiStyle() TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). - ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar + ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. @@ -5375,23 +5375,36 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Calculate auto-fit size, handle automatic resize const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->ContentSize); - ImVec2 size_full_modified(FLT_MAX, FLT_MAX); + bool use_current_size_for_scrollbar_x = window_just_created; + bool use_current_size_for_scrollbar_y = window_just_created; if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) { // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. if (!window_size_x_set_by_api) - window->SizeFull.x = size_full_modified.x = size_auto_fit.x; + { + window->SizeFull.x = size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } if (!window_size_y_set_by_api) - window->SizeFull.y = size_full_modified.y = size_auto_fit.y; + { + window->SizeFull.y = size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } } else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) { // Auto-fit may only grow window during the first few frames // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) - window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; + { + window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) - window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; + { + window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } if (!window->Collapsed) MarkIniSettingsDirty(window); } @@ -5403,18 +5416,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Decoration size const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); - // SCROLLBAR STATUS + // SCROLLBAR VISIBILITY - // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size). + // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size). if (!window->Collapsed) { // When reading the current size we need to read it after size constraints have been applied. // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; - ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0,0) : window->ContentSize + window->WindowPadding * 2.0f; - float size_x_for_scrollbars = (size_full_modified.x != FLT_MAX || window_just_created) ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; - float size_y_for_scrollbars = (size_full_modified.y != FLT_MAX || window_just_created) ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; + float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; + float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); if (window->ScrollbarX && !window->ScrollbarY) @@ -5597,8 +5611,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // - BeginTabBar() for right-most edge const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); - const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->InnerRect.GetWidth() - window->WindowPadding.x * 2.0f)); - const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->InnerRect.GetHeight() - window->WindowPadding.y * 2.0f)); + const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; @@ -5606,13 +5620,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // [LEGACY] Contents Region // FIXME-OBSOLETE: 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 other 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 + decoration_up_height; - window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.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->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->ScrollbarSizes.y + ImMin(window->ScrollbarSizes.y, window->WindowBorderSize))); + window->ContentsRegionRect.Max.x = window->ContentsRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + window->ContentsRegionRect.Max.y = window->ContentsRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); // 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.) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 58f1dbec..6abfbbf2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2168,6 +2168,7 @@ static void ShowDemoWindowLayout() static bool show_text_wrapped = false; static bool show_columns = true; static bool show_tab_bar = true; + static bool show_child = false; static bool explicit_content_size = false; static float contents_size_x = 300.0f; if (explicit_content_size) @@ -2182,7 +2183,9 @@ static void ShowDemoWindowLayout() ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size ImGui::Checkbox("Columns", &show_columns); // Will use contents size ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size + ImGui::Checkbox("Child", &show_child); // Will grow and use contents size ImGui::Checkbox("Explicit content size", &explicit_content_size); + ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); if (explicit_content_size) { ImGui::SameLine(); @@ -2235,6 +2238,11 @@ static void ShowDemoWindowLayout() if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } ImGui::EndTabBar(); } + if (show_child) + { + ImGui::BeginChild("child", ImVec2(0,0), true); + ImGui::EndChild(); + } ImGui::End(); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index becb5fe9..39307243 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -884,21 +884,22 @@ void ImGui::Scrollbar(ImGuiAxis axis) // Calculate scrollbar bounding box const ImRect outer_rect = window->Rect(); const ImRect inner_rect = window->InnerRect; + const float border_size = window->WindowBorderSize; const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; - IM_ASSERT(scrollbar_size > 0.0f); IM_UNUSED(scrollbar_size); + IM_ASSERT(scrollbar_size > 0.0f); const float other_scrollbar_size = window->ScrollbarSizes[axis]; ImDrawCornerFlags rounding_corners = (other_scrollbar_size <= 0.0f) ? ImDrawCornerFlags_BotRight : 0; ImRect bb; if (axis == ImGuiAxis_X) { - bb.Min = ImVec2(inner_rect.Min.x, inner_rect.Max.y); - bb.Max = ImVec2(inner_rect.Max.x, outer_rect.Max.y - window->WindowBorderSize); + bb.Min = ImVec2(inner_rect.Min.x, outer_rect.Max.y - border_size - scrollbar_size); + bb.Max = ImVec2(inner_rect.Max.x, outer_rect.Max.y); rounding_corners |= ImDrawCornerFlags_BotLeft; } else { - bb.Min = ImVec2(inner_rect.Max.x, inner_rect.Min.y); - bb.Max = ImVec2(outer_rect.Max.x - window->WindowBorderSize, window->InnerRect.Max.y); + bb.Min = ImVec2(outer_rect.Max.x - border_size - scrollbar_size, inner_rect.Min.y); + bb.Max = ImVec2(outer_rect.Max.x, window->InnerRect.Max.y); rounding_corners |= ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0; } ScrollbarEx(bb, id, axis, &window->Scroll[axis], inner_rect.Max[axis] - inner_rect.Min[axis], window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners); From 300d8dd6569d1b45e67fbed9b05b4cc077d30690 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 5 Jun 2019 15:32:37 +0200 Subject: [PATCH 11/12] Internals: Moved scrollbar visibility calculation block below the call to UpdateManualResize(). This commit is _intended_ to have no side-effect (next commit will). Also moved ItemWidthDefault calculation below rectangles. --- imgui.cpp | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 039f93f6..183b8c2d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5416,26 +5416,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Decoration size const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); - // SCROLLBAR VISIBILITY - - // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size). - if (!window->Collapsed) - { - // When reading the current size we need to read it after size constraints have been applied. - // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. - ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); - ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; - ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; - float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; - float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; - //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? - window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); - window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); - if (window->ScrollbarX && !window->ScrollbarY) - window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); - window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); - } - // POSITION // Popup latch its initial position, will position itself when it appears next frame @@ -5466,7 +5446,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) window->Pos = FindBestWindowPosForPopup(window); - // Clamp position so it stays visible + // Clamp position/size so it stays visible // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. ImRect viewport_rect(GetViewportRect()); if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) @@ -5501,11 +5481,25 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); window->ResizeBorderHeld = (signed char)border_held; - // Default item width. Make it proportional to window size if window manually resizes - if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) - window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); - else - window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); + // SCROLLBAR VISIBILITY + + // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size). + if (!window->Collapsed) + { + // When reading the current size we need to read it after size constraints have been applied. + // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; + ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; + float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; + float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + if (window->ScrollbarX && !window->ScrollbarY) + window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); + } // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) // Update various regions. Variables they depends on should be set above in this function. @@ -5547,6 +5541,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); window->InnerClipRect.ClipWithFull(host_rect); + // Default item width. Make it proportional to window size if window manually resizes + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) + window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); + else + window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); + // SCROLLING // Lock down maximum scrolling From c96f2c40571c32700e0568fb4165badc93a7559c Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 5 Jun 2019 15:33:41 +0200 Subject: [PATCH 12/12] Window: Fixed one case where auto-resize by double-clicking the resize grip would make either scrollbar appear for a single frame after the resize. Moved Scrollbar visibility block. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 11c98068..2833b29f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -42,6 +42,8 @@ Other Changes: will always allow submitting a 100x100 item without creating a scrollbar, regarding of WindowPadding. The exact meaning of ContentSize for decorated windows was previously ill-defined. - Window: Fixed auto-resize with AlwaysVerticalScrollbar or AlwaysHorizontalScrollbar flags. +- Window: Fixed one case where auto-resize by double-clicking the resize grip would make either scrollbar + appear for a single frame after the resize. - Columns: Fixed Separator from creating an extraneous draw command. (#125) - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect diff --git a/imgui.cpp b/imgui.cpp index 183b8c2d..36ad3b44 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1077,7 +1077,7 @@ static int FindWindowFocusIndex(ImGuiWindow* window); // Misc static void UpdateMouseInputs(); static void UpdateMouseWheel(); -static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); +static bool UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); static void RenderWindowOuterBorders(ImGuiWindow* window); static void 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); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); @@ -4829,15 +4829,18 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_ } // Handle resize for: Resize Grips, Borders, Gamepad -static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) +// Return true when using auto-fit (double click on resize grip) +static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) { ImGuiContext& g = *GImGui; ImGuiWindowFlags flags = window->Flags; + if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) - return; + return false; if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. - return; + return false; + bool ret_auto_fit = false; const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f); @@ -4871,6 +4874,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au { // Manual auto-fit when double-clicking size_target = CalcSizeAfterConstraint(window, size_auto_fit); + ret_auto_fit = true; ClearActiveID(); } else if (held) @@ -4945,6 +4949,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); window->Size = window->SizeFull; + return ret_auto_fit; } static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding) @@ -5478,7 +5483,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4 const float resize_grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); if (!window->Collapsed) - UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); + if (UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0])) + use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; window->ResizeBorderHeld = (signed char)border_held; // SCROLLBAR VISIBILITY