diff options
| author | Joe Carstairs <me@joeac.net> | 2025-08-25 18:22:00 +0100 |
|---|---|---|
| committer | Joe Carstairs <me@joeac.net> | 2025-08-25 18:22:00 +0100 |
| commit | 86487b8ff6e691f2b261a93733df8f4cc5dc7320 (patch) | |
| tree | 8d116acb31fe3bf8ce5d4201ae0bbc36ce6cc38a /schist_desktop_gui/src/gui/components/navigation | |
| parent | fe85652e4d3e8906824baddaafd05d19105579b8 (diff) | |
refactor navigation
Diffstat (limited to 'schist_desktop_gui/src/gui/components/navigation')
4 files changed, 149 insertions, 217 deletions
diff --git a/schist_desktop_gui/src/gui/components/navigation/new_navigation.rs b/schist_desktop_gui/src/gui/components/navigation/new_navigation.rs deleted file mode 100644 index b5c0c19..0000000 --- a/schist_desktop_gui/src/gui/components/navigation/new_navigation.rs +++ /dev/null @@ -1,72 +0,0 @@ -use super::Navigation; - -pub fn new_navigation<TOption>( - active_option: Option<TOption>, - options: Vec<TOption>, -) -> Navigation<TOption> -where - TOption: Clone + PartialEq, -{ - let active_option_index = active_option.clone().map_or(Option::None, |active_option| { - options.iter().position(|option| option.eq(&active_option)) - }); - if let Some(active_option_index) = active_option_index { - let split = options.split_at(active_option_index); - Navigation { - options_before_active: split.0.to_vec(), - active_option, - options_after_active: split.1.split_at(1).1.to_vec(), - } - } else { - Navigation { - options_before_active: options, - active_option, - options_after_active: vec![], - } - } -} - -#[cfg(test)] -mod test { - use super::Navigation; - - #[test] - fn when_active_option_at_start_of_options_then_finds_active_option() { - let navigation = Navigation::new(Some(1), vec![1, 2, 3, 4, 5]); - assert_eq!(Vec::<i32>::new(), navigation.options_before_active); - assert_eq!(Some(1), navigation.active_option); - assert_eq!(vec![2, 3, 4, 5], navigation.options_after_active); - } - - #[test] - fn when_active_option_in_middle_of_options_then_finds_active_option() { - let navigation = Navigation::new(Some(3), vec![1, 2, 3, 4, 5]); - assert_eq!(vec![1, 2], navigation.options_before_active); - assert_eq!(Some(3), navigation.active_option); - assert_eq!(vec![4, 5], navigation.options_after_active); - } - - #[test] - fn when_active_option_at_end_of_options_then_finds_active_option() { - let navigation = Navigation::new(Some(5), vec![1, 2, 3, 4, 5]); - assert_eq!(vec![1, 2, 3, 4], navigation.options_before_active); - assert_eq!(Some(5), navigation.active_option); - assert_eq!(Vec::<i32>::new(), navigation.options_after_active); - } - - #[test] - fn when_active_option_not_in_options_then_appends_active_option() { - let navigation = Navigation::new(Some(6), vec![1, 2, 3, 4, 5]); - assert_eq!(vec![1, 2, 3, 4, 5], navigation.options_before_active); - assert_eq!(Some(6), navigation.active_option); - assert_eq!(Vec::<i32>::new(), navigation.options_after_active); - } - - #[test] - fn when_no_active_option_then_all_options_are_before_active_option() { - let navigation = Navigation::new(None, vec![1, 2, 3, 4, 5]); - assert_eq!(vec![1, 2, 3, 4, 5], navigation.options_before_active); - assert_eq!(None, navigation.active_option); - assert_eq!(Vec::<i32>::new(), navigation.options_after_active); - } -} diff --git a/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs b/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs index f86867f..c44ddd8 100644 --- a/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs +++ b/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs @@ -1,127 +1,130 @@ use iced::Element; +use crate::traits::Component; + use super::{Action, Message, Navigation}; -pub fn update_navigation<'a, TOption>( - navigation: &mut Navigation<TOption>, - message: Message<TOption>, -) -> Action<TOption> +impl<'a, TOption> Component<'a, Message<TOption>, Action<TOption>> for Navigation<TOption> where - TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, + TOption: Clone + PartialEq + 'a, + Element<'a, Message<TOption>>: From<&'a TOption>, { - match message { - Message::SelectOption(option) => { - if navigation - .active_option - .as_ref() - .is_some_and(|active_option| active_option.clone() == option) - { - Action::None - } else if let Some(index) = navigation - .options_before_active - .iter() - .position(|o| o.clone() == option) - { - let split = navigation.options_before_active.split_at(index); - navigation.options_after_active = vec![ + fn update(&mut self, message: Message<TOption>) -> Action<TOption> { + let navigation: &mut Navigation<TOption> = self; + match message { + Message::SelectOption(option) => { + if navigation + .active_option + .as_ref() + .is_some_and(|active_option| TOption::eq(active_option, &option)) + { + Action::None + } else if let Some(index) = navigation + .options_before_active + .iter() + .position(|o| TOption::eq(o, &option)) + { + let split = navigation.options_before_active.split_at(index); + navigation.options_after_active = vec![ + navigation + .active_option + .clone() + .map_or(vec![], |active_option| vec![active_option]), + split.1.split_at(1).1.to_vec(), + navigation.options_after_active.clone(), + ] + .concat(); + navigation.options_before_active = split.0.to_vec(); + navigation.active_option = Some(option.clone()); + Action::SelectOption(option) + } else if let Some(index) = navigation + .options_after_active + .iter() + .position(|o| TOption::eq(o, &option)) + { + let split = navigation.options_after_active.split_at(index); + navigation.options_before_active = vec![ + navigation.options_before_active.clone(), + split.0.to_vec(), + navigation + .active_option + .clone() + .map_or(vec![], |active_option| vec![active_option]), + ] + .concat(); + navigation.active_option = Some(option.clone()); + navigation.options_after_active = split.1.split_at(1).1.to_vec(); + Action::SelectOption(option) + } else { + if let Some(active_option) = &navigation.active_option { + navigation.options_before_active.push(active_option.clone()); + } navigation - .active_option - .clone() - .map_or(vec![], |active_option| vec![active_option]), - split.1.split_at(1).1.to_vec(), - navigation.options_after_active.clone(), - ] - .concat(); - navigation.options_before_active = split.0.to_vec(); - navigation.active_option = Some(option.clone()); - Action::SelectOption(option) - } else if let Some(index) = navigation - .options_after_active - .iter() - .position(|o| o.clone() == option) - { - let split = navigation.options_after_active.split_at(index); - navigation.options_before_active = vec![ - navigation.options_before_active.clone(), - split.0.to_vec(), + .options_before_active + .append(&mut navigation.options_after_active); + navigation.active_option = Some(option.clone()); + navigation.options_after_active = vec![]; + Action::SelectOption(option) + } + } + Message::SetOptions(options) => { + let active_option_index = navigation .active_option .clone() - .map_or(vec![], |active_option| vec![active_option]), - ] - .concat(); - navigation.active_option = Some(option.clone()); - navigation.options_after_active = split.1.split_at(1).1.to_vec(); - Action::SelectOption(option) - } else { - if let Some(active_option) = &navigation.active_option { - navigation.options_before_active.push(active_option.clone()); + .map_or(Option::None, |active_option| { + options + .iter() + .position(|option| active_option == option.clone()) + }); + if let Some(active_option_index) = active_option_index { + let split = options.split_at(active_option_index); + navigation.options_before_active = split.0.to_vec(); + navigation.options_after_active = split.1.split_at(1).1.to_vec(); + Action::None + } else { + navigation.options_before_active = options + .split_last() + .map_or_else(Vec::new, |(_last, rest)| rest.to_vec()); + navigation.active_option = options.last().cloned(); + options + .last() + .cloned() + .map_or(Action::None, Action::SelectOption) } - navigation - .options_before_active - .append(&mut navigation.options_after_active); - navigation.active_option = Some(option.clone()); - navigation.options_after_active = vec![]; - Action::SelectOption(option) } - } - Message::SetOptions(options) => { - let active_option_index = - navigation - .active_option - .clone() - .map_or(Option::None, |active_option| { - options - .iter() - .position(|option| active_option == option.clone()) - }); - if let Some(active_option_index) = active_option_index { - let split = options.split_at(active_option_index); - navigation.options_before_active = split.0.to_vec(); - navigation.options_after_active = split.1.split_at(1).1.to_vec(); - Action::None - } else { - navigation.options_before_active = options - .split_last() - .map_or_else(Vec::new, |(_last, rest)| rest.to_vec()); - navigation.active_option = options.last().cloned(); - options - .last() - .cloned() - .map_or(Action::None, Action::SelectOption) - } - } - Message::SelectNext => { - if let Some(next) = navigation.options_after_active.clone().first() { - navigation.options_before_active = vec![ - navigation.options_before_active.clone(), - navigation.active_option.clone().map_or(vec![], |o| vec![o]), - ] - .concat(); - navigation.active_option = Some(next.clone()); - navigation.options_after_active = - navigation.options_after_active.split_at(1).1.to_vec(); - Action::SelectOption(next.clone()) - } else { - Action::None + Message::SelectNext => { + if let Some(next) = navigation.options_after_active.clone().first() { + navigation.options_before_active = vec![ + navigation.options_before_active.clone(), + navigation.active_option.clone().map_or(vec![], |o| vec![o]), + ] + .concat(); + navigation.active_option = Some(next.clone()); + navigation.options_after_active = + navigation.options_after_active.split_at(1).1.to_vec(); + Action::SelectOption(next.clone()) + } else { + Action::None + } } - } - Message::SelectPrev => { - if let Some(prev) = navigation.options_before_active.clone().last() { - navigation.options_after_active = vec![ - navigation.active_option.clone().map_or(vec![], |o| vec![o]), - navigation.options_after_active.clone(), - ] - .concat(); - navigation.active_option = Some(prev.clone()); - navigation.options_before_active = navigation - .options_before_active - .split_last() - .map(|split| split.1.to_vec()) - .unwrap_or_else(Vec::new); - Action::SelectOption(prev.clone()) - } else { - Action::None + Message::SelectPrev => { + if let Some(prev) = navigation.options_before_active.clone().last() { + navigation.options_after_active = vec![ + navigation.active_option.clone().map_or(vec![], |o| vec![o]), + navigation.options_after_active.clone(), + ] + .concat(); + navigation.active_option = Some(prev.clone()); + navigation.options_before_active = navigation + .options_before_active + .split_last() + .map(|split| split.1.to_vec()) + .unwrap_or_else(Vec::new); + Action::SelectOption(prev.clone()) + } else { + Action::None + } } } } diff --git a/schist_desktop_gui/src/gui/components/navigation/view_navigation.rs b/schist_desktop_gui/src/gui/components/navigation/view_navigation.rs index beec818..3f1da18 100644 --- a/schist_desktop_gui/src/gui/components/navigation/view_navigation.rs +++ b/schist_desktop_gui/src/gui/components/navigation/view_navigation.rs @@ -1,26 +1,27 @@ use iced::{widget::column, Element}; +use crate::traits::Viewable; + use super::{Message, Navigation}; -pub fn view_navigation<'a, TOption>( - navigation: &'a Navigation<TOption>, -) -> Element<'a, Message<TOption>> +impl<'a, TOption> Viewable<'a, Message<TOption>> for Navigation<TOption> where - TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, + TOption: Clone + PartialEq + 'a, + Element<'a, Message<TOption>>: From<&'a TOption>, { - let mut options = Vec::new(); - navigation - .options_before_active - .iter() - .map(|option| navigation.button(&option)) - .for_each(|option| options.push(option)); - if let Some(active_option) = navigation.active_option.as_ref() { - options.push(navigation.button(&active_option)); + fn view(&'a self) -> iced::Element<'a, Message<TOption>> { + let mut options = Vec::new(); + self.options_before_active + .iter() + .map(|option| self.view_navigation_button(&option)) + .for_each(|option| options.push(option)); + if let Some(active_option) = self.active_option.as_ref() { + options.push(self.view_navigation_button(&active_option)); + } + self.options_after_active + .iter() + .map(|option| self.view_navigation_button(&option)) + .for_each(|option| options.push(option)); + column(options).into() } - navigation - .options_after_active - .iter() - .map(|option| navigation.button(&option)) - .for_each(|option| options.push(option)); - column(options).into() } diff --git a/schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs b/schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs index 3132bf1..d65328c 100644 --- a/schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs +++ b/schist_desktop_gui/src/gui/components/navigation/view_navigation_button.rs @@ -4,24 +4,24 @@ use crate::gui::components::{active_button, inactive_button}; use super::{Message, Navigation}; -pub fn view_navigation_button<'a, TOption>( - navigation: &'a Navigation<TOption>, - option: &'a TOption, -) -> Element<'a, Message<TOption>> +impl<'a, TOption> Navigation<TOption> where - TOption: Clone + PartialEq + Into<Element<'a, Message<TOption>>>, + TOption: Clone + PartialEq + 'a, + Element<'a, Message<TOption>>: From<&'a TOption>, { - if navigation - .active_option - .as_ref() - .is_some_and(|o| *o == *option) - { - active_button(Into::<Element<'a, Message<TOption>>>::into(option.clone())).into() - } else { - inactive_button( - Into::<Element<'a, Message<TOption>>>::into(option.clone()), - Message::SelectOption(option.clone()), - ) + pub(super) fn view_navigation_button( + &'a self, + option: &'a TOption, + ) -> Element<'a, Message<TOption>> { + if self + .active_option + .as_ref() + .is_some_and(|o| TOption::eq(o, option)) + { + active_button(option) + } else { + inactive_button(option, Message::SelectOption(option.clone())) + } .into() } } |
