diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a895256ab..2c6574adf 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,8 @@ Other Changes: - RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - Window: Fixed initial width of collapsed windows not taking account of contents width (broken in 1.67). (#2336, #176) +- Scrollbar: Fade out and disable interaction when too small, in order to facilitate using the resize grab on very + small window, as well as reducing visual noise/overlap. - ListBox: Better optimized when clipped / non-visible. - InputTextMultiline: Better optimized when clipped / non-visible. - Font: Fixed high-level ImGui::CalcTextSize() used by most widgets from erroneously subtracting 1.0f*scale to diff --git a/imgui_internal.h b/imgui_internal.h index f25d208e2..e2bbfbf15 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1464,6 +1464,7 @@ namespace ImGui IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API void Scrollbar(ImGuiLayoutType direction); + IMGUI_API ImGuiID GetScrollbarID(ImGuiLayoutType direction); IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. // Widgets low-level behaviors diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 17dbeda4c..64ce6c485 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -710,6 +710,13 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) return pressed; } +ImGuiID ImGui::GetScrollbarID(ImGuiLayoutType direction) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + return window->GetID((direction == ImGuiLayoutType_Horizontal) ? "#SCROLLX" : "#SCROLLY"); +} + // Vertical/Horizontal scrollbar // The entire piece of code below is rather confusing because: // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) @@ -722,8 +729,8 @@ void ImGui::Scrollbar(ImGuiLayoutType direction) const bool horizontal = (direction == ImGuiLayoutType_Horizontal); const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY"); - + const ImGuiID id = GetScrollbarID(direction); + // Render background bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX); float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f; @@ -734,9 +741,21 @@ void ImGui::Scrollbar(ImGuiLayoutType direction) : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); if (!horizontal) bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); - if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f) + + const float bb_height = bb.GetHeight(); + if (bb.GetWidth() <= 0.0f || bb_height <= 0.0f) return; + // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab) + float alpha = 1.0f; + if ((direction == ImGuiLayoutType_Vertical) && bb_height < g.FontSize + g.Style.FramePadding.y * 2.0f) + { + alpha = ImSaturate((bb_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); + if (alpha <= 0.0f) + return; + } + const bool allow_interaction = (alpha >= 1.0f); + int window_rounding_corners; if (horizontal) window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); @@ -767,7 +786,7 @@ void ImGui::Scrollbar(ImGuiLayoutType direction) float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v); float scroll_ratio = ImSaturate(scroll_v / scroll_max); float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; - if (held && grab_h_norm < 1.0f) + if (held && allow_interaction && grab_h_norm < 1.0f) { float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y; float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; @@ -810,8 +829,8 @@ void ImGui::Scrollbar(ImGuiLayoutType direction) *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f; } - // Render - const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); + // Render grab + const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); ImRect grab_rect; if (horizontal) grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y);