1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
pub trait Scrollable { fn selected(&self) -> usize; fn len(&self) -> usize; fn set_selected(&mut self, selected: usize) -> bool; fn element_height(&self, index: usize) -> u16; fn visible_range(&self, height: u16) -> Box<dyn Iterator<Item = usize>>; fn visible_start_end(&self, height: u16) -> (usize, usize); fn up(&mut self, how_much: usize); fn down(&mut self, how_much: usize); } #[macro_export] macro_rules! scrollable { ($x:ty, $($y:item),*) => { impl Scrollable for $x { fn up(&mut self, how_much: usize) { let how_much = how_much % self.len(); self.set_selected((self.len() + self.selected() - how_much) % self.len()); } fn down(&mut self, how_much: usize) { let how_much = how_much % self.len(); self.set_selected((how_much + self.selected()) % self.len()); } fn visible_range(&self, height: u16) -> Box<dyn Iterator<Item = usize>> { let (a, b) = self.visible_start_end(height); Box::new((a..b).into_iter()) } fn visible_start_end(&self, height: u16) -> (usize, usize) { let mut last_first = 0; let mut current_height = 0; let mut i = 0; while i < self.len() { let eh = self.element_height(i); if current_height + eh > height { if i > self.selected() { break; } current_height = eh; last_first = i; } else { current_height += eh; } i += 1; } (last_first, i) } $($y)* } } }