use bevy::image::Image;
use bevy::prelude::*;
use bevy::ui::widget::NodeImageMode;
use super::stamps::{apply_animated, apply_pointer_handlers, stamp_common};
use crate::bridge::RNode;
use crate::canvas::blank_canvas_image;
use crate::protocol::{NodeId, props::Props};
use crate::svg::{ShapeKind, SvgShape, SvgSurface, SvgUserPos};
use crate::ui_map::apply_style;
pub(super) fn create_svg_root(
commands: &mut Commands,
images: &mut Assets<Image>,
id: NodeId,
props: &Props,
) -> Entity {
let handle = images.add(blank_canvas_image());
let mut node_img = ImageNode::new(handle);
node_img.image_mode = NodeImageMode::Stretch;
let mut ec = commands.spawn(RNode(id));
apply_style(&mut ec, &props.style);
ec.insert((node_img, SvgSurface::jsx(props.view_box)));
stamp_common(&mut ec, props);
ec.id()
}
pub(super) fn create_shape(
commands: &mut Commands,
id: NodeId,
kind: ShapeKind,
props: &Props,
) -> Entity {
let attrs = props.shape.clone().unwrap_or_default();
let mut ec = commands.spawn((RNode(id), SvgShape { kind, attrs }));
apply_shape_pointer(&mut ec, props);
apply_animated(&mut ec, props);
crate::transition::apply_shape_transition(&mut ec, props.shape.as_ref());
warn_shape_scroll(props);
ec.id()
}
pub(super) fn apply_shape_pointer(ec: &mut EntityCommands, props: &Props) {
apply_pointer_handlers(ec, props);
let any = props.on_click
|| props.on_pointer_down
|| props.on_pointer_move
|| props.on_pointer_up
|| props.on_pointer_enter
|| props.on_pointer_leave;
if any {
ec.insert_if_new(SvgUserPos::default());
} else {
ec.remove::<Interaction>();
ec.remove::<SvgUserPos>();
}
}
pub(super) fn warn_shape_scroll(props: &Props) {
for (present, name) in [(props.on_scroll, "onScroll"), (props.on_wheel, "onWheel")] {
if present {
crate::diag::report(
"svgShapeScroll",
name,
&format!(
"`{name}` on an SVG shape never fires \
(shapes are Node-less — no scroll surface)"
),
);
}
}
}
pub(super) fn update_shape_attrs(ec: &mut EntityCommands, props: &Props) {
let attrs = props.shape.clone().unwrap_or_default();
ec.queue(move |mut entity: EntityWorldMut| {
if entity.get::<SvgShape>().is_some_and(|s| s.attrs != attrs)
&& let Some(mut shape) = entity.get_mut::<SvgShape>()
{
shape.attrs = attrs;
}
});
}
pub(super) fn update_view_box(ec: &mut EntityCommands, props: &Props) {
let view_box = props.view_box;
ec.queue(move |mut entity: EntityWorldMut| {
if entity
.get::<SvgSurface>()
.is_some_and(|s| s.view_box != view_box)
&& let Some(mut surface) = entity.get_mut::<SvgSurface>()
{
surface.view_box = view_box;
surface.dirty = true;
}
});
}