Browse Source

Add item list

master
Ilya 4 years ago
parent
commit
5562b57ea5
  1. 45
      examples/test.rs
  2. 68
      src/calendar.rs
  3. 2
      src/lib.rs
  4. 116
      src/list_item.rs
  5. 14
      src/style.rs

45
examples/test.rs

@ -1,4 +1,6 @@
use embedded_components::{Calendar, ComponentStyle, Gauge, ScrollingCalendar}; use embedded_components::{
Calendar, ComponentStyle, Gauge, List, ListItem, ListItemData, ScrollingCalendar,
};
use embedded_graphics::{ use embedded_graphics::{
pixelcolor::{raw::RawU2, BinaryColor, Rgb888}, pixelcolor::{raw::RawU2, BinaryColor, Rgb888},
prelude::*, prelude::*,
@ -48,12 +50,21 @@ impl From<Rgb888> for TriColor {
fn main() -> Result<(), core::convert::Infallible> { fn main() -> Result<(), core::convert::Infallible> {
//let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(212, 104)); //let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(212, 104));
//let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(800, 480)); //let mut display = SimulatorDisplay::<BinaryColor>::new(Size::new(800, 480));
let mut display = SimulatorDisplay::<TriColor>::new(Size::new(800, 480)); let mut display = SimulatorDisplay::<TriColor>::new(Size::new(600, 448));
let fg_color = TriColor::Black; let fg_color = TriColor::Black;
let bg_color = TriColor::White; let bg_color = TriColor::White;
let hi_color = Some(TriColor::Red); let hi_color = Some(TriColor::Red);
let calendar_style = ComponentStyle {
border: 1,
bezel: 1,
fg_color,
bg_color,
hi_color: TriColor::Red,
border_color: TriColor::Black,
};
let gauge = Gauge { let gauge = Gauge {
top_left: Point::new(300, 300), top_left: Point::new(300, 300),
bezel: 1, bezel: 1,
@ -64,30 +75,30 @@ fn main() -> Result<(), core::convert::Infallible> {
bg_color, bg_color,
text: "test test test test test", text: "test test test test test",
}; };
gauge.draw(&mut display)?; //gauge.draw(&mut display)?;
let calendar = Calendar { let calendar = Calendar {
top_left: Point::new(10, 10), top_left: Point::new(10, 10),
size: Size::new(196, 196), size: Size::new(196, 196),
border: 1, style: calendar_style.clone(),
fg_color,
bg_color,
hi_color,
}; };
calendar.draw(&mut display)?; //calendar.draw(&mut display)?;
let calendar_style = ComponentStyle { let list = List {
border: 1, top_left: Point::new(320, 0),
bezel: 1, size: Size::new(280, 448),
fg_color, style: calendar_style.clone(),
bg_color, items_shown: 10,
hi_color: TriColor::Red, list_items: vec![
border_color: TriColor::Black, ListItemData::new("I", "Test task").with_progress(100f32),
ListItemData::new("O", "Other test task"),
],
}; };
list.draw(&mut display)?;
let calendar_week = ScrollingCalendar { let calendar_week = ScrollingCalendar {
top_left: Point::new(400, 0), top_left: Point::new(0, 0),
size: Size::new(396, 480), size: Size::new(320, 448),
style: calendar_style, style: calendar_style,
day: chrono::Local::now().naive_local().date(), day: chrono::Local::now().naive_local().date(),
//.checked_add_signed(chrono::Duration::days(28 * 4 * 0 - 14)) //.checked_add_signed(chrono::Duration::days(28 * 4 * 0 - 14))

68
src/calendar.rs

@ -88,9 +88,7 @@ where
pub struct CalendarMonth<C> { pub struct CalendarMonth<C> {
pub top_left: Point, pub top_left: Point,
pub size: Size, pub size: Size,
pub border: u32, pub style: ComponentStyle<C>,
pub fg_color: C,
pub bg_color: C,
pub month: chrono::Month, pub month: chrono::Month,
} }
@ -107,14 +105,17 @@ where
{ {
let rect = Rectangle::new( let rect = Rectangle::new(
self.top_left, self.top_left,
self.size + Size::new(self.border / 2 + 1, self.border / 2 + 1), self.size + Size::new(self.style.border / 2 + 1, self.style.border / 2 + 1),
); );
rect rect
.into_styled(PrimitiveStyle::with_stroke(self.fg_color, self.border)) .into_styled(PrimitiveStyle::with_stroke(
self.style.fg_color,
self.style.border,
))
.draw(target)?; .draw(target)?;
let month_font = font((self.size.height as f32 * 0.8 - 2.) as u32); let month_font = font((self.size.height as f32 * 0.8 - 2.) as u32);
let text_style = MonoTextStyle::new(&month_font, self.fg_color); let text_style = MonoTextStyle::new(&month_font, self.style.fg_color);
Text::new(self.month.name(), self.top_left, text_style) Text::new(self.month.name(), self.top_left, text_style)
.align_to(&rect, horizontal::Center, vertical::Center) .align_to(&rect, horizontal::Center, vertical::Center)
.draw(target)?; .draw(target)?;
@ -126,11 +127,7 @@ where
pub struct Calendar<C> { pub struct Calendar<C> {
pub top_left: Point, pub top_left: Point,
pub size: Size, pub size: Size,
pub border: u32, pub style: ComponentStyle<C>,
pub fg_color: C,
pub bg_color: C,
// If hi_color is None, the fg and bg colors are inverted instead.
pub hi_color: Option<C>,
} }
impl<C> Drawable for Calendar<C> impl<C> Drawable for Calendar<C>
@ -144,7 +141,7 @@ where
where where
D: DrawTarget<Color = C>, D: DrawTarget<Color = C>,
{ {
let border = self.border; let border = self.style.border;
let date_now = chrono::offset::Local::now().date(); let date_now = chrono::offset::Local::now().date();
let first_day = date_now.with_day(1).unwrap(); let first_day = date_now.with_day(1).unwrap();
@ -171,12 +168,11 @@ where
} else { } else {
width * empty_squares width * empty_squares
}; };
let calendar_month = CalendarMonth { let calendar_month = CalendarMonth {
border, style: self.style.clone(),
top_left: self.top_left, top_left: self.top_left,
size: Size::new(month_width, height), size: Size::new(month_width, height),
fg_color: self.fg_color,
bg_color: self.bg_color,
month: Month::from_u32(date_now.month()).unwrap(), month: Month::from_u32(date_now.month()).unwrap(),
}; };
calendar_month.draw(target)?; calendar_month.draw(target)?;
@ -196,22 +192,19 @@ where
>= 5; >= 5;
let is_today = day_of_month == date_now.day(); let is_today = day_of_month == date_now.day();
let (mut fg_color, mut bg_color, mut border) = match is_weekend ^ is_today { let style = self.style.clone();
false => (self.fg_color, self.bg_color, border),
true => (self.bg_color, self.fg_color, 0),
};
if is_today && self.hi_color.is_some() {
(fg_color, bg_color, border) = (self.bg_color, self.hi_color.unwrap(), 0);
}
let style = ComponentStyle { let mut style = match is_weekend ^ is_today {
fg_color, false => style.with_border(border),
bg_color, true => style.invert().with_border(0),
hi_color: fg_color,
border_color: fg_color,
border,
bezel: border,
}; };
if is_today && self.style.hi_color != self.style.bg_color {
style = ComponentStyle {
fg_color: style.hi_color,
bg_color: style.fg_color,
..style
}
}
let calendar_day = CalendarDay { let calendar_day = CalendarDay {
style, style,
@ -262,13 +255,6 @@ impl ScrollingWeek {
.succ() .succ()
.first_day_of_week()? .first_day_of_week()?
.checked_sub_signed(chrono::Duration::days(1)); .checked_sub_signed(chrono::Duration::days(1));
match self.succ().first_day_of_week() {
None => self
.first_day_of_week()?
.checked_add_signed(chrono::Duration::days(6)),
Some(date) => date.checked_sub_signed(chrono::Duration::days(1)),
}
} }
pub fn from_date(date: chrono::NaiveDate) -> ScrollingWeek { pub fn from_date(date: chrono::NaiveDate) -> ScrollingWeek {
@ -419,28 +405,24 @@ where
if first_day.weekday().number_from_monday() > 4 { if first_day.weekday().number_from_monday() > 4 {
let month = CalendarMonth { let month = CalendarMonth {
style: self.style.clone(),
top_left: self.top_left, top_left: self.top_left,
size: Size::new( size: Size::new(
width * first_day.weekday().number_from_monday(), width * (first_day.weekday().number_from_monday() - 1),
self.size.height, self.size.height,
), ),
border: self.style.border,
fg_color: self.style.fg_color,
bg_color: self.style.bg_color,
month: chrono::Month::from_u32(first_day.month()).unwrap(), month: chrono::Month::from_u32(first_day.month()).unwrap(),
}; };
month.draw(target)?; month.draw(target)?;
} else if last_day.weekday().number_from_monday() < 4 { } else if last_day.weekday().number_from_monday() < 4 {
let month = CalendarMonth { let month = CalendarMonth {
style: self.style.clone(),
top_left: self.top_left top_left: self.top_left
+ Point::new((width * last_day.weekday().number_from_monday()) as i32, 0), + Point::new((width * last_day.weekday().number_from_monday()) as i32, 0),
size: Size::new( size: Size::new(
width * (7 - last_day.weekday().number_from_monday()), width * (7 - last_day.weekday().number_from_monday()),
self.size.height, self.size.height,
), ),
border: self.style.border,
fg_color: self.style.fg_color,
bg_color: self.style.bg_color,
month: chrono::Month::from_u32( month: chrono::Month::from_u32(
last_day last_day
.checked_add_signed(chrono::Duration::days(1)) .checked_add_signed(chrono::Duration::days(1))

2
src/lib.rs

@ -1,9 +1,11 @@
mod bullet_counter; mod bullet_counter;
mod calendar; mod calendar;
mod gauge; mod gauge;
mod list_item;
mod style; mod style;
pub use bullet_counter::BulletCounter; pub use bullet_counter::BulletCounter;
pub use calendar::{Calendar, ScrollingCalendar}; pub use calendar::{Calendar, ScrollingCalendar};
pub use gauge::Gauge; pub use gauge::Gauge;
pub use list_item::{List, ListItem, ListItemData};
pub use style::ComponentStyle; pub use style::ComponentStyle;

116
src/list_item.rs

@ -1,26 +1,45 @@
use crate::ComponentStyle;
use embedded_graphics::{ use embedded_graphics::{
mono_font::{
ascii::{FONT_10X20, FONT_7X14},
MonoTextStyle,
},
pixelcolor::{BinaryColor, PixelColor}, pixelcolor::{BinaryColor, PixelColor},
prelude::*, prelude::*,
primitives::{Line, PrimitiveStyle, Rectangle}, primitives::{Line, PrimitiveStyle, Rectangle},
text::Text, text::{Baseline, Text},
}; };
use embedded_layout::prelude::*; use embedded_layout::prelude::*;
pub struct ListItemData { pub struct ListItemData {
pub text: &'a str, pub text: String,
pub icon: &'a str, 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<'a, C> { pub struct List<C> {
pub style: ComponentStyle<C>,
pub top_left: Point, pub top_left: Point,
pub border: u32,
pub size: Size, pub size: Size,
pub fg_color: C, pub items_shown: usize,
pub bg_color: C,
pub list_items: Vec<ListItemData>, pub list_items: Vec<ListItemData>,
} }
impl<C> Drawable for ListItem<'_, C> impl<C> Drawable for List<C>
where where
C: PixelColor + From<BinaryColor>, C: PixelColor + From<BinaryColor>,
{ {
@ -33,25 +52,40 @@ where
{ {
let rect = Rectangle::new(self.top_left, self.size); let rect = Rectangle::new(self.top_left, self.size);
rect rect
.into_styled(PrimitiveStyle::with_stroke(self.fg_color, self.border)) .into_styled(PrimitiveStyle::with_stroke(
self.style.bg_color,
self.style.border,
))
.draw(target)?; .draw(target)?;
rect rect
.into_styled(PrimitiveStyle::with_fill(self.fg_color)) .into_styled(PrimitiveStyle::with_fill(self.style.bg_color))
.draw(target)?; .draw(target)?;
// TODO: draw list items 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(()) Ok(())
} }
} }
pub struct ListItem<'a, C> { pub struct ListItem<'a, C> {
pub style: ComponentStyle<C>,
pub top_left: Point, pub top_left: Point,
pub border: u32,
pub size: Size, pub size: Size,
pub fg_color: C,
pub bg_color: C,
pub text: &'a str, pub text: &'a str,
pub icon: &'a str,
pub progress: f32,
} }
impl<C> Drawable for ListItem<'_, C> impl<C> Drawable for ListItem<'_, C>
@ -65,14 +99,62 @@ where
where where
D: DrawTarget<Color = C>, D: DrawTarget<Color = C>,
{ {
let rect = Rectangle::new(self.top_left, self.size); let rect = Rectangle::new(
self.top_left,
self.size + Size::new(self.style.border / 2 + 1, self.style.border / 2 + 1),
);
rect rect
.into_styled(PrimitiveStyle::with_stroke(self.fg_color, self.border)) .into_styled(PrimitiveStyle::with_fill(self.style.bg_color))
.draw(target)?; .draw(target)?;
rect rect
.into_styled(PrimitiveStyle::with_fill(self.fg_color)) .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)?; .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_10X20, 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(()) Ok(())
} }
} }

14
src/style.rs

@ -7,3 +7,17 @@ pub struct ComponentStyle<C> {
pub border: u32, pub border: u32,
pub bezel: u32, pub bezel: u32,
} }
impl<C> ComponentStyle<C> {
pub fn invert(self) -> Self {
ComponentStyle {
fg_color: self.bg_color,
bg_color: self.fg_color,
..self
}
}
pub fn with_border(self, border: u32) -> Self {
ComponentStyle { border, ..self }
}
}

Loading…
Cancel
Save