Make widgets generic over global state
This commit is contained in:
parent
715be147f9
commit
fe33465564
3 changed files with 40 additions and 30 deletions
|
|
@ -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>);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue