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},
|
display::{Position, Rgb565},
|
||||||
font::{HorizontalAlignment, VerticalAlignment},
|
font::{HorizontalAlignment, VerticalAlignment},
|
||||||
state::{ATCommandHelper, State, StateData, TextSettings},
|
state::{ATCommandHelper, Menu, MenuItem, State, StateData, TextSettings},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -232,10 +232,7 @@ impl State for EnterPinState {
|
|||||||
match helper.poll(&mut data.io) {
|
match helper.poll(&mut data.io) {
|
||||||
Some(response) => match response.unwrap() {
|
Some(response) => match response.unwrap() {
|
||||||
EnterPinResult::Ok => {
|
EnterPinResult::Ok => {
|
||||||
return Some(Box::new(TextState {
|
return Some(Box::new(MainMenuState::default()));
|
||||||
text: "SIM entered\nsuccessfully".to_owned(),
|
|
||||||
after: PhoneNumberState::default(),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
EnterPinResult::Error => {
|
EnterPinResult::Error => {
|
||||||
return Some(Box::new(TextState {
|
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)]
|
#[derive(Clone, Default)]
|
||||||
pub struct PhoneNumberState {
|
pub struct PhoneNumberState {
|
||||||
input: NumberInput,
|
input: NumberInput,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user