chat.rs 3.34 KiB
use embedded_graphics::{
geometry::{Point, Size},
mono_font::{ascii::FONT_10X20, MonoTextStyle},
pixelcolor::{Rgb565, RgbColor},
primitives::{Primitive, PrimitiveStyleBuilder, Rectangle},
text::renderer::TextRenderer,
Drawable,
};
use embedded_text::{style::TextBoxStyleBuilder, TextBox};
use heapless::String;
use crate::{
app::WIDTH,
keyboard::KeyCode,
storage::{Message, MessageDirection, Storage, MAX_CONTACT_CALLSIGN_LENGTH},
};
use super::{textbox::TextBox as MyTextBox, Element};
const MESSAGE_BOX_WIDTH: u32 = 200;
const MESSAGE_BOX_HEIGHT: u32 = 64;
pub struct Chat {
callsign: String<MAX_CONTACT_CALLSIGN_LENGTH>,
ssid: u8,
textbox: MyTextBox,
}
impl Chat {
pub fn new(callsign: String<MAX_CONTACT_CALLSIGN_LENGTH>, ssid: u8) -> Self {
Self {
callsign,
ssid,
textbox: MyTextBox::new(1, 218, 31, 1),
}
}
pub fn render<
E,
DT: embedded_graphics::prelude::DrawTarget<
Color = embedded_graphics::pixelcolor::Rgb565,
Error = E,
>,
>(
&mut self,
dt: &mut DT,
storage: &Storage,
) -> Result<(), E> {
let textbox_style = TextBoxStyleBuilder::new().build();
let character_style = MonoTextStyle::new(&FONT_10X20, Rgb565::BLACK);
let rect_style = PrimitiveStyleBuilder::new()
.fill_color(Rgb565::WHITE)
.build();
let mut y = 28;
for msg in storage.messages(&self.callsign, self.ssid) {
let bounds = Rectangle::new(
Point::new(4, y),
Size::new(MESSAGE_BOX_WIDTH, MESSAGE_BOX_HEIGHT),
);
let mut text_box =
TextBox::with_textbox_style(msg.content(), bounds, character_style, textbox_style);
let mut actual_bounds = calculate_bounding_box(&text_box);
if msg.direction() == MessageDirection::To {
let x = i32::try_from(WIDTH).unwrap()
- i32::try_from(actual_bounds.size.width).unwrap()
- 4;
text_box.bounds.top_left.x = x;
actual_bounds.top_left.x = x;
}
actual_bounds.into_styled(rect_style).draw(dt)?;
text_box.draw(dt)?;
y += i32::try_from(actual_bounds.size.height).unwrap() + 4;
}
self.textbox.render(dt)?;
Ok(())
}
pub fn key_push(&mut self, k: KeyCode, storage: &mut Storage) {
if k == KeyCode::Enter {
let text = self.textbox.clear();
let message =
Message::new(self.callsign.clone(), self.ssid, text, MessageDirection::To);
storage.push_message(message);
} else {
self.textbox.key_push(k);
}
}
}
fn calculate_bounding_box<S: TextRenderer>(tb: &TextBox<'_, S>) -> Rectangle {
const CHAR_WIDTH: u32 = 10;
const CHAR_HEIGHT: u32 = 20;
let mut x = 0;
let mut max_x = 0;
let mut y = 1;
for c in tb.text.chars() {
if c == '\n' || CHAR_WIDTH * x >= tb.bounds.size.width {
x = 0;
y += 1;
} else {
x += 1;
if x > max_x {
max_x = x;
}
}
}
Rectangle::new(
tb.bounds.top_left,
Size::new(max_x * CHAR_WIDTH, y * CHAR_HEIGHT),
)
}