use super::input_history::{InputHistory, ScrollDirection};
use super::scroll_policy::ScrollPolicy;
use crate::config::ScrollMode;
use std::time::Duration;
const ADAPTIVE_HISTORY_WINDOW: Duration = Duration::from_millis(5000);
const ADAPTIVE_HISTORY_CAP: usize = 128;
pub(super) enum ScrollStrategy {
Fixed,
Adaptive {
history: InputHistory,
policy: ScrollPolicy,
},
}
impl ScrollStrategy {
pub(super) fn from_mode(mode: ScrollMode) -> Self {
match mode {
ScrollMode::Fixed => Self::Fixed,
ScrollMode::Adaptive => Self::Adaptive {
history: InputHistory::new(ADAPTIVE_HISTORY_WINDOW, ADAPTIVE_HISTORY_CAP),
policy: ScrollPolicy::new(),
},
}
}
pub(super) fn step(&mut self, scroll_step: u32, cell_h: u32, dir: ScrollDirection) -> u32 {
match self {
Self::Fixed => scroll_step * cell_h,
Self::Adaptive { history, policy } => {
history.record(dir);
policy.effective_step(cell_h, dir, history)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fixed_is_scroll_step_times_cell_h() {
let mut s = ScrollStrategy::from_mode(ScrollMode::Fixed);
assert_eq!(s.step(3, 28, ScrollDirection::Down), 84);
for _ in 0..10 {
assert_eq!(s.step(3, 28, ScrollDirection::Down), 84);
}
}
#[test]
fn adaptive_ignores_scroll_step() {
let mut a = ScrollStrategy::from_mode(ScrollMode::Adaptive);
let mut b = ScrollStrategy::from_mode(ScrollMode::Adaptive);
assert_eq!(
a.step(3, 24, ScrollDirection::Down),
b.step(999, 24, ScrollDirection::Down),
);
}
#[test]
fn adaptive_accelerates_with_history() {
let mut s = ScrollStrategy::from_mode(ScrollMode::Adaptive);
assert_eq!(s.step(3, 24, ScrollDirection::Down), 48);
assert_eq!(s.step(3, 24, ScrollDirection::Down), 77);
}
#[test]
fn adaptive_isolates_directions() {
let mut s = ScrollStrategy::from_mode(ScrollMode::Adaptive);
for _ in 0..10 {
s.step(3, 24, ScrollDirection::Up);
}
assert_eq!(s.step(3, 24, ScrollDirection::Down), 48);
}
}