//! # Example: Custom View - Progress bar
//!
//! 
//!
//! This example shows what's necessary to implement a reusable View.
use embedded_graphics_simulator::{
BinaryColorTheme, OutputSettingsBuilder, SimulatorDisplay, Window,
};
use embedded_graphics::{
pixelcolor::BinaryColor, primitives::Rectangle, style::PrimitiveStyle, DrawTarget,
};
use embedded_layout::{
layout::linear::{spacing::FixedMargin, LinearLayout},
prelude::*,
};
pub struct ProgressBar {
progress: u32,
bounds: Rectangle,
}
impl ProgressBar {
/// The progress bar has a configurable position and size
fn new(position: Point, size: Size) -> Self {
Self {
bounds: Rectangle::with_size(position, size),
progress: 0,
}
}
fn with_progress(self, progress: u32) -> Self {
Self {
bounds: self.bounds,
progress,
}
}
}
/// Implementing `View` is required by the layout and alignment operations
/// `View` teaches `embedded-layout` where our object is, how big it is and how to move it.
impl View for ProgressBar {
#[inline]
fn translate(&mut self, by: Point) {
self.bounds.translate(by);
}
#[inline]
fn bounds(&self) -> Rectangle {
self.bounds
}
}
/// Need to implement `Drawable` for a _reference_ of our view
impl Drawable<BinaryColor> for &ProgressBar {
fn draw<D: DrawTarget<BinaryColor>>(self, display: &mut D) -> Result<(), D::Error> {
// Create styles
let border_style = PrimitiveStyle::with_stroke(BinaryColor::On, 1);
let progress_style = PrimitiveStyle::with_fill(BinaryColor::On);
// Create a 1px border
let border = self.bounds.into_styled(border_style);
// Create a rectangle that will indicate progress
let mut progress = Rectangle::with_size(
Point::zero(),
// sizes are calculated so that the rectangle will have a 1px margin
Size::new(
(self.bounds.size().width - 4) * self.progress / 100,
self.bounds.size().height - 4,
),
)
.into_styled(progress_style);
// Align progress bar within border
progress
.align_to_mut(&border, horizontal::Left, vertical::Center)
.translate(Point::new(2, 0));
// Draw views
border.draw(display)?;
progress.draw(display)?;
Ok(())
}
}
fn main() -> Result<(), core::convert::Infallible> {
let mut display: SimulatorDisplay<BinaryColor> = SimulatorDisplay::new(Size::new(128, 64));
let output_settings = OutputSettingsBuilder::new()
.theme(BinaryColorTheme::OledBlue)
.build();
// Create a Rectangle from the display's dimensions
let display_area = display.display_area();
// Two bigger progress bars
let progress1 = ProgressBar::new(Point::zero(), Size::new(64, 8)).with_progress(10);
let progress2 = ProgressBar::new(Point::zero(), Size::new(64, 8)).with_progress(50);
// Two smaller progress bars
let progress3 = ProgressBar::new(Point::zero(), Size::new(32, 6)).with_progress(50);
let progress4 = ProgressBar::new(Point::zero(), Size::new(32, 6)).with_progress(100);
// Arrange on display and draw
LinearLayout::vertical()
.with_spacing(FixedMargin(4))
.add_view(progress1)
.add_view(progress2)
.add_view(progress3)
.add_view(progress4)
.arrange()
.align_to(&display_area, horizontal::Center, vertical::Center)
.draw(&mut display)
.unwrap();
Window::new("Custom View example", &output_settings).show_static(&display);
Ok(())
}