summaryrefslogtreecommitdiff
path: root/schist_desktop_gui/src/gui/components/navigation/update_navigation.rs
blob: f86867f01512e25964d5c31881095de00e750c6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use iced::Element;

use super::{Action, Message, Navigation};

pub fn update_navigation<'a, TOption>(
    navigation: &mut Navigation<TOption>,
    message: Message<TOption>,
) -> Action<TOption>
where
    TOption: Clone + PartialEq + Into<Element<'a, Message<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![
                    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(),
                    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
                    .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::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
            }
        }
    }
}