scrollbar: Refactor ScrollbarState to have Cell inside. (#959)

## Break Change

- Now we added `Rc<Cell<>>` inside the ScrollbarState.

```diff
- scroll_state: Rc<Cell<ScrollbarState>>,
+ scroll_state: ScrollbarState,
```
This commit is contained in:
Jason Lee 2025-06-16 15:11:52 +08:00 committed by GitHub
parent 769c0990a4
commit 61283a71f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 50 additions and 50 deletions

View file

@ -1,4 +1,3 @@
use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use gpui::{ use gpui::{
@ -18,7 +17,7 @@ pub struct ScrollableStory {
focus_handle: gpui::FocusHandle, focus_handle: gpui::FocusHandle,
scroll_handle: ScrollHandle, scroll_handle: ScrollHandle,
scroll_size: gpui::Size<Pixels>, scroll_size: gpui::Size<Pixels>,
scroll_state: Rc<Cell<ScrollbarState>>, scroll_state: ScrollbarState,
items: Vec<String>, items: Vec<String>,
item_sizes: Rc<Vec<Size<Pixels>>>, item_sizes: Rc<Vec<Size<Pixels>>>,
test_width: Pixels, test_width: Pixels,
@ -41,7 +40,7 @@ impl ScrollableStory {
Self { Self {
focus_handle: cx.focus_handle(), focus_handle: cx.focus_handle(),
scroll_handle: ScrollHandle::new(), scroll_handle: ScrollHandle::new(),
scroll_state: Rc::new(Cell::new(ScrollbarState::default())), scroll_state: ScrollbarState::default(),
scroll_size: gpui::Size::default(), scroll_size: gpui::Size::default(),
items, items,
item_sizes: Rc::new(item_sizes), item_sizes: Rc::new(item_sizes),
@ -80,7 +79,7 @@ impl ScrollableStory {
.map(|_| size(self.test_width, ITEM_HEIGHT)) .map(|_| size(self.test_width, ITEM_HEIGHT))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into(); .into();
self.scroll_state.set(ScrollbarState::default()); self.scroll_state = ScrollbarState::default();
cx.notify(); cx.notify();
} }

View file

@ -1,8 +1,6 @@
use std::{ use std::{
any::Any, any::Any,
cell::Cell,
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
rc::Rc,
sync::Arc, sync::Arc,
}; };
@ -139,7 +137,7 @@ pub struct Tiles {
resizing_drag_data: Option<ResizeDrag>, resizing_drag_data: Option<ResizeDrag>,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
history: History<TileChange>, history: History<TileChange>,
scroll_state: Rc<Cell<ScrollbarState>>, scroll_state: ScrollbarState,
scroll_handle: ScrollHandle, scroll_handle: ScrollHandle,
} }
@ -193,7 +191,7 @@ impl Tiles {
resizing_drag_data: None, resizing_drag_data: None,
bounds: Bounds::default(), bounds: Bounds::default(),
history: History::new().group_interval(std::time::Duration::from_millis(100)), history: History::new().group_interval(std::time::Duration::from_millis(100)),
scroll_state: Rc::new(Cell::new(ScrollbarState::default())), scroll_state: ScrollbarState::default(),
scroll_handle: ScrollHandle::default(), scroll_handle: ScrollHandle::default(),
} }
} }

View file

@ -4,7 +4,7 @@
//! https://github.com/zed-industries/zed/blob/main/crates/gpui/examples/input.rs //! https://github.com/zed-industries/zed/blob/main/crates/gpui/examples/input.rs
use serde::Deserialize; use serde::Deserialize;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::cell::{Cell, RefCell}; use std::cell::RefCell;
use std::ops::{Deref, Range}; use std::ops::{Deref, Range};
use std::rc::Rc; use std::rc::Rc;
use unicode_segmentation::*; use unicode_segmentation::*;
@ -260,7 +260,7 @@ pub struct InputState {
pub(super) pattern: Option<regex::Regex>, pub(super) pattern: Option<regex::Regex>,
pub(super) validate: Option<Box<dyn Fn(&str) -> bool + 'static>>, pub(super) validate: Option<Box<dyn Fn(&str) -> bool + 'static>>,
pub(crate) scroll_handle: ScrollHandle, pub(crate) scroll_handle: ScrollHandle,
pub(super) scrollbar_state: Rc<Cell<ScrollbarState>>, pub(super) scroll_state: ScrollbarState,
/// The size of the scrollable content. /// The size of the scrollable content.
pub(crate) scroll_size: gpui::Size<Pixels>, pub(crate) scroll_size: gpui::Size<Pixels>,
pub(crate) line_number_width: Pixels, pub(crate) line_number_width: Pixels,
@ -337,7 +337,7 @@ impl InputState {
last_line_height: px(20.), last_line_height: px(20.),
last_cursor_offset: None, last_cursor_offset: None,
scroll_handle: ScrollHandle::new(), scroll_handle: ScrollHandle::new(),
scrollbar_state: Rc::new(Cell::new(ScrollbarState::default())), scroll_state: ScrollbarState::default(),
scroll_size: gpui::size(px(0.), px(0.)), scroll_size: gpui::size(px(0.), px(0.)),
preferred_x_offset: None, preferred_x_offset: None,
line_number_width: px(0.), line_number_width: px(0.),

View file

@ -7,7 +7,7 @@ use gpui::{
use crate::button::{Button, ButtonVariants as _}; use crate::button::{Button, ButtonVariants as _};
use crate::indicator::Indicator; use crate::indicator::Indicator;
use crate::input::clear_button; use crate::input::clear_button;
use crate::scroll::{Scrollbar, ScrollbarAxis}; use crate::scroll::Scrollbar;
use crate::ActiveTheme; use crate::ActiveTheme;
use crate::{h_flex, StyledExt}; use crate::{h_flex, StyledExt};
use crate::{IconName, Size}; use crate::{IconName, Size};
@ -308,15 +308,12 @@ impl RenderOnce for TextInput {
.left_0() .left_0()
.right(px(1.)) .right(px(1.))
.bottom_0() .bottom_0()
.child( .child(Scrollbar::vertical(
Scrollbar::vertical( entity_id,
entity_id, state.scroll_state.clone(),
state.scrollbar_state.clone(), state.scroll_handle.clone(),
state.scroll_handle.clone(), scroll_size,
scroll_size, )),
)
.axis(ScrollbarAxis::Vertical),
),
) )
} else { } else {
this this

View file

@ -1,6 +1,5 @@
use std::ops::Range; use std::ops::Range;
use std::time::Duration; use std::time::Duration;
use std::{cell::Cell, rc::Rc};
use crate::actions::{Cancel, Confirm, SelectNext, SelectPrev}; use crate::actions::{Cancel, Confirm, SelectNext, SelectPrev};
use crate::input::InputState; use crate::input::InputState;
@ -161,7 +160,7 @@ pub struct List<D: ListDelegate> {
querying: bool, querying: bool,
scrollbar_visible: bool, scrollbar_visible: bool,
vertical_scroll_handle: UniformListScrollHandle, vertical_scroll_handle: UniformListScrollHandle,
scrollbar_state: Rc<Cell<ScrollbarState>>, scroll_state: ScrollbarState,
pub(crate) size: Size, pub(crate) size: Size,
selected_index: Option<usize>, selected_index: Option<usize>,
right_clicked_index: Option<usize>, right_clicked_index: Option<usize>,
@ -193,7 +192,7 @@ where
selected_index: None, selected_index: None,
right_clicked_index: None, right_clicked_index: None,
vertical_scroll_handle: UniformListScrollHandle::new(), vertical_scroll_handle: UniformListScrollHandle::new(),
scrollbar_state: Rc::new(Cell::new(ScrollbarState::new())), scroll_state: ScrollbarState::default(),
max_height: None, max_height: None,
scrollbar_visible: true, scrollbar_visible: true,
selectable: true, selectable: true,
@ -295,7 +294,7 @@ where
Some(Scrollbar::uniform_scroll( Some(Scrollbar::uniform_scroll(
cx.entity().entity_id(), cx.entity().entity_id(),
self.scrollbar_state.clone(), self.scroll_state.clone(),
self.vertical_scroll_handle.clone(), self.vertical_scroll_handle.clone(),
)) ))
} }

View file

@ -12,7 +12,6 @@ use gpui::{
SharedString, StatefulInteractiveElement, Styled, WeakEntity, Window, SharedString, StatefulInteractiveElement, Styled, WeakEntity, Window,
}; };
use gpui::{MouseDownEvent, Subscription}; use gpui::{MouseDownEvent, Subscription};
use std::cell::Cell;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
@ -109,7 +108,7 @@ pub struct PopupMenu {
scrollable: bool, scrollable: bool,
external_link_icon: bool, external_link_icon: bool,
scroll_handle: ScrollHandle, scroll_handle: ScrollHandle,
scroll_state: Rc<Cell<ScrollbarState>>, scroll_state: ScrollbarState,
previous_focus_handle: Option<FocusHandle>, previous_focus_handle: Option<FocusHandle>,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
@ -144,7 +143,7 @@ impl PopupMenu {
bounds: Bounds::default(), bounds: Bounds::default(),
scrollable: false, scrollable: false,
scroll_handle: ScrollHandle::default(), scroll_handle: ScrollHandle::default(),
scroll_state: Rc::new(Cell::new(ScrollbarState::default())), scroll_state: ScrollbarState::default(),
external_link_icon: true, external_link_icon: true,
_subscriptions, _subscriptions,
}; };

View file

@ -75,7 +75,7 @@ where
pub struct ScrollViewState { pub struct ScrollViewState {
scroll_size: Rc<Cell<Size<Pixels>>>, scroll_size: Rc<Cell<Size<Pixels>>>,
state: Rc<Cell<ScrollbarState>>, state: ScrollbarState,
handle: ScrollHandle, handle: ScrollHandle,
} }
@ -84,7 +84,7 @@ impl Default for ScrollViewState {
Self { Self {
handle: ScrollHandle::new(), handle: ScrollHandle::new(),
scroll_size: Rc::new(Cell::new(Size::default())), scroll_size: Rc::new(Cell::new(Size::default())),
state: Rc::new(Cell::new(ScrollbarState::default())), state: ScrollbarState::default(),
} }
} }
} }

View file

@ -1,5 +1,6 @@
use std::{ use std::{
cell::Cell, cell::Cell,
ops::Deref,
rc::Rc, rc::Rc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -79,8 +80,11 @@ impl ScrollHandleOffsetable for UniformListScrollHandle {
} }
} }
#[derive(Debug, Clone)]
pub struct ScrollbarState(Rc<Cell<ScrollbarStateInner>>);
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ScrollbarState { pub struct ScrollbarStateInner {
hovered_axis: Option<ScrollbarAxis>, hovered_axis: Option<ScrollbarAxis>,
hovered_on_thumb: Option<ScrollbarAxis>, hovered_on_thumb: Option<ScrollbarAxis>,
dragged_axis: Option<ScrollbarAxis>, dragged_axis: Option<ScrollbarAxis>,
@ -93,7 +97,7 @@ pub struct ScrollbarState {
impl Default for ScrollbarState { impl Default for ScrollbarState {
fn default() -> Self { fn default() -> Self {
Self { Self(Rc::new(Cell::new(ScrollbarStateInner {
hovered_axis: None, hovered_axis: None,
hovered_on_thumb: None, hovered_on_thumb: None,
dragged_axis: None, dragged_axis: None,
@ -101,15 +105,19 @@ impl Default for ScrollbarState {
last_scroll_offset: point(px(0.), px(0.)), last_scroll_offset: point(px(0.), px(0.)),
last_scroll_time: None, last_scroll_time: None,
last_update: Instant::now(), last_update: Instant::now(),
} })))
} }
} }
impl ScrollbarState { impl Deref for ScrollbarState {
pub fn new() -> Self { type Target = Rc<Cell<ScrollbarStateInner>>;
Self::default()
}
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ScrollbarStateInner {
fn with_drag_pos(&self, axis: ScrollbarAxis, pos: Point<Pixels>) -> Self { fn with_drag_pos(&self, axis: ScrollbarAxis, pos: Point<Pixels>) -> Self {
let mut state = *self; let mut state = *self;
if axis.is_vertical() { if axis.is_vertical() {
@ -232,7 +240,7 @@ pub struct Scrollbar {
axis: ScrollbarAxis, axis: ScrollbarAxis,
scroll_handle: Rc<Box<dyn ScrollHandleOffsetable>>, scroll_handle: Rc<Box<dyn ScrollHandleOffsetable>>,
scroll_size: gpui::Size<Pixels>, scroll_size: gpui::Size<Pixels>,
state: Rc<Cell<ScrollbarState>>, state: ScrollbarState,
/// Maximum frames per second for scrolling by drag. Default is 120 FPS. /// Maximum frames per second for scrolling by drag. Default is 120 FPS.
/// ///
/// This is used to limit the update rate of the scrollbar when it is /// This is used to limit the update rate of the scrollbar when it is
@ -243,7 +251,7 @@ pub struct Scrollbar {
impl Scrollbar { impl Scrollbar {
fn new( fn new(
view_id: EntityId, view_id: EntityId,
state: Rc<Cell<ScrollbarState>>, state: ScrollbarState,
axis: ScrollbarAxis, axis: ScrollbarAxis,
scroll_handle: impl ScrollHandleOffsetable + 'static, scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>, scroll_size: gpui::Size<Pixels>,
@ -261,7 +269,7 @@ impl Scrollbar {
/// Create with vertical and horizontal scrollbar. /// Create with vertical and horizontal scrollbar.
pub fn both( pub fn both(
view_id: EntityId, view_id: EntityId,
state: Rc<Cell<ScrollbarState>>, state: ScrollbarState,
scroll_handle: impl ScrollHandleOffsetable + 'static, scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>, scroll_size: gpui::Size<Pixels>,
) -> Self { ) -> Self {
@ -277,7 +285,7 @@ impl Scrollbar {
/// Create with horizontal scrollbar. /// Create with horizontal scrollbar.
pub fn horizontal( pub fn horizontal(
view_id: EntityId, view_id: EntityId,
state: Rc<Cell<ScrollbarState>>, state: ScrollbarState,
scroll_handle: impl ScrollHandleOffsetable + 'static, scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>, scroll_size: gpui::Size<Pixels>,
) -> Self { ) -> Self {
@ -293,7 +301,7 @@ impl Scrollbar {
/// Create with vertical scrollbar. /// Create with vertical scrollbar.
pub fn vertical( pub fn vertical(
view_id: EntityId, view_id: EntityId,
state: Rc<Cell<ScrollbarState>>, state: ScrollbarState,
scroll_handle: impl ScrollHandleOffsetable + 'static, scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>, scroll_size: gpui::Size<Pixels>,
) -> Self { ) -> Self {
@ -309,7 +317,7 @@ impl Scrollbar {
/// Create vertical scrollbar for uniform list. /// Create vertical scrollbar for uniform list.
pub fn uniform_scroll( pub fn uniform_scroll(
view_id: EntityId, view_id: EntityId,
state: Rc<Cell<ScrollbarState>>, state: ScrollbarState,
scroll_handle: UniformListScrollHandle, scroll_handle: UniformListScrollHandle,
) -> Self { ) -> Self {
let scroll_size = scroll_handle let scroll_size = scroll_handle

View file

@ -1,4 +1,4 @@
use std::{cell::Cell, ops::Range, rc::Rc, time::Duration}; use std::{ops::Range, rc::Rc, time::Duration};
use crate::{ use crate::{
actions::{Cancel, SelectNext, SelectPrev}, actions::{Cancel, SelectNext, SelectPrev},
@ -147,9 +147,9 @@ pub struct Table<D: TableDelegate> {
fixed_cols: FixedCols, fixed_cols: FixedCols,
pub vertical_scroll_handle: UniformListScrollHandle, pub vertical_scroll_handle: UniformListScrollHandle,
pub vertical_scrollbar_state: Rc<Cell<ScrollbarState>>, pub vertical_scroll_state: ScrollbarState,
pub horizontal_scroll_handle: ScrollHandle, pub horizontal_scroll_handle: ScrollHandle,
pub horizontal_scrollbar_state: Rc<Cell<ScrollbarState>>, pub horizontal_scroll_state: ScrollbarState,
scrollbar_visible: Edges<bool>, scrollbar_visible: Edges<bool>,
selected_row: Option<usize>, selected_row: Option<usize>,
@ -391,8 +391,8 @@ where
fixed_cols: FixedCols::default(), fixed_cols: FixedCols::default(),
horizontal_scroll_handle: ScrollHandle::new(), horizontal_scroll_handle: ScrollHandle::new(),
vertical_scroll_handle: UniformListScrollHandle::new(), vertical_scroll_handle: UniformListScrollHandle::new(),
vertical_scrollbar_state: Rc::new(Cell::new(ScrollbarState::new())), vertical_scroll_state: ScrollbarState::default(),
horizontal_scrollbar_state: Rc::new(Cell::new(ScrollbarState::new())), horizontal_scroll_state: ScrollbarState::default(),
selection_state: SelectionState::Row, selection_state: SelectionState::Row,
selected_row: None, selected_row: None,
right_clicked_row: None, right_clicked_row: None,
@ -867,7 +867,7 @@ where
_: &mut Window, _: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement> {
let state = self.vertical_scrollbar_state.clone(); let state = self.vertical_scroll_state.clone();
Some( Some(
div() div()
@ -896,7 +896,7 @@ where
_: &mut Window, _: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement {
let state = self.horizontal_scrollbar_state.clone(); let state = self.horizontal_scroll_state.clone();
div() div()
.occlude() .occlude()