Skip to content
Snippets Groups Projects
Commit 413684db authored by Stephen D's avatar Stephen D
Browse files

contacts

parent 5386c939
No related branches found
No related tags found
No related merge requests found
use heapless::{String, Vec};
#[derive(Debug, Clone)]
pub struct Contact {
callsign: String<10>,
ssid: u8,
pub name: String<30>,
}
#[derive(Debug)]
pub struct ContactGroup {
pub contacts: Vec<Contact, 20>,
}
impl Default for ContactGroup {
fn default() -> Self {
let mut contacts = Vec::new();
contacts
.push(Contact {
callsign: String::try_from("VA3QAK").unwrap(),
ssid: 19,
name: String::try_from("Adrian").unwrap(),
})
.unwrap();
contacts
.push(Contact {
callsign: String::try_from("VE3SVF").unwrap(),
ssid: 239,
name: String::try_from("Sasha").unwrap(),
})
.unwrap();
contacts
.push(Contact {
callsign: String::try_from("VE3KCN").unwrap(),
ssid: 19,
name: String::try_from("Cam").unwrap(),
})
.unwrap();
Self { contacts }
}
}
use embedded_graphics::{pixelcolor::Rgb565, prelude::DrawTarget};
use heapless::{String, Vec};
use crate::{
contact::{Contact, ContactGroup},
gui::{chat::Chat, selector::Selector, status::StatusBar, Element},
keyboard::KeyCode,
voltage::VoltMeter,
};
pub enum View {
MainMenu(Selector<&'static str, [&'static str; 3]>),
Contacts(Selector<String<30>, Vec<String<30>, 3>>),
Chat(Chat),
}
impl View {
pub fn main_menu_with_id(id: usize) -> Self {
let menu = Selector::new(["Contacts", "Messages", "Settings"], id);
Self::MainMenu(menu)
}
pub fn from_main_menu_id(id: usize) -> Option<Self> {
match id {
0 => {
let group = ContactGroup::default();
let contact_names: Vec<_, 3> =
group.contacts.iter().map(|c| c.name.clone()).collect();
Some(Self::Contacts(Selector::new(
contact_names.try_into().unwrap(),
0,
)))
}
1 => Some(Self::Chat(Chat::new())),
_ => None,
}
}
pub fn to_main_menu_id(&self) -> usize {
match self {
View::MainMenu(_) => unreachable!(),
View::Contacts(_) => 0,
View::Chat(_) => 1,
}
}
}
impl Default for View {
fn default() -> Self {
Self::main_menu_with_id(0)
}
}
impl Element for View {
fn render<E, DT: DrawTarget<Color = Rgb565, Error = E>>(
&mut self,
dt: &mut DT,
) -> Result<(), E> {
match self {
View::MainMenu(m) => m.render(dt),
View::Contacts(c) => c.render(dt),
View::Chat(c) => c.render(dt),
}
}
fn key_push(&mut self, k: KeyCode) {
match self {
View::MainMenu(m) => m.key_push(k),
View::Contacts(c) => c.key_push(k),
View::Chat(c) => c.key_push(k),
}
}
fn touchpad_scroll(&mut self, x: i8, y: i8) {
match self {
View::MainMenu(m) => m.touchpad_scroll(x, y),
View::Contacts(c) => c.touchpad_scroll(x, y),
View::Chat(c) => c.touchpad_scroll(x, y),
}
}
}
pub struct Controller {
status: StatusBar,
selector: Selector<4>,
chat: Chat,
in_chat: bool,
cur_view: View,
}
impl Controller {
pub fn new(volt_meter: VoltMeter) -> Self {
Self {
status: StatusBar::new(volt_meter),
selector: Selector::new(["Contacts", "Messages", "Settings", "mrrp meow"]),
chat: Chat::new(),
in_chat: false,
cur_view: View::default(),
}
}
}
......@@ -33,35 +104,30 @@ impl Element for Controller {
self.status.render(dt)?;
if self.in_chat {
self.chat.render(dt)?;
} else {
self.selector.render(dt)?;
}
self.cur_view.render(dt)?;
Ok(())
}
fn key_push(&mut self, k: KeyCode) {
match k {
KeyCode::Touchpad => {
if self.selector.selected() == 1 {
self.in_chat = true;
match (&self.cur_view, k) {
(View::MainMenu(m), KeyCode::Touchpad) => {
if let Some(new_view) = View::from_main_menu_id(m.selected()) {
self.cur_view = new_view;
}
}
KeyCode::Back => {
self.in_chat = false;
}
_ if self.in_chat => self.chat.key_push(k),
(View::MainMenu(_), KeyCode::Back) => {}
(_, KeyCode::Back) => {
let id = self.cur_view.to_main_menu_id();
self.cur_view = View::main_menu_with_id(id);
}
_ => {}
(_, k) => self.cur_view.key_push(k),
}
}
fn touchpad_scroll(&mut self, x: i8, y: i8) {
if !self.in_chat {
self.selector.touchpad_scroll(x, y);
}
self.cur_view.touchpad_scroll(x, y);
}
}
use core::marker::PhantomData;
use embedded_graphics::{
mono_font::{ascii::FONT_10X20, MonoTextStyleBuilder},
pixelcolor::Rgb565,
......@@ -17,26 +19,39 @@ const BORDER_WIDTH: u32 = 4;
const SCREEN_WIDTH: u32 = 320;
const SCREEN_HEIGHT: u32 = 240;
pub struct Selector<const N: usize> {
options: [&'static str; N],
pub struct Selector<T: AsRef<str>, V: AsRef<[T]>> {
options: V,
width: u32,
height: u32,
selected: usize,
y_tracker: i8,
_phantom: PhantomData<T>,
}
impl<const N: usize> Selector<N> {
pub fn new(options: [&'static str; N]) -> Self {
let width = u32::try_from(options.iter().map(|x| x.len()).max().unwrap_or(0)).unwrap()
impl<T: AsRef<str>, V: AsRef<[T]>> Selector<T, V> {
pub fn new(options: V, selected: usize) -> Self {
assert!(selected < options.as_ref().len());
let width = u32::try_from(
options
.as_ref()
.iter()
.map(|x| x.as_ref().len())
.max()
.unwrap_or(0),
)
.unwrap()
* CHAR_WIDTH
+ BORDER_WIDTH * 2;
let height = u32::try_from(N).unwrap() * (CHAR_HEIGHT + BORDER_WIDTH) + BORDER_WIDTH;
let height = u32::try_from(options.as_ref().len()).unwrap() * (CHAR_HEIGHT + BORDER_WIDTH)
+ BORDER_WIDTH;
Self {
options,
width,
height,
selected: 0,
selected,
y_tracker: 0,
_phantom: PhantomData,
}
}
......@@ -45,7 +60,7 @@ impl<const N: usize> Selector<N> {
}
}
impl<const N: usize> Element for Selector<N> {
impl<T: AsRef<str>, V: AsRef<[T]>> Element for Selector<T, V> {
fn render<
E,
DT: embedded_graphics::prelude::DrawTarget<
......@@ -77,7 +92,7 @@ impl<const N: usize> Element for Selector<N> {
.text_color(Rgb565::BLACK)
.build();
for (i, text) in self.options.iter().enumerate() {
for (i, text) in self.options.as_ref().iter().enumerate() {
// Draw our background rectangles
let rect_style = if i == self.selected {
selected_rect_style
......@@ -101,7 +116,7 @@ impl<const N: usize> Element for Selector<N> {
// Render the text
Text::with_baseline(
text,
text.as_ref(),
Point::new(
(BORDER_WIDTH + start_x).try_into().unwrap(),
(start_y + i * (CHAR_HEIGHT + BORDER_WIDTH) + 1)
......@@ -128,7 +143,7 @@ impl<const N: usize> Element for Selector<N> {
} else if self.y_tracker > 50 {
self.y_tracker = 0;
if self.selected < N - 1 {
if self.selected < self.options.as_ref().len() - 1 {
self.selected += 1;
}
}
......
......@@ -2,6 +2,7 @@
#![no_main]
mod buffered_display;
mod contact;
mod controller;
mod gui;
mod keyboard;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment