Add component trait and vsplit
parent
5562b57ea5
commit
4194e63541
|
|
@ -1,5 +1,5 @@
|
||||||
use embedded_components::{
|
use embedded_components::{
|
||||||
Calendar, ComponentStyle, Gauge, List, ListItem, ListItemData, ScrollingCalendar,
|
Calendar, ComponentStyle, Gauge, List, ListItem, ListItemData, ScrollingCalendar, VSplit,
|
||||||
};
|
};
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
pixelcolor::{raw::RawU2, BinaryColor, Rgb888},
|
pixelcolor::{raw::RawU2, BinaryColor, Rgb888},
|
||||||
|
|
@ -85,8 +85,6 @@ fn main() -> Result<(), core::convert::Infallible> {
|
||||||
//calendar.draw(&mut display)?;
|
//calendar.draw(&mut display)?;
|
||||||
|
|
||||||
let list = List {
|
let list = List {
|
||||||
top_left: Point::new(320, 0),
|
|
||||||
size: Size::new(280, 448),
|
|
||||||
style: calendar_style.clone(),
|
style: calendar_style.clone(),
|
||||||
items_shown: 10,
|
items_shown: 10,
|
||||||
list_items: vec![
|
list_items: vec![
|
||||||
|
|
@ -94,18 +92,19 @@ fn main() -> Result<(), core::convert::Infallible> {
|
||||||
ListItemData::new("O", "Other test task"),
|
ListItemData::new("O", "Other test task"),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
list.draw(&mut display)?;
|
//list.draw(&mut display)?;
|
||||||
|
|
||||||
let calendar_week = ScrollingCalendar {
|
let calendar_week = ScrollingCalendar {
|
||||||
top_left: Point::new(0, 0),
|
|
||||||
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))
|
||||||
//.unwrap(),
|
//.unwrap(),
|
||||||
weeks: 5,
|
prev_weeks: 2,
|
||||||
|
next_weeks: 5,
|
||||||
};
|
};
|
||||||
calendar_week.draw(&mut display)?;
|
//calendar_week.draw(&mut display)?;
|
||||||
|
|
||||||
|
VSplit::new(calendar_week, list).draw(&mut display)?;
|
||||||
|
|
||||||
let output_settings = OutputSettingsBuilder::new()
|
let output_settings = OutputSettingsBuilder::new()
|
||||||
.theme(BinaryColorTheme::Default)
|
.theme(BinaryColorTheme::Default)
|
||||||
|
|
|
||||||
|
|
@ -311,11 +311,21 @@ impl ScrollingWeek {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScrollingCalendar<C> {
|
pub struct ScrollingCalendar<C> {
|
||||||
pub top_left: Point,
|
|
||||||
pub size: Size,
|
|
||||||
pub style: ComponentStyle<C>,
|
pub style: ComponentStyle<C>,
|
||||||
pub day: chrono::NaiveDate,
|
pub day: chrono::NaiveDate,
|
||||||
pub weeks: u32,
|
pub prev_weeks: u32,
|
||||||
|
pub next_weeks: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> ScrollingCalendar<C> {
|
||||||
|
pub fn new(style: ComponentStyle<C>, prev_weeks: u32, next_weeks: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
style,
|
||||||
|
day: chrono::Local::now().naive_local().date(),
|
||||||
|
prev_weeks,
|
||||||
|
next_weeks,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> Drawable for ScrollingCalendar<C>
|
impl<C> Drawable for ScrollingCalendar<C>
|
||||||
|
|
@ -329,20 +339,24 @@ where
|
||||||
where
|
where
|
||||||
D: DrawTarget<Color = C>,
|
D: DrawTarget<Color = C>,
|
||||||
{
|
{
|
||||||
let height = self.size.height / (1 + self.weeks * 2);
|
let top_left = target.bounding_box().top_left;
|
||||||
|
let size = target.bounding_box().size;
|
||||||
|
|
||||||
|
let total_weeks = self.prev_weeks + 1 + self.next_weeks;
|
||||||
|
let height = size.height / total_weeks;
|
||||||
let mut week = ScrollingWeek::from_date(
|
let mut week = ScrollingWeek::from_date(
|
||||||
self
|
self
|
||||||
.day
|
.day
|
||||||
.checked_sub_signed(chrono::Duration::days(self.weeks as i64 * 7))
|
.checked_sub_signed(chrono::Duration::days(self.prev_weeks as i64 * 7))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for i in 0..(1 + self.weeks * 2) {
|
for i in 0..total_weeks {
|
||||||
week = week.succ();
|
week = week.succ();
|
||||||
|
|
||||||
let calendar_week = CalendarWeek {
|
let calendar_week = CalendarWeek {
|
||||||
top_left: Point::new(self.top_left.x, self.top_left.y + (height * i) as i32),
|
top_left: Point::new(top_left.x, top_left.y + (height * i) as i32),
|
||||||
size: Size::new(self.size.width, height),
|
size: Size::new(size.width, height),
|
||||||
style: self.style.clone(),
|
style: self.style.clone(),
|
||||||
year: week.year(),
|
year: week.year(),
|
||||||
month: week.month(),
|
month: week.month(),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
use embedded_graphics::{pixelcolor::BinaryColor, prelude::*, primitives::Rectangle};
|
||||||
|
use embedded_layout::View;
|
||||||
|
|
||||||
|
pub trait Component {
|
||||||
|
fn set_top_left(&mut self, top_left: Point);
|
||||||
|
fn set_size(&mut self, size: Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Frame<D> {
|
||||||
|
drawtarget: D,
|
||||||
|
pub weight: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VSplit<T, U> {
|
||||||
|
pub left: T,
|
||||||
|
pub right: U,
|
||||||
|
pub ratio: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> VSplit<T, U> {
|
||||||
|
pub fn new(left: T, right: U) -> Self {
|
||||||
|
VSplit {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
ratio: 0.5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> VSplit<T, U> {
|
||||||
|
pub fn with_ratio(self, ratio: f32) -> Self {
|
||||||
|
VSplit { ratio, ..self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, T, U> Drawable for VSplit<T, U>
|
||||||
|
where
|
||||||
|
C: PixelColor + From<BinaryColor>,
|
||||||
|
T: Drawable<Color = C>,
|
||||||
|
U: Drawable<Color = C>,
|
||||||
|
{
|
||||||
|
type Color = C;
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error>
|
||||||
|
where
|
||||||
|
D: DrawTarget<Color = C>,
|
||||||
|
{
|
||||||
|
let top_left = target.bounding_box().top_left;
|
||||||
|
let size = target.bounding_box().size;
|
||||||
|
let left_width = (size.width as f32 * self.ratio) as u32;
|
||||||
|
|
||||||
|
self.left.draw(&mut target.clipped(&Rectangle::new(
|
||||||
|
top_left,
|
||||||
|
Size::new(left_width, size.height),
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
self.right.draw(&mut target.clipped(&Rectangle::new(
|
||||||
|
top_left + Point::new(left_width as i32, 0),
|
||||||
|
Size::new(size.width - left_width, size.height),
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HSplit<T, U> {
|
||||||
|
pub top_left: Point,
|
||||||
|
pub size: Size,
|
||||||
|
pub top: T,
|
||||||
|
pub bottom: U,
|
||||||
|
pub ratio: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> HSplit<T, U> {
|
||||||
|
pub fn with_ratio(self, ratio: f32) -> Self {
|
||||||
|
HSplit { ratio, ..self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, T, U> Drawable for HSplit<T, U>
|
||||||
|
where
|
||||||
|
C: PixelColor + From<BinaryColor>,
|
||||||
|
T: Drawable<Color = C>,
|
||||||
|
U: Drawable<Color = C>,
|
||||||
|
{
|
||||||
|
type Color = C;
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error>
|
||||||
|
where
|
||||||
|
D: DrawTarget<Color = C>,
|
||||||
|
{
|
||||||
|
let top_left = target.bounding_box().top_left;
|
||||||
|
let size = target.bounding_box().size;
|
||||||
|
let top_height = (size.height as f32 * self.ratio) as u32;
|
||||||
|
|
||||||
|
self
|
||||||
|
.top
|
||||||
|
.draw(&mut target.clipped(&Rectangle::new(top_left, Size::new(size.width, top_height))))?;
|
||||||
|
|
||||||
|
self.bottom.draw(&mut target.clipped(&Rectangle::new(
|
||||||
|
top_left + Point::new(0, top_height as i32),
|
||||||
|
Size::new(size.width, size.height - top_height),
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
mod bullet_counter;
|
mod bullet_counter;
|
||||||
mod calendar;
|
mod calendar;
|
||||||
|
mod frame;
|
||||||
mod gauge;
|
mod gauge;
|
||||||
mod list_item;
|
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 frame::{Component, HSplit, VSplit};
|
||||||
pub use gauge::Gauge;
|
pub use gauge::Gauge;
|
||||||
pub use list_item::{List, ListItem, ListItemData};
|
pub use list_item::{List, ListItem, ListItemData};
|
||||||
pub use style::ComponentStyle;
|
pub use style::ComponentStyle;
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,20 @@ impl<'a> ListItemData {
|
||||||
|
|
||||||
pub struct List<C> {
|
pub struct List<C> {
|
||||||
pub style: ComponentStyle<C>,
|
pub style: ComponentStyle<C>,
|
||||||
pub top_left: Point,
|
|
||||||
pub size: Size,
|
|
||||||
pub items_shown: usize,
|
pub items_shown: usize,
|
||||||
pub list_items: Vec<ListItemData>,
|
pub list_items: Vec<ListItemData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C> List<C> {
|
||||||
|
pub fn new(style: ComponentStyle<C>, list_items: Vec<ListItemData>, items_shown: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
style,
|
||||||
|
items_shown,
|
||||||
|
list_items,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<C> Drawable for List<C>
|
impl<C> Drawable for List<C>
|
||||||
where
|
where
|
||||||
C: PixelColor + From<BinaryColor>,
|
C: PixelColor + From<BinaryColor>,
|
||||||
|
|
@ -50,7 +58,10 @@ where
|
||||||
where
|
where
|
||||||
D: DrawTarget<Color = C>,
|
D: DrawTarget<Color = C>,
|
||||||
{
|
{
|
||||||
let rect = Rectangle::new(self.top_left, self.size);
|
let top_left = target.bounding_box().top_left;
|
||||||
|
let size = target.bounding_box().size;
|
||||||
|
|
||||||
|
let rect = Rectangle::new(top_left, size);
|
||||||
rect
|
rect
|
||||||
.into_styled(PrimitiveStyle::with_stroke(
|
.into_styled(PrimitiveStyle::with_stroke(
|
||||||
self.style.bg_color,
|
self.style.bg_color,
|
||||||
|
|
@ -61,13 +72,22 @@ where
|
||||||
.into_styled(PrimitiveStyle::with_fill(self.style.bg_color))
|
.into_styled(PrimitiveStyle::with_fill(self.style.bg_color))
|
||||||
.draw(target)?;
|
.draw(target)?;
|
||||||
|
|
||||||
let height = self.size.height / self.items_shown as u32;
|
let height = size.height / self.items_shown as u32;
|
||||||
|
|
||||||
for (i, item) in self.list_items.iter().enumerate().take(self.items_shown) {
|
for (i, item) in self.list_items.iter().enumerate().take(self.items_shown) {
|
||||||
|
let (fg_color, bg_color) = match item.progress >= 100f32 {
|
||||||
|
true => (self.style.bg_color, self.style.hi_color),
|
||||||
|
_ => (self.style.fg_color, self.style.bg_color),
|
||||||
|
};
|
||||||
|
let item_style = ComponentStyle {
|
||||||
|
fg_color,
|
||||||
|
bg_color,
|
||||||
|
..self.style.clone()
|
||||||
|
};
|
||||||
let list_item = ListItem {
|
let list_item = ListItem {
|
||||||
style: self.style.clone(),
|
style: item_style,
|
||||||
top_left: self.top_left + Point::new(0, (height as usize * i) as i32),
|
top_left: top_left + Point::new(0, (height as usize * i) as i32),
|
||||||
size: Size::new(self.size.width, height),
|
size: Size::new(size.width, height),
|
||||||
text: &item.text,
|
text: &item.text,
|
||||||
icon: &item.icon,
|
icon: &item.icon,
|
||||||
progress: item.progress,
|
progress: item.progress,
|
||||||
|
|
@ -114,6 +134,9 @@ where
|
||||||
.draw(target)?;
|
.draw(target)?;
|
||||||
|
|
||||||
let icon_square = Rectangle::new(self.top_left, Size::new(rect.size.height, rect.size.height));
|
let icon_square = Rectangle::new(self.top_left, Size::new(rect.size.height, rect.size.height));
|
||||||
|
icon_square
|
||||||
|
.into_styled(PrimitiveStyle::with_fill(self.style.fg_color))
|
||||||
|
.draw(target)?;
|
||||||
icon_square
|
icon_square
|
||||||
.into_styled(PrimitiveStyle::with_stroke(
|
.into_styled(PrimitiveStyle::with_stroke(
|
||||||
self.style.border_color,
|
self.style.border_color,
|
||||||
|
|
@ -121,7 +144,7 @@ where
|
||||||
))
|
))
|
||||||
.draw(target)?;
|
.draw(target)?;
|
||||||
|
|
||||||
let icon_style = MonoTextStyle::new(&FONT_10X20, self.style.hi_color);
|
let icon_style = MonoTextStyle::new(&FONT_10X20, self.style.bg_color);
|
||||||
|
|
||||||
let mut icon = Text::with_baseline(self.icon, self.top_left, icon_style, Baseline::Middle);
|
let mut icon = Text::with_baseline(self.icon, self.top_left, icon_style, Baseline::Middle);
|
||||||
let icon_box = icon.bounding_box();
|
let icon_box = icon.bounding_box();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue