Initial commit
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "buoyant"]
|
||||
path = buoyant
|
||||
url = git@github.com:chalbin73/buoyant.git
|
||||
1381
Cargo.lock
generated
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "co2-meter-iface"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
#buoyant = "0.6.0-alpha.0"
|
||||
buoyant = {path = "buoyant" }
|
||||
embedded-graphics = "0.8.1"
|
||||
embedded-graphics-simulator = "0.8.0"
|
||||
embedded-sprites = "0.2.0"
|
||||
heapless = "0.9.2"
|
||||
profont = "0.7.0"
|
||||
tinybmp = "0.6.0"
|
||||
19
assets/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
SVGS = $(wildcard ./*.svg)
|
||||
TARGET_BMPS = $(SVGS:.svg=.bmp)
|
||||
SIZE = 45
|
||||
BACKCOLOR = 080808
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(TARGET_BMPS)
|
||||
@echo $(SVGS)
|
||||
|
||||
clean:
|
||||
rm $(TARGET_BMPS)
|
||||
|
||||
%.bmp: %.png
|
||||
@convert $< -background "#$(BACKCOLOR)" -alpha remove -define bmp:subtype=RGB565 $@
|
||||
|
||||
%.png: %.svg
|
||||
inkscape -h $(SIZE) -w $(SIZE) $< -o $@
|
||||
|
||||
BIN
assets/co2-icon.bmp
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
81
assets/co2-icon.svg
Normal file
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="100mm"
|
||||
height="100mm"
|
||||
viewBox="0 0 100 100"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
sodipodi:docname="co2-icon.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="0.64"
|
||||
inkscape:cx="-160.15625"
|
||||
inkscape:cy="294.53125"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1032"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:36.3189px;font-family:'ProFont IIx Nerd Font Propo';-inkscape-font-specification:'ProFont IIx Nerd Font Propo';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#00ade7;fill-opacity:1;stroke-width:2.26994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2"
|
||||
x="76.022087"
|
||||
y="74.254074"
|
||||
id="text1-3"
|
||||
transform="scale(0.98156475,1.0187815)"
|
||||
inkscape:label="2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1-6"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:36.3189px;font-family:'ProFont IIx Nerd Font Propo';-inkscape-font-specification:'ProFont IIx Nerd Font Propo';fill:#00ade7;fill-opacity:1;stroke-width:2.26994"
|
||||
x="76.022087"
|
||||
y="74.254074">2</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:56.1282px;font-family:'ProFont IIx Nerd Font Propo';-inkscape-font-specification:'ProFont IIx Nerd Font Propo';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#00ade7;fill-opacity:1;stroke-width:3.50802;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2"
|
||||
x="5.6048326"
|
||||
y="81.050644"
|
||||
id="text1-3-3"
|
||||
transform="scale(0.98156475,1.0187815)"
|
||||
inkscape:label="2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1-6-5"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:56.1282px;font-family:'ProFont IIx Nerd Font Propo';-inkscape-font-specification:'ProFont IIx Nerd Font Propo';fill:#00ade7;fill-opacity:1;stroke-width:3.50802"
|
||||
x="5.6048326"
|
||||
y="81.050644">C</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:56.1282px;font-family:'ProFont IIx Nerd Font Propo';-inkscape-font-specification:'ProFont IIx Nerd Font Propo';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#00ade7;fill-opacity:1;stroke-width:3.50802;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2"
|
||||
x="40.805176"
|
||||
y="63.398773"
|
||||
id="text1-3-3-7"
|
||||
transform="scale(0.98156475,1.0187815)"
|
||||
inkscape:label="2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1-6-5-9"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:56.1282px;font-family:'ProFont IIx Nerd Font Propo';-inkscape-font-specification:'ProFont IIx Nerd Font Propo';fill:#00ade7;fill-opacity:1;stroke-width:3.50802"
|
||||
x="40.805176"
|
||||
y="63.398773">O</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
BIN
assets/humidity-icon.bmp
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
46
assets/humidity-icon.svg
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="38px"
|
||||
height="38px"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.6"
|
||||
fill="none"
|
||||
color="#bababa"
|
||||
data-darkreader-inline-color=""
|
||||
style="--darkreader-inline-color: var(--darkreader-text-bababa, #bcb7ae);"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="humidity-icon.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="9.5273334"
|
||||
inkscape:cx="19.785179"
|
||||
inkscape:cy="22.829053"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1032"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M20 14C20 9.58172 12 2 12 2C12 2 4 9.58172 4 14C4 18.4183 7.58172 22 12 22C16.4183 22 20 18.4183 20 14Z"
|
||||
stroke="#bababa"
|
||||
stroke-width="1.6"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke:#bababa;stroke:#0137f1;stroke-opacity:1"
|
||||
id="path1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/temperature-icon.bmp
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
102
assets/temperature-icon.svg
Normal file
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24px"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
fill="none"
|
||||
color="#ff6600"
|
||||
data-darkreader-inline-color=""
|
||||
style="--darkreader-inline-color: var(--darkreader-text-000000, #e8e6e3);"
|
||||
version="1.1"
|
||||
id="svg7"
|
||||
sodipodi:docname="temperature-icon.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs7" />
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="30.169889"
|
||||
inkscape:cx="10.523738"
|
||||
inkscape:cy="14.103466"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1032"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg7" />
|
||||
<path
|
||||
d="M6 11.9995C4.78555 12.9117 4 14.3641 4 15.9999C4 18.7613 6.23858 20.9999 9 20.9999C11.7614 20.9999 14 18.7613 14 15.9999C14 14.3641 13.2144 12.9117 12 11.9995"
|
||||
stroke="#ff6600"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: #ff6600;"
|
||||
id="path1" />
|
||||
<path
|
||||
d="M6 12V3H12V12"
|
||||
stroke="#ff6600"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: #ff6600;"
|
||||
id="path2" />
|
||||
<path
|
||||
d="M12 3L14 3"
|
||||
stroke="#ff6600"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: #ff6600;"
|
||||
id="path3" />
|
||||
<path
|
||||
d="M12 6L14 6"
|
||||
stroke="#ff6600"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: #ff6600;"
|
||||
id="path4" />
|
||||
<path
|
||||
d="M12 9H14"
|
||||
stroke="#ff6600"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: #ff6600;"
|
||||
id="path5" />
|
||||
<path
|
||||
d="M19 7C20.1046 7 21 6.10457 21 5C21 3.89543 20.1046 3 19 3C17.8954 3 17 3.89543 17 5C17 6.10457 17.8954 7 19 7Z"
|
||||
stroke="#ff6600"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: #ff6600;"
|
||||
id="path6" />
|
||||
<path
|
||||
d="M9 14C7.89543 14 7 14.8954 7 16C7 17.1046 7.89543 18 9 18C10.1046 18 11 17.1046 11 16C11 14.8954 10.1046 14 9 14ZM9 14V11"
|
||||
stroke="#ff6600"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-darkreader-inline-stroke=""
|
||||
style="--darkreader-inline-stroke: #ff6600;"
|
||||
id="path7" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/voc-icon.bmp
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
37
assets/voc-icon.svg
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="voc-icon.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="21.333333"
|
||||
inkscape:cx="6.2109375"
|
||||
inkscape:cy="14.226563"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1032"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M4 4H8V6H4V4ZM16 19H20V21H16V19ZM2 9H7V11H2V9ZM9 9H12V11H9V9ZM14 9H20V11H14V9ZM4 14H10V16H4V14ZM12 14H15V16H12V14ZM17 14H22V16H17V14ZM10 4H22V6H10V4ZM2 19H14V21H2V19Z"
|
||||
id="path1"
|
||||
style="stroke:none;stroke-opacity:1;fill:#cacaca;fill-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
buoyant
Submodule
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
@ -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,
|
||||
),
|
||||
))
|
||||
}
|
||||