use core::fmt;
use crate::VirtualizerKey;
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ScrollAnchor<K> {
pub key: K,
pub offset_in_viewport: u64,
}
impl<K: fmt::Debug> fmt::Debug for ScrollAnchor<K> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ScrollAnchor")
.field("key", &self.key)
.field("offset_in_viewport", &self.offset_in_viewport)
.finish()
}
}
pub fn capture_first_visible_anchor<K: VirtualizerKey>(
v: &virtualizer::Virtualizer<K>,
) -> Option<ScrollAnchor<K>> {
let visible = v.visible_range();
if visible.is_empty() {
return None;
}
let index = visible.start_index;
let start = v.item_start(index)?;
let key = v.key_for(index);
let offset_in_viewport = v.scroll_offset().saturating_sub(start);
Some(ScrollAnchor {
key,
offset_in_viewport,
})
}
pub fn apply_anchor<K: VirtualizerKey>(
v: &mut virtualizer::Virtualizer<K>,
anchor: &ScrollAnchor<K>,
mut key_to_index: impl FnMut(&K) -> Option<usize>,
) -> bool {
let Some(index) = key_to_index(&anchor.key) else {
return false;
};
let Some(start) = v.item_start(index) else {
return false;
};
let target = start.saturating_add(anchor.offset_in_viewport);
v.set_scroll_offset_clamped(target);
true
}