add offset to uniform list scroll state
This commit is contained in:
parent
fa788a39a4
commit
cfdc654a80
2 changed files with 40 additions and 22 deletions
|
@ -88,15 +88,24 @@ pub enum ScrollStrategy {
|
|||
/// May not be possible if there's not enough list items above the item scrolled to:
|
||||
/// in this case, the element will be placed at the closest possible position.
|
||||
Center,
|
||||
/// Scrolls the element to be at the given item index from the top of the viewport.
|
||||
ToPosition(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct DeferredScrollToItem {
|
||||
/// The item index to scroll to
|
||||
pub item_index: usize,
|
||||
/// The scroll strategy to use
|
||||
pub strategy: ScrollStrategy,
|
||||
/// The offset in number of items
|
||||
pub offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct UniformListScrollState {
|
||||
pub base_handle: ScrollHandle,
|
||||
pub deferred_scroll_to_item: Option<(usize, ScrollStrategy)>,
|
||||
pub deferred_scroll_to_item: Option<DeferredScrollToItem>,
|
||||
/// Size of the item, captured during last layout.
|
||||
pub last_item_size: Option<ItemSize>,
|
||||
/// Whether the list was vertically flipped during last layout.
|
||||
|
@ -126,7 +135,24 @@ impl UniformListScrollHandle {
|
|||
|
||||
/// Scroll the list to the given item index.
|
||||
pub fn scroll_to_item(&self, ix: usize, strategy: ScrollStrategy) {
|
||||
self.0.borrow_mut().deferred_scroll_to_item = Some((ix, strategy));
|
||||
self.0.borrow_mut().deferred_scroll_to_item = Some(DeferredScrollToItem {
|
||||
item_index: ix,
|
||||
strategy,
|
||||
offset: 0,
|
||||
});
|
||||
}
|
||||
|
||||
/// Scroll the list to the given item index with an offset.
|
||||
///
|
||||
/// For ScrollStrategy::Top, the item will be placed at the offset position from the top.
|
||||
///
|
||||
/// For ScrollStrategy::Center, the item will be centered between offset and the last visible item.
|
||||
pub fn scroll_to_item_with_offset(&self, ix: usize, strategy: ScrollStrategy, offset: usize) {
|
||||
self.0.borrow_mut().deferred_scroll_to_item = Some(DeferredScrollToItem {
|
||||
item_index: ix,
|
||||
strategy,
|
||||
offset,
|
||||
});
|
||||
}
|
||||
|
||||
/// Check if the list is flipped vertically.
|
||||
|
@ -139,7 +165,8 @@ impl UniformListScrollHandle {
|
|||
pub fn logical_scroll_top_index(&self) -> usize {
|
||||
let this = self.0.borrow();
|
||||
this.deferred_scroll_to_item
|
||||
.map(|(ix, _)| ix)
|
||||
.as_ref()
|
||||
.map(|deferred| deferred.item_index)
|
||||
.unwrap_or_else(|| this.base_handle.logical_scroll_top().0)
|
||||
}
|
||||
|
||||
|
@ -320,7 +347,8 @@ impl Element for UniformList {
|
|||
scroll_offset.x = Pixels::ZERO;
|
||||
}
|
||||
|
||||
if let Some((mut ix, scroll_strategy)) = shared_scroll_to_item {
|
||||
if let Some(deferred_scroll) = shared_scroll_to_item {
|
||||
let mut ix = deferred_scroll.item_index;
|
||||
if y_flipped {
|
||||
ix = self.item_count.saturating_sub(ix + 1);
|
||||
}
|
||||
|
@ -329,16 +357,18 @@ impl Element for UniformList {
|
|||
let item_top = item_height * ix + padding.top;
|
||||
let item_bottom = item_top + item_height;
|
||||
let scroll_top = -updated_scroll_offset.y;
|
||||
let offset_pixels = item_height * deferred_scroll.offset;
|
||||
let mut scrolled_to_top = false;
|
||||
if item_top < scroll_top + padding.top {
|
||||
|
||||
if item_top < scroll_top + padding.top + offset_pixels {
|
||||
scrolled_to_top = true;
|
||||
updated_scroll_offset.y = -(item_top) + padding.top;
|
||||
updated_scroll_offset.y = -(item_top) + padding.top + offset_pixels;
|
||||
} else if item_bottom > scroll_top + list_height - padding.bottom {
|
||||
scrolled_to_top = true;
|
||||
updated_scroll_offset.y = -(item_bottom - list_height) - padding.bottom;
|
||||
}
|
||||
|
||||
match scroll_strategy {
|
||||
match deferred_scroll.strategy {
|
||||
ScrollStrategy::Top => {}
|
||||
ScrollStrategy::Center => {
|
||||
if scrolled_to_top {
|
||||
|
@ -355,15 +385,6 @@ impl Element for UniformList {
|
|||
}
|
||||
}
|
||||
}
|
||||
ScrollStrategy::ToPosition(sticky_index) => {
|
||||
let target_y_in_viewport = item_height * sticky_index;
|
||||
let target_scroll_top = item_top - target_y_in_viewport;
|
||||
let max_scroll_top =
|
||||
(content_height - list_height).max(Pixels::ZERO);
|
||||
let new_scroll_top =
|
||||
target_scroll_top.clamp(Pixels::ZERO, max_scroll_top);
|
||||
updated_scroll_offset.y = -new_scroll_top;
|
||||
}
|
||||
}
|
||||
scroll_offset = *updated_scroll_offset
|
||||
}
|
||||
|
|
|
@ -4207,10 +4207,7 @@ impl ProjectPanel {
|
|||
this.marked_entries.clear();
|
||||
if is_sticky {
|
||||
if let Some((_, _, index)) = this.index_for_entry(entry_id, worktree_id) {
|
||||
let strategy = sticky_index
|
||||
.map(ScrollStrategy::ToPosition)
|
||||
.unwrap_or(ScrollStrategy::Top);
|
||||
this.scroll_handle.scroll_to_item(index, strategy);
|
||||
this.scroll_handle.scroll_to_item_with_offset(index, ScrollStrategy::Top, sticky_index.unwrap_or(0));
|
||||
cx.notify();
|
||||
// move down by 1px so that clicked item
|
||||
// don't count as sticky anymore
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue