use super::*;
pub(super) struct NodeSubView<'a> {
node: MainThreadBound<&'a RenderNode>,
state: MainThreadBound<&'a RefCell<&'a mut HydroState>>,
env: MainThreadBound<Environment>,
stretch: StretchAxis,
priority: i32,
measure_cache: MainThreadBound<RefCell<Vec<(ProposalSize, ViewDimensions)>>>,
resolved_text: Option<ResolvedNodeTextMeasure>,
}
struct ResolvedNodeTextMeasure {
input: ResolvedTextLayoutInput,
service: std::sync::Arc<TextMeasureService>,
max_lines: Option<usize>,
}
fn try_resolve_node_text_leaf(
node: &RenderNode,
env: &Environment,
) -> Option<(ResolvedTextLayoutInput, Option<usize>)> {
match node {
RenderNode::Text(text) => Some((
resolve_text_layout_input(&text.content.get(), text.alignment.get(), env),
text.line_limit,
)),
RenderNode::Opacity(node) => try_resolve_node_text_leaf(&node.child, env),
RenderNode::Scale(node) => try_resolve_node_text_leaf(&node.child, env),
RenderNode::Rotation(node) => try_resolve_node_text_leaf(&node.child, env),
RenderNode::Offset(node) => try_resolve_node_text_leaf(&node.child, env),
RenderNode::Retain(node) => try_resolve_node_text_leaf(&node.child, env),
RenderNode::Dynamic(node) => try_resolve_node_text_leaf(&node.child, env),
RenderNode::Env(node) => try_resolve_node_text_leaf(&node.child, &node.env),
RenderNode::Wrapper(node) => try_resolve_node_text_leaf(&node.child, &node.env),
_ => None,
}
}
impl<'a> NodeSubView<'a> {
pub(super) fn new(
node: &'a RenderNode,
state: &'a RefCell<&'a mut HydroState>,
env: &'a Environment,
) -> Self {
let resolved_text = try_resolve_node_text_leaf(node, env).map(|(input, max_lines)| {
ResolvedNodeTextMeasure {
input,
service: std::sync::Arc::clone(&state.borrow().text),
max_lines,
}
});
Self {
stretch: node.stretch(),
priority: node.priority(),
node: MainThreadBound::new(node),
state: MainThreadBound::new(state),
env: MainThreadBound::new(env.clone()),
measure_cache: MainThreadBound::new(RefCell::new(Vec::new())),
resolved_text,
}
}
fn apply_stretch(
&self,
mut dimensions: ViewDimensions,
proposal: ProposalSize,
) -> ViewDimensions {
if self.stretch.stretches_horizontal()
&& let Some(width) = proposal.width
{
dimensions.size.width = dimensions.size.width.max(width);
}
if self.stretch.stretches_vertical()
&& let Some(height) = proposal.height
{
dimensions.size.height = dimensions.size.height.max(height);
}
dimensions
}
}
impl SubView for NodeSubView<'_> {
fn measure(&self, proposal: ProposalSize) -> ViewDimensions {
if let Some(resolved) = &self.resolved_text {
let layout = resolved.service.shape(&resolved.input, proposal.width);
let dimensions = text_dimensions_from_layout(&layout, resolved.max_lines);
return self.apply_stretch(dimensions, proposal);
}
if let Some((_, dimensions)) = self
.measure_cache
.borrow()
.iter()
.find(|(cached, _)| *cached == proposal)
{
return dimensions.clone();
}
let dimensions = {
let mut state = self.state.borrow_mut();
self.node.measure(&mut state, &self.env, proposal)
};
let dimensions = self.apply_stretch(dimensions, proposal);
self.measure_cache
.borrow_mut()
.push((proposal, dimensions.clone()));
dimensions
}
fn stretch_axis(&self) -> StretchAxis {
self.stretch
}
fn priority(&self) -> i32 {
self.priority
}
}