Add Block widget

This commit is contained in:
Joscha 2024-03-09 00:52:14 +01:00
parent e31eea8178
commit 2c8f9685b9
7 changed files with 131 additions and 6 deletions

View file

@ -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<u8>) -> Srgba {
let [r, g, b, a] = color.0;
Srgba::new(r, g, b, a).into_format()

View file

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

View file

@ -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`.
///
/// ```

View file

@ -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()
}

View file

@ -1,3 +1,5 @@
pub use block::*;
pub use text::*;
mod block;
mod text;

View file

@ -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<C> Widget<C> 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(())
}
}

View file

@ -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(())
}