use super::item::Item;
pub struct List<T>
where
T: Clone,
{
pub top_index: u8,
pub bottom_index: u8,
pub lines_to_show: i8,
pub selected_index: i8,
pub items: Vec<Item<T>>,
}
impl<T> List<T>
where
T: Clone,
{
pub fn new(lines_to_show: i8) -> Self {
List {
items: vec![],
top_index: lines_to_show as u8 - 1,
selected_index: (lines_to_show - 1),
lines_to_show,
bottom_index: 0,
}
}
pub fn up(&mut self, matches: &[Item<T>]) {
let match_count = matches.len() as i8;
if self.selected_index > 0 {
self.selected_index -= 1;
} else if self.top_index < (match_count - 1) as u8 {
self.bottom_index += 1;
self.top_index += 1;
}
self.floor_selected_index();
}
pub fn down(&mut self) {
if self.selected_index < self.top_index as i8 {
self.selected_index += 1;
}
if self.selected_index > self.lines_to_show - 1 && self.bottom_index > 0 {
self.bottom_index -= 1;
self.top_index -= 1;
if self.selected_index > 0 {
self.selected_index -= 1;
}
}
self.floor_selected_index();
}
pub fn reset_selection(&mut self) {
self.top_index = self.lines_to_show as u8 - 1;
self.bottom_index = 0;
self.selected_index = self.lines_to_show - 1;
}
fn floor_selected_index(&mut self) {
let index_of_first_blank = self.items.iter().rev().position(|item| item.is_blank);
if let Some(rev_index) = index_of_first_blank {
let index = self.lines_to_show - rev_index as i8;
if self.selected_index < index && index < self.lines_to_show {
self.selected_index = index;
}
else if self.selected_index < index {
self.selected_index = index - 1;
}
}
}
pub fn update(&mut self, matches: &[Item<T>]) {
log::info!("Updating view with {} match(es)", matches.len());
let mut to_render: Vec<Item<T>> = Vec::new();
for i in self.bottom_index..self.top_index + 1 {
if matches.len() > (i).into() {
to_render.push(matches[i as usize].clone());
} else {
to_render.push(Item::empty());
}
}
to_render.reverse();
self.items = to_render;
self.floor_selected_index();
}
pub fn get_selected(&self) -> &Item<T> {
let index = self.selected_index as usize;
&self.items[index]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone)]
struct TestItem {
name: String,
}
fn item(name: &str) -> Item<TestItem> {
Item::new(
String::from(name),
TestItem {
name: String::from(name),
},
)
}
struct Setup {
items: Vec<Item<TestItem>>,
few_items: Vec<Item<TestItem>>,
view: List<TestItem>,
}
impl Setup {
fn new(lines_to_show: i8) -> Self {
let view = List::<TestItem>::new(lines_to_show);
Setup {
items: vec![
item("A"),
item("B"),
item("C"),
item("D"),
item("E"),
item("F"),
item("G"),
item("H"),
item("I"),
item("J"),
item("K"),
item("L"),
item("M"),
],
few_items: vec![item("A"), item("B"), item("C")],
view,
}
}
}
#[test]
fn test_update() {
let mut setup = Setup::new(8);
setup.view.update(&setup.items);
assert_eq!(setup.view.items.len(), 8);
assert_eq!(setup.view.selected_index, 7); assert_eq!(setup.view.get_selected().item.as_ref().unwrap().name, "A")
}
#[test]
fn test_up() {
let mut setup = Setup::new(8);
setup.view.update(&setup.items);
setup.view.up(&setup.items); setup.view.up(&setup.items); setup.view.up(&setup.items);
assert_eq!(setup.view.items.len(), 8);
assert_eq!(setup.view.selected_index, 4);
}
#[test]
fn test_up_to_extremis() {
let mut setup = Setup::new(8);
setup.view.update(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
setup.view.up(&setup.items);
assert_eq!(setup.view.items.len(), 8);
assert_eq!(setup.view.selected_index, 0);
}
#[test]
fn test_down_at_bottom() {
let mut setup = Setup::new(8);
setup.view.update(&setup.items);
setup.view.down();
assert_eq!(setup.view.items.len(), 8);
assert_eq!(setup.view.selected_index, 7);
}
#[test]
fn test_down() {
let mut setup = Setup::new(8);
setup.view.update(&setup.items);
setup.view.up(&setup.items); setup.view.up(&setup.items); setup.view.up(&setup.items); setup.view.down();
assert_eq!(setup.view.items.len(), 8);
assert_eq!(setup.view.selected_index, 5);
}
#[test]
fn test_few() {
let mut setup = Setup::new(8);
setup.view.update(&setup.few_items);
setup.view.up(&setup.few_items); setup.view.up(&setup.few_items); setup.view.up(&setup.few_items); setup.view.up(&setup.few_items);
assert_eq!(setup.view.items.len(), 8); assert_eq!(setup.view.selected_index, 5);
}
}