use super::{ListEvent, ListItem};
use ratatui::widgets::ListState as RatatuiListState;
#[derive(Debug)]
pub struct ListState<T>
where
T: ListItem,
{
pub(crate) title: Option<String>,
pub(crate) items: Vec<T>,
pub(crate) filter: Option<String>,
pub(crate) tab_value: usize,
pub(crate) state: RatatuiListState,
pub(crate) scrollbar: bool,
}
impl<T> Default for ListState<T>
where
T: ListItem,
{
fn default() -> Self
{
Self::new()
}
}
impl<T> ListState<T>
where
T: ListItem,
{
pub fn new() -> Self
{
Self {
title: None,
items: vec![],
filter: None,
tab_value: 20,
state: RatatuiListState::default(),
scrollbar: false,
}
}
pub fn set_scrollbar(
&mut self,
value: bool,
)
{
self.scrollbar = value;
}
pub fn with_scrollbar(mut self) -> Self
{
self.set_scrollbar(true);
self
}
pub fn has_scrollbar(&self) -> bool
{
self.scrollbar
}
pub fn set_title<S>(
&mut self,
title: S,
) where
S: AsRef<str>,
{
self.title = Some(
title
.as_ref()
.to_string(),
);
}
pub fn with_title<S>(
mut self,
title: S,
) -> Self
where
S: AsRef<str>,
{
self.set_title(title);
self
}
pub fn has_title(&self) -> bool
{
self.title
.is_some()
}
pub fn title(&self) -> &Option<String>
{
&self.title
}
pub fn add_item(
&mut self,
item: T,
)
{
self.items
.push(item);
self.items
.sort_by(T::sort_by);
}
pub fn add_items(
&mut self,
items: Vec<T>,
)
{
for item in items
{
self.items
.push(item);
}
self.items
.sort_by(T::sort_by);
}
pub fn with_items(
mut self,
items: Vec<T>,
) -> Self
{
self.add_items(items);
self
}
pub fn remove_item(
&mut self,
item: &T,
) -> bool
{
if let Some(index) = self
.items
.iter()
.position(
|a| {
std::ptr::eq(
a, item,
)
},
)
{
self.items
.remove(index);
true
}
else
{
false
}
}
pub fn items(&self) -> &Vec<T>
{
&self.items
}
pub fn items_mut(&mut self) -> &mut Vec<T>
{
&mut self.items
}
pub fn filtered_items(&self) -> Vec<&T>
{
self.items
.iter()
.filter(
|i| {
i.filter(
self.filter
.as_ref(),
)
},
)
.collect::<Vec<_>>()
}
pub fn set_filter<S>(
&mut self,
filter: S,
) where
S: AsRef<str>,
{
self.filter = Some(
filter
.as_ref()
.to_string(),
);
}
pub fn with_filter<S>(
mut self,
filter: S,
) -> Self
where
S: AsRef<str>,
{
self.set_filter(filter);
self
}
pub fn with_optional_filter<S>(
mut self,
filter: Option<S>,
) -> Self
where
S: AsRef<str>,
{
if let Some(filter) = filter
{
self.set_filter(filter);
}
self
}
pub fn clear_filter(&mut self)
{
self.filter = None;
}
pub fn has_filter(&self) -> bool
{
self.filter
.is_some()
}
pub fn filter(&self) -> &Option<String>
{
&self.filter
}
pub fn set_tab_value(
&mut self,
value: usize,
)
{
self.tab_value = value;
}
pub fn with_tab_value(
mut self,
value: usize,
) -> Self
{
self.set_tab_value(value);
self
}
pub fn tab_value(&self) -> usize
{
self.tab_value
}
pub fn select_next(&mut self)
{
self.state
.select_next();
}
pub(crate) fn select_next_tab(&mut self)
{
let start = self
.state
.selected()
.unwrap_or(0);
self.state
.select(Some(start + self.tab_value));
}
pub fn select_previous(&mut self)
{
self.state
.select_previous();
}
pub(crate) fn select_previous_tab(&mut self)
{
let start = self
.state
.selected()
.unwrap_or(0);
self.state
.select(Some(start.saturating_sub(self.tab_value)));
}
pub fn select_first(&mut self)
{
self.state
.select_first();
}
pub fn select_last(&mut self)
{
self.state
.select_last();
}
pub fn clear_selection(&mut self)
{
self.state
.select(None);
}
pub fn clear(&mut self)
{
self.items
.clear();
self.state
.select(None);
}
pub fn has_selection(&self) -> bool
{
self.state
.selected()
.is_some()
}
pub fn get_selected(&mut self) -> Option<&mut T>
{
self.state
.selected()
.and_then(
|index| {
self.items
.iter_mut()
.filter(
|i| {
i.filter(
self.filter
.clone(),
)
},
)
.nth(index)
},
)
}
pub(crate) fn return_selected(&mut self) -> ListEvent<T>
{
if let Some(selected) = self.get_selected()
{
ListEvent::Select(selected)
}
else
{
ListEvent::Handled
}
}
}