From 8ca035e6ff2088115399adf143ee13fbd6644754 Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Thu, 19 Oct 2023 10:06:10 +0200 Subject: [PATCH] prepare for layouting --- src/main.rs | 23 ++++++++++++++------- src/nodes/layout.rs | 32 +++++++++++++++++++++++++++++ src/nodes/mod.rs | 49 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 src/nodes/layout.rs diff --git a/src/main.rs b/src/main.rs index 6dbd50e..cf80076 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ use glutin::{ }; use taffy::Taffy; use weak_table::PtrWeakKeyHashMap; -use crate::nodes::{Node, render_recursively, RenderContext}; +use crate::nodes::{layout_recursively, Node, render_recursively, RenderContext}; mod nodes; @@ -48,7 +48,9 @@ fn main() { taffy_map.insert(root.clone(), root_node); let mut context = RenderContext { - canvas + canvas, + taffy_map, + taffy }; event_loop.run(move |event, _target, control_flow| match event { @@ -66,7 +68,16 @@ fn main() { _ => {} }, Event::RedrawRequested(_) => { - render(&buffer_context, &surface, &window, &mut context, &root, &taffy_map, &taffy); + layout_recursively(&root, &mut context); + let src_nodes = context.taffy_map.values().map(|v| v.to_owned()).collect::>(); + context.taffy_map.remove_expired(); + let dst_nodes = context.taffy_map.values().map(|v| v.to_owned()).collect::>(); + for src_node in src_nodes { + if !dst_nodes.contains(&src_node) { + context.taffy.remove(src_node).unwrap(); + } + } + render(&buffer_context, &surface, &window, &mut context, &root); }, _ => {} }) @@ -115,9 +126,7 @@ fn render( surface: &Surface, window: &Window, context: &mut RenderContext, - root_node: &Arc, - taffy_map: &TaffyMap, - taffy: &Taffy + root_node: &Arc ) { // Make sure the canvas has the right size: let size = window.inner_size(); @@ -126,7 +135,7 @@ fn render( context.canvas.clear_rect(0, 0, size.width, size.height, Color::black()); // Do the render passes here - render_recursively(root_node, context, taffy_map, taffy); + render_recursively(root_node, context); // Tell renderer to execute all drawing commands context.canvas.flush(); diff --git a/src/nodes/layout.rs b/src/nodes/layout.rs new file mode 100644 index 0000000..71013e3 --- /dev/null +++ b/src/nodes/layout.rs @@ -0,0 +1,32 @@ +use femtovg::Renderer; +use crate::nodes::{Node, NodeChildren, Overflow, RenderContext, Style}; +use taffy::style::{Style as TaffyStyle}; + +pub struct Layout { + style: Style, + children: NodeChildren +} + +impl Layout { + pub(crate) fn new() -> Layout { + Layout { + style: Style { + layout: TaffyStyle::default(), + overflow: Overflow::Visible + }, + children: NodeChildren::new() + } + } +} + +impl Node for Layout { + fn style(&self) -> &Style { + &self.style + } + fn children(&self) -> Option<&NodeChildren> { + Some(&self.children) + } + fn render(&self, context: &mut RenderContext, _layout: taffy::layout::Layout, render_children: &dyn Fn(&mut RenderContext)) { + render_children(context); + } +} \ No newline at end of file diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index eba9d6b..e184f47 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -1,3 +1,5 @@ +pub mod layout; + use std::sync::Arc; use femtovg::{Canvas, Color, Renderer}; use femtovg::renderer::OpenGl; @@ -9,7 +11,9 @@ use taffy::Taffy; use crate::{GNode, TaffyMap}; pub struct RenderContext { - pub(crate) canvas: Canvas, + pub canvas: Canvas, + pub taffy_map: TaffyMap, + pub taffy: Taffy } #[derive(Copy, Clone, Default)] @@ -39,14 +43,41 @@ pub trait Node { fn children(&self) -> Option<&NodeChildren>; /// Render the node and its children. render_children gets ['children'] and calls this function there as well. When drawing, the canvas is translated to the node's location. /// Canvas considers 0, 0 to be top left corner (for location after layouting happens) - fn render(&self, context: &mut RenderContext, layout: &Layout, render_children: &dyn Fn(&mut RenderContext)); + fn render(&self, context: &mut RenderContext, layout: Layout, render_children: &dyn Fn(&mut RenderContext)); } -pub fn render_recursively(selfref: &Arc, context: &mut RenderContext, taffy_map: &TaffyMap, taffy: &Taffy) { - let styles = selfref.style(); - let node = taffy_map.get(selfref).unwrap(); - let layout = taffy.layout(*node).unwrap(); - let sself = selfref.clone(); +pub fn layout_recursively(node: &Arc, context: &mut RenderContext) -> taffy::node::Node { + let taffy_node = context.taffy_map.get(node); + let taffy_node = match taffy_node { + Some(taffy_node) => taffy_node, + None => { + let taffy_node = context.taffy.new_leaf(node.style().layout.to_owned()).unwrap(); + context.taffy_map.insert(node.clone(), taffy_node); + context.taffy_map.get(node).unwrap() + } + }; + + let taffy_node = taffy_node.to_owned(); + + match node.children() { + None => {}, + Some(children) => { + let mut t_children = Vec::with_capacity(children.len()); + for child in children { + t_children.push(layout_recursively(child, context).to_owned()); + } + context.taffy.set_children(taffy_node, t_children.as_slice()).unwrap(); + } + } + + taffy_node +} + +pub fn render_recursively(node: &Arc, context: &mut RenderContext) { + let styles = node.style(); + let taffy_node = context.taffy_map.get(node).unwrap(); + let layout = *context.taffy.layout(*taffy_node).unwrap(); + let sself = node.clone(); context.canvas.save(); context.canvas.translate(layout.location.x, layout.location.y); match styles.overflow { @@ -63,7 +94,7 @@ pub fn render_recursively(selfref: &Arc, context: &mut RenderContext Node for RedBoxDemo { fn children(&self) -> Option<&NodeChildren> { None } - fn render<'a>(&self, context: &mut RenderContext, _layout: &Layout, _render_children: &dyn Fn(&mut RenderContext)) { + fn render(&self, context: &mut RenderContext, _layout: Layout, _render_children: &dyn Fn(&mut RenderContext)) { context.canvas.clear_rect( 0, 0,