From fe3346556459d9d35df8dcec9cc66ce3ae8d8118 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 7 Mar 2024 16:34:10 +0100 Subject: [PATCH] Make widgets generic over global state --- showbits-common/src/node.rs | 14 +++++++------- showbits-common/src/render.rs | 33 ++++++++++++++++++--------------- showbits-common/src/widget.rs | 23 +++++++++++++++-------- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/showbits-common/src/node.rs b/showbits-common/src/node.rs index 69455b9..9c06fb0 100644 --- a/showbits-common/src/node.rs +++ b/showbits-common/src/node.rs @@ -5,15 +5,15 @@ use taffy::{ TaffyTree, TrackSizingFunction, }; -use crate::Widget; +use crate::{BoxedWidget, Widget}; -pub struct Node { +pub struct Node { layout: Style, children: Vec, - widget: Option>, + widget: Option>, } -impl Node { +impl Node { pub fn empty() -> Self { Self { layout: Style::default(), @@ -27,12 +27,12 @@ impl Node { self } - pub fn widget(mut self, widget: W) -> Self { + pub fn widget + 'static>(mut self, widget: W) -> Self { self.widget = Some(Box::new(widget)); self } - pub fn register(self, tree: &mut TaffyTree>) -> TaffyResult { + pub fn register(self, tree: &mut TaffyTree>) -> TaffyResult { let id = tree.new_with_children(self.layout, &self.children)?; tree.set_node_context(id, self.widget)?; Ok(id) @@ -170,7 +170,7 @@ macro_rules! layout_setter_rect { }; } -impl Node { +impl Node { layout_setter!(display: Display); layout_setter!(overflow: Point); diff --git a/showbits-common/src/render.rs b/showbits-common/src/render.rs index af30def..9409ed2 100644 --- a/showbits-common/src/render.rs +++ b/showbits-common/src/render.rs @@ -1,7 +1,7 @@ use image::RgbImage; use taffy::{AvailableSpace, NodeId, Point, Size, TaffyResult, TaffyTree}; -use crate::{Rect, Vec2, View, Widget}; +use crate::{BoxedWidget, Rect, Vec2, View}; fn point_to_vec2(point: Point) -> Vec2 { Vec2::new(point.x as i32, point.y as i32) @@ -11,23 +11,25 @@ fn size_to_vec2(size: Size) -> Vec2 { Vec2::new(size.width as i32, size.height as i32) } -fn layout( - tree: &mut TaffyTree>, +fn layout( + tree: &mut TaffyTree>, + ctx: &mut C, root: NodeId, available: Size, ) -> TaffyResult<()> { tree.enable_rounding(); // Just to make sure tree.compute_layout_with_measure(root, available, |known, available, _node, context| { if let Some(widget) = context { - widget.size(known, available) + widget.size(ctx, known, available) } else { Size::ZERO } }) } -fn render_to_view( - tree: &mut TaffyTree>, +fn render_to_view( + tree: &mut TaffyTree>, + ctx: &mut C, node: NodeId, view: &mut View<'_>, ) -> anyhow::Result<()> { @@ -36,8 +38,8 @@ fn render_to_view( let mut view = view.dup().zoom(area); // First pass - if let Some(ctx) = tree.get_node_context_mut(node) { - ctx.draw_below(&mut view)?; + if let Some(widget) = tree.get_node_context_mut(node) { + widget.draw_below(ctx, &mut view)?; } // Render children @@ -48,23 +50,24 @@ fn render_to_view( } children.sort_unstable_by_key(|(order, _)| *order); for (_, child) in children { - render_to_view(tree, child, &mut view)?; + render_to_view(tree, ctx, child, &mut view)?; } // Second pass - if let Some(ctx) = tree.get_node_context_mut(node) { - ctx.draw_above(&mut view)?; + if let Some(widget) = tree.get_node_context_mut(node) { + widget.draw_above(ctx, &mut view)?; } Ok(()) } -pub fn render( - tree: &mut TaffyTree>, +pub fn render( + tree: &mut TaffyTree>, + ctx: &mut C, root: NodeId, available: Size, ) -> anyhow::Result { - layout(tree, root, available)?; + layout(tree, ctx, root, available)?; let layout = tree.layout(root)?; assert_eq!(layout.location.x, 0.0); @@ -73,7 +76,7 @@ pub fn render( let (width, height) = size_to_vec2(layout.size).to_u32(); let mut image = RgbImage::new(width, height); - render_to_view(tree, root, &mut View::new(&mut image))?; + render_to_view(tree, ctx, root, &mut View::new(&mut image))?; Ok(image) } diff --git a/showbits-common/src/widget.rs b/showbits-common/src/widget.rs index c5684f0..c39e71c 100644 --- a/showbits-common/src/widget.rs +++ b/showbits-common/src/widget.rs @@ -2,22 +2,29 @@ use taffy::{AvailableSpace, Size}; use crate::{Node, View}; -pub trait Widget { +pub trait Widget { #[allow(unused_variables)] - fn size(&mut self, known: Size>, available: Size) -> Size { + fn size( + &mut self, + ctx: &mut C, + known: Size>, + available: Size, + ) -> Size { Size::ZERO } - fn draw_below(&mut self, view: &mut View<'_>) -> anyhow::Result<()>; - fn draw_above(&mut self, view: &mut View<'_>) -> anyhow::Result<()>; + fn draw_below(&mut self, ctx: &mut C, view: &mut View<'_>) -> anyhow::Result<()>; + fn draw_above(&mut self, ctx: &mut C, view: &mut View<'_>) -> anyhow::Result<()>; } -pub trait WidgetExt { - fn node(self) -> Node; +pub type BoxedWidget = Box>; + +pub trait WidgetExt { + fn node(self) -> Node; } -impl WidgetExt for W { - fn node(self) -> Node { +impl + 'static> WidgetExt for W { + fn node(self) -> Node { Node::empty().widget(self) } }