From 0a6c9e0f74adfea8b47f16973779b80ea7dbef7c Mon Sep 17 00:00:00 2001 From: Maciek <108873945+rozwader@users.noreply.github.com> Date: Wed, 16 Sep 2026 18:30:55 +0200 Subject: [PATCH] fix: fixed scrollbar overlapping with the scrollview content (#817) --- .../src/components/scrollview.rs | 28 ++++++++++++++++++- .../src/layout/settings_shell.rs | 1 + .../src/view/app/cluster/cluster_settings.rs | 1 + .../src/view/app/cluster/overview.rs | 1 + .../view/app/cluster/package_manager/views.rs | 2 ++ .../src/view/app/cluster/screenshots.rs | 1 + 6 files changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/oneclient_app/src/components/scrollview.rs b/packages/oneclient_app/src/components/scrollview.rs index 46978be6..cadeed8e 100644 --- a/packages/oneclient_app/src/components/scrollview.rs +++ b/packages/oneclient_app/src/components/scrollview.rs @@ -4,6 +4,7 @@ use freya::prelude::*; use crate::theme::colors; const LAZY_OVERSCAN: i64 = 3; +const SCROLLBAR_GUTTER: f32 = 14.; pub(crate) fn normalize_wheel_delta(delta: f64, scale_factor: f64) -> f32 { if delta == 0.0 { @@ -86,6 +87,7 @@ pub struct ScrollArea { padding: Gaps, spacing: f32, show_scrollbar: bool, + scrollbar_gutter: bool, horizontal: bool, content_width: f32, stick_bottom: bool, @@ -111,6 +113,7 @@ impl ScrollArea { padding: Gaps::default(), spacing: 0., show_scrollbar: true, + scrollbar_gutter: false, horizontal: false, content_width: 0., stick_bottom: false, @@ -148,6 +151,11 @@ impl ScrollArea { self } + pub fn scrollbar_gutter(mut self, gutter: bool) -> Self { + self.scrollbar_gutter = gutter; + self + } + pub fn horizontal(mut self, content_width: f32) -> Self { self.horizontal = true; self.content_width = content_width; @@ -244,6 +252,7 @@ impl ScrollArea { let spacing = self.spacing; let padding = self.padding; let show_scrollbar = self.show_scrollbar; + let scrollbar_gutter = self.scrollbar_gutter; let stick_bottom = self.stick_bottom; let on_user_scroll = self.on_user_scroll.clone(); @@ -293,10 +302,26 @@ impl ScrollArea { let pressing_v = use_memo(move || drag_start.read().is_some()); let pressing_h = use_memo(move || drag_start_x.read().is_some()); + let gutter = if show_v && scrollbar_gutter { + SCROLLBAR_GUTTER + } else { + 0. + }; + let padding = if gutter > 0. { + Gaps::new( + padding.top(), + padding.right() + gutter, + padding.bottom(), + padding.left(), + ) + } else { + padding + }; + let ctx = ScrollAreaCtx { corrected_x, corrected_y, - viewport_w: vp_w, + viewport_w: (vp_w - gutter).max(0.), viewport_h: vp_h, viewport_top: vp_top, viewport_left: vp_left, @@ -536,6 +561,7 @@ impl PartialEq for ScrollArea { && self.padding == other.padding && self.spacing == other.spacing && self.show_scrollbar == other.show_scrollbar + && self.scrollbar_gutter == other.scrollbar_gutter && self.horizontal == other.horizontal && self.content_width == other.content_width && self.stick_bottom == other.stick_bottom diff --git a/packages/oneclient_app/src/layout/settings_shell.rs b/packages/oneclient_app/src/layout/settings_shell.rs index c1d44c5a..3eaef38d 100644 --- a/packages/oneclient_app/src/layout/settings_shell.rs +++ b/packages/oneclient_app/src/layout/settings_shell.rs @@ -439,6 +439,7 @@ impl Component for SettingsShell { .width(Size::fill()) .height(Size::flex(1.0)) .show_scrollbar(true) + .scrollbar_gutter(true) .spacing(4.) .scroll_controller(scroll) .on_ctx(|ctx| { diff --git a/packages/oneclient_app/src/view/app/cluster/cluster_settings.rs b/packages/oneclient_app/src/view/app/cluster/cluster_settings.rs index 02de529e..3d1de122 100644 --- a/packages/oneclient_app/src/view/app/cluster/cluster_settings.rs +++ b/packages/oneclient_app/src/view/app/cluster/cluster_settings.rs @@ -69,6 +69,7 @@ impl Component for ClusterSettings { ScrollArea::new() .width(Size::fill()) .height(Size::fill()) + .scrollbar_gutter(true) .spacing(4.) .child(section_header("GAME")) .child( diff --git a/packages/oneclient_app/src/view/app/cluster/overview.rs b/packages/oneclient_app/src/view/app/cluster/overview.rs index 73fd5153..160616e9 100644 --- a/packages/oneclient_app/src/view/app/cluster/overview.rs +++ b/packages/oneclient_app/src/view/app/cluster/overview.rs @@ -39,6 +39,7 @@ impl Component for ClusterOverview { ScrollArea::new() .width(Size::fill()) .height(Size::fill()) + .scrollbar_gutter(true) .child( rect() .vertical() diff --git a/packages/oneclient_app/src/view/app/cluster/package_manager/views.rs b/packages/oneclient_app/src/view/app/cluster/package_manager/views.rs index ea2c99f8..c2b82416 100644 --- a/packages/oneclient_app/src/view/app/cluster/package_manager/views.rs +++ b/packages/oneclient_app/src/view/app/cluster/package_manager/views.rs @@ -623,6 +623,7 @@ impl Component for ContentBox { ScrollArea::new() .width(Size::fill()) .height(Size::fill()) + .scrollbar_gutter(true) .lazy(count, CARD_H, CARD_SPACING, move |i| { let item = items[i].clone(); let key = item.package_id.clone(); @@ -636,6 +637,7 @@ impl Component for ContentBox { CardLayout::Grid => ScrollArea::new() .width(Size::fill()) .height(Size::fill()) + .scrollbar_gutter(true) .content(move |ctx: ScrollAreaCtx| { grid_content(&items, package_type, cluster_id, grid_columns, ctx).into_element() }) diff --git a/packages/oneclient_app/src/view/app/cluster/screenshots.rs b/packages/oneclient_app/src/view/app/cluster/screenshots.rs index cb7e8ce2..bc3e24c9 100644 --- a/packages/oneclient_app/src/view/app/cluster/screenshots.rs +++ b/packages/oneclient_app/src/view/app/cluster/screenshots.rs @@ -139,6 +139,7 @@ impl Component for ClusterScreenshots { let body = ScrollArea::new() .width(Size::fill()) .height(Size::flex(1.0)) + .scrollbar_gutter(true) .children(vec![content]); let confirm_overlay = confirm_delete.read().then(|| {