use super::*;
impl RenderNode {
pub(crate) fn build(
view: AnyView,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let view = match view.downcast::<Native<Color>>() {
Ok(color) => {
return RenderNode::Color(ColorNode {
color: (*color).into_inner().resolve(env),
});
}
Err(view) => view,
};
let view = match view.downcast::<Native<ResolvedColor>>() {
Ok(color) => {
return RenderNode::Color(ColorNode {
color: Computed::constant((*color).into_inner()),
});
}
Err(view) => view,
};
let view = match view.downcast::<Native<TextConfig>>() {
Ok(text) => {
let config = (*text).into_inner();
return RenderNode::Text(Box::new(TextNode {
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
content: config.content,
alignment: config.paragraph_alignment,
line_limit: config.line_limit.map(core::num::NonZeroUsize::get),
}));
}
Err(view) => view,
};
let view = match view.downcast::<Native<FixedContainer>>() {
Ok(container) => {
let (layout, children) = (*container).into_inner().into_inner();
let signals = renderer.signals.clone();
let guards = layout.watch_invalidation(Rc::new(move || {
signals.request_refresh();
}));
#[cfg(feature = "accessibility")]
let accessibility_child_env = accessibility_container_child_environment(env);
#[cfg(feature = "accessibility")]
let child_env = accessibility_child_env.as_ref().unwrap_or(env);
#[cfg(not(feature = "accessibility"))]
let child_env = env;
let children = children
.into_iter()
.map(|child| {
RenderNode::build(
normalize_layout_view(child, child_env),
child_env,
renderer,
)
})
.collect();
return RenderNode::Container(Box::new(ContainerNode {
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
layout,
children,
#[cfg(feature = "accessibility")]
accessibility_child_env,
placed: Vec::new(),
_guards: guards,
}));
}
Err(view) => view,
};
let view = match view.downcast::<Native<LazyContainer>>() {
Ok(container) => {
let direction = container.as_inner().direction();
let (layout, children) = (*container).into_inner().into_inner();
let wants_transition = env
.get::<waterui_layout::collection_transition::CollectionTransition>()
.is_some();
if let Some(axis) =
lazy_stack_axis_config(layout.as_ref(), direction).filter(|_| !wants_transition)
{
return RenderNode::build_lazy_stack(axis, children, env, renderer);
}
return RenderNode::build_collection(layout, children, env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Opacity>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::Opacity(Box::new(OpacityNode {
value,
child: RenderNode::build(content, env, renderer),
}));
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Scale>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::Scale(Box::new(ScaleNode {
value,
child: RenderNode::build(content, env, renderer),
}));
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Rotation>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::Rotation(Box::new(RotationNode {
value,
child: RenderNode::build(content, env, renderer),
}));
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Offset>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::Offset(Box::new(OffsetNode {
value,
child: RenderNode::build(content, env, renderer),
}));
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Environment>>() {
Ok(meta) => {
let (content, scoped_env) =
flatten_environment_metadata_owned(AnyView::new(*meta), env);
let scoped_env = restore_a11y_naming_scope(env, scoped_env);
let child = RenderNode::build(content, &scoped_env, renderer);
return RenderNode::Env(Box::new(EnvNode {
env: scoped_env,
child,
}));
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Retain>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::Retain(Box::new(RetainNode {
_retain: value,
child: RenderNode::build(content, env, renderer),
}));
}
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<AccessibilityLabel>>() {
Ok(meta) => return RenderNode::build_naming_scoped(*meta, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<AccessibilityIdentifier>>() {
Ok(meta) => {
let IgnorableMetadata { content, value } = *meta;
#[cfg(feature = "accessibility")]
{
let scoped = a11y_scoped_env(env, &ScopedAccessibilityIdentifier::new(value));
let child = RenderNode::build(content, &scoped, renderer);
return RenderNode::Env(Box::new(EnvNode { env: scoped, child }));
}
#[cfg(not(feature = "accessibility"))]
{
drop(value);
return RenderNode::build(content, env, renderer);
}
}
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<AccessibilityRole>>() {
Ok(meta) => return RenderNode::build_naming_scoped(*meta, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<AccessibilityHidden>>() {
Ok(meta) => return RenderNode::build_env_scoped(*meta, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<AccessibilityChildren>>() {
Ok(meta) => return RenderNode::build_env_scoped(*meta, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<AccessibilityState>>() {
Ok(meta) => {
let IgnorableMetadata { content, value } = *meta;
let scoped = a11y_scoped_env_for_state(env, &value);
let child = RenderNode::build(content, &scoped, renderer);
return RenderNode::Env(Box::new(EnvNode { env: scoped, child }));
}
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<AccessibilityStateSignal>>() {
Ok(meta) => return RenderNode::build_env_scoped(*meta, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Metadata<Secure>>() {
Ok(meta) => return RenderNode::build(meta.content, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Metadata<StandardDynamicRange>>() {
Ok(meta) => {
let mut scoped = env.clone();
scoped.insert(DynamicRangePreference(false));
let child = RenderNode::build(meta.content, &scoped, renderer);
return RenderNode::Env(Box::new(EnvNode { env: scoped, child }));
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<HighDynamicRange>>() {
Ok(meta) => {
let mut scoped = env.clone();
scoped.insert(DynamicRangePreference(true));
let child = RenderNode::build(meta.content, &scoped, renderer);
return RenderNode::Env(Box::new(EnvNode { env: scoped, child }));
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<IgnoreSafeArea>>() {
Ok(meta) => return RenderNode::build(meta.content, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Metadata<ContextMenu>>() {
Ok(meta) => return RenderNode::build(meta.content, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Metadata<Background>>() {
Ok(meta) => return RenderNode::build(meta.content, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Metadata<NavigationTransitionSource>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::NavigationTransitionSource(value.id()),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<NavigationTransitionDestination>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::NavigationTransitionDestination(value.id()),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<IgnorableMetadata<MaterialBackground>>() {
Ok(meta) => return RenderNode::build(meta.content, env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Metadata<ClipShape>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::Clip(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Border>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::Border(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Shadow>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::Shadow(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<LayoutPriority>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::LayoutPriority(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Cursor>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::Cursor(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Draggable>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::Draggable(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<DropDestination>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::DropDestination(DropDestinationHandles::from_destination(value)),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<ResolvedContextMenu>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::ContextMenu(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Hittable>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::Hittable(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<OnEvent>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::OnEvent(Rc::new(RefCell::new(value))),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<GestureObserver>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
let GestureObserver {
gesture, action, ..
} = value;
let effect = GestureObserverEffect {
gesture,
action: Rc::new(RefCell::new(action)),
#[cfg(feature = "accessibility")]
default_a11y_label: renderer.accessibility_label_from_view(&content, env),
gesture_group_identity: gesture_group_identity(&content),
};
return RenderNode::build_wrapper(
WrapperEffect::GestureObserver(effect),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<Focused>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_wrapper(
WrapperEffect::Focused(value),
content,
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<LifeCycleHook>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_lifecycle(value, content, env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<ScrollView>>() {
Ok(scroll) => {
let (axis, content, controller) = (*scroll).into_inner().into_inner();
let content = normalize_layout_view(content, env);
return RenderNode::Scroll(Box::new(ScrollNode {
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
axis,
child: RenderNode::build(content, env, renderer),
controller,
applied_scroll_generation: Cell::new(0),
handle: None,
content_size: Size::zero(),
viewport: Size::zero(),
env: env.clone(),
}));
}
Err(view) => view,
};
let view = match view.downcast::<Native<SceneView>>() {
Ok(scene_view) => {
return RenderNode::build_scene_view_node(*scene_view, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<GpuSurface>>() {
Ok(surface) => {
return RenderNode::build_gpu_surface((*surface).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<ViewEffectErased>>() {
Ok(effect) => {
return RenderNode::build_view_effect((*effect).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Metadata<AppliedFilter>>() {
Ok(meta) => {
let Metadata { content, value } = *meta;
return RenderNode::build_applied_filter(value, content, env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<Dynamic>>() {
Ok(dynamic) => {
return RenderNode::build_dynamic_host((*dynamic).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<ButtonConfig>>() {
Ok(button) => {
return RenderNode::build_button((*button).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<ResolvedMenu>>() {
Ok(menu) => return RenderNode::build_menu((*menu).into_inner(), env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Native<ToggleConfig>>() {
Ok(toggle) => return RenderNode::build_toggle((*toggle).into_inner(), env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Native<SliderConfig>>() {
Ok(slider) => return RenderNode::build_slider((*slider).into_inner(), env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Native<StepperConfig>>() {
Ok(stepper) => {
return RenderNode::build_stepper((*stepper).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<ProgressConfig>>() {
Ok(progress) => {
return RenderNode::build_progress((*progress).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<DatePickerConfig>>() {
Ok(date_picker) => {
return RenderNode::build_date_picker((*date_picker).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<ColorPickerConfig>>() {
Ok(color_picker) => {
return RenderNode::build_color_picker((*color_picker).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<PickerConfig>>() {
Ok(picker) => {
return RenderNode::build_picker((*picker).into_inner(), env);
}
Err(view) => view,
};
let view = match view.downcast::<Native<ResolvedTextFieldConfig>>() {
Ok(text_field) => {
return RenderNode::build_text_field((*text_field).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<SecureFieldConfig>>() {
Ok(secure_field) => {
return RenderNode::build_secure_field((*secure_field).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<BadgeConfig>>() {
Ok(badge) => return RenderNode::build_badge((*badge).into_inner(), env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Native<ListConfig>>() {
Ok(list) => return RenderNode::build_list((*list).into_inner(), env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Native<TableConfig>>() {
Ok(table) => return RenderNode::build_table((*table).into_inner(), env),
Err(view) => view,
};
let view = match view.downcast::<Native<SystemIcon>>() {
Ok(icon) => unsupported_system_icon(icon.as_inner()),
Err(view) => view,
};
let view = match view.downcast::<Native<ResolvedGradient>>() {
Ok(gradient) => return RenderNode::build_gradient((*gradient).into_inner(), env),
Err(view) => view,
};
let view = match view.downcast::<Native<ResolvedShape>>() {
Ok(shape) => return RenderNode::build_shape((*shape).into_inner(), env),
Err(view) => view,
};
let view = match view.downcast::<Native<ResolvedMorphShape>>() {
Ok(shape) => return RenderNode::build_morph_shape((*shape).into_inner(), env),
Err(view) => view,
};
let view = match view.downcast::<Native<MapConfig>>() {
Ok(map) => return RenderNode::build_map((*map).into_inner(), env, renderer),
Err(view) => view,
};
let view = match view.downcast::<WebView>() {
Ok(webview) if env.get::<Hook<WebView>>().is_none() => {
return RenderNode::build_webview(*webview, env, renderer);
}
Ok(webview) => AnyView::new(*webview),
Err(view) => view,
};
let view = match view.downcast::<Native<NavigationView>>() {
Ok(navigation) => {
return RenderNode::build_navigation_view(
(*navigation).into_inner(),
env,
renderer,
);
}
Err(view) => view,
};
let view = match view.downcast::<Native<NavigationSplitLayout>>() {
Ok(split) => {
return RenderNode::build_navigation_split((*split).into_inner(), env, renderer);
}
Err(view) => view,
};
let view = match view.downcast::<Native<NavigationStack<(), ()>>>() {
Ok(stack) => {
return RenderNode::build_navigation_stack((*stack).into_inner(), env);
}
Err(view) => view,
};
let view = match view.downcast::<Native<TabsLayout>>() {
Ok(tabs) => return RenderNode::build_tabs((*tabs).into_inner(), env, renderer),
Err(view) => view,
};
let view = match view.downcast::<Native<Spacer>>() {
Ok(spacer) => return RenderNode::build_spacer((*spacer).into_inner(), env),
Err(view) => view,
};
let view = match view.downcast::<Native<()>>() {
Ok(_) => return RenderNode::build_empty(env),
Err(view) => view,
};
let view = match view.downcast::<Divider>() {
Ok(divider) => return RenderNode::build_divider(*divider, env),
Err(view) => view,
};
let view = match view.downcast::<Str>() {
Ok(text) => return RenderNode::build_str(*text, env),
Err(view) => view,
};
RenderNode::build(AnyView::new(view.body(env)), env, renderer)
}
fn build_wrapper(
effect: WrapperEffect,
content: AnyView,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
RenderNode::Wrapper(Box::new(WrapperNode {
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
effect,
env: env.clone(),
child: RenderNode::build(content, env, renderer),
}))
}
fn build_lifecycle(
hook: LifeCycleHook,
content: AnyView,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let effect = match hook.lifecycle() {
LifeCycle::Appear => LifeCycleEffect {
appear: Cell::new(Some(DeferredLifeCycleHook::new(hook, env.clone()))),
disappear: None,
},
LifeCycle::Disappear => LifeCycleEffect {
appear: Cell::new(None),
disappear: Some(DeferredLifeCycleHook::new(hook, env.clone())),
},
_ => panic!("hydrolysis lifecycle variant is not supported"),
};
RenderNode::build_wrapper(WrapperEffect::LifeCycle(effect), content, env, renderer)
}
fn build_env_scoped<T: MetadataKey + Clone + 'static>(
meta: IgnorableMetadata<T>,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let IgnorableMetadata { content, value } = meta;
let scoped = a11y_scoped_env(env, &value);
let child = RenderNode::build(content, &scoped, renderer);
RenderNode::Env(Box::new(EnvNode { env: scoped, child }))
}
fn build_naming_scoped<T: MetadataKey + Clone + 'static>(
meta: IgnorableMetadata<T>,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let IgnorableMetadata { content, value } = meta;
#[cfg(feature = "accessibility")]
let scoped = a11y_naming_scoped_env(env, &value);
#[cfg(not(feature = "accessibility"))]
let scoped = a11y_scoped_env(env, &value);
let child = RenderNode::build(content, &scoped, renderer);
RenderNode::Env(Box::new(EnvNode { env: scoped, child }))
}
fn build_collection(
layout: Box<dyn Layout>,
views: AnyViews<AnyView>,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let dirty = Rc::new(Cell::new(false));
let dirty_key = Rc::new(());
let key = Rc::as_ptr(&dirty_key) as usize;
let signals = renderer.signals.clone();
let guard = views.watch(.., {
let dirty = Rc::clone(&dirty);
move |_changed| {
dirty.set(true);
signals.mark_collection_dirty(key, 0);
}
});
#[cfg(feature = "accessibility")]
let item_env = accessibility_container_child_environment(env);
#[cfg(feature = "accessibility")]
let accessibility_container_env = item_env.as_ref().map(|_| env.clone());
#[cfg(feature = "accessibility")]
let env = item_env.as_ref().unwrap_or(env);
let len = views.len().get();
let entries = (0..len)
.map(|index| {
let id = views
.get_id(index)
.unwrap_or_else(|| panic!("hydrolysis collection: item {index} has no id"));
let view = views
.get_view(index)
.unwrap_or_else(|| panic!("hydrolysis collection: item {index} missing"));
CollectionEntry::stable(
id,
RenderNode::build(normalize_layout_view(view, env), env, renderer),
)
})
.collect();
let transition = collection_transition_runtime(env, layout.as_ref());
RenderNode::Collection(Box::new(CollectionNode {
layout,
views,
env: env.clone(),
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
#[cfg(feature = "accessibility")]
accessibility_container_env,
entries,
placed: Vec::new(),
transition,
dirty,
_dirty_key: dirty_key,
_guard: guard,
}))
}
fn build_lazy_stack(
axis: LazyStackAxisConfig,
views: AnyViews<AnyView>,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let dirty_key = Rc::new(());
let dirty = Rc::new(Cell::new(true));
let key = Rc::as_ptr(&dirty_key) as usize;
let signals = renderer.signals.clone();
let dirty_for_watch = Rc::clone(&dirty);
let guard = views.watch(.., move |_changed| {
dirty_for_watch.set(true);
signals.mark_collection_dirty(key, 0);
});
let signals = renderer.signals.clone();
let direction_guard = axis.direction().watch(move |_| signals.request_refresh());
#[cfg(feature = "accessibility")]
let item_env = accessibility_container_child_environment(env);
#[cfg(feature = "accessibility")]
let accessibility_container_env = item_env.as_ref().map(|_| env.clone());
#[cfg(feature = "accessibility")]
let env = item_env.as_ref().unwrap_or(env);
RenderNode::LazyStack(Box::new(LazyStackNode {
axis,
views,
env: env.clone(),
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
#[cfg(feature = "accessibility")]
accessibility_container_env,
extent_index: RefCell::new(VirtualExtentIndex::default()),
item_cache: RefCell::new(VisibleSubviewCache::new()),
visible_range: RefCell::new(0..0),
estimate: Cell::new(0.0),
dirty,
_dirty_key: dirty_key,
_guard: guard,
_direction_guard: direction_guard,
}))
}
fn build_scene_view_node(
scene_view: Native<SceneView>,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let mut content = scene_view.into_inner().into_content();
let signals = renderer.signals.clone();
content.set_invalidator(Some(Rc::new(move || {
signals.request_refresh();
})));
RenderNode::SceneView(Box::new(SceneViewNode {
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
content: RefCell::new(content),
}))
}
fn build_gpu_surface(
surface: GpuSurface,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let runtime = Rc::new(RefCell::new(EmbeddedGpuSurfaceRuntime::new(surface, env)));
renderer.register_node_gpu_surface(Rc::clone(&runtime));
RenderNode::GpuSurface(Box::new(GpuSurfaceNode {
#[cfg(feature = "accessibility")]
accessibility_identity: Rc::new(()),
runtime,
}))
}
fn build_view_effect(
mut effect: ViewEffectErased,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let content = effect.take_content();
let child = RenderNode::build(normalize_layout_view(content, env), env, renderer);
let runtime = Rc::new(RefCell::new(ViewEffectRuntime::new(effect)));
renderer.register_node_view_effect(Rc::clone(&runtime));
RenderNode::ViewEffect(Box::new(ViewEffectNode {
runtime,
child: RefCell::new(child),
laid_out: Cell::new(Size::zero()),
env: env.clone(),
}))
}
fn build_applied_filter(
filter: AppliedFilter,
content: AnyView,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let runtime = Rc::new(RefCell::new(AppliedFilterRuntime::new(filter)));
renderer.register_node_applied_filter(Rc::clone(&runtime));
let child = RenderNode::build(normalize_layout_view(content, env), env, renderer);
RenderNode::AppliedFilter(Box::new(AppliedFilterNode {
runtime,
child,
env: env.clone(),
}))
}
fn build_dynamic_host(
dynamic: waterui_core::dynamic::Dynamic,
env: &Environment,
renderer: &mut HydrolysisRenderer,
) -> RenderNode {
let identity = dynamic.identity();
let pending: Rc<RefCell<Option<AnyView>>> = Rc::new(RefCell::new(None));
let source = dynamic.clone();
let signals = renderer.signals.clone();
dynamic.connect_with_pending_view(Rc::clone(&pending), {
let pending = Rc::clone(&pending);
move |update| {
let is_initial = update
.metadata()
.try_get::<DynamicInitialContent>()
.is_some();
*pending.borrow_mut() = Some(update.into_value());
if !is_initial {
signals.mark_dynamic_dirty(identity, 0);
}
}
});
let initial = pending.borrow_mut().take();
let child = match initial {
Some(content) => RenderNode::build(content, env, renderer),
None => RenderNode::build(AnyView::new(()), env, renderer),
};
RenderNode::Dynamic(Box::new(DynamicHostNode {
source,
pending,
env: env.clone(),
child,
}))
}
}