Initial commit
This commit is contained in:
39
src/images.rs
Normal file
39
src/images.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use std::{cell::UnsafeCell, mem::MaybeUninit};
|
||||
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use tinybmp::Bmp;
|
||||
|
||||
thread_local! {
|
||||
pub static HUMIDITY_ICON: UnsafeCell<MaybeUninit<Bmp<'static, Rgb565>>> = const { UnsafeCell::new(MaybeUninit::zeroed()) };
|
||||
pub static TEMPERATURE_ICON: UnsafeCell<MaybeUninit<Bmp<'static, Rgb565>>> = const { UnsafeCell::new(MaybeUninit::zeroed()) };
|
||||
pub static VOC_ICON: UnsafeCell<MaybeUninit<Bmp<'static, Rgb565>>> = const { UnsafeCell::new(MaybeUninit::zeroed()) };
|
||||
pub static CO2_ICON: UnsafeCell<MaybeUninit<Bmp<'static, Rgb565>>> = const { UnsafeCell::new(MaybeUninit::zeroed()) };
|
||||
}
|
||||
|
||||
macro_rules! load_image {
|
||||
($stat:expr, $path:expr) => {
|
||||
$stat
|
||||
.with(|x| *x.get() = MaybeUninit::new(Bmp::from_slice(include_bytes!($path)).unwrap()));
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! get_image {
|
||||
($image:expr) => {
|
||||
unsafe {
|
||||
&*std::mem::transmute::<*mut MaybeUninit<Bmp<Rgb565>>, *mut Bmp<Rgb565>>(
|
||||
$image.with(|g| g.get()),
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prepare_images()
|
||||
{
|
||||
unsafe {
|
||||
load_image!(HUMIDITY_ICON, "../assets/humidity-icon.bmp");
|
||||
load_image!(TEMPERATURE_ICON, "../assets/temperature-icon.bmp");
|
||||
load_image!(VOC_ICON, "../assets/voc-icon.bmp");
|
||||
load_image!(CO2_ICON, "../assets/co2-icon.bmp");
|
||||
}
|
||||
}
|
||||
167
src/main.rs
Normal file
167
src/main.rs
Normal file
@ -0,0 +1,167 @@
|
||||
#![feature(unsafe_cell_access)]
|
||||
|
||||
mod images;
|
||||
mod triangle;
|
||||
|
||||
use core::fmt::Write;
|
||||
use std::{cell::UnsafeCell, mem::MaybeUninit};
|
||||
|
||||
use buoyant::{primitives::Point, render::StrokedShape, view::prelude::*};
|
||||
use embedded_graphics::{
|
||||
pixelcolor::{Rgb565, Rgb888},
|
||||
prelude::*,
|
||||
};
|
||||
use embedded_graphics_simulator::{OutputSettings, SimulatorDisplay, Window};
|
||||
use embedded_sprites::{include_image, sprite::Sprite};
|
||||
use heapless::format;
|
||||
use profont::{PROFONT_12_POINT, PROFONT_14_POINT, PROFONT_18_POINT, PROFONT_24_POINT};
|
||||
use tinybmp::Bmp;
|
||||
|
||||
use crate::triangle::Triangle;
|
||||
|
||||
const BACKGROUND_COLOR: Rgb565 = Rgb565::BLACK;
|
||||
const DEFAULT_COLOR: Rgb565 = Rgb565::WHITE;
|
||||
|
||||
fn main()
|
||||
{
|
||||
images::prepare_images();
|
||||
|
||||
let mut window = Window::new("Hello World", &OutputSettings::default());
|
||||
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(320, 240));
|
||||
display.clear(BACKGROUND_COLOR);
|
||||
|
||||
hello_view()
|
||||
.as_drawable(display.size(), DEFAULT_COLOR)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
|
||||
window.show_static(&display);
|
||||
}
|
||||
|
||||
fn hello_view() -> impl View<Rgb565>
|
||||
{
|
||||
VStack::new((
|
||||
HStack::new((
|
||||
main_menu_indicator(MenuIndicatorType::Temperature(31.5)),
|
||||
main_menu_indicator(MenuIndicatorType::Humidity(36.2)),
|
||||
))
|
||||
.with_spacing(5),
|
||||
HStack::new((
|
||||
main_menu_indicator(MenuIndicatorType::Co2(1329)),
|
||||
main_menu_indicator(MenuIndicatorType::Voc(29)),
|
||||
))
|
||||
.with_spacing(5),
|
||||
))
|
||||
.with_spacing(5)
|
||||
}
|
||||
|
||||
const FRAME_STROKE: u32 = 2;
|
||||
const FRAME_COLOR: Rgb565 = Rgb565::new(5, 9, 5);
|
||||
|
||||
pub enum MenuIndicatorType
|
||||
{
|
||||
Temperature(f32),
|
||||
Humidity(f32),
|
||||
Co2(u32),
|
||||
Voc(u32),
|
||||
}
|
||||
|
||||
impl MenuIndicatorType
|
||||
{
|
||||
pub fn get_corresponding_icon(
|
||||
&self,
|
||||
) -> &'static std::thread::LocalKey<UnsafeCell<MaybeUninit<Bmp<'static, Rgb565>>>>
|
||||
{
|
||||
match self
|
||||
{
|
||||
MenuIndicatorType::Temperature(_) => &images::TEMPERATURE_ICON,
|
||||
MenuIndicatorType::Humidity(_) => &images::HUMIDITY_ICON,
|
||||
MenuIndicatorType::Co2(_) => &images::CO2_ICON,
|
||||
MenuIndicatorType::Voc(_) => &images::VOC_ICON,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_corresponding_unit_string(&self) -> &'static str
|
||||
{
|
||||
match self
|
||||
{
|
||||
MenuIndicatorType::Temperature(_) => "C",
|
||||
MenuIndicatorType::Humidity(_) => "%",
|
||||
MenuIndicatorType::Co2(_) => "ppm",
|
||||
MenuIndicatorType::Voc(_) => "ppb",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_str(&self) -> heapless::String<16>
|
||||
{
|
||||
match self
|
||||
{
|
||||
MenuIndicatorType::Temperature(temp) => format!(16; "{:.1}", temp).unwrap(),
|
||||
MenuIndicatorType::Humidity(hum) => format!(16; "{:.1}", hum).unwrap(),
|
||||
MenuIndicatorType::Co2(co2) => format!(16; "{}", co2).unwrap(),
|
||||
MenuIndicatorType::Voc(voc) => format!(16; "{}", voc).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main_menu_indicator(indicator_type: MenuIndicatorType) -> impl View<Rgb565>
|
||||
{
|
||||
Rectangle
|
||||
.corner_radius(10)
|
||||
.stroked(FRAME_STROKE)
|
||||
.foreground_color(FRAME_COLOR)
|
||||
.background(Alignment::Center, || {
|
||||
ZStack::new((
|
||||
Rectangle
|
||||
.corner_radius(15)
|
||||
.foreground_color(Rgb565::new(1, 2, 1)),
|
||||
VStack::new((
|
||||
HStack::new((
|
||||
Spacer::default(),
|
||||
buoyant::view::Image::new(get_image!(
|
||||
indicator_type.get_corresponding_icon()
|
||||
)),
|
||||
Spacer::default(),
|
||||
)),
|
||||
HStack::new((
|
||||
Spacer::default(),
|
||||
tendency_indicator(Tendency::Rising),
|
||||
Text::new(indicator_type.get_value_str(), &PROFONT_24_POINT),
|
||||
Text::new(
|
||||
indicator_type.get_corresponding_unit_string(),
|
||||
&PROFONT_18_POINT,
|
||||
)
|
||||
.foreground_color(Rgb565::CSS_DARK_GRAY)
|
||||
.flex_frame()
|
||||
.with_infinite_max_height()
|
||||
.with_vertical_alignment(VerticalAlignment::Bottom)
|
||||
.with_max_height(25),
|
||||
Spacer::default(),
|
||||
)),
|
||||
))
|
||||
.with_alignment(HorizontalAlignment::Center)
|
||||
.flex_frame(),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub enum Tendency
|
||||
{
|
||||
Rising,
|
||||
Steady,
|
||||
Falling,
|
||||
}
|
||||
|
||||
fn tendency_indicator(tendency: Tendency) -> impl View<Rgb565>
|
||||
{
|
||||
VStack::new((
|
||||
StrokedShape::new(
|
||||
Triangle::new(Point::new(0, 5), Point::new(10, 0), Point::new(0, 10)),
|
||||
10,
|
||||
),
|
||||
StrokedShape::new(
|
||||
Triangle::new(Point::new(0, 5), Point::new(10, 0), Point::new(0, 10)),
|
||||
10,
|
||||
),
|
||||
))
|
||||
}
|
||||
0
src/triangle.rs
Normal file
0
src/triangle.rs
Normal file
Reference in New Issue
Block a user