use bevy::asset::{AssetServer, Assets, Handle};
use bevy::ecs::bundle::Bundle;
use bevy::ecs::entity::Entity;
use bevy::ecs::system::Commands;
use bevy::image::Image;
use super::attribute::AnyAttribute;
use super::event::AnyElementEvent;
use crate::bridge::ResolvedTextStyle;
use crate::ext::ElementFlags;
use crate::protocol::{NodeId, props::Props};
use crate::style::{Style, Writer};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Common(u8);
impl Common {
pub const IDENTITY: Self = Self(1);
pub const VARIANTS: Self = Self(1 << 1);
pub const POINTER: Self = Self(1 << 2);
pub const SCROLL: Self = Self(1 << 3);
pub const WHEEL: Self = Self(1 << 4);
pub const ALL: Self = Self(0b11111);
pub const fn with(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
}
pub type SpawnFn = fn(&mut SpawnCtx<'_, '_, '_>) -> Entity;
pub struct Element {
pub name: &'static str,
pub flags: ElementFlags,
pub attrs: &'static [&'static dyn AnyAttribute],
pub required: &'static [&'static dyn AnyAttribute],
pub common: Common,
pub writers: &'static [&'static Writer],
pub suppress: &'static [&'static Writer],
pub events: &'static [&'static dyn AnyElementEvent],
pub default_style: Option<fn() -> Style>,
pub spawn: Option<SpawnFn>,
pub ts_ref: Option<&'static str>,
}
impl Element {
pub const fn new(name: &'static str) -> Self {
Self {
name,
flags: ElementFlags::NODE,
attrs: &[],
required: &[],
common: Common::ALL,
writers: &[],
suppress: &[],
events: &[],
default_style: None,
spawn: None,
ts_ref: None,
}
}
}
impl std::fmt::Debug for Element {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Element({:?})", self.name)
}
}
pub struct SpawnCtx<'a, 'w, 's> {
pub commands: &'a mut Commands<'w, 's>,
pub images: &'a mut Assets<Image>,
pub assets: &'a AssetServer,
pub(crate) fonts: &'a crate::plugin::Fonts,
pub id: NodeId,
pub kind: &'a str,
pub props: &'a Props,
pub style: &'a Option<Style>,
pub text: Option<&'a str>,
pub flags: ElementFlags,
}
impl SpawnCtx<'_, '_, '_> {
pub fn spawn(&mut self, extra: impl Bundle) -> Entity {
let base = (crate::bridge::ReactNode(self.id), self.flags);
if self.flags.node_less {
self.commands.spawn((base, extra)).id()
} else {
self.commands
.spawn((
base,
crate::ui_map::fresh_style_bundle(self.style, self.flags),
extra,
))
.id()
}
}
pub fn blank_image(&mut self) -> Handle<Image> {
self.images.add(crate::raster::blank_image())
}
pub fn text_style(&self) -> ResolvedTextStyle {
crate::ui_map::resolved_text_style(self.style.as_ref(), self.fonts, false)
}
}