use crate::ComponentStyle; use embedded_graphics::{ mono_font::{ ascii::{FONT_10X20, FONT_7X14}, MonoTextStyle, }, pixelcolor::{BinaryColor, PixelColor}, prelude::*, primitives::{Line, PrimitiveStyle, Rectangle}, text::{Baseline, Text}, }; use embedded_layout::prelude::*; pub struct ListItemData { pub text: String, pub icon: String, pub progress: f32, } impl<'a> ListItemData { pub fn new(icon: &'a str, text: &'a str) -> Self { Self { icon: String::from(icon), text: String::from(text), progress: 0f32, } } pub fn with_progress(self, progress: f32) -> Self { Self { progress, ..self } } } pub struct List { pub style: ComponentStyle, pub top_left: Point, pub size: Size, pub items_shown: usize, pub list_items: Vec, } impl Drawable for List where C: PixelColor + From, { type Color = C; type Output = (); fn draw(&self, target: &mut D) -> Result where D: DrawTarget, { let rect = Rectangle::new(self.top_left, self.size); rect .into_styled(PrimitiveStyle::with_stroke( self.style.bg_color, self.style.border, )) .draw(target)?; rect .into_styled(PrimitiveStyle::with_fill(self.style.bg_color)) .draw(target)?; let height = self.size.height / self.items_shown as u32; for (i, item) in self.list_items.iter().enumerate().take(self.items_shown) { let list_item = ListItem { style: self.style.clone(), top_left: self.top_left + Point::new(0, (height as usize * i) as i32), size: Size::new(self.size.width, height), text: &item.text, icon: &item.icon, progress: item.progress, }; list_item.draw(target)?; } Ok(()) } } pub struct ListItem<'a, C> { pub style: ComponentStyle, pub top_left: Point, pub size: Size, pub text: &'a str, pub icon: &'a str, pub progress: f32, } impl Drawable for ListItem<'_, C> where C: PixelColor + From, { type Color = C; type Output = (); fn draw(&self, target: &mut D) -> Result where D: DrawTarget, { let rect = Rectangle::new( self.top_left, self.size + Size::new(self.style.border / 2 + 1, self.style.border / 2 + 1), ); rect .into_styled(PrimitiveStyle::with_fill(self.style.bg_color)) .draw(target)?; rect .into_styled(PrimitiveStyle::with_stroke( self.style.border_color, self.style.border, )) .draw(target)?; let icon_square = Rectangle::new(self.top_left, Size::new(rect.size.height, rect.size.height)); icon_square .into_styled(PrimitiveStyle::with_stroke( self.style.border_color, self.style.border, )) .draw(target)?; let icon_style = MonoTextStyle::new(&FONT_10X20, self.style.hi_color); let mut icon = Text::with_baseline(self.icon, self.top_left, icon_style, Baseline::Middle); let icon_box = icon.bounding_box(); icon.position = self.top_left + Point::new( (self.size.height / 2 - icon_box.size.width / 2) as i32, (self.size.height / 2) as i32, ); icon.draw(&mut target.clipped(&rect))?; let text_style = MonoTextStyle::new(&FONT_7X14, self.style.fg_color); let mut text = Text::with_baseline(self.text, self.top_left, text_style, Baseline::Middle); let text_box = text.bounding_box(); text.position = self.top_left + Point::new( (self.size.height as f32 * 1.2) as i32, self.size.height as i32 / 2, ); text.draw(&mut target.clipped(&rect))?; if self.progress >= 100f32 { let strikethrough = Line::new( text.position + Point::new(0, 1), text.position + Point::new(text_box.size.width as i32, 1), ); strikethrough .into_styled(PrimitiveStyle::with_stroke(self.style.fg_color, 2)) .draw(target)?; } Ok(()) } }