Basic blocking

This commit is contained in:
rewin
2024-02-20 00:16:35 +03:00
parent 6c9cd6106e
commit 5551c12c74
3 changed files with 217 additions and 16 deletions
+25 -1
View File
@@ -41,10 +41,20 @@ function unpack_vnode(
if (id != null) {
console.log("onchange", id, input.value);
const value = input.value;
register_new_change(id, value);
register_new_change(id, "onchange", value);
}
}
}
if (node_data["onclick"] == true) {
element.onclick = (event: Event) => {
var input = event.target as HTMLInputElement;
const id = input.getAttribute("id");
if (id != null) {
console.log("onclick", id);
register_new_change(id, "onclick", "");
}
}
}
return element;
}
}
@@ -225,6 +235,20 @@ function append_style(parent : HTMLElement) {
align-items: center;
}
.blocking-button {
background-color: #3333336e; /* Темный фон */
color: #fff; /* Светлый текст */
border: none; /* Убрать стандартную рамку */
border-radius: 7px; /* Закругленные границы */
padding: 5px; /* Внутренний отступ */
outline: none; /* Убрать контур при фокусе */
}
.blocking-button:hover {
border: 2px solid #555; /* Стиль границы при фокусе */
background-color: #222; /* Немного темнее фон при фокусе */
}
`;
+39 -13
View File
@@ -1,8 +1,9 @@
use bevy::{ecs::world::unsafe_world_cell::UnsafeEntityCell, prelude::*, window::PrimaryWindow};
use space_editor::space_prefab::component::MeshPrimitivePrefab;
use crate::{ui::inspector::wasm::notify_dom_changed, wasm::StaticBuffer};
use super::utils::{show_reflect, Element, InspectedEntity, ReflectChange, VirtualDom};
use super::utils::{blocking_component, show_reflect, Element, InspectedEntity, ReflectChange, VirtualDom};
pub struct InspectorPlugin;
@@ -18,6 +19,10 @@ impl Plugin for InspectorPlugin {
app.world
.resource_mut::<InspectorFunctions>()
.add_simple::<Transform>();
app.world
.resource_mut::<InspectorFunctions>()
.add_simple::<MeshPrimitivePrefab>();
}
}
@@ -69,8 +74,28 @@ fn show_selected(world: &mut World) {
let cell = world.as_unsafe_world_cell();
let mut virtial_dom = cell.get_resource_mut::<VirtualDom>().unwrap();
//Process events from real DOM
if let Some(changes) = super::utils::wasm::ONCHAGE_BUFFER.take_message() {
for (id, kind, value) in changes {
info!("change: {} {} {}", id, kind, value);
if kind == "onchange" {
info!("change: {} : {}", id, value);
virtial_dom
.on_change_events
.execute(cell.world_mut(), id, value);
} else if kind == "onclick" {
info!("click: {} : {}", id, value);
virtial_dom
.on_click_events
.execute(cell.world_mut(), id, value);
}
}
}
let blocking_element = blocking_component();
let Some(selection) = cell.get_resource::<crate::interaction::Selection>() else {
let muts = virtial_dom.render(None);
let muts = virtial_dom.render(blocking_element);
let q_window = cell
.world_mut()
.query_filtered::<&Window, With<PrimaryWindow>>()
@@ -87,16 +112,7 @@ fn show_selected(world: &mut World) {
let _app_type_registry = cell.get_resource::<AppTypeRegistry>().unwrap();
let e = cell.get_entity(selected_entity).unwrap();
if let Some(changes) = super::utils::wasm::ONCHAGE_BUFFER.take_message() {
for (id, kind, value) in changes {
if kind == "onchange" {
info!("change: {} : {}", id, value);
virtial_dom
.on_change_events
.execute(cell.world_mut(), id, value);
}
}
}
let mut inspected = InspectedEntity::none();
inspected.id = Some(e.id());
@@ -137,7 +153,17 @@ fn show_selected(world: &mut World) {
..Default::default()
});
let muts = virtial_dom.render(Some(element));
let super_root = Element::Component(super::utils::Component {
tag: "div".to_string(),
attributes: vec![
("style".to_string(), "height: 100%; display: flex; flex-direction: column".to_string()),
],
children: vec![blocking_element.unwrap(), element],
..default()
});
let muts = virtial_dom.render(Some(super_root));
let q_window = cell
.world_mut()
+153 -2
View File
@@ -1,5 +1,8 @@
use ::serde::{Deserialize, Serialize};
use bevy::{ecs::component::ComponentId, prelude::*, reflect::ReflectFromPtr, utils::HashMap};
use bevy::{ecs::component::ComponentId, prelude::*, reflect::{DynamicEnum, DynamicStruct, DynamicVariant, ReflectFromPtr, TypeInfo, VariantInfo}, utils::HashMap};
use space_editor::{prelude::PrefabMarker, space_prefab::component::*};
use crate::scene::SceneElement;
trait NodeProp: Clone + PartialEq {}
@@ -83,11 +86,18 @@ impl VirtualDom {
onchange_enabled = true;
}
let mut onclick_enabled = false;
if let Some(onclick) = component.onclick {
self.on_click_events.add_event(id.clone(), onclick);
onclick_enabled = true;
}
VNode::Component(VComponent {
tag: component.tag,
attributes: component.attributes.into_iter().collect(),
id: Some(id),
onchange: onchange_enabled,
onclick: onclick_enabled,
children: component
.children
.into_iter()
@@ -116,6 +126,40 @@ impl VirtualDom {
}
}
pub fn blocking_component() -> Option<Element> {
Some(Element::Component(Component {
tag: "div".to_string(),
attributes: vec![
("style".to_string(), "padding: 10px;".to_string()),
("class".to_string(), "inspector".to_string()),
],
children: vec![
Element::Component(Component {
tag: "button".to_string(),
attributes: vec![
("class".to_string(), "blocking-button".to_string()),
],
onclick: Some(Box::new(WorldCommandExecutor {
func: Box::new(|world| {
world.spawn((
MeshPrimitivePrefab::Cube(1.0),
SpatialBundle::default(),
SceneElement,
PrefabMarker
));
})
})),
children: vec![
Element::Text("Add blocking mesh".to_string())
],
..default()
})
],
..default()
}))
}
#[cfg(feature = "wasm")]
pub mod wasm {
use wasm_bindgen::prelude::*;
@@ -214,6 +258,16 @@ impl WebEventExecutor for ReflectValueExecutor {
}
}
struct WorldCommandExecutor {
func: Box<dyn Fn(&mut World) + Send + Sync>,
}
impl WebEventExecutor for WorldCommandExecutor {
fn execute(&mut self, world: &mut World, _value: String) {
(self.func)(world);
}
}
struct EntityChangeExecutor {
entity: Entity,
func: Box<dyn Fn(&mut World, Entity, String) + Send + Sync>,
@@ -450,7 +504,103 @@ pub fn show_reflect(r: &dyn Reflect, reflect: ReflectChange) -> Option<Element>
bevy::reflect::ReflectRef::List(_) => None,
bevy::reflect::ReflectRef::Array(_) => None,
bevy::reflect::ReflectRef::Map(_) => None,
bevy::reflect::ReflectRef::Enum(_) => None,
bevy::reflect::ReflectRef::Enum(v) => {
let Some(type_info) = v.get_represented_type_info() else {
error!("invalid reflect impl: type info mismatch");
return None;
};
let type_info = match type_info {
TypeInfo::Enum(info) => info,
_ => unreachable!("invalid reflect impl: type info mismatch"),
};
Some(Element::Component(Component {
tag: "div".to_string(),
attributes: vec![
("style".to_string(), "display: flex; flex-direction: column".to_string()),
],
children: vec![
Element::Component(Component {
tag: "select".to_string(),
attributes: vec![],
children: type_info.iter().enumerate().map(|(i, variant)| {
let mut attributes = vec![
("value".to_string(), variant.name().to_string()),
];
let is_active_variant = i == v.variant_index();
if is_active_variant {
attributes.push(("selected".to_string(), "".to_string()));
}
Element::Component(Component {
tag: "option".to_string(),
attributes,
children: vec![Element::Text(variant.name().to_string())],
..default()
})
}).collect(),
onchange: Some(
EntityChangeExecutor::new_boxed(
reflect.entity_id,
|world, entity, value : String| {
info!("MeshPrimitivePrefab change: {:?} {}", entity, value);
let Some(mut e) = world.get_entity_mut(entity) else {
return;
};
let Some(mut variant) = e.get_mut::<MeshPrimitivePrefab>() else {
return;
};
// pub enum MeshPrimitivePrefab {
// Cube(f32),
// Box(BoxPrefab),
// Sphere(SpherePrefab),
// Quad(QuadPrefab),
// Capsule(CapsulePrefab),
// Circle(CirclePrefab),
// Cylinder(CylinderPrefab),
// Icosphere(IcospherePrefab),
// Plane(PlanePrefab),
// RegularPolygon(RegularPolygonPrefab),
// Torus(TorusPrefab),
// }
if value == "Cube" {
*variant = MeshPrimitivePrefab::Cube(1.0);
} else if value == "Box" {
*variant = MeshPrimitivePrefab::Box(BoxPrefab::default());
} else if value == "Sphere" {
*variant = MeshPrimitivePrefab::Sphere(SpherePrefab::default());
} else if value == "Quad" {
*variant = MeshPrimitivePrefab::Quad(QuadPrefab::default());
} else if value == "Capsule" {
*variant = MeshPrimitivePrefab::Capsule(CapsulePrefab::default());
} else if value == "Circle" {
*variant = MeshPrimitivePrefab::Circle(CirclePrefab::default());
} else if value == "Cylinder" {
*variant = MeshPrimitivePrefab::Cylinder(CylinderPrefab::default());
} else if value == "Icosphere" {
*variant = MeshPrimitivePrefab::Icosphere(IcospherePrefab::default());
} else if value == "Plane" {
*variant = MeshPrimitivePrefab::Plane(PlanePrefab::default());
} else if value == "RegularPolygon" {
*variant = MeshPrimitivePrefab::RegularPolygon(RegularPolygonPrefab::default());
} else if value == "Torus" {
*variant = MeshPrimitivePrefab::Torus(TorusPrefab::default());
}
}
)
),
..default()
})
],
..default()
}))
},
bevy::reflect::ReflectRef::Value(v) => {
if let Some(s) = v.downcast_ref::<String>() {
Some(Element::Component(Component {
@@ -512,6 +662,7 @@ pub struct VComponent {
pub children: Vec<VNode>,
pub id: Option<String>,
pub onchange: bool,
pub onclick: bool,
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]