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 where T: Clone + PartialEq + Eq + Debug + Default, { #[setters(strip_option)] pub sorting_block: Option, #[setters(strip_option)] pub sort_options: Option>>, #[setters(strip_option)] pub sort_by_fn: Option Ordering>, #[setters(strip_option)] pub searching_block: Option, #[setters(strip_option)] pub search_error_block: Option, #[setters(strip_option)] pub search_field_fn: Option &str>, #[setters(strip_option)] pub filtering_block: Option, #[setters(strip_option)] pub filter_error_block: Option, #[setters(strip_option)] pub filter_field_fn: Option &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 [](&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.[](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.down.key => $self.[](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.home.key => $self.[](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.end.key => $self.[](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.left.key || $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.right.key => { $self.[](props) } _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.submit.key => $self.[](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.esc.key => $self.[](props), _ if props.searching_block.is_some() && $self.app.get_current_route() == *props.searching_block.as_ref().unwrap() => { $self.[]() } _ if props.filtering_block.is_some() && $self.app.get_current_route() == *props.filtering_block.as_ref().unwrap() => { $self.[]() } _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.filter.key => $self.[](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.search.key => $self.[](props), _ if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.sort.key => $self.[](props), _ => false, } } else { false } } fn [](&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 [](&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 [](&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 [](&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 [](&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 [](&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 [](&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 [](&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 [](&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 [](&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 [](&mut $self) -> bool { $crate::handle_text_box_keys!( $self, $self.key, $table.search.as_mut().unwrap() ); true } fn [](&mut $self) -> bool { $crate::handle_text_box_keys!( $self, $self.key, $table.filter.as_mut().unwrap() ); true } } }; } impl TableHandlingProps 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, } } }