From 6e2bb3fb584a0c5ca92d6b02d584a9028bfacc03 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 14 Feb 2025 13:54:02 +0800 Subject: [PATCH] scrollbar: Update scrollbar hitbox to it bounds, not fill the full of parent view. (#624) And revert some #621 wrong changes for hover to show scrollbar. --- crates/ui/src/scroll/scrollbar.rs | 29 +++++++++++++++++++++++------ crates/ui/src/table.rs | 20 ++++++++++++++------ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/crates/ui/src/scroll/scrollbar.rs b/crates/ui/src/scroll/scrollbar.rs index bae1c07d..3fa3bdc3 100644 --- a/crates/ui/src/scroll/scrollbar.rs +++ b/crates/ui/src/scroll/scrollbar.rs @@ -32,7 +32,7 @@ impl ScrollbarShow { } const BORDER_WIDTH: Pixels = px(0.); -const WIDTH: Pixels = px(12.); +pub(crate) const WIDTH: Pixels = px(12.); const MIN_THUMB_SIZE: f32 = 80.; const THUMB_RADIUS: Pixels = Pixels(4.0); const THUMB_INSET: Pixels = Pixels(3.); @@ -123,8 +123,8 @@ impl ScrollbarState { fn with_hovered(&self, axis: Option) -> Self { let mut state = *self; state.hovered_axis = axis; - if self.is_scrollbar_visible() { - state.last_scroll_time = Some(Instant::now()); + if axis.is_some() { + state.last_scroll_time = Some(std::time::Instant::now()); } state } @@ -132,6 +132,9 @@ impl ScrollbarState { fn with_hovered_on_thumb(&self, axis: Option) -> Self { let mut state = *self; state.hovered_on_thumb = axis; + if axis.is_some() { + state.last_scroll_time = Some(std::time::Instant::now()); + } state } @@ -159,7 +162,8 @@ impl ScrollbarState { } fn is_scrollbar_visible(&self) -> bool { - if self.hovered_axis.is_some() || self.dragged_axis.is_some() { + // On drag + if self.dragged_axis.is_some() { return true; } @@ -629,6 +633,15 @@ impl Element for Scrollbar { let is_visible = self.state.get().is_scrollbar_visible(); let is_hover_to_show = cx.theme().scrollbar_show.is_hover(); + // Update last_scroll_time when offset is changed. + if self.scroll_handle.offset() != self.state.get().last_scroll_offset { + self.state.set( + self.state + .get() + .with_last_scroll(self.scroll_handle.offset(), Some(Instant::now())), + ); + } + window.with_content_mask( Some(ContentMask { bounds: hitbox_bounds, @@ -754,10 +767,14 @@ impl Element for Scrollbar { move |event: &MouseMoveEvent, _, _, cx| { let mut notify = false; + // When is hover to show mode or it was visible, + // we need to update the hovered state and increase the last_scroll_time. + let need_hover_to_update = is_hover_to_show || is_visible; // Update hovered state for scrollbar - if bounds.contains(&event.position) { + if bounds.contains(&event.position) && need_hover_to_update { + state.set(state.get().with_hovered(Some(axis))); + if state.get().hovered_axis != Some(axis) { - state.set(state.get().with_hovered(Some(axis))); notify = true; } } else { diff --git a/crates/ui/src/table.rs b/crates/ui/src/table.rs index f0101d43..69ba2c60 100644 --- a/crates/ui/src/table.rs +++ b/crates/ui/src/table.rs @@ -4,15 +4,16 @@ use crate::{ context_menu::ContextMenuExt, h_flex, popup_menu::PopupMenu, - scroll::{ScrollableMask, Scrollbar, ScrollbarState}, + scroll::{self, ScrollableMask, Scrollbar, ScrollbarState}, v_flex, ActiveTheme, Icon, IconName, Sizable, Size, StyleSized as _, }; use gpui::{ actions, canvas, div, prelude::FluentBuilder, px, uniform_list, App, AppContext, Axis, Bounds, Context, Div, DragMoveEvent, Edges, Empty, EntityId, EventEmitter, FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, ListSizingBehavior, MouseButton, MouseDownEvent, - ParentElement, Pixels, Point, Render, ScrollHandle, ScrollStrategy, SharedString, Stateful, - StatefulInteractiveElement as _, Styled, Task, UniformListScrollHandle, Window, + ParentElement, Pixels, Point, Render, ScrollHandle, ScrollStrategy, ScrollWheelEvent, + SharedString, Stateful, StatefulInteractiveElement as _, Styled, Task, UniformListScrollHandle, + Window, }; mod loading; @@ -861,11 +862,15 @@ where Some( div() + .occlude() .absolute() .top(self.size.table_row_height()) - .left_0() .right_0() .bottom_0() + .w(scroll::WIDTH) + .on_scroll_wheel(cx.listener(|_, _: &ScrollWheelEvent, _, cx| { + cx.notify(); + })) .child( Scrollbar::uniform_scroll( cx.entity().entity_id(), @@ -885,12 +890,15 @@ where let state = self.horizontal_scrollbar_state.clone(); div() + .occlude() .absolute() - .top_0() .left_0() .right_0() .bottom_0() - .size_full() + .h(scroll::WIDTH) + .on_scroll_wheel(cx.listener(|_, _: &ScrollWheelEvent, _, cx| { + cx.notify(); + })) .child(Scrollbar::horizontal( cx.entity().entity_id(), state,