mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-29 09:08:58 +00:00
Part of change pass to bevy
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { type InspectorDomChanged } from "dist/studio/studio";
|
import { register_new_change, type InspectorDomChanged } from "@storyteller/studio";
|
||||||
|
|
||||||
console.log("Hello, World!");
|
console.log("Hello, World!");
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ function unpack_vnode(
|
|||||||
var attr = node_data["attributes"][i];
|
var attr = node_data["attributes"][i];
|
||||||
element.setAttribute(attr[0], attr[1]);
|
element.setAttribute(attr[0], attr[1]);
|
||||||
}
|
}
|
||||||
|
element.setAttribute("onchange_id", node_data["onchange"]);
|
||||||
//apply children
|
//apply children
|
||||||
if (node_data["children"] != undefined) {
|
if (node_data["children"] != undefined) {
|
||||||
for (var j = 0; j < node_data["children"].length; j++) {
|
for (var j = 0; j < node_data["children"].length; j++) {
|
||||||
@@ -24,6 +25,17 @@ function unpack_vnode(
|
|||||||
element.appendChild(child_element);
|
element.appendChild(child_element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//add onchange hook if input
|
||||||
|
if (node_data["tag"] == "input") {
|
||||||
|
element.onchange = (event: Event) => {
|
||||||
|
const input = event.target as HTMLInputElement;
|
||||||
|
const id = input.getAttribute("onchange_id");
|
||||||
|
if (id) {
|
||||||
|
const value = input.value;
|
||||||
|
register_new_change(id, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,21 +49,31 @@ function apply_muts(
|
|||||||
var lit_root = document.getElementById("inspector");
|
var lit_root = document.getElementById("inspector");
|
||||||
var shadowroot = lit_root?.shadowRoot;
|
var shadowroot = lit_root?.shadowRoot;
|
||||||
var root = shadowroot?.getElementById("inspector");
|
var root = shadowroot?.getElementById("inspector");
|
||||||
console.log("root", root);
|
|
||||||
if (root) {
|
if (root) {
|
||||||
//remove all children
|
//remove all children
|
||||||
while (root.firstChild) {
|
|
||||||
root.removeChild(root.firstChild);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
console.log("root not found");
|
console.log("root not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var vdom = JSON.parse(event.detail);
|
var muts = JSON.parse(event.detail);
|
||||||
|
|
||||||
var element = unpack_vnode(vdom);
|
if (muts.length > 0) {
|
||||||
root.appendChild(element);
|
console.log("muts", muts);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < muts.length; i++) {
|
||||||
|
var mut = muts[i];
|
||||||
|
if (mut["ReplaceAll"] != undefined) {
|
||||||
|
var vnode = mut["ReplaceAll"];
|
||||||
|
var element = unpack_vnode(vnode);
|
||||||
|
while (root.firstChild) {
|
||||||
|
root.removeChild(root.firstChild);
|
||||||
|
}
|
||||||
|
root.appendChild(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log('Selection has been cleared.');
|
console.log('Selection has been cleared.');
|
||||||
@@ -61,7 +83,6 @@ function apply_muts(
|
|||||||
document.addEventListener('inspector-dom-changed', (event: CustomEvent) => {
|
document.addEventListener('inspector-dom-changed', (event: CustomEvent) => {
|
||||||
// Cast the event to the InspectorDomChanged type to access its details in TypeScript
|
// Cast the event to the InspectorDomChanged type to access its details in TypeScript
|
||||||
const customEvent = event as InspectorDomChanged;
|
const customEvent = event as InspectorDomChanged;
|
||||||
console.log(customEvent);
|
|
||||||
// Now you can access the detail property, which is either a string or null
|
// Now you can access the detail property, which is either a string or null
|
||||||
apply_muts(customEvent);
|
apply_muts(customEvent);
|
||||||
});
|
});
|
||||||
|
|||||||
+74
-16
@@ -1,6 +1,6 @@
|
|||||||
use std::{sync::{Arc, Mutex, RwLock}, thread::yield_now};
|
use std::{any::Any, sync::{Arc, Mutex, RwLock}, thread::yield_now};
|
||||||
|
|
||||||
use bevy::{ecs::world::unsafe_world_cell::{UnsafeEntityCell, UnsafeWorldCell}, prelude::*, reflect::TypeData, utils::{hashbrown::HashMap, tracing::field}, window::PrimaryWindow};
|
use bevy::{ecs::{component::ComponentId, world::unsafe_world_cell::{UnsafeEntityCell, UnsafeWorldCell}}, prelude::*, reflect::{ReflectFromPtr, TypeData}, utils::{hashbrown::HashMap, tracing::field}, window::PrimaryWindow};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use space_editor::{prelude::Selected, space_editor_ui::inspector::inspect};
|
use space_editor::{prelude::Selected, space_editor_ui::inspector::inspect};
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
@@ -8,7 +8,7 @@ use web_sys::HtmlElement;
|
|||||||
|
|
||||||
use crate::{ui::inspector::wasm::notify_dom_changed, wasm::{StaticBuffer, WasmMessageBuffer}};
|
use crate::{ui::inspector::wasm::notify_dom_changed, wasm::{StaticBuffer, WasmMessageBuffer}};
|
||||||
|
|
||||||
use super::utils::{show_reflect, ComponentProp, InspectedEntity, VComponent, VNode};
|
use super::utils::{show_reflect, ComponentProp, InspectedEntity, ReflectChange, VComponent, VNode, VirtualDom};
|
||||||
|
|
||||||
pub struct InspectorPlugin;
|
pub struct InspectorPlugin;
|
||||||
|
|
||||||
@@ -58,6 +58,9 @@ impl InspectorFunctions {
|
|||||||
fn show_selected(
|
fn show_selected(
|
||||||
world: &mut World
|
world: &mut World
|
||||||
) {
|
) {
|
||||||
|
if !world.is_resource_added::<VirtualDom>() {
|
||||||
|
world.init_resource::<VirtualDom>();
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let cell = world.as_unsafe_world_cell();
|
let cell = world.as_unsafe_world_cell();
|
||||||
|
|
||||||
@@ -69,25 +72,87 @@ fn show_selected(
|
|||||||
|
|
||||||
let mut functions = cell.get_resource_mut::<InspectorFunctions>().unwrap();
|
let mut functions = cell.get_resource_mut::<InspectorFunctions>().unwrap();
|
||||||
|
|
||||||
|
let mut virtial_dom = cell.get_resource_mut::<VirtualDom>().unwrap();
|
||||||
|
let app_type_registry = cell.get_resource::<AppTypeRegistry>().unwrap();
|
||||||
|
let app_type_registry = app_type_registry.read();
|
||||||
|
|
||||||
let e = cell.get_entity(selected_entity).unwrap();
|
let e = cell.get_entity(selected_entity).unwrap();
|
||||||
|
|
||||||
let mut cell = InspectedEntity::none();
|
if let Some(changes) = super::utils::wasm::ONCHAGE_BUFFER.take_message() {
|
||||||
cell.id = Some(e.id());
|
for (change_id, value) in changes {
|
||||||
cell.components = functions.get_reflect_copy(&e);
|
info!("change: {} : {}", change_id, value);
|
||||||
|
|
||||||
|
let change = serde_json::from_str::<ReflectChange>(&change_id).unwrap();
|
||||||
|
let c_id = ComponentId::new(
|
||||||
|
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 mut refl = app_type_registry.get_type_data::<ReflectFromPtr>(cell.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(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>() {
|
||||||
|
*v = value.parse().unwrap();
|
||||||
|
} else if let Some(v) = refl_value.downcast_mut::<f64>() {
|
||||||
|
*v = value.parse().unwrap();
|
||||||
|
} else if let Some(v) = refl_value.downcast_mut::<bool>() {
|
||||||
|
*v = value.parse().unwrap();
|
||||||
|
} else if let Some(v) = refl_value.downcast_mut::<i32>() {
|
||||||
|
*v = value.parse().unwrap();
|
||||||
|
} else if let Some(v) = refl_value.downcast_mut::<i64>() {
|
||||||
|
*v = value.parse().unwrap();
|
||||||
|
} else if let Some(v) = refl_value.downcast_mut::<u32>() {
|
||||||
|
*v = value.parse().unwrap();
|
||||||
|
} else if let Some(v) = refl_value.downcast_mut::<u64>() {
|
||||||
|
*v = value.parse().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let mut inspected = InspectedEntity::none();
|
||||||
|
inspected.id = Some(e.id());
|
||||||
|
inspected.components = functions.get_reflect_copy(&e);
|
||||||
|
|
||||||
|
let id = e.id();
|
||||||
|
|
||||||
|
let components = cell.components().clone();
|
||||||
let vnode = VNode::Component(VComponent {
|
let vnode = VNode::Component(VComponent {
|
||||||
tag: "div".to_string(),
|
tag: "div".to_string(),
|
||||||
attributes: vec![
|
attributes: vec![
|
||||||
|
|
||||||
],
|
],
|
||||||
children: cell.components.into_iter().map(|c| show_reflect(c.as_ref())).filter_map(|c| c).collect(),
|
children: inspected.components.into_iter().map(|c| {
|
||||||
|
show_reflect(
|
||||||
|
c.as_ref(),
|
||||||
|
ReflectChange {
|
||||||
|
entity_id: id.index(),
|
||||||
|
generation: id.generation(),
|
||||||
|
reflect_path: "".to_string(),
|
||||||
|
compoent_id: format!("{:?}", components.get_id(c.get_represented_type_info().unwrap().type_id()).unwrap()),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.filter_map(|v| v)
|
||||||
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let muts = virtial_dom.create_mutations(Some(vnode));
|
||||||
|
|
||||||
let q_window = world.query_filtered::<&Window, With<PrimaryWindow>>().single(world);
|
|
||||||
|
|
||||||
let _ = notify_dom_changed(q_window, serde_json::to_string(&vnode).unwrap());
|
let q_window = cell.world_mut().query_filtered::<&Window, With<PrimaryWindow>>().single(cell.world());
|
||||||
|
|
||||||
|
let _ = notify_dom_changed(q_window, serde_json::to_string(&muts).unwrap());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,12 +194,5 @@ declare global {
|
|||||||
wasm::dispatch_to_js(q_window, "inspector-dom-changed", &msg)
|
wasm::dispatch_to_js(q_window, "inspector-dom-changed", &msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static MUTATION_BUFFER: WasmMessageBuffer<String> = WasmMessageBuffer::new();
|
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = getMutation)]
|
|
||||||
pub fn get_mutation() -> String {
|
|
||||||
|
|
||||||
|
|
||||||
MUTATION_BUFFER.take_message().unwrap_or("{}".to_string())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+76
-23
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
use bevy::{prelude::*, utils::HashMap};
|
use bevy::{prelude::*, utils::HashMap};
|
||||||
use ::serde::{Serialize, Deserialize};
|
use ::serde::{Serialize, Deserialize};
|
||||||
use uuid::*;
|
use uuid::*;
|
||||||
@@ -7,7 +9,45 @@ trait NodeProp : Clone + PartialEq {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_predefined(r : &dyn Reflect) -> Option<VNode> {
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub enum Mutation {
|
||||||
|
ReplaceAll(VNode),
|
||||||
|
RemoveAll
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Resource)]
|
||||||
|
pub struct VirtualDom {
|
||||||
|
last_node : Option<VNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualDom {
|
||||||
|
pub fn create_mutations(&mut self, node : Option<VNode>) -> Vec<Mutation> {
|
||||||
|
if self.last_node == node {
|
||||||
|
return vec![]
|
||||||
|
} else {
|
||||||
|
self.last_node = node.clone();
|
||||||
|
return vec![Mutation::ReplaceAll(node.unwrap())]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wasm")]
|
||||||
|
pub mod wasm {
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
use crate::wasm::{StaticBuffer, WasmMessageBuffer};
|
||||||
|
|
||||||
|
pub static ONCHAGE_BUFFER: WasmMessageBuffer<Vec<(String, String)>> = WasmMessageBuffer::new();
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = register_new_change)]
|
||||||
|
pub fn register_new_change(change : String, value : String) {
|
||||||
|
let mut data = ONCHAGE_BUFFER.take_message().unwrap_or_default();
|
||||||
|
data.push((change, value));
|
||||||
|
ONCHAGE_BUFFER.write_message(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_predefined(r : &dyn Reflect, onchange : ReflectChange) -> Option<VNode> {
|
||||||
if let Some(name) = r.downcast_ref::<Name>() {
|
if let Some(name) = r.downcast_ref::<Name>() {
|
||||||
Some(VNode::Component(VComponent {
|
Some(VNode::Component(VComponent {
|
||||||
tag: "input".to_string(),
|
tag: "input".to_string(),
|
||||||
@@ -16,19 +56,20 @@ fn check_predefined(r : &dyn Reflect) -> Option<VNode> {
|
|||||||
("value".to_string(), name.to_string()),
|
("value".to_string(), name.to_string()),
|
||||||
],
|
],
|
||||||
children: vec![],
|
children: vec![],
|
||||||
onchange: None
|
onchange: Some(onchange.add_path("name").to_string())
|
||||||
}))
|
}))
|
||||||
} else if let Some(transform) = r.downcast_ref::<Transform>() {
|
} else if let Some(transform) = r.downcast_ref::<Transform>() {
|
||||||
|
|
||||||
Some(VNode::Component(VComponent {
|
Some(VNode::Component(VComponent {
|
||||||
tag: "div".to_string(),
|
tag: "div".to_string(),
|
||||||
attributes: vec![],
|
attributes: vec![],
|
||||||
children: vec![
|
children: vec![
|
||||||
VNode::Text("Pos: ".to_string()),
|
VNode::Text("Pos: ".to_string()),
|
||||||
show_reflect(&transform.translation).unwrap(),
|
show_reflect(&transform.translation, onchange.add_path("translation")).unwrap(),
|
||||||
VNode::Text("Rot: ".to_string()),
|
VNode::Text("Rot: ".to_string()),
|
||||||
show_reflect(&transform.rotation).unwrap(),
|
show_reflect(&transform.rotation, onchange.add_path("rotation")).unwrap(),
|
||||||
VNode::Text("Scale: ".to_string()),
|
VNode::Text("Scale: ".to_string()),
|
||||||
show_reflect(&transform.scale).unwrap(),
|
show_reflect(&transform.scale, onchange.add_path("scale")).unwrap(),
|
||||||
],
|
],
|
||||||
onchange: None
|
onchange: None
|
||||||
}))
|
}))
|
||||||
@@ -116,9 +157,9 @@ fn check_predefined(r : &dyn Reflect) -> Option<VNode> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_reflect(r : &dyn Reflect) -> Option<VNode> {
|
pub fn show_reflect(r : &dyn Reflect, reflect: ReflectChange) -> Option<VNode> {
|
||||||
|
|
||||||
if let Some(vnode) = check_predefined(r) {
|
if let Some(vnode) = check_predefined(r, reflect.clone()) {
|
||||||
return Some(vnode);
|
return Some(vnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +195,7 @@ pub fn show_reflect(r : &dyn Reflect) -> Option<VNode> {
|
|||||||
("value".to_string(), s.to_string()),
|
("value".to_string(), s.to_string()),
|
||||||
],
|
],
|
||||||
children: vec![],
|
children: vec![],
|
||||||
onchange: None
|
onchange: Some(reflect.to_string())
|
||||||
}))
|
}))
|
||||||
} else if let Some(b) = v.downcast_ref::<bool>() {
|
} else if let Some(b) = v.downcast_ref::<bool>() {
|
||||||
Some(VNode::Component(VComponent {
|
Some(VNode::Component(VComponent {
|
||||||
@@ -164,7 +205,7 @@ pub fn show_reflect(r : &dyn Reflect) -> Option<VNode> {
|
|||||||
("value".to_string(), b.to_string()),
|
("value".to_string(), b.to_string()),
|
||||||
],
|
],
|
||||||
children: vec![],
|
children: vec![],
|
||||||
onchange: None
|
onchange: Some(reflect.to_string())
|
||||||
}))
|
}))
|
||||||
} else if let Some(i) = v.downcast_ref::<i32>() {
|
} else if let Some(i) = v.downcast_ref::<i32>() {
|
||||||
Some(VNode::Component(VComponent {
|
Some(VNode::Component(VComponent {
|
||||||
@@ -174,7 +215,7 @@ pub fn show_reflect(r : &dyn Reflect) -> Option<VNode> {
|
|||||||
("value".to_string(), i.to_string()),
|
("value".to_string(), i.to_string()),
|
||||||
],
|
],
|
||||||
children: vec![],
|
children: vec![],
|
||||||
onchange: None
|
onchange: Some(reflect.to_string())
|
||||||
}))
|
}))
|
||||||
} else if let Some(f) = v.downcast_ref::<f32>() {
|
} else if let Some(f) = v.downcast_ref::<f32>() {
|
||||||
Some(VNode::Component(VComponent {
|
Some(VNode::Component(VComponent {
|
||||||
@@ -184,7 +225,7 @@ pub fn show_reflect(r : &dyn Reflect) -> Option<VNode> {
|
|||||||
("value".to_string(), f.to_string()),
|
("value".to_string(), f.to_string()),
|
||||||
],
|
],
|
||||||
children: vec![],
|
children: vec![],
|
||||||
onchange: None
|
onchange: Some(reflect.to_string())
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
Some(VNode::Text(format!("{:?}", v)))
|
Some(VNode::Text(format!("{:?}", v)))
|
||||||
@@ -204,7 +245,7 @@ pub struct VComponent {
|
|||||||
pub tag: String,
|
pub tag: String,
|
||||||
pub attributes: Vec<(String, String)>,
|
pub attributes: Vec<(String, String)>,
|
||||||
pub children: Vec<VNode>,
|
pub children: Vec<VNode>,
|
||||||
pub onchange: Option<String> // event name if onchange is set
|
pub onchange: Option<String> // id for onchange detection
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -213,17 +254,6 @@ pub enum VNode {
|
|||||||
Component(VComponent),
|
Component(VComponent),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Element<P: NodeProp> {
|
|
||||||
last_prop: Option<P>,
|
|
||||||
last_elements: Vec<VNode>,
|
|
||||||
prop_event : HashMap<String, Box<dyn FnMut(&mut P, &str)>>,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VirtualDom {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InspectedEntity {
|
pub struct InspectedEntity {
|
||||||
pub id: Option<Entity>,
|
pub id: Option<Entity>,
|
||||||
pub components: Vec<Box<dyn Reflect>>,
|
pub components: Vec<Box<dyn Reflect>>,
|
||||||
@@ -241,6 +271,29 @@ impl Clone for ComponentProp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ReflectChange {
|
||||||
|
pub entity_id : u32,
|
||||||
|
pub generation : u32,
|
||||||
|
pub reflect_path: String,
|
||||||
|
pub compoent_id: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReflectChange {
|
||||||
|
pub fn add_path(&self, path : &str) -> ReflectChange {
|
||||||
|
ReflectChange {
|
||||||
|
entity_id : self.entity_id,
|
||||||
|
generation : self.generation,
|
||||||
|
compoent_id : self.compoent_id.clone(),
|
||||||
|
reflect_path : format!("{}.{}", self.reflect_path, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
serde_json::to_string(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> PartialEq for ComponentProp {
|
impl<'a> PartialEq for ComponentProp {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
recursive_reflect_eq(self.component.as_ref(), other.component.as_ref())
|
recursive_reflect_eq(self.component.as_ref(), other.component.as_ref())
|
||||||
|
|||||||
Reference in New Issue
Block a user