diff --git a/showbits-common/src/lib.rs b/showbits-common/src/lib.rs index c3084df..912418e 100644 --- a/showbits-common/src/lib.rs +++ b/showbits-common/src/lib.rs @@ -1,8 +1,8 @@ -pub use crate::{node::*, rect::*, render::*, vec2::*, view::*, widget::*}; +pub use crate::{node::*, rect::*, tree::*, vec2::*, view::*, widget::*}; mod node; mod rect; -mod render; +mod tree; mod vec2; mod view; mod widget; diff --git a/showbits-common/src/node.rs b/showbits-common/src/node.rs index 9c06fb0..ce54bf3 100644 --- a/showbits-common/src/node.rs +++ b/showbits-common/src/node.rs @@ -2,10 +2,10 @@ use taffy::{ AlignContent, AlignItems, AlignSelf, Dimension, Display, FlexDirection, FlexWrap, GridAutoFlow, GridPlacement, JustifyContent, LengthPercentage, LengthPercentageAuto, Line, NodeId, NonRepeatedTrackSizingFunction, Overflow, Point, Position, Rect, Size, Style, TaffyResult, - TaffyTree, TrackSizingFunction, + TrackSizingFunction, }; -use crate::{BoxedWidget, Widget}; +use crate::{BoxedWidget, Tree, Widget}; pub struct Node { layout: Style, @@ -32,7 +32,8 @@ impl Node { self } - pub fn register(self, tree: &mut TaffyTree>) -> TaffyResult { + pub fn register(self, tree: &mut Tree) -> TaffyResult { + let tree = tree.taffy_tree(); let id = tree.new_with_children(self.layout, &self.children)?; tree.set_node_context(id, self.widget)?; Ok(id) diff --git a/showbits-common/src/render.rs b/showbits-common/src/render.rs deleted file mode 100644 index 9409ed2..0000000 --- a/showbits-common/src/render.rs +++ /dev/null @@ -1,82 +0,0 @@ -use image::RgbImage; -use taffy::{AvailableSpace, NodeId, Point, Size, TaffyResult, TaffyTree}; - -use crate::{BoxedWidget, Rect, Vec2, View}; - -fn point_to_vec2(point: Point) -> Vec2 { - Vec2::new(point.x as i32, point.y as i32) -} - -fn size_to_vec2(size: Size) -> Vec2 { - Vec2::new(size.width as i32, size.height as i32) -} - -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(ctx, known, available) - } else { - Size::ZERO - } - }) -} - -fn render_to_view( - tree: &mut TaffyTree>, - ctx: &mut C, - node: NodeId, - view: &mut View<'_>, -) -> anyhow::Result<()> { - let layout = tree.layout(node)?; - let area = Rect::from_nw(point_to_vec2(layout.location), size_to_vec2(layout.size)); - let mut view = view.dup().zoom(area); - - // First pass - if let Some(widget) = tree.get_node_context_mut(node) { - widget.draw_below(ctx, &mut view)?; - } - - // Render children - let mut children = vec![]; - for child in tree.children(node)? { - let order = tree.layout(child)?.order; - children.push((order, child)); - } - children.sort_unstable_by_key(|(order, _)| *order); - for (_, child) in children { - render_to_view(tree, ctx, child, &mut view)?; - } - - // Second pass - if let Some(widget) = tree.get_node_context_mut(node) { - widget.draw_above(ctx, &mut view)?; - } - - Ok(()) -} - -pub fn render( - tree: &mut TaffyTree>, - ctx: &mut C, - root: NodeId, - available: Size, -) -> anyhow::Result { - layout(tree, ctx, root, available)?; - - let layout = tree.layout(root)?; - assert_eq!(layout.location.x, 0.0); - assert_eq!(layout.location.y, 0.0); - // TODO Check how taffy treats the border? - - let (width, height) = size_to_vec2(layout.size).to_u32(); - let mut image = RgbImage::new(width, height); - render_to_view(tree, ctx, root, &mut View::new(&mut image))?; - - Ok(image) -} diff --git a/showbits-common/src/tree.rs b/showbits-common/src/tree.rs new file mode 100644 index 0000000..e2a6d5f --- /dev/null +++ b/showbits-common/src/tree.rs @@ -0,0 +1,108 @@ +use image::RgbImage; +use taffy::{AvailableSpace, NodeId, Point, Size, TaffyResult, TaffyTree}; + +use crate::{BoxedWidget, Rect, Vec2, View}; + +fn point_to_vec2(point: Point) -> Vec2 { + Vec2::new(point.x as i32, point.y as i32) +} + +fn size_to_vec2(size: Size) -> Vec2 { + Vec2::new(size.width as i32, size.height as i32) +} + +pub struct Tree { + tree: TaffyTree>, +} + +impl Tree { + pub fn new() -> Self { + Self { + tree: TaffyTree::new(), + } + } + + pub(crate) fn taffy_tree(&mut self) -> &mut TaffyTree> { + &mut self.tree + } + + fn layout( + &mut self, + ctx: &mut C, + root: NodeId, + available: Size, + ) -> TaffyResult<()> { + self.tree.enable_rounding(); // Just to make sure + self.tree.compute_layout_with_measure( + root, + available, + |known, available, _node, context| { + if let Some(widget) = context { + widget.size(ctx, known, available) + } else { + Size::ZERO + } + }, + ) + } + + fn render_to_view( + &mut self, + ctx: &mut C, + node: NodeId, + view: &mut View<'_>, + ) -> anyhow::Result<()> { + let layout = self.tree.layout(node)?; + let area = Rect::from_nw(point_to_vec2(layout.location), size_to_vec2(layout.size)); + let mut view = view.dup().zoom(area); + + // First pass + if let Some(widget) = self.tree.get_node_context_mut(node) { + widget.draw_below(ctx, &mut view)?; + } + + // Render children + let mut children = vec![]; + for child in self.tree.children(node)? { + let order = self.tree.layout(child)?.order; + children.push((order, child)); + } + children.sort_unstable_by_key(|(order, _)| *order); + for (_, child) in children { + self.render_to_view(ctx, child, &mut view)?; + } + + // Second pass + if let Some(widget) = self.tree.get_node_context_mut(node) { + widget.draw_above(ctx, &mut view)?; + } + + Ok(()) + } + + pub fn render( + &mut self, + ctx: &mut C, + root: NodeId, + available: Size, + ) -> anyhow::Result { + self.layout(ctx, root, available)?; + + let layout = self.tree.layout(root)?; + assert_eq!(layout.location.x, 0.0); + assert_eq!(layout.location.y, 0.0); + // TODO Check how taffy treats the border? + + let (width, height) = size_to_vec2(layout.size).to_u32(); + let mut image = RgbImage::new(width, height); + self.render_to_view(ctx, root, &mut View::new(&mut image))?; + + Ok(image) + } +} + +impl Default for Tree { + fn default() -> Self { + Self::new() + } +}