use super::*;
impl RenderNode {
pub(super) fn priority(&self) -> i32 {
match self {
RenderNode::Wrapper(node) => match &node.effect {
WrapperEffect::LayoutPriority(priority) => priority.get(),
_ => node.child.priority(),
},
RenderNode::Opacity(node) => node.child.priority(),
RenderNode::Scale(node) => node.child.priority(),
RenderNode::Rotation(node) => node.child.priority(),
RenderNode::Offset(node) => node.child.priority(),
RenderNode::Retain(node) => node.child.priority(),
RenderNode::Env(node) => node.child.priority(),
RenderNode::Dynamic(node) => node.child.priority(),
RenderNode::AppliedFilter(node) => node.child.priority(),
_ => 0,
}
}
pub(super) fn kind(&self) -> &'static str {
match self {
RenderNode::Color(_) => "Color",
RenderNode::Text(_) => "Text",
RenderNode::Container(_) => "Container",
RenderNode::Opacity(_) => "Opacity",
RenderNode::Scale(_) => "Scale",
RenderNode::Rotation(_) => "Rotation",
RenderNode::Offset(_) => "Offset",
RenderNode::Retain(_) => "Retain",
RenderNode::Env(_) => "Env",
RenderNode::Dynamic(_) => "Dynamic",
RenderNode::SceneView(_) => "SceneView",
RenderNode::GpuSurface(_) => "GpuSurface",
RenderNode::ViewEffect(_) => "ViewEffect",
RenderNode::AppliedFilter(_) => "AppliedFilter",
RenderNode::Scroll(_) => "Scroll",
RenderNode::LazyStack(_) => "LazyStack",
RenderNode::Collection(_) => "Collection",
RenderNode::Wrapper(_) => "Wrapper",
RenderNode::Widget(_) => "Widget",
}
}
pub(super) fn child_nodes(&self) -> Vec<&RenderNode> {
match self {
RenderNode::Container(node) => node.children.iter().collect(),
RenderNode::Opacity(node) => vec![&node.child],
RenderNode::Scale(node) => vec![&node.child],
RenderNode::Rotation(node) => vec![&node.child],
RenderNode::Offset(node) => vec![&node.child],
RenderNode::Retain(node) => vec![&node.child],
RenderNode::Env(node) => vec![&node.child],
RenderNode::Dynamic(node) => vec![&node.child],
RenderNode::AppliedFilter(node) => vec![&node.child],
RenderNode::Wrapper(node) => vec![&node.child],
RenderNode::Scroll(node) => vec![&node.child],
_ => Vec::new(),
}
}
pub(super) fn stretch(&self) -> StretchAxis {
match self {
RenderNode::Color(_) => StretchAxis::Both,
RenderNode::Text(_) => StretchAxis::None,
RenderNode::Container(container) => {
let child_axes: Vec<StretchAxis> =
container.children.iter().map(RenderNode::stretch).collect();
container.layout.stretch_axis(&child_axes)
}
RenderNode::Opacity(node) => node.child.stretch(),
RenderNode::Scale(node) => node.child.stretch(),
RenderNode::Rotation(node) => node.child.stretch(),
RenderNode::Offset(node) => node.child.stretch(),
RenderNode::Retain(node) => node.child.stretch(),
RenderNode::Env(node) => node.child.stretch(),
RenderNode::Dynamic(node) => node.child.stretch(),
RenderNode::SceneView(_) => StretchAxis::Both,
RenderNode::GpuSurface(_) => StretchAxis::Both,
RenderNode::ViewEffect(_) => StretchAxis::None,
RenderNode::AppliedFilter(node) => node.child.stretch(),
RenderNode::Scroll(_) => StretchAxis::Both,
RenderNode::LazyStack(_) => StretchAxis::None,
RenderNode::Collection(node) => {
node.layout.stretch_axis(&[])
}
RenderNode::Wrapper(node) => node.child.stretch(),
RenderNode::Widget(node) => node.stretch,
}
}
pub(super) fn measure(
&self,
state: &mut HydroState,
env: &Environment,
proposal: ProposalSize,
) -> ViewDimensions {
match self {
RenderNode::Color(_) => ViewDimensions::new(Size::new(
proposal.width.unwrap_or(0.0),
proposal.height.unwrap_or(0.0),
)),
RenderNode::Text(text) => HydrolysisRenderer::measure_text_dimensions(
state,
text.content.get(),
text.alignment.get(),
env,
proposal.width,
text.line_limit,
),
RenderNode::Container(container) => {
let cell = RefCell::new(state);
let subs: Vec<NodeSubView> = container
.children
.iter()
.map(|child| NodeSubView::new(child, &cell, env))
.collect();
let refs: Vec<&dyn SubView> = subs.iter().map(|sub| sub as &dyn SubView).collect();
ViewDimensions::new(container.layout.size_that_fits(proposal, &refs))
}
RenderNode::Opacity(node) => node.child.measure(state, env, proposal),
RenderNode::Scale(node) => node.child.measure(state, env, proposal),
RenderNode::Rotation(node) => node.child.measure(state, env, proposal),
RenderNode::Offset(node) => node.child.measure(state, env, proposal),
RenderNode::Retain(node) => node.child.measure(state, env, proposal),
RenderNode::Env(node) => node.child.measure(state, &node.env, proposal),
RenderNode::Dynamic(node) => node.child.measure(state, env, proposal),
RenderNode::SceneView(_) => ViewDimensions::new(Size::new(
proposal.width.unwrap_or(0.0),
proposal.height.unwrap_or(0.0),
)),
RenderNode::GpuSurface(_) => ViewDimensions::new(Size::new(
proposal.width.unwrap_or(0.0),
proposal.height.unwrap_or(0.0),
)),
RenderNode::ViewEffect(node) => node.child.borrow().measure(state, &node.env, proposal),
RenderNode::AppliedFilter(node) => node.child.measure(state, &node.env, proposal),
RenderNode::Scroll(_) => ViewDimensions::new(Size::new(
proposal.width.unwrap_or(0.0),
proposal.height.unwrap_or(0.0),
)),
RenderNode::LazyStack(node) => node.measure(state, proposal),
RenderNode::Collection(node) => node.measure(state, proposal),
RenderNode::Wrapper(node) => node.child.measure(state, &node.env, proposal),
RenderNode::Widget(node) => node.behavior.measure(state, proposal, &node.env),
}
}
pub(crate) fn layout(
&mut self,
renderer: &mut HydrolysisRenderer,
env: &Environment,
size: Size,
) {
match self {
RenderNode::Container(container) => {
let rects = {
let cell = RefCell::new(&mut renderer.state);
let subs: Vec<NodeSubView> = container
.children
.iter()
.map(|child| NodeSubView::new(child, &cell, env))
.collect();
let refs: Vec<&dyn SubView> =
subs.iter().map(|sub| sub as &dyn SubView).collect();
container.layout.place(Rect::from_size(size), &refs)
};
for (child, rect) in container.children.iter_mut().zip(rects.iter()) {
child.layout(renderer, env, *rect.size());
}
container.placed = rects;
}
RenderNode::Opacity(node) => node.child.layout(renderer, env, size),
RenderNode::Scale(node) => node.child.layout(renderer, env, size),
RenderNode::Rotation(node) => node.child.layout(renderer, env, size),
RenderNode::Offset(node) => node.child.layout(renderer, env, size),
RenderNode::Retain(node) => node.child.layout(renderer, env, size),
RenderNode::Env(node) => {
let node_env = node.env.clone();
node.child.layout(renderer, &node_env, size);
}
RenderNode::Wrapper(node) => {
let node_env = node.env.clone();
node.child.layout(renderer, &node_env, size);
}
RenderNode::Dynamic(node) => node.child.layout(renderer, env, size),
RenderNode::Scroll(node) => {
let child_proposal = match node.axis {
ScrollAxis::Horizontal => ProposalSize::new(None, Some(size.height)),
ScrollAxis::Vertical => ProposalSize::new(Some(size.width), None),
ScrollAxis::All => ProposalSize::UNSPECIFIED,
_ => panic!("hydrolysis render tree: unsupported scroll axis"),
};
let intrinsic = node
.child
.measure(&mut renderer.state, env, child_proposal)
.size;
let content_size = match node.axis {
ScrollAxis::Horizontal => {
Size::new(intrinsic.width.max(size.width), size.height)
}
ScrollAxis::Vertical => {
Size::new(size.width, intrinsic.height.max(size.height))
}
ScrollAxis::All => Size::new(
intrinsic.width.max(size.width),
intrinsic.height.max(size.height),
),
_ => panic!("hydrolysis render tree: unsupported scroll axis"),
};
node.child.layout(renderer, env, content_size);
let handle = if let Some(handle) = node.handle.as_mut() {
handle.rebind(
node.axis,
f64::from(size.width),
f64::from(size.height),
f64::from(content_size.width),
f64::from(content_size.height),
)
} else {
ScrollHandle::new(
node.axis,
f64::from(size.width),
f64::from(size.height),
f64::from(content_size.width),
f64::from(content_size.height),
)
};
if let Some(controller) = &node.controller {
let generation = renderer.read_signal(&controller.generation());
if generation != node.applied_scroll_generation.get() {
let target = renderer.read_signal(&controller.target());
let _ = handle.scroll_to(f64::from(target.x), f64::from(target.y));
node.applied_scroll_generation.set(generation);
}
}
node.handle = Some(handle);
node.content_size = content_size;
node.viewport = size;
}
RenderNode::Collection(node) => node.layout(renderer, size),
RenderNode::ViewEffect(node) => {
if size != node.laid_out.get() {
let node_env = node.env.clone();
node.child.borrow_mut().layout(renderer, &node_env, size);
node.laid_out.set(size);
}
}
RenderNode::AppliedFilter(node) => {
let node_env = node.env.clone();
node.child.layout(renderer, &node_env, size);
}
RenderNode::Color(_)
| RenderNode::Text(_)
| RenderNode::SceneView(_)
| RenderNode::GpuSurface(_)
| RenderNode::LazyStack(_)
| RenderNode::Widget(_) => {}
}
}
}