Make widgets generic over global state

This commit is contained in:
Joscha 2024-03-07 16:34:10 +01:00
parent 715be147f9
commit fe33465564
3 changed files with 40 additions and 30 deletions

View file

@ -5,15 +5,15 @@ use taffy::{
TaffyTree, TrackSizingFunction, TaffyTree, TrackSizingFunction,
}; };
use crate::Widget; use crate::{BoxedWidget, Widget};
pub struct Node { pub struct Node<C> {
layout: Style, layout: Style,
children: Vec<NodeId>, children: Vec<NodeId>,
widget: Option<Box<dyn Widget>>, widget: Option<BoxedWidget<C>>,
} }
impl Node { impl<C> Node<C> {
pub fn empty() -> Self { pub fn empty() -> Self {
Self { Self {
layout: Style::default(), layout: Style::default(),
@ -27,12 +27,12 @@ impl Node {
self self
} }
pub fn widget<W: Widget + 'static>(mut self, widget: W) -> Self { pub fn widget<W: Widget<C> + 'static>(mut self, widget: W) -> Self {
self.widget = Some(Box::new(widget)); self.widget = Some(Box::new(widget));
self self
} }
pub fn register(self, tree: &mut TaffyTree<Box<dyn Widget>>) -> TaffyResult<NodeId> { pub fn register(self, tree: &mut TaffyTree<BoxedWidget<C>>) -> TaffyResult<NodeId> {
let id = tree.new_with_children(self.layout, &self.children)?; let id = tree.new_with_children(self.layout, &self.children)?;
tree.set_node_context(id, self.widget)?; tree.set_node_context(id, self.widget)?;
Ok(id) Ok(id)
@ -170,7 +170,7 @@ macro_rules! layout_setter_rect {
}; };
} }
impl Node { impl<C> Node<C> {
layout_setter!(display: Display); layout_setter!(display: Display);
layout_setter!(overflow: Point<Overflow>); layout_setter!(overflow: Point<Overflow>);

View file

@ -1,7 +1,7 @@
use image::RgbImage; use image::RgbImage;
use taffy::{AvailableSpace, NodeId, Point, Size, TaffyResult, TaffyTree}; 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<f32>) -> Vec2 { fn point_to_vec2(point: Point<f32>) -> Vec2 {
Vec2::new(point.x as i32, point.y as i32) Vec2::new(point.x as i32, point.y as i32)
@ -11,23 +11,25 @@ fn size_to_vec2(size: Size<f32>) -> Vec2 {
Vec2::new(size.width as i32, size.height as i32) Vec2::new(size.width as i32, size.height as i32)
} }
fn layout( fn layout<C>(
tree: &mut TaffyTree<Box<dyn Widget>>, tree: &mut TaffyTree<BoxedWidget<C>>,
ctx: &mut C,
root: NodeId, root: NodeId,
available: Size<AvailableSpace>, available: Size<AvailableSpace>,
) -> TaffyResult<()> { ) -> TaffyResult<()> {
tree.enable_rounding(); // Just to make sure tree.enable_rounding(); // Just to make sure
tree.compute_layout_with_measure(root, available, |known, available, _node, context| { tree.compute_layout_with_measure(root, available, |known, available, _node, context| {
if let Some(widget) = context { if let Some(widget) = context {
widget.size(known, available) widget.size(ctx, known, available)
} else { } else {
Size::ZERO Size::ZERO
} }
}) })
} }
fn render_to_view( fn render_to_view<C>(
tree: &mut TaffyTree<Box<dyn Widget>>, tree: &mut TaffyTree<BoxedWidget<C>>,
ctx: &mut C,
node: NodeId, node: NodeId,
view: &mut View<'_>, view: &mut View<'_>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
@ -36,8 +38,8 @@ fn render_to_view(
let mut view = view.dup().zoom(area); let mut view = view.dup().zoom(area);
// First pass // First pass
if let Some(ctx) = tree.get_node_context_mut(node) { if let Some(widget) = tree.get_node_context_mut(node) {
ctx.draw_below(&mut view)?; widget.draw_below(ctx, &mut view)?;
} }
// Render children // Render children
@ -48,23 +50,24 @@ fn render_to_view(
} }
children.sort_unstable_by_key(|(order, _)| *order); children.sort_unstable_by_key(|(order, _)| *order);
for (_, child) in children { for (_, child) in children {
render_to_view(tree, child, &mut view)?; render_to_view(tree, ctx, child, &mut view)?;
} }
// Second pass // Second pass
if let Some(ctx) = tree.get_node_context_mut(node) { if let Some(widget) = tree.get_node_context_mut(node) {
ctx.draw_above(&mut view)?; widget.draw_above(ctx, &mut view)?;
} }
Ok(()) Ok(())
} }
pub fn render( pub fn render<C>(
tree: &mut TaffyTree<Box<dyn Widget>>, tree: &mut TaffyTree<BoxedWidget<C>>,
ctx: &mut C,
root: NodeId, root: NodeId,
available: Size<AvailableSpace>, available: Size<AvailableSpace>,
) -> anyhow::Result<RgbImage> { ) -> anyhow::Result<RgbImage> {
layout(tree, root, available)?; layout(tree, ctx, root, available)?;
let layout = tree.layout(root)?; let layout = tree.layout(root)?;
assert_eq!(layout.location.x, 0.0); 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 (width, height) = size_to_vec2(layout.size).to_u32();
let mut image = RgbImage::new(width, height); 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) Ok(image)
} }

View file

@ -2,22 +2,29 @@ use taffy::{AvailableSpace, Size};
use crate::{Node, View}; use crate::{Node, View};
pub trait Widget { pub trait Widget<C> {
#[allow(unused_variables)] #[allow(unused_variables)]
fn size(&mut self, known: Size<Option<f32>>, available: Size<AvailableSpace>) -> Size<f32> { fn size(
&mut self,
ctx: &mut C,
known: Size<Option<f32>>,
available: Size<AvailableSpace>,
) -> Size<f32> {
Size::ZERO Size::ZERO
} }
fn draw_below(&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, view: &mut View<'_>) -> anyhow::Result<()>; fn draw_above(&mut self, ctx: &mut C, view: &mut View<'_>) -> anyhow::Result<()>;
} }
pub trait WidgetExt { pub type BoxedWidget<C> = Box<dyn Widget<C>>;
fn node(self) -> Node;
pub trait WidgetExt<C> {
fn node(self) -> Node<C>;
} }
impl<W: Widget + 'static> WidgetExt for W { impl<C, W: Widget<C> + 'static> WidgetExt<C> for W {
fn node(self) -> Node { fn node(self) -> Node<C> {
Node::empty().widget(self) Node::empty().widget(self)
} }
} }