From a9dbfce8f959957173670b333494c9d1cd099d4c Mon Sep 17 00:00:00 2001 From: MrSubidubi Date: Thu, 14 Aug 2025 17:22:55 +0200 Subject: [PATCH] Impl for uniformlist and notify cleanupds --- crates/gpui/src/elements/uniform_list.rs | 35 ++++++-- crates/ui/src/components/scrollbar.rs | 108 +++++++++++++---------- 2 files changed, 91 insertions(+), 52 deletions(-) diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index cdf90d4eb8..9c601aac1d 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -5,10 +5,10 @@ //! elements with uniform height. use crate::{ - AnyElement, App, AvailableSpace, Bounds, ContentMask, Element, ElementId, GlobalElementId, - Hitbox, InspectorElementId, InteractiveElement, Interactivity, IntoElement, IsZero, LayoutId, - ListSizingBehavior, Overflow, Pixels, Point, ScrollHandle, Size, StyleRefinement, Styled, - Window, point, size, + AnyElement, App, AvailableSpace, Bounds, ContentMask, Element, ElementId, Entity, + GlobalElementId, Hitbox, InspectorElementId, InteractiveElement, Interactivity, IntoElement, + IsZero, LayoutId, ListSizingBehavior, Overflow, Pixels, Point, ScrollHandle, Size, + StyleRefinement, Styled, Window, point, size, }; use smallvec::SmallVec; use std::{cell::RefCell, cmp, ops::Range, rc::Rc}; @@ -71,7 +71,7 @@ pub struct UniformList { /// Frame state used by the [UniformList]. pub struct UniformListFrameState { items: SmallVec<[AnyElement; 32]>, - decorations: SmallVec<[AnyElement; 1]>, + decorations: SmallVec<[AnyElement; 2]>, } /// A handle for controlling the scroll position of a uniform list. @@ -529,6 +529,31 @@ pub trait UniformListDecoration { ) -> AnyElement; } +impl UniformListDecoration for Entity { + fn compute( + &self, + visible_range: Range, + bounds: Bounds, + scroll_offset: Point, + item_height: Pixels, + item_count: usize, + window: &mut Window, + cx: &mut App, + ) -> AnyElement { + self.update(cx, |inner, cx| { + inner.compute( + visible_range, + bounds, + scroll_offset, + item_height, + item_count, + window, + cx, + ) + }) + } +} + impl UniformList { /// Selects a specific list item for measurement. pub fn with_width_from_item(mut self, item_index: Option) -> Self { diff --git a/crates/ui/src/components/scrollbar.rs b/crates/ui/src/components/scrollbar.rs index 6fed7238a4..292e37f556 100644 --- a/crates/ui/src/components/scrollbar.rs +++ b/crates/ui/src/components/scrollbar.rs @@ -237,40 +237,43 @@ where } } -// impl UniformListDecoration -// for ScrollbarState -// { -// fn compute( -// &self, -// visible_range: Range, -// bounds: Bounds, -// scroll_offset: Point, -// item_height: Pixels, -// item_count: usize, -// window: &mut Window, -// cx: &mut App, -// ) -> gpui::AnyElement { -// let element = ScrollbarElement::new(self); -// } -// } +impl UniformListDecoration + for ScrollbarStateWrapper +{ + fn compute( + &self, + _visible_range: Range, + _bounds: Bounds, + _scroll_offset: Point, + _item_height: Pixels, + _item_count: usize, + _window: &mut Window, + _cx: &mut App, + ) -> gpui::AnyElement { + ScrollbarElement { + state: self.0.clone(), + } + .into_any() + } +} -// impl WithScrollbar for UniformList { -// type Output = Self; +impl WithScrollbar for UniformList { + type Output = Self; -// fn custom_scrollbars( -// self, -// config: Scrollbars, -// window: &mut Window, -// cx: &mut App, -// ) -> Self::Output -// where -// S: ScrollbarVisibilitySetting, -// T: ScrollableHandle, -// { -// let scrollbar = get_scrollbar_state(config, std::panic::Location::caller(), window, cx); -// self.with_decoration(scrollbar) -// } -// } + fn custom_scrollbars( + self, + config: Scrollbars, + window: &mut Window, + cx: &mut App, + ) -> Self::Output + where + S: ScrollbarVisibilitySetting, + T: ScrollableHandle, + { + let scrollbar = get_scrollbar_state(config, std::panic::Location::caller(), window, cx); + self.with_decoration(scrollbar) + } +} #[derive(PartialEq, Eq)] pub enum ScrollAxes { @@ -568,6 +571,16 @@ impl ScrollbarState { &self.scroll_handle } + fn set_offset(&mut self, offset: Point, cx: &mut Context) { + if self.scroll_handle.offset() != offset { + self.scroll_handle.set_offset(offset); + self.notify_parent(cx); + } + + // We always want to show scrollbars in cases where the offset is updated. + self.show_scrollbars(cx); + } + fn is_dragging(&self) -> bool { self.thumb_state.is_dragging() } @@ -1044,7 +1057,7 @@ impl Element for ScrollbarEl if thumb_bounds.contains(&event.position) { let offset = event.position.along(*axis) - thumb_bounds.origin.along(*axis); - state.set_dragging(*axis, offset, cx) + state.set_dragging(*axis, offset, cx); } else { let scroll_handle = state.scroll_handle(); let click_offset = scrollbar_layout.compute_click_offset( @@ -1052,12 +1065,13 @@ impl Element for ScrollbarEl scroll_handle.max_offset(), ScrollbarMouseEvent::TrackClick, ); - scroll_handle.set_offset( + state.set_offset( scroll_handle.offset().apply_along(*axis, |_| click_offset), + cx, ); + }; - cx.stop_propagation(); - } + cx.stop_propagation(); }); } }); @@ -1071,10 +1085,14 @@ impl Element for ScrollbarEl { let scroll_handle = state.read(cx).scroll_handle(); let current_offset = scroll_handle.offset(); - scroll_handle.set_offset( - current_offset + event.delta.pixel_delta(window.line_height()), - ); - state.update(cx, |state, cx| state.show_scrollbars(cx)); + state.update(cx, |state, cx| { + state.set_offset( + current_offset + event.delta.pixel_delta(window.line_height()), + cx, + ); + state.show_scrollbars(cx); + cx.stop_propagation(); + }); } } }); @@ -1096,13 +1114,10 @@ impl Element for ScrollbarEl scroll_handle.max_offset(), ScrollbarMouseEvent::ThumbDrag(drag_state), ); - scroll_handle.set_offset( - scroll_handle.offset().apply_along(axis, |_| drag_offset), - ); + let new_offset = + scroll_handle.offset().apply_along(axis, |_| drag_offset); - // todo! Needed? - window.refresh(); - state.update(cx, |state, cx| state.notify_parent(cx)); + state.update(cx, |state, cx| state.set_offset(new_offset, cx)); cx.stop_propagation(); } } @@ -1133,7 +1148,6 @@ impl Element for ScrollbarEl state.update(cx, |state, cx| { if state.is_dragging() { state.scroll_handle().drag_ended(); - state.notify_parent(cx); } if !state.parent_hovered(&event.position) {