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 crate::{ app::WIDTH, message::{MessageDirection, MessageGroup}, }; use super::{textbox::TextBox as MyTextBox, Element}; const MESSAGE_BOX_WIDTH: u32 = 200; const MESSAGE_BOX_HEIGHT: u32 = 64; pub struct Chat { message_group: MessageGroup, textbox: MyTextBox, } impl Chat { pub fn new() -> Self { Self { message_group: MessageGroup::default(), textbox: MyTextBox::new(1, 218, 31, 1), } } } impl Element for Chat { type KeyPushReturn = (); fn render< E, DT: embedded_graphics::prelude::DrawTarget< Color = embedded_graphics::pixelcolor::Rgb565, Error = E, >, >( &mut self, dt: &mut DT, ) -> 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 self.message_group.iter() { 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(()) } fn key_push(&mut self, k: crate::keyboard::KeyCode) { 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' || x >= CHAR_WIDTH * tb.bounds.size.width { x = 0; y += 1; } else { x += 1; max_x = x; } } Rectangle::new( tb.bounds.top_left, Size::new(max_x * CHAR_WIDTH, y * CHAR_HEIGHT), ) }