Add a scroll to top of item function to scroll handle

This enables settings UI to scroll to the top of a selected header
instead of just when the header is visible
This commit is contained in:
Anthony
2025-10-07 16:20:17 -04:00
parent 557199052e
commit 5b85cdcf3c
2 changed files with 47 additions and 12 deletions

View File

@@ -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(),
});
}
/// Scrolls the minimal amount to ensure that the child is
/// fully visible
/// 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 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;
}

View File

@@ -1095,7 +1095,7 @@ impl SettingsWindow {
.map(|pair| pair.0)
{
this.scroll_handle
.scroll_to_item(section_index);
.scroll_to_top_of_item(section_index);
}
}