Implement simple menu system
This commit is contained in:
parent
b6517d2ee6
commit
e30e71516e
79
src/state.rs
79
src/state.rs
@ -157,3 +157,82 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MENU_HEIGHT: usize = 240 / 30;
|
||||
|
||||
pub trait MenuItem {
|
||||
fn as_text(&self) -> String;
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct Menu<T: MenuItem> {
|
||||
items: Vec<T>,
|
||||
idx: usize,
|
||||
scroll: usize,
|
||||
}
|
||||
|
||||
impl<T: MenuItem> Menu<T> {
|
||||
pub fn with_item(mut self, item: T) -> Menu<T> {
|
||||
self.items.push(item);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn poll<'s>(&'s mut self, io: &mut AsyncIO) -> Option<&'s T> {
|
||||
use crate::async_io::KeypadButton;
|
||||
|
||||
for _ in 0..io.keypad.get_presses(KeypadButton::KeypadC) {
|
||||
self.previous();
|
||||
}
|
||||
for _ in 0..io.keypad.get_presses(KeypadButton::KeypadD) {
|
||||
self.next();
|
||||
}
|
||||
|
||||
if io.keypad.get_presses(KeypadButton::KeypadA) > 0 {
|
||||
Some(&self.items[self.idx])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn previous(&mut self) {
|
||||
if self.idx == 0 {
|
||||
// Wrap index around
|
||||
self.idx = self.items.len() - 1;
|
||||
if self.idx >= (self.scroll + MENU_HEIGHT) {
|
||||
self.scroll = (self.idx - MENU_HEIGHT) + 1;
|
||||
}
|
||||
} else {
|
||||
self.idx -= 1;
|
||||
if self.idx < self.scroll {
|
||||
self.scroll = self.idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
self.idx = (self.idx + 1) % self.items.len();
|
||||
if self.idx == 0 {
|
||||
self.scroll = 0;
|
||||
} else if self.idx >= (self.scroll + MENU_HEIGHT) {
|
||||
self.scroll = (self.idx - MENU_HEIGHT) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, data: &mut StateData) {
|
||||
for (i, (idx, item)) in self
|
||||
.items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(self.scroll)
|
||||
.take(MENU_HEIGHT)
|
||||
.enumerate()
|
||||
{
|
||||
let mut settings = TextSettings::default();
|
||||
if idx == self.idx {
|
||||
settings.bg = Rgb565::white();
|
||||
settings.fg = Rgb565::black();
|
||||
}
|
||||
data.draw_text(item.as_text(), Position::new(0, (i * 30) as i16), settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ use crate::{
|
||||
},
|
||||
display::{Position, Rgb565},
|
||||
font::{HorizontalAlignment, VerticalAlignment},
|
||||
state::{ATCommandHelper, State, StateData, TextSettings},
|
||||
state::{ATCommandHelper, Menu, MenuItem, State, StateData, TextSettings},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -232,10 +232,7 @@ impl State for EnterPinState {
|
||||
match helper.poll(&mut data.io) {
|
||||
Some(response) => match response.unwrap() {
|
||||
EnterPinResult::Ok => {
|
||||
return Some(Box::new(TextState {
|
||||
text: "SIM entered\nsuccessfully".to_owned(),
|
||||
after: PhoneNumberState::default(),
|
||||
}));
|
||||
return Some(Box::new(MainMenuState::default()));
|
||||
}
|
||||
EnterPinResult::Error => {
|
||||
return Some(Box::new(TextState {
|
||||
@ -275,6 +272,61 @@ impl State for EnterPinState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
enum MainMenuItem {
|
||||
#[default]
|
||||
Item1,
|
||||
Item2,
|
||||
Item3,
|
||||
Item4,
|
||||
Item5,
|
||||
Item6,
|
||||
}
|
||||
impl MenuItem for MainMenuItem {
|
||||
fn as_text(&self) -> String {
|
||||
match self {
|
||||
MainMenuItem::Item1 => "item1",
|
||||
MainMenuItem::Item2 => "item2",
|
||||
MainMenuItem::Item3 => "item3",
|
||||
MainMenuItem::Item4 => "item4",
|
||||
MainMenuItem::Item5 => "item5",
|
||||
MainMenuItem::Item6 => "item6",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MainMenuState {
|
||||
menu: Menu<MainMenuItem>,
|
||||
}
|
||||
|
||||
impl Default for MainMenuState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
menu: Menu::default()
|
||||
.with_item(MainMenuItem::Item1)
|
||||
.with_item(MainMenuItem::Item2)
|
||||
.with_item(MainMenuItem::Item3)
|
||||
.with_item(MainMenuItem::Item4)
|
||||
.with_item(MainMenuItem::Item5)
|
||||
.with_item(MainMenuItem::Item6),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl State for MainMenuState {
|
||||
fn update(&mut self, data: &mut StateData) -> Option<Box<dyn State>> {
|
||||
self.menu.poll(&mut data.io);
|
||||
None
|
||||
}
|
||||
|
||||
fn draw(&self, data: &mut StateData) {
|
||||
data.clear_screen(Rgb565::black().as_color());
|
||||
self.menu.draw(data);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PhoneNumberState {
|
||||
input: NumberInput,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user