diff --git a/src/controller.rs b/src/controller.rs index 8c7bf0ed0af3c6aa30598a17c3a1c1878880fa06..8c50cd49a2645e73991288d2ccb3cdcc6c793359 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -93,6 +93,8 @@ impl Default for View { } impl Element for View { + type T = (); + fn render<E, DT: DrawTarget<Color = Rgb565, Error = E>>( &mut self, dt: &mut DT, @@ -111,7 +113,9 @@ impl Element for View { View::MainMenu(m) => m.key_push(k), View::Contacts(c) => c.key_push(k), View::ContactOptions(c, _) => c.key_push(k), - View::ContactView(c, _) => c.key_push(k), + View::ContactView(c, _) => { + c.key_push(k); + } View::Chat(c) => c.key_push(k), } } @@ -147,6 +151,8 @@ impl Controller { } impl Element for Controller { + type T = (); + fn render<E, DT: DrawTarget<Color = Rgb565, Error = E>>( &mut self, dt: &mut DT, @@ -161,7 +167,7 @@ impl Element for Controller { } fn key_push(&mut self, k: KeyCode) { - match (&self.cur_view, k) { + match (&mut self.cur_view, k) { (View::MainMenu(m), KeyCode::Touchpad) => { if let Some(new_view) = View::from_main_menu_id(m.selected(), &self.contacts) { self.cur_view = new_view; @@ -204,6 +210,14 @@ impl Element for Controller { self.cur_view = View::new_main_menu(id); } + (View::ContactView(cv, contact_id), k) => { + if cv.key_push(k) { + self.contacts.contacts.remove(*contact_id); + + self.cur_view = View::new_contacts(*contact_id, &self.contacts); + } + } + (_, k) => self.cur_view.key_push(k), } } diff --git a/src/gui/button.rs b/src/gui/button.rs new file mode 100644 index 0000000000000000000000000000000000000000..a3aa538722942ab8a8cc679cbed8d84ffcca586f --- /dev/null +++ b/src/gui/button.rs @@ -0,0 +1,101 @@ +use embedded_graphics::{ + geometry::{Point, Size}, + mono_font::{ascii::FONT_10X20, MonoTextStyleBuilder}, + pixelcolor::{Rgb565, RgbColor}, + primitives::{Primitive, PrimitiveStyleBuilder, Rectangle}, + text::{Baseline, Text}, + Drawable, +}; + +use crate::keyboard::KeyCode; + +use super::Element; + +const CHAR_WIDTH: u32 = 10; +const CHAR_HEIGHT: u32 = 20; +const BORDER_WIDTH: u32 = 4; +const BACKGROUND_COLOR: Rgb565 = Rgb565::new(31, 41, 0); // #FFA500 +const BORDER_COLOR: Rgb565 = Rgb565::new(31, 26, 0); // 0xFF6600 + +pub struct Button { + x: i32, + y: i32, + + text: &'static str, + pub selected: bool, +} + +impl Button { + pub fn new(x: i32, y: i32, text: &'static str) -> Self { + Self { + x, + y, + text, + selected: false, + } + } +} + +impl Element for Button { + type T = bool; + + fn render< + E, + DT: embedded_graphics::prelude::DrawTarget< + Color = embedded_graphics::pixelcolor::Rgb565, + Error = E, + >, + >( + &mut self, + dt: &mut DT, + ) -> Result<(), E> { + let width = CHAR_WIDTH * u32::try_from(self.text.len()).unwrap() + BORDER_WIDTH * 2; + let height = CHAR_HEIGHT + BORDER_WIDTH * 2; + + // Draw border/background + let unselected_rect_style = PrimitiveStyleBuilder::new() + .stroke_color(BORDER_COLOR) + .stroke_width(BORDER_WIDTH) + .fill_color(BACKGROUND_COLOR) + .build(); + + let selected_rect_style = PrimitiveStyleBuilder::new() + .stroke_color(BORDER_COLOR) + .stroke_width(BORDER_WIDTH) + .fill_color(Rgb565::WHITE) + .build(); + + let rect_style = if self.selected { + selected_rect_style + } else { + unselected_rect_style + }; + + Rectangle::new(Point::new(self.x, self.y), Size::new(width, height)) + .into_styled(rect_style) + .draw(dt)?; + + // Draw text + let text_x = self.x + i32::try_from(BORDER_WIDTH).unwrap(); + let text_y = self.y + i32::try_from(BORDER_WIDTH).unwrap(); + + let text_style = MonoTextStyleBuilder::new() + .font(&FONT_10X20) + .text_color(Rgb565::BLACK) + .build(); + + Text::with_baseline( + self.text, + Point::new(text_x, text_y), + text_style, + Baseline::Top, + ) + .draw(dt)?; + + Ok(()) + } + + fn key_push(&mut self, k: KeyCode) -> bool { + k == KeyCode::Touchpad + } +} diff --git a/src/gui/chat.rs b/src/gui/chat.rs index 31bcf5ca2120fd651aa7adbd05c1cf70b8bfdf1a..a1ba3a8f93f8c38f658ef51238226c4048ffa382 100644 --- a/src/gui/chat.rs +++ b/src/gui/chat.rs @@ -13,6 +13,8 @@ impl Chat { } impl Element for Chat { + type T = (); + fn render< E, DT: embedded_graphics::prelude::DrawTarget< diff --git a/src/gui/contact_view.rs b/src/gui/contact_view.rs index 29a393e0ce03ffd6ee880ce27ea3fdf05abbbab3..14da19e9709d928098cb0d5d3e837f8a1e52e685 100644 --- a/src/gui/contact_view.rs +++ b/src/gui/contact_view.rs @@ -9,6 +9,7 @@ use embedded_graphics::{ use heapless::String; use super::{ + button::Button, scroll_tracker::{ScrollAction, ScrollTracker}, textbox::{self, TextBox}, Element, @@ -24,6 +25,7 @@ pub struct ContactView { name: TextBox, callsign: TextBox, ssid: TextBox, + delete: Button, tracker: ScrollTracker, selected: usize, } @@ -59,12 +61,16 @@ impl ContactView { ssid.set_text(&ssid_buf).unwrap(); ssid.selected = false; + let mut delete = Button::new(LABEL_X, 160, "Delete"); + delete.selected = false; + Self { contact, editable, name, callsign, ssid, + delete, tracker: ScrollTracker::new(), selected: 0, } @@ -92,6 +98,8 @@ impl ContactView { } impl Element for ContactView { + type T = bool; + fn render< E, DT: embedded_graphics::prelude::DrawTarget< @@ -135,7 +143,10 @@ impl Element for ContactView { self.callsign.render(dt)?; self.ssid.selected = self.selected == 2; - self.ssid.render(dt)? + self.ssid.render(dt)?; + + self.delete.selected = self.selected == 3; + self.delete.render(dt)?; } else { Text::with_baseline( &self.contact.name, @@ -167,17 +178,21 @@ impl Element for ContactView { Ok(()) } - fn key_push(&mut self, k: crate::keyboard::KeyCode) { + // Returns true if contact should be deleted + fn key_push(&mut self, k: crate::keyboard::KeyCode) -> bool { if !self.editable { - return; + return false; } match self.selected { 0 => self.name.key_push(k), 1 => self.callsign.key_push(k), 2 => self.ssid.key_push(k), + 3 => return self.delete.key_push(k), _ => unreachable!(), } + + false } fn touchpad_scroll(&mut self, _x: i8, y: i8) { @@ -188,7 +203,7 @@ impl Element for ContactView { } } ScrollAction::Next => { - if self.selected < 2 { + if self.selected < 3 { self.selected += 1; } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 7f8e3d4e8f526ca3237188e27ab1a6bf5c02564f..bb79983b512fc108c6256624b63dfbdd965ba9a3 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -2,6 +2,7 @@ use embedded_graphics::{draw_target::DrawTarget, pixelcolor::Rgb565}; use crate::keyboard::KeyCode; +pub mod button; pub mod chat; pub mod contact_view; pub mod scroll_tracker; @@ -10,12 +11,14 @@ pub mod status; pub mod textbox; pub trait Element { + type T; + fn render<E, DT: DrawTarget<Color = Rgb565, Error = E>>( &mut self, dt: &mut DT, ) -> Result<(), E>; - fn key_push(&mut self, _k: KeyCode) {} + fn key_push(&mut self, _k: KeyCode) -> Self::T; fn touchpad_scroll(&mut self, _x: i8, _y: i8) {} } diff --git a/src/gui/selector.rs b/src/gui/selector.rs index 1e44065cde455048e285f748d6fcb76cf484ff5a..39894b8c693764fa9ebfa1b58872d565a3be38cc 100644 --- a/src/gui/selector.rs +++ b/src/gui/selector.rs @@ -9,6 +9,8 @@ use embedded_graphics::{ Drawable, }; +use crate::keyboard::KeyCode; + use super::{ scroll_tracker::{ScrollAction, ScrollTracker}, Element, @@ -64,6 +66,8 @@ impl<T: AsRef<str>, V: AsRef<[T]>> Selector<T, V> { } impl<T: AsRef<str>, V: AsRef<[T]>> Element for Selector<T, V> { + type T = (); + fn render< E, DT: embedded_graphics::prelude::DrawTarget< @@ -133,6 +137,8 @@ impl<T: AsRef<str>, V: AsRef<[T]>> Element for Selector<T, V> { Ok(()) } + fn key_push(&mut self, _k: KeyCode) {} + fn touchpad_scroll(&mut self, _x: i8, y: i8) { match self.tracker.scroll(y) { ScrollAction::Previous => { diff --git a/src/gui/status.rs b/src/gui/status.rs index 9f0b3a8c276776b8221fc0ddb3fc75c6431990a1..999ba938fc7aeb3b61776fdfe63b48339967e672 100644 --- a/src/gui/status.rs +++ b/src/gui/status.rs @@ -28,6 +28,8 @@ impl StatusBar { } impl Element for StatusBar { + type T = (); + fn render< E, DT: embedded_graphics::prelude::DrawTarget< diff --git a/src/gui/textbox.rs b/src/gui/textbox.rs index 490676d85580de80b249baa12af7645552bfc0d8..9a4fbdecce813b456fa557eda85478bea084c01c 100644 --- a/src/gui/textbox.rs +++ b/src/gui/textbox.rs @@ -112,6 +112,8 @@ impl TextBox { } impl Element for TextBox { + type T = (); + fn render<E, DT: DrawTarget<Color = Rgb565, Error = E>>( &mut self, dt: &mut DT,