Tidy views

This commit is contained in:
2025-11-28 18:32:28 +01:00
parent b46666a703
commit 0a183e7b3e
13 changed files with 214 additions and 119 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

After

Width:  |  Height:  |  Size: 538 B

View File

@ -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" />
<rect
style="fill:#3e3e3e;fill-opacity:1;stroke:none;stroke-width:10.4178;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1"
id="rect3"
width="92.56852"
height="34.62767"
x="-41.28426"
y="79.852249"
rx="10.363558"
ry="15.606441" />
<path
sodipodi:type="star"
style="fill:#3e3e3e;fill-opacity:1;stroke:#080808;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:#1c1c1c;fill-opacity:1;stroke:none;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path1"
inkscape:flatsided="true"
sodipodi:sides="3"
@ -78,7 +69,7 @@
transform="matrix(0.82051985,0,0,0.88816373,-16.031162,29.570393)" />
<path
sodipodi:type="star"
style="fill:#db0000;fill-opacity:1;stroke:#080808;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:#db0000;fill-opacity:1;stroke:none;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path1-1"
inkscape:flatsided="true"
sodipodi:sides="3"
@ -93,5 +84,11 @@
d="m 74.007276,52.321038 c -4.837576,8.378928 -91.913956,8.378928 -96.751533,-1e-6 -4.837577,-8.378929 38.700614,-83.789285 48.375767,-83.789285 9.675153,0 53.213343,75.410357 48.375766,83.789286 z"
inkscape:transform-center-y="12.403106"
transform="matrix(-0.82051985,0,0,-0.88816373,26.031162,164.76177)" />
<circle
style="fill:#1c1c1c;fill-opacity:1;stroke:#080808;stroke-width:5.96404155;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="path2"
cx="5.0000005"
cy="97.166092"
r="43.119678" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

After

Width:  |  Height:  |  Size: 538 B

View File

@ -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" />
<rect
style="fill:#3e3e3e;fill-opacity:1;stroke:none;stroke-width:10.4178;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1"
id="rect3"
width="92.56852"
height="34.62767"
x="-41.28426"
y="79.852249"
rx="10.363558"
ry="15.606441" />
<path
sodipodi:type="star"
style="fill:#00e565;fill-opacity:1;stroke:#080808;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:#00e565;fill-opacity:1;stroke:none;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path1"
inkscape:flatsided="true"
sodipodi:sides="3"
@ -78,7 +69,7 @@
transform="matrix(0.82051985,0,0,0.88816373,-16.031162,29.570393)" />
<path
sodipodi:type="star"
style="fill:#3e3e3e;fill-opacity:1;stroke:#080808;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:#1c1c1c;fill-opacity:1;stroke:none;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path1-1"
inkscape:flatsided="true"
sodipodi:sides="3"
@ -93,5 +84,11 @@
d="m 74.007276,52.321038 c -4.837576,8.378928 -91.913956,8.378928 -96.751533,-1e-6 -4.837577,-8.378929 38.700614,-83.789285 48.375767,-83.789285 9.675153,0 53.213343,75.410357 48.375766,83.789286 z"
inkscape:transform-center-y="12.403106"
transform="matrix(-0.82051985,0,0,-0.88816373,26.031162,164.76177)" />
<circle
style="fill:#1c1c1c;fill-opacity:1;stroke:#080808;stroke-width:5.97976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="path2"
cx="5.0000005"
cy="97.166092"
r="43.119678" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

After

Width:  |  Height:  |  Size: 538 B

View File

@ -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" />
<rect
style="fill:#f6ab00;fill-opacity:1;stroke:none;stroke-width:10.4178;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1"
id="rect3"
width="92.56852"
height="34.62767"
x="-41.28426"
y="79.852249"
rx="10.363558"
ry="15.606441" />
<path
sodipodi:type="star"
style="fill:#3e3e3e;fill-opacity:1;stroke:#080808;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:#1c1c1c;fill-opacity:1;stroke:none;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path1"
inkscape:flatsided="true"
sodipodi:sides="3"
@ -78,7 +69,7 @@
transform="matrix(0.82051985,0,0,0.88816373,-16.031162,29.570393)" />
<path
sodipodi:type="star"
style="fill:#3e3e3e;fill-opacity:1;stroke:#080808;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:#1c1c1c;fill-opacity:1;stroke:none;stroke-width:6.94267343;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path1-1"
inkscape:flatsided="true"
sodipodi:sides="3"
@ -93,5 +84,11 @@
d="m 74.007276,52.321038 c -4.837576,8.378928 -91.913956,8.378928 -96.751533,-1e-6 -4.837577,-8.378929 38.700614,-83.789285 48.375767,-83.789285 9.675153,0 53.213343,75.410357 48.375766,83.789286 z"
inkscape:transform-center-y="12.403106"
transform="matrix(-0.82051985,0,0,-0.88816373,26.031162,164.76177)" />
<circle
style="fill:#f6ab00;fill-opacity:1;stroke:#080808;stroke-width:5.97976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:0.2;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="path2"
cx="5.0000005"
cy="97.166092"
r="43.119678" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

12
src/colors.rs Normal file
View File

@ -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;

View File

@ -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<MaybeUninit<Bmp<'static, Rgb565>>> = const { UnsafeCell::new(MaybeUninit::zeroed()) };
}
pub type StaticImage = std::thread::LocalKey<UnsafeCell<MaybeUninit<Bmp<'static, Rgb565>>>>;
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<Bmp<Rgb565>>, *mut Bmp<Rgb565>>(
$image.with(|g| g.get()),
)

View File

@ -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<Rgb565> = 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<Rgb565> {
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<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(),
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,

3
src/views.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod detail;
pub mod icon;
pub mod menu;

52
src/views/detail.rs Normal file
View File

@ -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<Rgb565> {
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)
}

18
src/views/icon.rs Normal file
View File

@ -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<Rgb565> {
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)
}

85
src/views/menu.rs Normal file
View File

@ -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<Rgb565> {
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<Rgb565> {
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<Rgb565> {
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)
}