// This file is part of Deja-vu. // // Deja-vu is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Deja-vu is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Deja-vu. If not, see . // use std::collections::{hash_map, HashMap}; use ratatui::widgets::ListState; #[derive(Default, Debug, Clone, PartialEq)] pub struct StatefulList { pub state: ListState, pub items: Vec, pub last_selected: Option, pub selected: HashMap, } impl StatefulList { #[must_use] pub fn new() -> StatefulList { StatefulList { state: ListState::default(), items: Vec::new(), last_selected: None, selected: HashMap::new(), } } pub fn clear_items(&mut self) { // Clear list and rebuild with provided items self.items.clear(); } #[must_use] pub fn get_selected(&self) -> Option<&T> { if let Some(i) = self.state.selected() { self.items.get(i) } else { None } } pub fn pop_selected(&mut self) -> Option { if let Some(i) = self.state.selected() { Some(self.items[i].clone()) } else { None } } fn select_first_item(&mut self) { if self.items.is_empty() { self.state.select(None); } else { self.state.select(Some(0)); } self.last_selected = None; } pub fn set_items(&mut self, items: Vec) { // Clear list and rebuild with provided items self.clear_items(); for item in items { self.items.push(item); } // Reset state and select first item (if available) self.state = ListState::default(); self.select_first_item(); } pub fn next(&mut self) { if self.items.is_empty() { return; } let i = match self.state.selected() { Some(i) => { if i >= self.items.len() - 1 { 0 } else { i + 1 } } None => self.last_selected.unwrap_or(0), }; self.state.select(Some(i)); } pub fn previous(&mut self) { if self.items.is_empty() { return; } let i = match self.state.selected() { Some(i) => { if i == 0 { self.items.len() - 1 } else { i - 1 } } None => self.last_selected.unwrap_or(0), }; self.state.select(Some(i)); } pub fn toggle_selected(&mut self) { if let Some(i) = self.state.selected() { if let hash_map::Entry::Vacant(e) = self.selected.entry(i) { // Was NOT selected, WILL be shortly self.last_selected = Some(i); e.insert(true); } else { // WAS selected, will NOT be shortly self.last_selected = None; self.selected.remove(&i); } } } }