From 209505bbf66fd63c0eedb0e566dc6a31da37376a Mon Sep 17 00:00:00 2001
From: Stephen D <webmaster@scd31.com>
Date: Sun, 14 Apr 2024 10:58:23 -0300
Subject: [PATCH] contact delete button

---
 src/controller.rs       |  18 ++++++-
 src/gui/button.rs       | 101 ++++++++++++++++++++++++++++++++++++++++
 src/gui/chat.rs         |   2 +
 src/gui/contact_view.rs |  23 +++++++--
 src/gui/mod.rs          |   5 +-
 src/gui/selector.rs     |   6 +++
 src/gui/status.rs       |   2 +
 src/gui/textbox.rs      |   2 +
 8 files changed, 152 insertions(+), 7 deletions(-)
 create mode 100644 src/gui/button.rs

diff --git a/src/controller.rs b/src/controller.rs
index 8c7bf0e..8c50cd4 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 0000000..a3aa538
--- /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 31bcf5c..a1ba3a8 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 29a393e..14da19e 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 7f8e3d4..bb79983 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 1e44065..39894b8 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 9f0b3a8..999ba93 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 490676d..9a4fbde 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,
-- 
GitLab