virtualizer_adapter/
anchor.rs1use core::fmt;
2
3use crate::VirtualizerKey;
4
5#[derive(Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct ScrollAnchor<K> {
16 pub key: K,
17 pub offset_in_viewport: u64,
19}
20
21impl<K: fmt::Debug> fmt::Debug for ScrollAnchor<K> {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 f.debug_struct("ScrollAnchor")
24 .field("key", &self.key)
25 .field("offset_in_viewport", &self.offset_in_viewport)
26 .finish()
27 }
28}
29
30pub fn capture_first_visible_anchor<K: VirtualizerKey>(
34 v: &virtualizer::Virtualizer<K>,
35) -> Option<ScrollAnchor<K>> {
36 let visible = v.visible_range();
37 if visible.is_empty() {
38 return None;
39 }
40 let index = visible.start_index;
41 let start = v.item_start(index)?;
42 let key = v.key_for(index);
43 let offset_in_viewport = v.scroll_offset().saturating_sub(start);
44 Some(ScrollAnchor {
45 key,
46 offset_in_viewport,
47 })
48}
49
50pub fn apply_anchor<K: VirtualizerKey>(
56 v: &mut virtualizer::Virtualizer<K>,
57 anchor: &ScrollAnchor<K>,
58 mut key_to_index: impl FnMut(&K) -> Option<usize>,
59) -> bool {
60 let Some(index) = key_to_index(&anchor.key) else {
61 return false;
62 };
63 let Some(start) = v.item_start(index) else {
64 return false;
65 };
66 let target = start.saturating_add(anchor.offset_in_viewport);
67 v.set_scroll_offset_clamped(target);
68 true
69}