From 0a183e7b3e27e05355a80cec0a6c0dcf1c3e9715 Mon Sep 17 00:00:00 2001 From: Albin Chaboissier Date: Fri, 28 Nov 2025 18:32:28 +0100 Subject: [PATCH] Tidy views --- assets/indic-falling.bmp | Bin 538 -> 538 bytes assets/indic-falling.svg | 23 +++++------ assets/indic-rising.bmp | Bin 538 -> 538 bytes assets/indic-rising.svg | 23 +++++------ assets/indic-steady.bmp | Bin 538 -> 538 bytes assets/indic-steady.svg | 23 +++++------ src/colors.rs | 12 ++++++ src/images.rs | 7 +++- src/main.rs | 87 ++++----------------------------------- src/views.rs | 3 ++ src/views/detail.rs | 52 +++++++++++++++++++++++ src/views/icon.rs | 18 ++++++++ src/views/menu.rs | 85 ++++++++++++++++++++++++++++++++++++++ 13 files changed, 214 insertions(+), 119 deletions(-) create mode 100644 src/colors.rs create mode 100644 src/views.rs create mode 100644 src/views/detail.rs create mode 100644 src/views/icon.rs create mode 100644 src/views/menu.rs diff --git a/assets/indic-falling.bmp b/assets/indic-falling.bmp index c56a0358a09dd1aefcd7a4c0c584a7cf2de96c7c..859d6add5c7abda46f6ecab108c10c875494ba48 100644 GIT binary patch literal 538 zcmZ?rm11H5gDxOh1H@cFECR%g3<3_t*;r4jg5uV($ds`m~H0FnVhy<*O@h9`i)@PK{N|82gr8hfIvkLMF$ug zN-Hp&U^wBZfGo-|gW(3l4TT8^F+~TE2nZtdGpvA#F|2^71gg5ASmEg4=%82uWPxo` zXmHdxEb$l!7fU#50C^ynXn^=I=%@h_I}GQ8#DQu#5;_t*;r4jg5uV($ds`m~H0FnVhy<*O@h9`i)@PK{N|82gr8hfIvkLMF$ug zN-Hp&U^wBZfGo-|gW(3l4TT8^F+~TE2nZtdGpvA#F|2^7M5scjgqQ_aIRm7U;R2iw zGV_8XN0Y!~gQkF{h@^z1grQbDK~+svO%+8JAZ!wF z - + diff --git a/assets/indic-rising.bmp b/assets/indic-rising.bmp index 0fb32f02ba925b70b631b57e142320acd3324d73..bc6741150dee242f93b19c68d2fa48116bc664d3 100644 GIT binary patch literal 538 zcmZ?rm11H5gDxOh1H@cFECR%g3<3_t*;r4jg5uV($ds`m~H0FnVhy<*O@h9`i)@PK{N|82gr8hfWRbyBmo#3 zLML)OmUt|IDz+FX@>pUql4z0uNCX5C`VT`z9!ngCssyQ8B+vwei-0VM%0)mMAu108 zMHYc=N0^2%5n&og3}iRNWgs35CSnzH_t*;r4jg5uV($ds`m~H0FnVhy<*O@h9`i)@PK{N|82gr8hfWX5Nhb3Ta z2;C&`-150)lK`@4s^$yF7mlf#2(iNwAQ2Em=wD_C6I*5oQHf9ml35J4sSU0QB$ftN z`P>qw6GT6^bmV9fU{O>7LRC#wO%Sc3*dzdP1+q$4O-!*=%_f1Rl5IlIgxrMPgr5nu z3N4ic`Q{Cq4m$$AVFS5PlNBMN!>-8+5>w$q7GvRp_+%Aar3zFPNR$(- a@+AvIAB0rmJi~T|O^Fj(45Z%$t`7jMLxP3? diff --git a/assets/indic-rising.svg b/assets/indic-rising.svg index 2507ddb..6a6818a 100644 --- a/assets/indic-rising.svg +++ b/assets/indic-rising.svg @@ -28,8 +28,8 @@ inkscape:document-units="mm" inkscape:export-bgcolor="#080808ff" inkscape:zoom="32" - inkscape:cx="3.46875" - inkscape:cy="9.140625" + inkscape:cx="3.640625" + inkscape:cy="8.328125" inkscape:window-width="1916" inkscape:window-height="1032" inkscape:window-x="0" @@ -50,18 +50,9 @@ height="197.24825" x="-44.312061" y="-1.4580333" /> - + diff --git a/assets/indic-steady.bmp b/assets/indic-steady.bmp index af79bb947d48df4863592f79dd35082173835666..9f35aee73e0d8b3b84b91fa89b4c5406e9d49085 100644 GIT binary patch literal 538 zcmZ?rm11H5gDxOh1H@cFECR%g3<3_t*;r4jg5uV($ds`m~H0FnVhy<*O@h9`i)@PK{N|82gr8hfWRbyBmo#3 zLML)OmUt|IDz+FX@>pUql4z0uNCX5C`VT`z9!ngCssyQeq`;)fr1?kzrgD*lqb0)@ zhp!G_8MZhY0(l^p7%IF4iGZNOTSr4jjz$TH8kp#V&5aTdHDEj#{ZIp&7`k4DEsY>s xEYa<7NYu^1c*$YJHk0SVJYXqbb23}hpRJpjj9obdnv literal 538 zcmZ?rm11H5gDxOh1H@cFECR%g3<3_t*;r4jg5uV($ds`m~H0FnVhy<*O@h9`i)@PK{N|82gr8hfWX5Nhb3Ta z2;C&`-150)lK`@4s^$yF7mlf#2(iNwAQ2Em=wD_C6I*5oQHf9ml35J4sSU0QB$ftN z`P>qw6GT6^1nRa-%zEs3*zpJu9(H`}nV98h*f87SD=KW5-LM!{#NlhhY*f96L3)8E lVzGk*n_IBC*^vX&Z;l)Ym54BK - + diff --git a/src/colors.rs b/src/colors.rs new file mode 100644 index 0000000..03d9bc8 --- /dev/null +++ b/src/colors.rs @@ -0,0 +1,12 @@ +use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::prelude::RgbColor; +use embedded_graphics::prelude::WebColors; + +pub const BACKGROUND_COLOR: Rgb565 = Rgb565::BLACK; +pub const FRAME_BACKGROUD_COLOR: Rgb565 = Rgb565::new(1, 2, 1); +pub const FRAME_STROKE_COLOR: Rgb565 = Rgb565::new(4, 9, 4); + +pub const MAIN_TEXT_COLOR: Rgb565 = Rgb565::WHITE; +pub const SUB_TEXT_COLOR: Rgb565 = Rgb565::CSS_DARK_GRAY; + +pub const FRAME_STROKE: u32 = 3; diff --git a/src/images.rs b/src/images.rs index a8b4a9f..e698aa3 100644 --- a/src/images.rs +++ b/src/images.rs @@ -1,4 +1,5 @@ -use std::{cell::UnsafeCell, mem::MaybeUninit}; +use std::cell::UnsafeCell; +use std::mem::MaybeUninit; use embedded_graphics::pixelcolor::Rgb565; use tinybmp::Bmp; @@ -15,6 +16,8 @@ thread_local! { pub static TENDENCY_FALLING: UnsafeCell>> = const { UnsafeCell::new(MaybeUninit::zeroed()) }; } +pub type StaticImage = std::thread::LocalKey>>>; + macro_rules! load_image { ($stat:expr, $path:expr) => { $stat @@ -26,6 +29,8 @@ macro_rules! load_image { macro_rules! get_image { ($image:expr) => { unsafe { + use std::mem::MaybeUninit; + use tinybmp::Bmp; &*std::mem::transmute::<*mut MaybeUninit>, *mut Bmp>( $image.with(|g| g.get()), ) diff --git a/src/main.rs b/src/main.rs index 0672883..6833498 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,19 @@ //#![feature(unsafe_cell_access)] +mod colors; mod images; +mod views; -use core::fmt::Write; use std::cell::UnsafeCell; use std::mem::MaybeUninit; -use buoyant::primitives::Point; -use buoyant::render::StrokedShape; use buoyant::view::prelude::*; use embedded_graphics::pixelcolor::Rgb565; -use embedded_graphics::pixelcolor::Rgb888; use embedded_graphics::prelude::*; use embedded_graphics_simulator::OutputSettings; use embedded_graphics_simulator::SimulatorDisplay; use embedded_graphics_simulator::Window; -use embedded_sprites::include_image; -use embedded_sprites::sprite::Sprite; use heapless::format; -use profont::PROFONT_12_POINT; -use profont::PROFONT_14_POINT; -use profont::PROFONT_18_POINT; -use profont::PROFONT_24_POINT; use tinybmp::Bmp; const BACKGROUND_COLOR: Rgb565 = Rgb565::BLACK; @@ -34,7 +26,12 @@ fn main() { let mut display: SimulatorDisplay = SimulatorDisplay::new(Size::new(320, 240)); display.clear(BACKGROUND_COLOR); - hello_view() + // views::menu::menu_view() + // .as_drawable(display.size(), DEFAULT_COLOR) + // .draw(&mut display) + // .unwrap(); + + views::detail::detailed_view(MenuIndicatorType::Temperature(38.3), Tendency::Steady) .as_drawable(display.size(), DEFAULT_COLOR) .draw(&mut display) .unwrap(); @@ -42,25 +39,6 @@ fn main() { window.show_static(&display); } -fn hello_view() -> impl View { - VStack::new(( - HStack::new(( - main_menu_indicator(MenuIndicatorType::Temperature(31.5), Tendency::Falling), - main_menu_indicator(MenuIndicatorType::Humidity(36.2), Tendency::Steady), - )) - .with_spacing(5), - HStack::new(( - main_menu_indicator(MenuIndicatorType::Co2(1329), Tendency::Rising), - main_menu_indicator(MenuIndicatorType::Voc(29), Tendency::Falling), - )) - .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), @@ -99,55 +77,6 @@ impl MenuIndicatorType { } } -fn main_menu_indicator(indicator_type: MenuIndicatorType, tendency: Tendency) -> impl View { - 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(), - ZStack::new(( - Rectangle - .corner_radius(10) - //.stroked_offset(5, StrokeOffset::Outer) - .foreground_color(Rgb565::new(4, 9, 4)), - buoyant::view::Image::new(get_image!( - indicator_type.get_corresponding_icon() - )), - )) - .flex_frame() - .with_max_size(53, 53) - .with_min_size(53, 53), - Spacer::default(), - )), - HStack::new(( - Spacer::default(), - tendency_indicator(tendency), - 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, diff --git a/src/views.rs b/src/views.rs new file mode 100644 index 0000000..38dde75 --- /dev/null +++ b/src/views.rs @@ -0,0 +1,3 @@ +pub mod detail; +pub mod icon; +pub mod menu; diff --git a/src/views/detail.rs b/src/views/detail.rs new file mode 100644 index 0000000..0bcf0ff --- /dev/null +++ b/src/views/detail.rs @@ -0,0 +1,52 @@ +use buoyant::layout::HorizontalAlignment; +use buoyant::layout::VerticalAlignment; +use buoyant::view::HStack; +use buoyant::view::Spacer; +use buoyant::view::Text; +use buoyant::view::VStack; +use buoyant::view::View; +use buoyant::view::ViewExt; +use embedded_graphics::pixelcolor::Rgb565; +use profont::PROFONT_18_POINT; +use profont::PROFONT_24_POINT; + +use crate::MenuIndicatorType; +use crate::Tendency; +use crate::colors::FRAME_STROKE_COLOR; +use crate::colors::MAIN_TEXT_COLOR; +use crate::colors::SUB_TEXT_COLOR; +use crate::tendency_indicator; +use crate::views::icon::icon_box_view; + +pub fn detailed_view(indicator: MenuIndicatorType, tendency: Tendency) -> impl View { + VStack::new(( + // Header + HStack::new(( + icon_box_view(FRAME_STROKE_COLOR, indicator.get_corresponding_icon()), + Spacer::default().flex_frame().with_max_width(10), + tendency_indicator(tendency), + Text::new(indicator.get_value_str(), &PROFONT_24_POINT) + .foreground_color(MAIN_TEXT_COLOR), + Text::new(indicator.get_corresponding_unit_string(), &PROFONT_18_POINT) + .foreground_color(SUB_TEXT_COLOR) + .flex_frame() + .with_infinite_max_height() + .with_vertical_alignment(VerticalAlignment::Bottom) + .with_max_height(25), + Spacer::default(), + Text::new("Temperature", &PROFONT_18_POINT) + .foreground_color(SUB_TEXT_COLOR) + .flex_frame() + .with_infinite_max_height() + .with_vertical_alignment(VerticalAlignment::Bottom) + .with_max_height(25), + Spacer::default().flex_frame().with_max_width(10), + )), + // Window + Spacer::default() + .flex_frame() + .with_infinite_max_width() + .with_infinite_max_height(), + )) + .with_alignment(HorizontalAlignment::Leading) +} diff --git a/src/views/icon.rs b/src/views/icon.rs new file mode 100644 index 0000000..8d0f5c1 --- /dev/null +++ b/src/views/icon.rs @@ -0,0 +1,18 @@ +use buoyant::view::View; +use buoyant::view::ViewExt; +use buoyant::view::ZStack; +use buoyant::view::shape::Rectangle; +use embedded_graphics::pixelcolor::Rgb565; + +use crate::get_image; +use crate::images::StaticImage; + +pub fn icon_box_view(box_color: Rgb565, icon: &'static StaticImage) -> impl View { + ZStack::new(( + Rectangle.corner_radius(10).foreground_color(box_color), + buoyant::view::Image::new(get_image!(icon)), + )) + .flex_frame() + .with_max_size(53, 53) + .with_min_size(53, 53) +} diff --git a/src/views/menu.rs b/src/views/menu.rs new file mode 100644 index 0000000..23d7a7a --- /dev/null +++ b/src/views/menu.rs @@ -0,0 +1,85 @@ +use buoyant::view::VStack; +use buoyant::view::View; + +use buoyant::view::prelude::*; +use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::prelude::*; +use profont::PROFONT_18_POINT; +use profont::PROFONT_24_POINT; + +use crate::MenuIndicatorType; +use crate::Tendency; +use crate::colors::FRAME_BACKGROUD_COLOR; +use crate::colors::FRAME_STROKE; +use crate::colors::FRAME_STROKE_COLOR; +use crate::colors::MAIN_TEXT_COLOR; +use crate::colors::SUB_TEXT_COLOR; +use crate::get_image; +use crate::views::icon::icon_box_view; + +pub fn menu_view() -> impl View { + VStack::new(( + HStack::new(( + main_menu_indicator(MenuIndicatorType::Temperature(31.5), Tendency::Falling), + main_menu_indicator(MenuIndicatorType::Humidity(36.2), Tendency::Steady), + )) + .with_spacing(5), + HStack::new(( + main_menu_indicator(MenuIndicatorType::Co2(1329), Tendency::Rising), + main_menu_indicator(MenuIndicatorType::Voc(29), Tendency::Falling), + )) + .with_spacing(5), + )) + .with_spacing(5) +} + +fn main_menu_indicator(indicator_type: MenuIndicatorType, tendency: Tendency) -> impl View { + Rectangle + .corner_radius(10) + .stroked(FRAME_STROKE) + .foreground_color(FRAME_STROKE_COLOR) + .background(Alignment::Center, || { + ZStack::new(( + Rectangle + .corner_radius(15) + .foreground_color(FRAME_BACKGROUD_COLOR), + VStack::new(( + HStack::new(( + Spacer::default(), + icon_box_view(FRAME_STROKE_COLOR, indicator_type.get_corresponding_icon()), + Spacer::default(), + )), + HStack::new(( + Spacer::default(), + tendency_indicator(tendency), + Text::new(indicator_type.get_value_str(), &PROFONT_24_POINT) + .foreground_color(MAIN_TEXT_COLOR), + Text::new( + indicator_type.get_corresponding_unit_string(), + &PROFONT_18_POINT, + ) + .foreground_color(SUB_TEXT_COLOR) + .flex_frame() + .with_infinite_max_height() + .with_vertical_alignment(VerticalAlignment::Bottom) + .with_max_height(25), + Spacer::default(), + )), + )) + .with_alignment(HorizontalAlignment::Center) + .flex_frame(), + )) + }) +} + +fn tendency_indicator(tendency: Tendency) -> impl View { + HStack::new(( + Image::new(get_image!(tendency.get_corresponding_icon())) + .flex_frame() + .with_min_size(10, 20) + .with_max_size(10, 20), + Spacer::default(), + )) + .flex_frame() + .with_max_width(15) +}