use crate::{
Easing, ScrollAnchor, Tween, VirtualizerKey, apply_anchor, capture_first_visible_anchor,
};
#[derive(Clone, Debug)]
pub struct Controller<K> {
v: virtualizer::Virtualizer<K>,
tween: Option<Tween>,
}
impl<K: VirtualizerKey> Controller<K> {
pub fn new(options: virtualizer::VirtualizerOptions<K>) -> Self {
Self {
v: virtualizer::Virtualizer::new(options),
tween: None,
}
}
pub fn from_virtualizer(v: virtualizer::Virtualizer<K>) -> Self {
Self { v, tween: None }
}
pub fn virtualizer(&self) -> &virtualizer::Virtualizer<K> {
&self.v
}
pub fn virtualizer_mut(&mut self) -> &mut virtualizer::Virtualizer<K> {
&mut self.v
}
pub fn into_virtualizer(self) -> virtualizer::Virtualizer<K> {
self.v
}
pub fn is_animating(&self) -> bool {
self.tween.is_some()
}
pub fn cancel_animation(&mut self) {
self.tween = None;
}
pub fn on_viewport_size(&mut self, viewport_main: u32) {
self.v.set_viewport_size(viewport_main);
}
pub fn on_scroll(&mut self, scroll_offset: u64, now_ms: u64) {
self.cancel_animation();
self.v.apply_scroll_offset_event(scroll_offset, now_ms);
}
pub fn tick(&mut self, now_ms: u64) -> Option<u64> {
let Some(tween) = self.tween else {
self.v.update_scrolling(now_ms);
return None;
};
let off = tween.sample(now_ms);
self.v.apply_scroll_offset_event_clamped(off, now_ms);
if tween.is_done(now_ms) {
self.tween = None;
self.v.set_is_scrolling(false);
}
Some(self.v.scroll_offset())
}
pub fn scroll_to_index(&mut self, index: usize, align: virtualizer::Align, now_ms: u64) -> u64 {
let off = self.v.scroll_to_index_offset(index, align);
self.v.apply_scroll_offset_event_clamped(off, now_ms);
self.v.scroll_offset()
}
pub fn scroll_to_offset(&mut self, offset: u64, now_ms: u64) -> u64 {
self.v.apply_scroll_offset_event_clamped(offset, now_ms);
self.v.scroll_offset()
}
pub fn start_tween_to_index(
&mut self,
index: usize,
align: virtualizer::Align,
now_ms: u64,
duration_ms: u64,
easing: Easing,
) -> u64 {
let to = self.v.scroll_to_index_offset(index, align);
self.start_tween_to_offset(to, now_ms, duration_ms, easing)
}
pub fn start_tween_to_offset(
&mut self,
offset: u64,
now_ms: u64,
duration_ms: u64,
easing: Easing,
) -> u64 {
let to = self.v.clamp_scroll_offset(offset);
let from = self.v.scroll_offset();
self.tween = Some(Tween::new(from, to, now_ms, duration_ms, easing));
to
}
pub fn capture_first_visible_anchor(&self) -> Option<ScrollAnchor<K>> {
capture_first_visible_anchor(&self.v)
}
pub fn capture_anchor_at_offset_in_viewport(
&self,
offset_in_viewport: u64,
) -> Option<ScrollAnchor<K>> {
let abs = self.v.scroll_offset().saturating_add(offset_in_viewport);
let item = self.v.virtual_item_keyed_for_offset(abs)?;
let offset_in_viewport = self.v.scroll_offset().saturating_sub(item.start);
Some(ScrollAnchor {
key: item.key,
offset_in_viewport,
})
}
pub fn apply_anchor(
&mut self,
anchor: &ScrollAnchor<K>,
key_to_index: impl FnMut(&K) -> Option<usize>,
) -> bool {
self.cancel_animation();
apply_anchor(&mut self.v, anchor, key_to_index)
}
}