From fd33832609044060de869fe3b0e18b078562f703 Mon Sep 17 00:00:00 2001 From: MrSubidubi Date: Wed, 13 Aug 2025 18:15:40 +0200 Subject: [PATCH] Do not notify the parent unintentionally --- crates/gpui/src/window.rs | 4 +- crates/ui/src/components/scrollbar.rs | 116 ++++++++++++++++++-------- 2 files changed, 83 insertions(+), 37 deletions(-) diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 0d7e3d3e0c..85620102e0 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -2504,7 +2504,7 @@ impl Window { &mut self, key: impl Into, cx: &mut App, - init: impl FnOnce(&mut Self, &mut Context) -> S, + init: impl FnOnce(&mut Self, &mut App) -> S, ) -> Entity { let current_view = self.current_view(); self.with_global_id(key.into(), |global_id, window| { @@ -2537,7 +2537,7 @@ impl Window { pub fn use_state( &mut self, cx: &mut App, - init: impl FnOnce(&mut Self, &mut Context) -> S, + init: impl FnOnce(&mut Self, &mut App) -> S, ) -> Entity { self.use_keyed_state( ElementId::CodeLocation(*core::panic::Location::caller()), diff --git a/crates/ui/src/components/scrollbar.rs b/crates/ui/src/components/scrollbar.rs index 7b9ea36471..6fed7238a4 100644 --- a/crates/ui/src/components/scrollbar.rs +++ b/crates/ui/src/components/scrollbar.rs @@ -1,13 +1,13 @@ use std::{fmt::Debug, marker::PhantomData, ops::Not, time::Duration}; use gpui::{ - Along, App, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, Context, Corner, Corners, - CursorStyle, Div, Edges, Element, ElementId, Entity, EntityId, GlobalElementId, Hitbox, - HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero, LayoutId, ListState, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, - Position, Render, ScrollHandle, ScrollWheelEvent, Size, Stateful, StatefulInteractiveElement, - Style, Styled, Task, UniformListScrollHandle, Window, prelude::FluentBuilder as _, px, quad, - relative, size, + Along, App, AppContext as _, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, Context, + Corner, Corners, CursorStyle, Div, Edges, Element, ElementId, Entity, EntityId, + GlobalElementId, Hitbox, HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero, + LayoutId, ListState, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, + Pixels, Point, Position, Render, ScrollHandle, ScrollWheelEvent, Size, Stateful, + StatefulInteractiveElement, Style, Styled, Task, UniformList, UniformListDecoration, + UniformListScrollHandle, Window, prelude::FluentBuilder as _, px, quad, relative, size, }; use settings::SettingsStore; use smallvec::SmallVec; @@ -92,6 +92,23 @@ pub mod scrollbars { impl Global for ScrollbarAutoHide {} } +fn get_scrollbar_state( + mut config: Scrollbars, + caller_location: &'static std::panic::Location, + window: &mut Window, + cx: &mut App, +) -> Entity> +where + S: ScrollbarVisibilitySetting, + T: ScrollableHandle, +{ + let element_id = config.id.take().unwrap_or_else(|| caller_location.into()); + + window.use_keyed_state(element_id, cx, |window, cx| { + ScrollbarStateWrapper(cx.new(|cx| ScrollbarState::new_from_config(config, window, cx))) + }) +} + pub trait WithScrollbar: Sized { type Output; @@ -146,7 +163,7 @@ impl WithScrollbar for Stateful
{ #[track_caller] fn custom_scrollbars( self, - mut config: Scrollbars, + config: Scrollbars, window: &mut Window, cx: &mut App, ) -> Self::Output @@ -154,16 +171,11 @@ impl WithScrollbar for Stateful
{ S: ScrollbarVisibilitySetting, T: ScrollableHandle, { - let element_id = config - .id - .take() - .unwrap_or_else(|| core::panic::Location::caller().into()); - - let scrollbar = window.use_keyed_state(element_id.clone(), cx, |window, cx| { - ScrollbarState::new_from_config(config, window, cx) - }); - - render_scrollbar(scrollbar, self, cx) + render_scrollbar( + get_scrollbar_state(config, std::panic::Location::caller(), window, cx), + self, + cx, + ) } } @@ -173,7 +185,7 @@ impl WithScrollbar for Div { #[track_caller] fn custom_scrollbars( self, - mut config: Scrollbars, + config: Scrollbars, window: &mut Window, cx: &mut App, ) -> Self::Output @@ -181,14 +193,7 @@ impl WithScrollbar for Div { S: ScrollbarVisibilitySetting, T: ScrollableHandle, { - let element_id = config - .id - .take() - .unwrap_or_else(|| core::panic::Location::caller().into()); - - let scrollbar = window.use_keyed_state(element_id.clone(), cx, |window, cx| { - ScrollbarState::new_from_config(config, window, cx) - }); + let scrollbar = get_scrollbar_state(config, std::panic::Location::caller(), window, cx); // We know this ID stays consistent as long as the element is rendered for // consecutive frames, which is sufficient for our use case here let scrollbar_entity_id = scrollbar.entity_id(); @@ -202,7 +207,7 @@ impl WithScrollbar for Div { } fn render_scrollbar( - scrollbar: Entity>, + scrollbar: Entity>, div: Stateful
, cx: &App, ) -> Stateful
@@ -210,28 +215,63 @@ where S: ScrollbarVisibilitySetting, T: ScrollableHandle, { - if scrollbar.read(cx).disabled() { + let state = &scrollbar.read(cx).0; + + if state.read(cx).disabled() { div } else { - div.when_some(scrollbar.read(cx).handle_to_track(), |this, handle| { + div.when_some(state.read(cx).handle_to_track(), |this, handle| { this.track_scroll(handle) }) .when_some( - scrollbar + state .read(cx) .space_to_reserve_for(ScrollbarAxis::Horizontal), |this, space| this.pb(space), ) .when_some( - scrollbar - .read(cx) - .space_to_reserve_for(ScrollbarAxis::Vertical), + state.read(cx).space_to_reserve_for(ScrollbarAxis::Vertical), |this, space| this.pr(space), ) - .child(scrollbar) + .child(state.clone()) } } +// 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 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) +// } +// } + #[derive(PartialEq, Eq)] pub enum ScrollAxes { Horizontal, @@ -417,6 +457,12 @@ impl VisibilityState { } } +/// This is used to ensure notifies within the state do not notify the parent +/// unintentionally. +struct ScrollbarStateWrapper( + Entity>, +); + /// A scrollbar state that should be persisted across frames. struct ScrollbarState { thumb_state: ThumbState,