Move render code into Tree

This commit is contained in:
Joscha 2024-03-08 12:10:45 +01:00
parent ce2f986983
commit 9a25856548
4 changed files with 114 additions and 87 deletions

View file

@ -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 node;
mod rect; mod rect;
mod render; mod tree;
mod vec2; mod vec2;
mod view; mod view;
mod widget; mod widget;

View file

@ -2,10 +2,10 @@ use taffy::{
AlignContent, AlignItems, AlignSelf, Dimension, Display, FlexDirection, FlexWrap, GridAutoFlow, AlignContent, AlignItems, AlignSelf, Dimension, Display, FlexDirection, FlexWrap, GridAutoFlow,
GridPlacement, JustifyContent, LengthPercentage, LengthPercentageAuto, Line, NodeId, GridPlacement, JustifyContent, LengthPercentage, LengthPercentageAuto, Line, NodeId,
NonRepeatedTrackSizingFunction, Overflow, Point, Position, Rect, Size, Style, TaffyResult, NonRepeatedTrackSizingFunction, Overflow, Point, Position, Rect, Size, Style, TaffyResult,
TaffyTree, TrackSizingFunction, TrackSizingFunction,
}; };
use crate::{BoxedWidget, Widget}; use crate::{BoxedWidget, Tree, Widget};
pub struct Node<C> { pub struct Node<C> {
layout: Style, layout: Style,
@ -32,7 +32,8 @@ impl<C> Node<C> {
self self
} }
pub fn register(self, tree: &mut TaffyTree<BoxedWidget<C>>) -> TaffyResult<NodeId> { pub fn register(self, tree: &mut Tree<C>) -> TaffyResult<NodeId> {
let tree = tree.taffy_tree();
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)

View file

@ -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<f32>) -> Vec2 {
Vec2::new(point.x as i32, point.y as i32)
}
fn size_to_vec2(size: Size<f32>) -> Vec2 {
Vec2::new(size.width as i32, size.height as i32)
}
fn layout<C>(
tree: &mut TaffyTree<BoxedWidget<C>>,
ctx: &mut C,
root: NodeId,
available: Size<AvailableSpace>,
) -> 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<C>(
tree: &mut TaffyTree<BoxedWidget<C>>,
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<C>(
tree: &mut TaffyTree<BoxedWidget<C>>,
ctx: &mut C,
root: NodeId,
available: Size<AvailableSpace>,
) -> anyhow::Result<RgbImage> {
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)
}

108
showbits-common/src/tree.rs Normal file
View file

@ -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<f32>) -> Vec2 {
Vec2::new(point.x as i32, point.y as i32)
}
fn size_to_vec2(size: Size<f32>) -> Vec2 {
Vec2::new(size.width as i32, size.height as i32)
}
pub struct Tree<C> {
tree: TaffyTree<BoxedWidget<C>>,
}
impl<C> Tree<C> {
pub fn new() -> Self {
Self {
tree: TaffyTree::new(),
}
}
pub(crate) fn taffy_tree(&mut self) -> &mut TaffyTree<BoxedWidget<C>> {
&mut self.tree
}
fn layout(
&mut self,
ctx: &mut C,
root: NodeId,
available: Size<AvailableSpace>,
) -> 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<AvailableSpace>,
) -> anyhow::Result<RgbImage> {
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<C> Default for Tree<C> {
fn default() -> Self {
Self::new()
}
}