Files
managarr/src/handlers/table_handler.rs

403 lines
14 KiB
Rust

use crate::models::stateful_table::SortOption;
use crate::models::Route;
use derive_setters::Setters;
use std::cmp::Ordering;
use std::fmt::Debug;
#[derive(Setters)]
pub struct TableHandlingProps<T>
where
T: Clone + PartialEq + Eq + Debug + Default,
{
#[setters(strip_option)]
pub sorting_block: Option<Route>,
#[setters(strip_option)]
pub sort_options: Option<Vec<SortOption<T>>>,
#[setters(strip_option)]
pub sort_by_fn: Option<fn(&T, &T) -> Ordering>,
#[setters(strip_option)]
pub searching_block: Option<Route>,
#[setters(strip_option)]
pub search_error_block: Option<Route>,
#[setters(strip_option)]
pub search_field_fn: Option<fn(&T) -> &str>,
#[setters(strip_option)]
pub filtering_block: Option<Route>,
#[setters(strip_option)]
pub filter_error_block: Option<Route>,
#[setters(strip_option)]
pub filter_field_fn: Option<fn(&T) -> &str>,
#[setters(skip)]
pub table_block: Route,
}
#[macro_export]
macro_rules! handle_table_events {
($self:expr, $name:ty, $table:expr, $row:ident) => {
paste::paste! {
fn [<handle_ $name _table_events>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
if $self.is_ready() {
match $self.key {
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.up.key => $self.[<handle_ $name _table_scroll_up>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.down.key => $self.[<handle_ $name _table_scroll_down>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.home.key => $self.[<handle_ $name _table_home>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.end.key => $self.[<handle_ $name _table_end>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.left.key
|| $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.right.key =>
{
$self.[<handle_ $name _table_left_right>](props)
}
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.submit.key => $self.[<handle_ $name _table_submit>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.esc.key => $self.[<handle_ $name _table_esc>](props),
_ if props.searching_block.is_some()
&& $self.app.get_current_route() == *props.searching_block.as_ref().unwrap() =>
{
$self.[<handle_ $name _table_search_box_input>]()
}
_ if props.filtering_block.is_some()
&& $self.app.get_current_route() == *props.filtering_block.as_ref().unwrap() =>
{
$self.[<handle_ $name _table_filter_box_input>]()
}
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.filter.key => $self.[<handle_ $name _table_filter_key>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.search.key => $self.[<handle_ $name _table_search_key>](props),
_ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.sort.key => $self.[<handle_ $name _table_sort_key>](props),
_ => false,
}
} else {
false
}
}
fn [<handle_ $name _table_scroll_up>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
match $self.app.get_current_route() {
_ if props.table_block == $self.app.get_current_route() => {
$table.scroll_up();
true
}
_ if props.sorting_block.is_some()
&& $self.app.get_current_route() == *props.sorting_block.as_ref().unwrap() =>
{
$table.sort.as_mut().unwrap().scroll_up();
true
}
_ => false,
}
}
fn [<handle_ $name _table_scroll_down>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
match $self.app.get_current_route() {
_ if props.table_block == $self.app.get_current_route() => {
$table.scroll_down();
true
}
_ if props.sorting_block.is_some()
&& $self.app.get_current_route() == *props.sorting_block.as_ref().unwrap() =>
{
$table
.sort
.as_mut()
.unwrap()
.scroll_down();
true
}
_ => false,
}
}
fn [<handle_ $name _table_home>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
match $self.app.get_current_route() {
_ if props.table_block == $self.app.get_current_route() => {
$table.scroll_to_top();
true
}
_ if props.sorting_block.is_some()
&& $self.app.get_current_route() == *props.sorting_block.as_ref().unwrap() =>
{
$table
.sort
.as_mut()
.unwrap()
.scroll_to_top();
true
}
_ if props.searching_block.is_some()
&& $self.app.get_current_route() == *props.searching_block.as_ref().unwrap() =>
{
$table
.search
.as_mut()
.unwrap()
.scroll_home();
true
}
_ if props.filtering_block.is_some()
&& $self.app.get_current_route() == *props.filtering_block.as_ref().unwrap() =>
{
$table
.filter
.as_mut()
.unwrap()
.scroll_home();
true
}
_ => false,
}
}
fn [<handle_ $name _table_end>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
match $self.app.get_current_route() {
_ if props.table_block == $self.app.get_current_route() => {
$table.scroll_to_bottom();
true
}
_ if props.sorting_block.is_some()
&& $self.app.get_current_route() == *props.sorting_block.as_ref().unwrap() =>
{
$table
.sort
.as_mut()
.unwrap()
.scroll_to_bottom();
true
}
_ if props.searching_block.is_some()
&& $self.app.get_current_route() == *props.searching_block.as_ref().unwrap() =>
{
$table
.search
.as_mut()
.unwrap()
.reset_offset();
true
}
_ if props.filtering_block.is_some()
&& $self.app.get_current_route() == *props.filtering_block.as_ref().unwrap() =>
{
$table
.filter
.as_mut()
.unwrap()
.reset_offset();
true
}
_ => false,
}
}
fn [<handle_ $name _table_left_right>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
match $self.app.get_current_route() {
_ if props.searching_block.is_some()
&& $self.app.get_current_route() == *props.searching_block.as_ref().unwrap() =>
{
$crate::handle_text_box_left_right_keys!(
$self,
$self.key,
$table.search.as_mut().unwrap()
);
true
}
_ if props.filtering_block.is_some()
&& $self.app.get_current_route() == *props.filtering_block.as_ref().unwrap() =>
{
$crate::handle_text_box_left_right_keys!(
$self,
$self.key,
$table.filter.as_mut().unwrap()
);
true
}
_ => false,
}
}
fn [<handle _$name _table_submit>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
match $self.app.get_current_route() {
_ if props.sorting_block.is_some()
&& $self.app.get_current_route() == *props.sorting_block.as_ref().unwrap() =>
{
if let Some(sort_by_fn) = props.sort_by_fn {
$table.items.sort_by(sort_by_fn);
}
$table.apply_sorting();
$self.app.pop_navigation_stack();
true
}
_ if props.searching_block.is_some()
&& $self.app.get_current_route() == *props.searching_block.as_ref().unwrap() =>
{
$self.app.pop_navigation_stack();
$self.app.should_ignore_quit_key = false;
if $table.search.is_some() {
let search_field_fn = props
.search_field_fn
.expect("Search field function is required");
let has_match = $table.apply_search(search_field_fn);
if !has_match {
$self.app.push_navigation_stack(
props
.search_error_block
.expect("Search error block is undefined"),
);
}
}
true
}
_ if props.filtering_block.is_some()
&& $self.app.get_current_route() == *props.filtering_block.as_ref().unwrap() =>
{
$self.app.pop_navigation_stack();
$self.app.should_ignore_quit_key = false;
if $table.filter.is_some() {
let filter_field_fn = props
.filter_field_fn
.expect("Search field function is required");
let has_match = $table.apply_filter(filter_field_fn);
if !has_match {
$self.app.push_navigation_stack(
props
.filter_error_block
.expect("Search error block is undefined"),
);
}
}
true
}
_ => false,
}
}
fn [<handle_ $name _table_esc>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
match $self.app.get_current_route() {
_ if props.sorting_block.is_some()
&& $self.app.get_current_route() == *props.sorting_block.as_ref().unwrap() =>
{
$self.app.pop_navigation_stack();
true
}
_ if (props.searching_block.is_some()
&& $self.app.get_current_route() == *props.searching_block.as_ref().unwrap())
|| (props.search_error_block.is_some()
&& $self.app.get_current_route() == *props.search_error_block.as_ref().unwrap()) =>
{
$self.app.pop_navigation_stack();
$table.reset_search();
$self.app.should_ignore_quit_key = false;
true
}
_ if (props.filtering_block.is_some()
&& $self.app.get_current_route() == *props.filtering_block.as_ref().unwrap())
|| (props.filter_error_block.is_some()
&& $self.app.get_current_route() == *props.filter_error_block.as_ref().unwrap()) =>
{
$self.app.pop_navigation_stack();
$table.reset_filter();
$self.app.should_ignore_quit_key = false;
true
}
_ if props.table_block == $self.app.get_current_route()
&& $table.filtered_items.is_some() =>
{
$table.reset_filter();
true
}
_ => false,
}
}
fn [<handle_ $name _table_filter_key>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
if matches!($self.app.get_current_route(), _ if props.table_block == $self.app.get_current_route()) {
$self
.app
.push_navigation_stack(props.filtering_block.expect("Filtering block is undefined").into());
$table.reset_filter();
$table.filter = Some(HorizontallyScrollableText::default());
$self.app.should_ignore_quit_key = true;
true
} else {
false
}
}
fn [<handle_ $name _table_search_key>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
if matches!($self.app.get_current_route(), _ if props.table_block == $self.app.get_current_route()) {
$self
.app
.push_navigation_stack(props.searching_block.expect("Searching block is undefined"));
$table.search = Some(HorizontallyScrollableText::default());
$self.app.should_ignore_quit_key = true;
true
} else {
false
}
}
fn [<handle_ $name _table_sort_key>](&mut $self, props: $crate::handlers::table_handler::TableHandlingProps<$row>) -> bool {
if matches!($self.app.get_current_route(), _ if props.table_block == $self.app.get_current_route()) {
$table.sorting(
props
.sort_options
.as_ref()
.expect("Sort options are undefined")
.clone(),
);
$self
.app
.push_navigation_stack(props.sorting_block.expect("Sorting block is undefined"));
true
} else {
false
}
}
fn [<handle_ $name _table_search_box_input>](&mut $self) -> bool {
$crate::handle_text_box_keys!(
$self,
$self.key,
$table.search.as_mut().unwrap()
);
true
}
fn [<handle_ $name _table_filter_box_input>](&mut $self) -> bool {
$crate::handle_text_box_keys!(
$self,
$self.key,
$table.filter.as_mut().unwrap()
);
true
}
}
};
}
impl<T> TableHandlingProps<T>
where
T: Clone + PartialEq + Eq + Debug + Default,
{
pub fn new(table_block: Route) -> Self {
TableHandlingProps {
sorting_block: None,
sort_options: None,
sort_by_fn: None,
searching_block: None,
search_error_block: None,
search_field_fn: None,
filtering_block: None,
filter_error_block: None,
filter_field_fn: None,
table_block,
}
}
}