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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -75,7 +75,7 @@ where
pub struct ScrollViewState {
scroll_size: Rc<Cell<Size<Pixels>>>,
state: Rc<Cell<ScrollbarState>>,
state: ScrollbarState,
handle: ScrollHandle,
}
@ -84,7 +84,7 @@ impl Default for ScrollViewState {
Self {
handle: ScrollHandle::new(),
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::{
cell::Cell,
ops::Deref,
rc::Rc,
time::{Duration, Instant},
};
@ -79,8 +80,11 @@ impl ScrollHandleOffsetable for UniformListScrollHandle {
}
}
#[derive(Debug, Clone)]
pub struct ScrollbarState(Rc<Cell<ScrollbarStateInner>>);
#[derive(Debug, Clone, Copy)]
pub struct ScrollbarState {
pub struct ScrollbarStateInner {
hovered_axis: Option<ScrollbarAxis>,
hovered_on_thumb: Option<ScrollbarAxis>,
dragged_axis: Option<ScrollbarAxis>,
@ -93,7 +97,7 @@ pub struct ScrollbarState {
impl Default for ScrollbarState {
fn default() -> Self {
Self {
Self(Rc::new(Cell::new(ScrollbarStateInner {
hovered_axis: None,
hovered_on_thumb: None,
dragged_axis: None,
@ -101,15 +105,19 @@ impl Default for ScrollbarState {
last_scroll_offset: point(px(0.), px(0.)),
last_scroll_time: None,
last_update: Instant::now(),
}
})))
}
}
impl ScrollbarState {
pub fn new() -> Self {
Self::default()
}
impl Deref for ScrollbarState {
type Target = Rc<Cell<ScrollbarStateInner>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ScrollbarStateInner {
fn with_drag_pos(&self, axis: ScrollbarAxis, pos: Point<Pixels>) -> Self {
let mut state = *self;
if axis.is_vertical() {
@ -232,7 +240,7 @@ pub struct Scrollbar {
axis: ScrollbarAxis,
scroll_handle: Rc<Box<dyn ScrollHandleOffsetable>>,
scroll_size: gpui::Size<Pixels>,
state: Rc<Cell<ScrollbarState>>,
state: ScrollbarState,
/// 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
@ -243,7 +251,7 @@ pub struct Scrollbar {
impl Scrollbar {
fn new(
view_id: EntityId,
state: Rc<Cell<ScrollbarState>>,
state: ScrollbarState,
axis: ScrollbarAxis,
scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>,
@ -261,7 +269,7 @@ impl Scrollbar {
/// Create with vertical and horizontal scrollbar.
pub fn both(
view_id: EntityId,
state: Rc<Cell<ScrollbarState>>,
state: ScrollbarState,
scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>,
) -> Self {
@ -277,7 +285,7 @@ impl Scrollbar {
/// Create with horizontal scrollbar.
pub fn horizontal(
view_id: EntityId,
state: Rc<Cell<ScrollbarState>>,
state: ScrollbarState,
scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>,
) -> Self {
@ -293,7 +301,7 @@ impl Scrollbar {
/// Create with vertical scrollbar.
pub fn vertical(
view_id: EntityId,
state: Rc<Cell<ScrollbarState>>,
state: ScrollbarState,
scroll_handle: impl ScrollHandleOffsetable + 'static,
scroll_size: gpui::Size<Pixels>,
) -> Self {
@ -309,7 +317,7 @@ impl Scrollbar {
/// Create vertical scrollbar for uniform list.
pub fn uniform_scroll(
view_id: EntityId,
state: Rc<Cell<ScrollbarState>>,
state: ScrollbarState,
scroll_handle: UniformListScrollHandle,
) -> Self {
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::{
actions::{Cancel, SelectNext, SelectPrev},
@ -147,9 +147,9 @@ pub struct Table<D: TableDelegate> {
fixed_cols: FixedCols,
pub vertical_scroll_handle: UniformListScrollHandle,
pub vertical_scrollbar_state: Rc<Cell<ScrollbarState>>,
pub vertical_scroll_state: ScrollbarState,
pub horizontal_scroll_handle: ScrollHandle,
pub horizontal_scrollbar_state: Rc<Cell<ScrollbarState>>,
pub horizontal_scroll_state: ScrollbarState,
scrollbar_visible: Edges<bool>,
selected_row: Option<usize>,
@ -391,8 +391,8 @@ where
fixed_cols: FixedCols::default(),
horizontal_scroll_handle: ScrollHandle::new(),
vertical_scroll_handle: UniformListScrollHandle::new(),
vertical_scrollbar_state: Rc::new(Cell::new(ScrollbarState::new())),
horizontal_scrollbar_state: Rc::new(Cell::new(ScrollbarState::new())),
vertical_scroll_state: ScrollbarState::default(),
horizontal_scroll_state: ScrollbarState::default(),
selection_state: SelectionState::Row,
selected_row: None,
right_clicked_row: None,
@ -867,7 +867,7 @@ where
_: &mut Window,
cx: &mut Context<Self>,
) -> Option<impl IntoElement> {
let state = self.vertical_scrollbar_state.clone();
let state = self.vertical_scroll_state.clone();
Some(
div()
@ -896,7 +896,7 @@ where
_: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
let state = self.horizontal_scrollbar_state.clone();
let state = self.horizontal_scroll_state.clone();
div()
.occlude()