@@ -3034,7 +3034,20 @@ struct ScrollHandleState {
child_bounds: Vec<Bounds<Pixels>>,
scroll_to_bottom: bool,
overflow: Point<Overflow>,
- active_item: Option<usize>,
+ active_item: Option<ScrollActiveItem>,
+}
+
+#[derive(Default, Debug, Clone, Copy)]
+struct ScrollActiveItem {
+ index: usize,
+ strategy: ScrollStrategy,
+}
+
+#[derive(Default, Debug, Clone, Copy)]
+enum ScrollStrategy {
+ #[default]
+ FirstVisible,
+ Top,
}
/// A handle to the scrollable aspects of an element.
@@ -3097,26 +3110,48 @@ impl ScrollHandle {
/// Update [ScrollHandleState]'s active item for scrolling to in prepaint
pub fn scroll_to_item(&self, ix: usize) {
let mut state = self.0.borrow_mut();
- state.active_item = Some(ix);
+ state.active_item = Some(ScrollActiveItem {
+ index: ix,
+ strategy: ScrollStrategy::default(),
+ });
+ }
+
+ /// Update [ScrollHandleState]'s active item for scrolling to in prepaint
+ /// This scrolls the minimal amount to ensure that the child is the first visible element
+ pub fn scroll_to_top_of_item(&self, ix: usize) {
+ let mut state = self.0.borrow_mut();
+ state.active_item = Some(ScrollActiveItem {
+ index: ix,
+ strategy: ScrollStrategy::Top,
+ });
}
- /// Scrolls the minimal amount to ensure that the child is
- /// fully visible
+ /// Scrolls the minimal amount to either ensure that the child is
+ /// fully visible or the top element of the view depends on the
+ /// scroll strategy
fn scroll_to_active_item(&self) {
let mut state = self.0.borrow_mut();
- let Some(active_item_index) = state.active_item else {
+ let Some(active_item) = state.active_item else {
return;
};
- let active_item = match state.child_bounds.get(active_item_index) {
+
+ let active_item = match state.child_bounds.get(active_item.index) {
Some(bounds) => {
let mut scroll_offset = state.offset.borrow_mut();
- if state.overflow.y == Overflow::Scroll {
- if bounds.top() + scroll_offset.y < state.bounds.top() {
+ match active_item.strategy {
+ ScrollStrategy::FirstVisible => {
+ if state.overflow.y == Overflow::Scroll {
+ if bounds.top() + scroll_offset.y < state.bounds.top() {
+ scroll_offset.y = state.bounds.top() - bounds.top();
+ } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
+ scroll_offset.y = state.bounds.bottom() - bounds.bottom();
+ }
+ }
+ }
+ ScrollStrategy::Top => {
scroll_offset.y = state.bounds.top() - bounds.top();
- } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
- scroll_offset.y = state.bounds.bottom() - bounds.bottom();
}
}
@@ -3129,7 +3164,7 @@ impl ScrollHandle {
}
None
}
- None => Some(active_item_index),
+ None => Some(active_item),
};
state.active_item = active_item;
}