use crate::events::ElementSpawn;
use crate::props::Properties;
use crate::widgets::Widget;
use bevy::color::Color;
use bevy::prelude::{
BorderColor, ChildOf, Component, Entity, GlobalTransform, Interaction, Transform, World,
};
use bevy::ui::{BackgroundColor, Node};
use rustc_hash::FxHashMap;
use smol_str::SmolStr;
#[derive(Debug)]
pub struct Element {
pub widget: Box<dyn Widget>,
pub props: Properties<ElementProps>,
pub id: Option<ElementId>,
pub children: Vec<Element>,
}
impl Element {
pub fn spawn(
&self,
world: &mut World,
parent: Option<Entity>,
reg: &mut FxHashMap<ElementId, Entity>,
) -> Entity {
let props = &self.props.default;
let root_entity = world
.spawn((
self.props.clone(),
props.node.clone(),
Interaction::None,
Transform::default(),
GlobalTransform::default(),
BackgroundColor(props.bg_color.unwrap_or(Color::NONE)),
props.border_color.unwrap_or(BorderColor::DEFAULT),
ElementState::Inactive,
))
.id();
if let Some(parent_entity) = parent {
world.entity_mut(root_entity).insert(ChildOf(parent_entity));
}
if let Some(id) = &self.id {
world.entity_mut(root_entity).insert(id.clone());
}
let target_entity = self.widget.spawn(root_entity, world);
for child in &self.children {
child.spawn(world, Some(target_entity), reg);
}
if let Some(id) = self.id() {
reg.insert(id, root_entity);
}
world.trigger(ElementSpawn {
entity: root_entity,
id: self.id(),
});
root_entity
}
#[inline(always)]
pub fn id(&self) -> Option<ElementId> {
self.id.clone()
}
}
#[derive(Clone, Debug, Default)]
pub struct ElementProps {
pub node: Node,
pub bg_color: Option<Color>,
pub border_color: Option<BorderColor>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Component)]
pub struct ElementId(SmolStr);
impl ElementId {
#[inline(always)]
pub fn new(s: impl AsRef<str>) -> Self {
Self(SmolStr::new(s))
}
#[inline(always)]
pub fn new_static(s: &'static str) -> Self {
Self(SmolStr::new_static(s))
}
}
impl From<&'static str> for ElementId {
#[inline(always)]
fn from(s: &'static str) -> Self {
Self::new_static(s)
}
}
impl PartialEq<str> for ElementId {
#[inline(always)]
fn eq(&self, other: &str) -> bool {
self.0.as_str() == other
}
}
impl PartialEq<&str> for ElementId {
#[inline(always)]
fn eq(&self, other: &&str) -> bool {
self.0.as_str() == *other
}
}
impl PartialEq<ElementId> for &str {
#[inline(always)]
fn eq(&self, other: &ElementId) -> bool {
*self == other.0.as_str()
}
}
impl PartialEq<String> for ElementId {
#[inline(always)]
fn eq(&self, other: &String) -> bool {
self.0.as_str() == other.as_str()
}
}
impl PartialEq<ElementId> for String {
#[inline(always)]
fn eq(&self, other: &ElementId) -> bool {
self.as_str() == other.0.as_str()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Component)]
pub enum ElementState {
Active,
Inactive,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Component)]
pub struct ElementActive;