From 7e0c3e850ab4dd4bb20ebe057b491f0c854c7bfc Mon Sep 17 00:00:00 2001 From: rewin Date: Fri, 2 Feb 2024 21:14:54 +0300 Subject: [PATCH] testing --- studio-frontend/src/app/app.element.ts | 10 +- studio-frontend/src/app/inspector.element.ts | 21 ++ studio/Cargo.toml | 5 + studio/src/blocking/mod.rs | 18 ++ studio/src/lib.rs | 2 + studio/src/ui/inspector.rs | 235 +++++++++++++++++++ studio/src/ui/mod.rs | 2 + 7 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 studio-frontend/src/app/inspector.element.ts create mode 100644 studio/src/blocking/mod.rs create mode 100644 studio/src/ui/inspector.rs diff --git a/studio-frontend/src/app/app.element.ts b/studio-frontend/src/app/app.element.ts index 9f1e3fc..0183907 100644 --- a/studio-frontend/src/app/app.element.ts +++ b/studio-frontend/src/app/app.element.ts @@ -6,6 +6,7 @@ import { type EntitySelectEvent, type EntitySpawnEvent, type SceneStateEvent, + type InspectorDomChanged, TransformSpace, TransformType, SceneState, @@ -27,9 +28,11 @@ import "./icon.element"; import "./toolbar.element"; import "./transform-toolbar.element"; import "./tree.element"; +import "./inspector.element"; import "./app.element.scss"; + interface SceneObject extends Omit { children: SceneObject[]; } @@ -114,6 +117,8 @@ export class AppElement extends LitElement { }); } + + @on("window:entity-select") onEntitySelectionChange({ detail: entity }: EntitySelectEvent): void { const sceneObject = this.#entityMap.get(entity!); @@ -189,6 +194,7 @@ export class AppElement extends LitElement { class="app-root" ${ref(this.#canvasProvider as any)} > + ${this.bvhPath ? html` ` : html` + +
${this.sceneObjects.map(obj => html` html` +
+ +
+ `; + +} \ No newline at end of file diff --git a/studio/Cargo.toml b/studio/Cargo.toml index 4ad8e00..7aac79c 100644 --- a/studio/Cargo.toml +++ b/studio/Cargo.toml @@ -33,9 +33,14 @@ web-sys = { version = "0.3.65", optional = true, features = [ "Document", "HtmlElement", "Window", + "Element", + "Node", + "NodeList" ] } space_editor = {git = "https://github.com/rewin123/space_editor", rev = "ce83f86dc902787ab16213f3209276a784654df6"} anyhow.workspace = true +dioxus = "0.4.3" +futures-util = "0.3.30" [features] wasm = [ diff --git a/studio/src/blocking/mod.rs b/studio/src/blocking/mod.rs new file mode 100644 index 0000000..4cafc2f --- /dev/null +++ b/studio/src/blocking/mod.rs @@ -0,0 +1,18 @@ +use bevy::prelude::*; + +#[cfg(feature = "wasm")] +use wasm_bindgen::prelude::*; + +pub struct BlockingPlugin; + +impl Plugin for BlockingPlugin { + fn build(&self, app: &mut App) { + + } +} + +#[cfg_attr(feature = "wasm", wasm_bindgen(js_name = test_blocking))] +pub fn test_blocking() -> bool { + info!("test_blocking"); + true +} \ No newline at end of file diff --git a/studio/src/lib.rs b/studio/src/lib.rs index c59f6eb..dcfbd7b 100644 --- a/studio/src/lib.rs +++ b/studio/src/lib.rs @@ -20,6 +20,8 @@ mod scene; mod skybox; mod ui; pub mod viewport; +pub mod blocking; + mod world_grid; pub use crate::{ diff --git a/studio/src/ui/inspector.rs b/studio/src/ui/inspector.rs new file mode 100644 index 0000000..8df8085 --- /dev/null +++ b/studio/src/ui/inspector.rs @@ -0,0 +1,235 @@ +use std::sync::{Arc, Mutex, RwLock}; + +use bevy::{prelude::*, utils::hashbrown::HashMap, window::PrimaryWindow}; +use dioxus::{core::{ElementId, Mutations}, prelude::*}; +use wasm_bindgen::JsCast; +use web_sys::HtmlElement; + +use crate::{ui::inspector::wasm::notify_dom_changed, wasm::{StaticBuffer, WasmMessageBuffer}}; + +pub struct InspectorPlugin; + +impl Plugin for InspectorPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, init); + + app.add_systems(Update, apply_muts); + } +} + +struct InspectorDom { + dom: VirtualDom, +} + +fn init( + world: &mut World, +) { + let mut dom = VirtualDom::new(inspector); + + world.insert_non_send_resource(InspectorDom { dom }); + + // let muts = dom.rebuild(); + + // info!("{:?}", muts); + + // let json = serde_json::to_string(&muts).unwrap(); + + // q_mutation_queue.edits.push(json.clone()); + + // info!("{:?}", json); + + // #[cfg(feature = "wasm")] + // { + // wasm::MUTATION_BUFFER.write_message(json); + // notify_dom_changed(q_window); +} + +fn recursive_find( + id : &str, + element: &web_sys::Node, +) -> Option { + if let Some(el) = element.as_any().downcast_ref::() { + if el.id() == *id { + return Some(el.clone()); + } + } + let children = element.child_nodes(); + + for i in 0..children.length() { + if let Some(child) = children.get(i) { + if let Some(element) = recursive_find(id, &child) { + return Some(element); + } + } + } + + None +} + +fn apply_muts( + mut dom : NonSendMut, +) { + if let Some(window) = web_sys::window() { + window.capture_events(); + window.release_events(); + info!("apply_muts 1"); + if let Some(document) = window.document() { + + info!("apply_muts 2"); + + if let Some(mut page_root) = document.get_elements_by_name("sts-inspector").item(0) { + let mut page_root = page_root.dyn_into::().unwrap(); + info!("apply_muts 3"); + + let dom = &mut dom.dom; + let muts = dom.render_immediate(); + + let mut element_stack = vec![]; + + for m in muts.edits.iter() { + match m { + dioxus::core::Mutation::AppendChildren { id, m } => { + for stack_idx in 0..*m { + let (id, template) = element_stack.pop().unwrap(); + recursive_add_dom( + &id, + &template, + &mut page_root, + &document, + ); + } + }, + dioxus::core::Mutation::AssignId { path, id } => todo!(), + dioxus::core::Mutation::CreatePlaceholder { id } => todo!(), + dioxus::core::Mutation::CreateTextNode { value, id } => todo!(), + dioxus::core::Mutation::HydrateText { path, value, id } => todo!(), + dioxus::core::Mutation::LoadTemplate { name, index, id } => { + let mut template = None; + for t in muts.templates.iter() { + if t.name == *name { + template = Some(t); + break; + } + } + + if let Some(template) = template { + element_stack.push((id.clone(), template.roots[*index].clone())); + } + }, + dioxus::core::Mutation::ReplaceWith { id, m } => todo!(), + dioxus::core::Mutation::ReplacePlaceholder { path, m } => todo!(), + dioxus::core::Mutation::InsertAfter { id, m } => todo!(), + dioxus::core::Mutation::InsertBefore { id, m } => todo!(), + dioxus::core::Mutation::SetAttribute { name, value, id, ns } => todo!(), + dioxus::core::Mutation::SetText { value, id } => todo!(), + dioxus::core::Mutation::NewEventListener { name, id } => todo!(), + dioxus::core::Mutation::RemoveEventListener { name, id } => todo!(), + dioxus::core::Mutation::Remove { id } => todo!(), + dioxus::core::Mutation::PushRoot { id } => todo!(), + } + } + } + } + } +} + +fn recursive_add_dom( + element_id: &ElementId, + template: &TemplateNode, + parent: &mut web_sys::Element, + document: &web_sys::Document, +) { + match *template { + TemplateNode::Element { tag, namespace, attrs, children } => { + let mut element = document.create_element(tag).unwrap(); + element.set_attribute("id", format!("element_{}", element_id.0).as_str()).unwrap(); + + for attr in attrs { + match *attr { + TemplateAttribute::Static { name, value, namespace } => { + element.set_attribute(name, value).unwrap(); + }, + TemplateAttribute::Dynamic { id } => { + // TODO + }, + } + } + + parent.append_child(&element).unwrap(); + + for child in children { + recursive_add_dom(element_id, child, &mut element, document); + } + }, + TemplateNode::Text { text } => { + let text_node = document.create_element("p").unwrap(); + text_node.set_text_content(Some(text)); + parent.append_child(&text_node).unwrap(); + }, + TemplateNode::Dynamic { id } => { + todo!() + }, + TemplateNode::DynamicText { id } => { + todo!() + }, + } +} + +fn inspector( + cx: Scope +) -> Element { + + cx.render(rsx!{ + div { + "Inspector", + div { + "hello world" + } + } + }) +} + + +#[cfg(feature = "wasm")] +mod wasm { + use bevy::{prelude::*, window::PrimaryWindow}; + use serde_json::json; + use wasm_bindgen::prelude::*; + use crate::wasm::*; + + use super::*; + + #[wasm_bindgen(typescript_custom_section)] + const EVENT_DECLARATION: &str = r#" +/** + * An event indicating that an entity has been selected or that the selection + * has been cleared. + */ +export interface InspectorDomChanged extends CustomEvent { + /** The selected entity ID. If `null`, the selection has been cleared. */ + detail: string | null; +} + +declare global { + export interface HTMLElementEventMap { + "inspector-dom-changed": InspectorDomChanged; + } +} + "#; + + pub(super) fn notify_dom_changed( + q_window: Query<&Window, With>, + ) -> Result<(), String> { + + wasm::dispatch_to_js(q_window.single(), "inspector-dom-changed", &Option::::None) + } + + pub static MUTATION_BUFFER: WasmMessageBuffer = WasmMessageBuffer::new(); + + #[wasm_bindgen(js_name = getMutation)] + pub fn get_mutation() -> String { + + + MUTATION_BUFFER.take_message().unwrap_or("{}".to_string()) + } +} \ No newline at end of file diff --git a/studio/src/ui/mod.rs b/studio/src/ui/mod.rs index 227e76b..32a9ef7 100644 --- a/studio/src/ui/mod.rs +++ b/studio/src/ui/mod.rs @@ -3,11 +3,13 @@ use bevy::prelude::*; use self::fps::FpsCounterPlugin; mod fps; +mod inspector; pub struct UiLayerPlugin; impl Plugin for UiLayerPlugin { fn build(&self, app: &mut App) { app.add_plugins(FpsCounterPlugin); + app.add_plugins(inspector::InspectorPlugin); } }