embedded_multi_page_hmi/page/
enter_string.rs

1#[allow(unused_imports)]
2use super::super::setting::Setting;
3
4use super::super::setting::CellSetting;
5use super::basic::BasicPage;
6
7use std::fmt::{Debug, Display};
8#[allow(unused_imports)]
9use std::str::FromStr;
10#[allow(unused_imports)]
11use std::string::String;
12
13/// Page that allows to enter an ascii string composed of fixed set of characters.
14///
15/// Interaction is as follows:
16/// * entering the page -> previous collected characters are shown
17/// * entering the page first time -> factory default collected characters are shown
18///
19/// * next - selects the next character from the set of allowed characters
20/// * previous - selects the previous character from the set of allowed characthers
21/// * action - appends the selected character to the so far collected characters
22/// * back - removes (most right character from the collected characters)
23/// * home - leaves the page with UP-navigation
24///
25/// If previous button does not exist, next starts at the beginning after reaching
26/// the end.
27///
28/// Back can be emulated with next and action if not available.
29/// Home can be emulated with next and action if not available.
30pub struct EnterStringPage<'a, T> {
31    pub basic: BasicPage,
32    allowed_characters: &'static str,
33    current_char: usize,
34    max_chars: usize,
35    pub buffer: String,
36
37    back: Option<&'static str>, // the Back menu entry in language
38    up: Option<&'static str>,   // the OK/Up/leave menu entry in language
39    value: &'a CellSetting<T>,  // the value to store
40}
41
42impl<'a, T: Copy + FromStr + Display> EnterStringPage<'a, T>
43where
44    <T as FromStr>::Err: Debug,
45{
46    pub fn new(
47        basic: BasicPage,
48        allowed_characters: &'static str,
49        back: Option<&'static str>,
50        up: Option<&'static str>,
51        value: &'a CellSetting<T>,
52    ) -> Self {
53        let mut max_chars = allowed_characters.len();
54        if back.is_some() {
55            max_chars += 1;
56        }
57        if up.is_some() {
58            max_chars += 1;
59        }
60        let buffer = format!("{}", value.get());
61        EnterStringPage {
62            basic,
63            allowed_characters,
64            current_char: 0,
65            buffer,
66            back,
67            up,
68            max_chars,
69            value,
70        }
71    }
72
73    /// Determine if finish action is presented and selected
74    fn is_finish(&self) -> bool {
75        match self.up {
76            None => false,
77            Some(_) => {
78                if self.current_char >= self.allowed_characters.len() {
79                    return match self.back {
80                        None => true,
81                        Some(_) => self.current_char > self.allowed_characters.len(),
82                    };
83                }
84                false
85            }
86        }
87    }
88
89    /// Determine if back action is presented and selected
90    fn is_back(&self) -> bool {
91        match self.back {
92            None => false,
93            Some(_) => self.current_char == self.allowed_characters.len(),
94        }
95    }
96
97    /// Process the action input
98    ///
99    /// Action is one of:
100    ///
101    /// * Add the selected character to internal buffer
102    /// * Remove last from internal buffer
103    /// * Finish the page and return to upper page.
104    ///   * Side effect: Update the value it page cares for
105    ///
106    /// h2. Args
107    ///
108
109    pub fn action_string(&self) -> &'static str {
110        if self.is_back() {
111            if let Some(back) = self.back {
112                return back;
113            }
114        }
115        if self.is_finish() {
116            if let Some(up) = self.up {
117                self.value.set_string(&self.buffer[..]);
118                return up;
119            }
120        }
121        &self.allowed_characters[self.current_char..self.current_char + 1]
122    }
123}
124
125use super::super::*;
126
127impl<T: Copy + FromStr + Display> PageInteractionInterface for EnterStringPage<'_, T>
128where
129    <T as FromStr>::Err: Debug,
130{
131    fn dispatch(&mut self, interaction: Interaction) -> PageNavigation {
132        match interaction {
133            Interaction::Action => {
134                if self.is_back() {
135                    self.buffer.pop();
136                    return PageNavigation::Update;
137                }
138                if self.is_finish() {
139                    return PageNavigation::Up;
140                }
141                self.buffer.push(
142                    self.allowed_characters
143                        .chars()
144                        .nth(self.current_char)
145                        .unwrap(),
146                );
147                PageNavigation::Update
148            }
149            Interaction::Back => {
150                self.buffer.pop();
151                PageNavigation::Update
152            }
153            Interaction::Home => {
154                self.value.set_string(&self.buffer[..]);
155                PageNavigation::Up
156            }
157            Interaction::Next => {
158                self.current_char += 1;
159                if self.current_char >= self.max_chars {
160                    self.current_char = 0;
161                }
162                PageNavigation::Update
163            }
164            // if previous interaction is not available, this implementation is never called
165            // but it does not hurt
166            Interaction::Previous => {
167                if self.current_char == 0 {
168                    self.current_char = self.max_chars - 1;
169                } else {
170                    self.current_char -= 1;
171                }
172                PageNavigation::Update
173            }
174        }
175    }
176}
177
178impl<T> PageBaseInterface for EnterStringPage<'_, T> {
179    fn update<'a>(
180        &mut self,
181        _title_of_subpages: Option<Box<dyn Iterator<Item = &'a str> + 'a>>,
182    ) -> Result<PageNavigation, PageError> {
183        // print the current text
184        Ok(PageNavigation::Update)
185    }
186
187    fn title(&self) -> &str {
188        self.basic.title
189    }
190}
191
192#[cfg(test)]
193mod tests;