Files
storyteller-bevy/studio/src/ui/utils.rs
T
2024-02-19 22:09:37 +03:00

774 lines
27 KiB
Rust

use ::serde::{Deserialize, Serialize};
use bevy::{ecs::component::ComponentId, prelude::*, reflect::ReflectFromPtr, utils::HashMap};
trait NodeProp: Clone + PartialEq {}
#[derive(Serialize, Deserialize)]
pub enum Mutation {
SetAttibute {
id: String,
attribute: String,
value: String,
},
ReplaceAll(VNode),
RemoveAll,
}
#[derive(Default)]
pub struct Component {
pub tag: String,
pub attributes: Vec<(String, String)>,
pub children: Vec<Element>,
pub onchange: Option<Box<dyn WebEventExecutor + Send + Sync>>,
pub onclick: Option<Box<dyn WebEventExecutor + Send + Sync>>,
}
pub enum Element {
Text(String),
Component(Component),
}
pub trait WebEventExecutor {
fn execute(&mut self, world: &mut World, data: String);
}
#[derive(Default)]
pub struct WebEventStorage {
pub events: HashMap<String, Box<dyn WebEventExecutor + Send + Sync>>,
}
impl WebEventStorage {
pub fn add_event(&mut self, id: String, event: Box<dyn WebEventExecutor + Send + Sync>) {
self.events.insert(id, event);
}
pub fn execute(&mut self, world: &mut World, id: String, data: String) {
if let Some(event) = self.events.get_mut(&id) {
event.execute(world, data);
} else {
println!("No event found for id: {}", id);
}
}
}
#[derive(Default, Resource)]
pub struct VirtualDom {
last_node: Option<VNode>,
pub on_change_events: WebEventStorage,
pub on_click_events: WebEventStorage,
}
impl VirtualDom {
pub fn render(&mut self, element: Option<Element>) -> Vec<Mutation> {
let mut id_counter = 0;
if let Some(element) = element {
let node = self.recursive_unpack_element(&mut id_counter, element);
self.create_mutations(node)
} else {
self.create_mutations(VNode::Text("".to_string()))
}
}
fn recursive_unpack_element(&mut self, counter: &mut usize, element: Element) -> VNode {
match element {
Element::Text(text) => VNode::Text(text),
Element::Component(component) => {
let id = format!("node_{}", *counter);
*counter += 1;
let mut onchange_enabled = false;
if let Some(onchange) = component.onchange {
self.on_change_events.add_event(id.clone(), onchange);
onchange_enabled = true;
}
VNode::Component(VComponent {
tag: component.tag,
attributes: component.attributes.into_iter().collect(),
id: Some(id),
onchange: onchange_enabled,
children: component
.children
.into_iter()
.map(|e| self.recursive_unpack_element(counter, e))
.collect(),
})
}
}
}
pub fn create_mutations(&mut self, node: VNode) -> Vec<Mutation> {
if self.last_node == Some(node.clone()) {
vec![]
} else {
if let Some(last_node) = &self.last_node {
if last_node.is_same_structure(&node) {
let muts = node.get_same_structure_muts(last_node);
self.last_node = Some(node.clone());
return muts;
}
}
self.last_node = Some(node.clone());
vec![Mutation::ReplaceAll(node)]
}
}
}
#[cfg(feature = "wasm")]
pub mod wasm {
use wasm_bindgen::prelude::*;
use crate::wasm::{StaticBuffer, WasmMessageBuffer};
pub static ONCHAGE_BUFFER: WasmMessageBuffer<Vec<(String, String, String)>> = WasmMessageBuffer::new();
#[wasm_bindgen(js_name = register_new_change)]
pub fn register_new_change(id: String, kind: String, value: String) {
let mut data = ONCHAGE_BUFFER.take_message().unwrap_or_default();
data.push((id, kind, value));
ONCHAGE_BUFFER.write_message(data);
}
}
struct ReflectValueExecutor {
change: ReflectChange,
}
impl From<ReflectChange> for ReflectValueExecutor {
fn from(change: ReflectChange) -> Self {
ReflectValueExecutor { change }
}
}
impl WebEventExecutor for ReflectValueExecutor {
fn execute(&mut self, world: &mut World, value: String) {
unsafe {
let world = world.as_unsafe_world_cell();
let app_type_registry: &AppTypeRegistry =
world.get_resource::<AppTypeRegistry>().unwrap();
let type_registry = app_type_registry.read();
let e = world.get_entity(self.change.entity_id).unwrap();
let c_id = ComponentId::new(
self.change
.compoent_id
.split('(')
.nth(1)
.unwrap()
.split(')')
.next()
.unwrap()
.parse()
.unwrap(),
);
if let Some(mut c) = e.get_mut_by_id(c_id) {
let refl = type_registry
.get_type_data::<ReflectFromPtr>(
world
.components()
.get_info_unchecked(c_id)
.type_id()
.unwrap(),
)
.unwrap()
.as_reflect_mut(c.as_mut());
if let Ok(refl_value) = refl.reflect_path_mut(self.change.reflect_path.as_str()) {
if let Some(v) = refl_value.downcast_mut::<String>() {
*v = value;
} else if let Some(v) = refl_value.downcast_mut::<f32>() {
if let Ok(value) = value.parse::<f32>() {
*v = value;
}
} else if let Some(v) = refl_value.downcast_mut::<f64>() {
if let Ok(value) = value.parse::<f64>() {
*v = value;
}
} else if let Some(v) = refl_value.downcast_mut::<bool>() {
if let Ok(value) = value.parse::<bool>() {
*v = value;
}
} else if let Some(v) = refl_value.downcast_mut::<i32>() {
if let Ok(value) = value.parse::<i32>() {
*v = value;
}
} else if let Some(v) = refl_value.downcast_mut::<i64>() {
if let Ok(value) = value.parse::<i64>() {
*v = value;
}
} else if let Some(v) = refl_value.downcast_mut::<u32>() {
if let Ok(value) = value.parse::<u32>() {
*v = value;
}
} else if let Some(v) = refl_value.downcast_mut::<u64>() {
if let Ok(value) = value.parse::<u64>() {
*v = value;
}
}
}
}
}
}
}
struct EntityChangeExecutor {
entity: Entity,
func: Box<dyn Fn(&mut World, Entity, String) + Send + Sync>,
}
impl WebEventExecutor for EntityChangeExecutor {
fn execute(&mut self, world: &mut World, value: String) {
(self.func)(world, self.entity, value);
}
}
impl EntityChangeExecutor {
fn new(
entity: Entity,
func: impl Fn(&mut World, Entity, String) + Send + Sync + 'static,
) -> Self {
EntityChangeExecutor {
entity,
func: Box::new(func),
}
}
fn new_boxed(
entity: Entity,
func: impl Fn(&mut World, Entity, String) + Send + Sync + 'static,
) -> Box<Self> {
Box::new(EntityChangeExecutor::new(entity, func))
}
}
fn euler_to_degrees(euler: (f32, f32, f32)) -> (f32, f32, f32) {
(
euler.0.to_degrees(),
euler.1.to_degrees(),
euler.2.to_degrees(),
)
}
fn check_predefined(r: &dyn Reflect, onchange: ReflectChange) -> Option<Element> {
if let Some(name) = r.downcast_ref::<Name>() {
Some(Element::Component(Component {
tag: "div".to_string(),
attributes: vec![(
"style".to_string(),
"font-weight: bold; font-size: 24px".to_string(),
)],
children: vec![Element::Text(format!("{}", &name))],
..default()
}))
} else if let Some(transform) = r.downcast_ref::<Transform>() {
Some(Element::Component(Component {
tag: "div".to_string(),
attributes: vec![(
"style".to_string(),
"display: flex; flex-direction: column".to_string(),
)],
children: vec![
Element::Text("Pos: ".to_string()),
show_reflect(&transform.translation, onchange.add_path("translation")).unwrap(),
Element::Text("Rot: ".to_string()),
show_reflect(&transform.rotation, onchange.add_path("rotation")).unwrap(),
Element::Text("Scale: ".to_string()),
show_reflect(&transform.scale, onchange.add_path("scale")).unwrap(),
],
..default()
}))
} else if let Some(quat) = r.downcast_ref::<Quat>() {
let euler = quat.to_euler(EulerRot::XYZ);
let degrees = euler_to_degrees(euler);
Some(Element::Component(Component {
tag: "div".to_string(),
attributes: vec![("class".to_string(), "struct-grid".to_string())],
children: vec![
Element::Text("X: ".to_string()),
Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), format!("{:.2}", degrees.0)),
("step".to_string(), "0.01".to_string()),
],
children: vec![],
onchange: Some(EntityChangeExecutor::new_boxed(
onchange.entity_id,
|world: &mut World, entity, value: String| {
let Some(mut value) = value.parse::<f32>().ok() else {
return;
};
if value == -180.0 {
value = 180.0;
}
let value = value.to_radians();
let mut e = world.get_entity_mut(entity).unwrap();
let mut transform = e.get_mut::<Transform>().unwrap();
if transform.is_changed() {
return;
}
let euler = transform.rotation.to_euler(EulerRot::XYZ);
transform.rotation =
Quat::from_euler(EulerRot::XYZ, value, euler.1, euler.2);
},
)),
..default()
}),
Element::Text("Y: ".to_string()),
Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), format!("{:.2}", degrees.1)),
("step".to_string(), "0.01".to_string()),
],
children: vec![],
onchange: Some(EntityChangeExecutor::new_boxed(
onchange.entity_id,
|world: &mut World, entity, value: String| {
let Some(mut value) = value.parse::<f32>().ok() else {
return;
};
if value == -180.0 {
value = 180.0;
}
let mut e = world.get_entity_mut(entity).unwrap();
let mut transform = e.get_mut::<Transform>().unwrap();
if transform.is_changed() {
return;
}
let value = value.to_radians();
let euler = transform.rotation.to_euler(EulerRot::XYZ);
transform.rotation *= Quat::from_axis_angle(Vec3::Y, value - euler.1);
},
)),
..default()
}),
Element::Text("Z: ".to_string()),
Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), format!("{:.2}", degrees.2)),
("step".to_string(), "0.01".to_string()),
],
children: vec![],
onchange: Some(EntityChangeExecutor::new_boxed(
onchange.entity_id,
|world: &mut World, entity, value: String| {
let Some(mut value) = value.parse::<f32>().ok() else {
return;
};
if value == -180.0 {
value = 180.0;
}
let value = value.to_radians();
let mut e = world.get_entity_mut(entity).unwrap();
let mut transform = e.get_mut::<Transform>().unwrap();
if transform.is_changed() {
return;
}
let euler = transform.rotation.to_euler(EulerRot::XYZ);
transform.rotation =
Quat::from_euler(EulerRot::XYZ, euler.0, euler.1, value);
},
)),
..default()
}),
],
..default()
}))
} else {
r.downcast_ref::<Vec3>().map(|vec| {
Element::Component(Component {
tag: "div".to_string(),
attributes: vec![("class".to_string(), "struct-grid".to_string())],
children: vec![
Element::Text("X: ".to_string()),
Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), format!("{:.2}", vec.x)),
("step".to_string(), "0.01".to_string()),
],
children: vec![],
onchange: Some(Box::new(ReflectValueExecutor::from(
onchange.add_path("x"),
))),
..default()
}),
Element::Text("Y: ".to_string()),
Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), format!("{:.2}", vec.y)),
("step".to_string(), "0.01".to_string()),
],
children: vec![],
onchange: Some(Box::new(ReflectValueExecutor::from(
onchange.add_path("y"),
))),
..default()
}),
Element::Text("Z: ".to_string()),
Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), format!("{:.2}", vec.z)),
("step".to_string(), "0.01".to_string()),
],
children: vec![],
onchange: Some(Box::new(ReflectValueExecutor::from(
onchange.add_path("z"),
))),
..default()
}),
],
..default()
})
})
}
}
pub fn show_reflect(r: &dyn Reflect, reflect: ReflectChange) -> Option<Element> {
if let Some(vnode) = check_predefined(r, reflect.clone()) {
return Some(vnode);
}
match r.reflect_ref() {
bevy::reflect::ReflectRef::Struct(_v) => None,
bevy::reflect::ReflectRef::TupleStruct(_) => None,
bevy::reflect::ReflectRef::Tuple(_) => None,
bevy::reflect::ReflectRef::List(_) => None,
bevy::reflect::ReflectRef::Array(_) => None,
bevy::reflect::ReflectRef::Map(_) => None,
bevy::reflect::ReflectRef::Enum(_) => None,
bevy::reflect::ReflectRef::Value(v) => {
if let Some(s) = v.downcast_ref::<String>() {
Some(Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "text".to_string()),
("value".to_string(), s.to_string()),
],
children: vec![],
onchange: Some(Box::new(ReflectValueExecutor::from(reflect))),
..default()
}))
} else if let Some(b) = v.downcast_ref::<bool>() {
Some(Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "checkbox".to_string()),
("value".to_string(), b.to_string()),
],
children: vec![],
onchange: Some(Box::new(ReflectValueExecutor::from(reflect))),
..default()
}))
} else if let Some(i) = v.downcast_ref::<i32>() {
Some(Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), i.to_string()),
],
children: vec![],
onchange: Some(Box::new(ReflectValueExecutor::from(reflect))),
..default()
}))
} else if let Some(f) = v.downcast_ref::<f32>() {
Some(Element::Component(Component {
tag: "input".to_string(),
attributes: vec![
("type".to_string(), "number".to_string()),
("value".to_string(), f.to_string()),
],
children: vec![],
onchange: Some(Box::new(ReflectValueExecutor::from(reflect))),
..default()
}))
} else {
Some(Element::Text(format!("{:?}", v)))
}
}
}
}
impl<T: Clone + PartialEq> NodeProp for T {}
#[derive(Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct VComponent {
pub tag: String,
pub attributes: Vec<(String, String)>,
pub children: Vec<VNode>,
pub id: Option<String>,
pub onchange: bool,
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum VNode {
Text(String),
Component(VComponent),
}
impl VNode {
pub fn is_same_structure(&self, other: &VNode) -> bool {
match (self, other) {
(VNode::Text(s1), VNode::Text(s2)) => s1 == s2,
(VNode::Text(_), VNode::Component(_)) => false,
(VNode::Component(_), VNode::Text(_)) => false,
(VNode::Component(c1), VNode::Component(c2)) => {
if c1.tag != c2.tag {
false
} else if c1.children.len() != c2.children.len() {
return false;
} else {
for i in 0..c1.children.len() {
if !c1.children[i].is_same_structure(&c2.children[i]) {
return false;
}
}
return true;
}
}
}
}
pub fn get_same_structure_muts(&self, older: &VNode) -> Vec<Mutation> {
let mut res = vec![];
match (self, older) {
(VNode::Text(_s1), VNode::Text(_s2)) => res,
(VNode::Text(_), VNode::Component(_)) => res,
(VNode::Component(_), VNode::Text(_)) => res,
(VNode::Component(new), VNode::Component(old)) => {
for idx in 0..new.attributes.len() {
if new.attributes.get(idx) != old.attributes.get(idx) {
res.push(Mutation::SetAttibute {
id: old.id.as_ref().unwrap().clone(),
attribute: new.attributes[idx].0.clone(),
value: new.attributes[idx].1.clone(),
});
}
}
for i in 0..new.children.len() {
res.append(&mut new.children[i].get_same_structure_muts(&old.children[i]));
}
res
}
}
}
}
pub struct InspectedEntity {
pub id: Option<Entity>,
pub components: Vec<Box<dyn Reflect>>,
}
pub struct ComponentProp {
pub component: Box<dyn Reflect>,
}
impl Clone for ComponentProp {
fn clone(&self) -> Self {
Self {
component: self.component.clone_value(),
}
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct ReflectChange {
pub entity_id: Entity,
pub reflect_path: String,
pub compoent_id: String,
}
impl ReflectChange {
pub fn add_path(&self, path: &str) -> ReflectChange {
ReflectChange {
entity_id: self.entity_id,
compoent_id: self.compoent_id.clone(),
reflect_path: format!("{}.{}", self.reflect_path, path),
}
}
}
impl PartialEq for ComponentProp {
fn eq(&self, other: &Self) -> bool {
recursive_reflect_eq(self.component.as_ref(), other.component.as_ref())
}
}
pub fn recursive_reflect_eq(a: &dyn Reflect, b: &dyn Reflect) -> bool {
let ref_a = a.reflect_ref();
let _ref_b = b.reflect_ref();
match ref_a {
bevy::reflect::ReflectRef::Struct(a) => {
let bevy::reflect::ReflectRef::Struct(b) = b.reflect_ref() else {
return false;
};
if a.field_len() != b.field_len() {
return false;
}
for i in 0..a.field_len() {
if !recursive_reflect_eq(a.field_at(i).unwrap(), b.field_at(i).unwrap()) {
return false;
}
}
}
bevy::reflect::ReflectRef::TupleStruct(a) => {
let bevy::reflect::ReflectRef::TupleStruct(b) = b.reflect_ref() else {
return false;
};
if a.field_len() != b.field_len() {
return false;
}
for i in 0..a.field_len() {
if !recursive_reflect_eq(a.field(i).unwrap(), b.field(i).unwrap()) {
return false;
}
}
}
bevy::reflect::ReflectRef::Tuple(a) => {
let bevy::reflect::ReflectRef::Tuple(b) = b.reflect_ref() else {
return false;
};
if a.field_len() != b.field_len() {
return false;
}
for i in 0..a.field_len() {
if !recursive_reflect_eq(a.field(i).unwrap(), b.field(i).unwrap()) {
return false;
}
}
}
bevy::reflect::ReflectRef::List(a) => {
let bevy::reflect::ReflectRef::List(b) = b.reflect_ref() else {
return false;
};
if a.len() != b.len() {
return false;
}
for i in 0..a.len() {
if !recursive_reflect_eq(a.get(i).unwrap(), b.get(i).unwrap()) {
return false;
}
}
}
bevy::reflect::ReflectRef::Array(a) => {
let bevy::reflect::ReflectRef::Array(b) = b.reflect_ref() else {
return false;
};
if a.len() != b.len() {
return false;
}
for i in 0..a.len() {
if !recursive_reflect_eq(a.get(i).unwrap(), b.get(i).unwrap()) {
return false;
}
}
}
bevy::reflect::ReflectRef::Map(a) => {
let bevy::reflect::ReflectRef::Map(b) = b.reflect_ref() else {
return false;
};
if a.len() != b.len() {
return false;
};
for i in 0..a.len() {
let (a_key, a_value) = a.get_at(i).unwrap();
let Some(b_value) = b.get(a_key) else {
return false;
};
if !recursive_reflect_eq(a_value, b_value) {
return false;
}
}
}
bevy::reflect::ReflectRef::Enum(a) => {
let bevy::reflect::ReflectRef::Enum(b) = b.reflect_ref() else {
return false;
};
if a.variant_name() != b.variant_name() {
return false;
}
if a.field_len() != b.field_len() {
return false;
}
for i in 0..a.field_len() {
if !recursive_reflect_eq(a.field_at(i).unwrap(), b.field_at(i).unwrap()) {
return false;
}
}
}
bevy::reflect::ReflectRef::Value(a) => {
let bevy::reflect::ReflectRef::Value(b) = b.reflect_ref() else {
return false;
};
if let Some(res) = a.reflect_partial_eq(b) {
return res;
} else {
return false;
}
}
}
false
}
impl PartialEq for InspectedEntity {
fn eq(&self, other: &Self) -> bool {
if self.id != other.id {
return false;
}
if self.components.len() != other.components.len() {
return false;
}
for i in 0..self.components.len() {
if !recursive_reflect_eq(self.components[i].as_ref(), other.components[i].as_ref()) {
return false;
}
}
true
}
}
impl InspectedEntity {
pub fn none() -> Self {
Self {
id: None,
components: Vec::new(),
}
}
}