From 2c8f9685b96b58fa59f27843f394fe4d7873938a Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 9 Mar 2024 00:52:14 +0100 Subject: [PATCH] Add Block widget --- showbits-common/src/color.rs | 4 ++ showbits-common/src/rect.rs | 16 ++++++ showbits-common/src/vec2.rs | 8 +++ showbits-common/src/view.rs | 4 ++ showbits-common/src/widgets.rs | 2 + showbits-common/src/widgets/block.rs | 77 ++++++++++++++++++++++++++ showbits-thermal-printer/src/drawer.rs | 26 +++++++-- 7 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 showbits-common/src/widgets/block.rs diff --git a/showbits-common/src/color.rs b/showbits-common/src/color.rs index b6de01e..3774ad0 100644 --- a/showbits-common/src/color.rs +++ b/showbits-common/src/color.rs @@ -1,5 +1,9 @@ use palette::Srgba; +pub const TRANSPARENT: Srgba = Srgba::new(0.0, 0.0, 0.0, 0.0); +pub const BLACK: Srgba = Srgba::new(0.0, 0.0, 0.0, 1.0); +pub const WHITE: Srgba = Srgba::new(1.0, 1.0, 1.0, 1.0); + pub fn from_image_color(color: image::Rgba) -> Srgba { let [r, g, b, a] = color.0; Srgba::new(r, g, b, a).into_format() diff --git a/showbits-common/src/rect.rs b/showbits-common/src/rect.rs index f967525..e8e1e2e 100644 --- a/showbits-common/src/rect.rs +++ b/showbits-common/src/rect.rs @@ -73,6 +73,22 @@ impl Rect { Self::from_nw_se(nw, se) } + pub const fn north(self) -> i32 { + self.north + } + + pub const fn south(self) -> i32 { + self.south + } + + pub const fn west(self) -> i32 { + self.west + } + + pub const fn east(self) -> i32 { + self.east + } + pub const fn corner_nw(self) -> Vec2 { Vec2::new(self.west, self.north) } diff --git a/showbits-common/src/vec2.rs b/showbits-common/src/vec2.rs index 4e69c1d..8b9820f 100644 --- a/showbits-common/src/vec2.rs +++ b/showbits-common/src/vec2.rs @@ -32,6 +32,14 @@ impl Vec2 { (x, y) } + pub fn with_x(self, x: i32) -> Self { + Self { x, ..self } + } + + pub fn with_y(self, y: i32) -> Self { + Self { y, ..self } + } + /// The vector pointing from `self` to `other`. /// /// ``` diff --git a/showbits-common/src/view.rs b/showbits-common/src/view.rs index ba91d36..762207b 100644 --- a/showbits-common/src/view.rs +++ b/showbits-common/src/view.rs @@ -31,6 +31,10 @@ impl<'a> View<'a> { self.area.size() } + pub fn area(&self) -> Rect { + Rect::from_nw(Vec2::ZERO, self.size()) + } + fn pos_to_buffer_pos(&self, pos: Vec2) -> Vec2 { pos + self.area.corner_nw() } diff --git a/showbits-common/src/widgets.rs b/showbits-common/src/widgets.rs index ced299a..6ed6399 100644 --- a/showbits-common/src/widgets.rs +++ b/showbits-common/src/widgets.rs @@ -1,3 +1,5 @@ +pub use block::*; pub use text::*; +mod block; mod text; diff --git a/showbits-common/src/widgets/block.rs b/showbits-common/src/widgets/block.rs new file mode 100644 index 0000000..55662bb --- /dev/null +++ b/showbits-common/src/widgets/block.rs @@ -0,0 +1,77 @@ +use palette::Srgba; +use taffy::Layout; + +use crate::{color, Rect, Vec2, View, Widget}; + +pub struct Block { + border: Srgba, + background: Srgba, +} + +impl Block { + pub fn new() -> Self { + Self { + border: color::TRANSPARENT, + background: color::TRANSPARENT, + } + } + + pub fn border(mut self, color: Srgba) -> Self { + self.border = color; + self + } + + pub fn background(mut self, color: Srgba) -> Self { + self.background = color; + self + } +} + +impl Default for Block { + fn default() -> Self { + Self::new() + } +} + +impl Widget for Block { + fn draw_below( + &mut self, + _ctx: &mut C, + view: &mut View<'_>, + layout: &Layout, + ) -> anyhow::Result<()> { + let area = view.area(); + + // Background + view.rect(area, self.background); + + // And now... the border! + // + // It is important not to draw pixels twice in case the border color is + // transparent. That's why the logic below is a bit more complex. + let left = layout.border.left as i32; + let right = layout.border.right as i32; + let top = layout.border.top as i32; + let bottom = layout.border.bottom as i32; + if top > 0 { + let border = Rect::from_nw(area.corner_nw(), area.size().with_y(top)); + view.rect(border, self.border); + } + if bottom > 0 { + let border = Rect::from_sw(area.corner_sw(), area.size().with_y(bottom)); + view.rect(border, self.border); + } + if left > 0 { + let nw = area.corner_nw() + Vec2::new(0, top); + let size = Vec2::new(left, area.size().y - top - bottom); + view.rect(Rect::from_nw(nw, size), self.border); + } + if right > 0 { + let ne = area.corner_ne() + Vec2::new(0, top); + let size = Vec2::new(right, area.size().y - top - bottom); + view.rect(Rect::from_ne(ne, size), self.border); + } + + Ok(()) + } +} diff --git a/showbits-thermal-printer/src/drawer.rs b/showbits-thermal-printer/src/drawer.rs index a9070ed..2058661 100644 --- a/showbits-thermal-printer/src/drawer.rs +++ b/showbits-thermal-printer/src/drawer.rs @@ -1,7 +1,7 @@ use cosmic_text::{Attrs, Metrics}; use palette::Srgba; use showbits_common::{ - widgets::{FontStuff, HasFontStuff, Text}, + widgets::{Block, FontStuff, HasFontStuff, Text}, Node, Tree, WidgetExt, }; use taffy::style_helpers::{length, percent}; @@ -70,19 +70,33 @@ impl Drawer { let text = Text::simple( &mut self.ctx.font_stuff, - Metrics::new(16.0, 32.0), + Metrics::new(16.0, 24.0), Attrs::new(), - "Hello world!", + "Hello\nworld!", ) .node() - .margin_horiz(length(10.0)) + .margin_horiz(length(8.0)) + .margin_vert(length(2.0)) .register(&mut tree)?; - let root = Node::empty() - .size_width(percent(1.0)) + let wrap = Block::new() + .background(Srgba::new(0.0, 1.0, 0.0, 0.3)) + .node() .child(text) .register(&mut tree)?; + let root = Block::new() + .border(Srgba::new(1.0, 0.0, 0.0, 0.5)) + .node() + .size_width(percent(1.0)) + .border_top(length(5.0)) + .border_right(length(10.0)) + .border_bottom(length(15.0)) + .border_left(length(20.0)) + .padding_all(length(10.0)) + .child(wrap) + .register(&mut tree)?; + self.printer.print_tree(&mut tree, &mut self.ctx, root)?; Ok(()) }