Add use_state_send()
This commit is contained in:
parent
5a4b1d60e9
commit
9776f179f9
|
|
@ -28,7 +28,7 @@ fn main() {
|
||||||
#[component]
|
#[component]
|
||||||
fn Editor(cx: Scope) -> Element {
|
fn Editor(cx: Scope) -> Element {
|
||||||
// TODO: When selected entity is despawned, need to reset this to None
|
// TODO: When selected entity is despawned, need to reset this to None
|
||||||
let selected_entity = use_state(cx, || Option::<Entity>::None);
|
let selected_entity = use_state_send(cx, || Option::<Entity>::None);
|
||||||
|
|
||||||
render! {
|
render! {
|
||||||
node {
|
node {
|
||||||
|
|
@ -42,19 +42,23 @@ fn Editor(cx: Scope) -> Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> Element {
|
fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseStateSend<Option<Entity>>) -> Element {
|
||||||
let entities = use_query_filtered::<(Entity, DebugName), Without<Node>>(cx);
|
let entities = use_query_filtered::<(Entity, DebugName), Without<Node>>(cx);
|
||||||
let entities = entities.query();
|
let entities = entities.query();
|
||||||
let mut entities = entities.into_iter().collect::<Vec<_>>();
|
let mut entities = entities.into_iter().collect::<Vec<_>>();
|
||||||
entities.sort_by_key(|(entity, _)| *entity);
|
entities.sort_by_key(|(entity, _)| *entity);
|
||||||
|
|
||||||
let spawn_entity = use_system(cx, |world: &mut World| {
|
let spawn_entity = use_system(cx, {
|
||||||
world.spawn_empty();
|
let selected_entity = (*selected_entity).clone();
|
||||||
|
move |world: &mut World| {
|
||||||
|
let new_entity = world.spawn_empty();
|
||||||
|
selected_entity.write(Some(new_entity.id()));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
render! {
|
render! {
|
||||||
node {
|
node {
|
||||||
onclick: move |_| selected_entity.set(None),
|
onclick: move |_| selected_entity.write(None),
|
||||||
flex_direction: "column",
|
flex_direction: "column",
|
||||||
if entities.is_empty() {
|
if entities.is_empty() {
|
||||||
rsx! { "No entities exist" }
|
rsx! { "No entities exist" }
|
||||||
|
|
@ -63,16 +67,16 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> El
|
||||||
for (entity, name) in entities {
|
for (entity, name) in entities {
|
||||||
Button {
|
Button {
|
||||||
onclick: move |event: Event<PointerButton>| if *event.data == PointerButton::Primary {
|
onclick: move |event: Event<PointerButton>| if *event.data == PointerButton::Primary {
|
||||||
if Some(entity) == ***selected_entity {
|
if Some(entity) == *selected_entity.read() {
|
||||||
selected_entity.set(None);
|
selected_entity.write(None);
|
||||||
} else {
|
} else {
|
||||||
selected_entity.set(Some(entity));
|
selected_entity.write(Some(entity));
|
||||||
}
|
}
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
},
|
},
|
||||||
base_color: if Some(entity) == ***selected_entity { Some(VIOLET_700) } else { None },
|
base_color: if Some(entity) == *selected_entity.read() { Some(VIOLET_700) } else { None },
|
||||||
click_color: if Some(entity) == ***selected_entity { Some(VIOLET_400) } else { None },
|
click_color: if Some(entity) == *selected_entity.read() { Some(VIOLET_400) } else { None },
|
||||||
hover_color: if Some(entity) == ***selected_entity { Some(VIOLET_500) } else { None },
|
hover_color: if Some(entity) == *selected_entity.read() { Some(VIOLET_500) } else { None },
|
||||||
match name.name {
|
match name.name {
|
||||||
Some(name) => format!("{name}"),
|
Some(name) => format!("{name}"),
|
||||||
_ => format!("Entity ({:?})", name.entity)
|
_ => format!("Entity ({:?})", name.entity)
|
||||||
|
|
@ -93,11 +97,11 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> El
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn EntityInspector<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> Element {
|
fn EntityInspector<'a>(cx: Scope, selected_entity: &'a UseStateSend<Option<Entity>>) -> Element {
|
||||||
let world = use_world(cx);
|
let world = use_world(cx);
|
||||||
let type_registry = use_resource::<AppTypeRegistry>(cx).read();
|
let type_registry = use_resource::<AppTypeRegistry>(cx).read();
|
||||||
let components = selected_entity
|
let components = selected_entity
|
||||||
.get()
|
.read()
|
||||||
.map(|selected_entity| {
|
.map(|selected_entity| {
|
||||||
let entity_ref = world.get_entity(selected_entity).unwrap();
|
let entity_ref = world.get_entity(selected_entity).unwrap();
|
||||||
let mut components = entity_ref
|
let mut components = entity_ref
|
||||||
|
|
@ -118,7 +122,7 @@ fn EntityInspector<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
render! {
|
render! {
|
||||||
if selected_entity.is_none() {
|
if selected_entity.read().is_none() {
|
||||||
rsx! {
|
rsx! {
|
||||||
node {
|
node {
|
||||||
margin: "8",
|
margin: "8",
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ mod events;
|
||||||
mod hot_reload;
|
mod hot_reload;
|
||||||
mod parse_attributes;
|
mod parse_attributes;
|
||||||
mod tick;
|
mod tick;
|
||||||
|
mod use_state_send;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
apply_mutations::BevyTemplate,
|
apply_mutations::BevyTemplate,
|
||||||
|
|
@ -29,6 +30,7 @@ use dioxus::core::{Element, ElementId, Scope, VirtualDom};
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::ecs_hooks::*;
|
pub use super::ecs_hooks::*;
|
||||||
pub use super::elements::*;
|
pub use super::elements::*;
|
||||||
|
pub use super::use_state_send::*;
|
||||||
pub use super::{DioxusUiBundle, DioxusUiPlugin, DioxusUiRoot};
|
pub use super::{DioxusUiBundle, DioxusUiPlugin, DioxusUiRoot};
|
||||||
pub use bevy_mod_picking::pointer::PointerButton;
|
pub use bevy_mod_picking::pointer::PointerButton;
|
||||||
pub use dioxus;
|
pub use dioxus;
|
||||||
|
|
|
||||||
46
src/use_state_send.rs
Normal file
46
src/use_state_send.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
// https://github.com/DioxusLabs/dioxus-std/blob/8db5b1e8a3b8c81f3174a0c9cb951c87058289ca/std/src/utils/rw/use_rw.rs
|
||||||
|
|
||||||
|
use dioxus::prelude::ScopeState;
|
||||||
|
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
||||||
|
|
||||||
|
pub fn use_state_send<T: Send + Sync + 'static>(
|
||||||
|
cx: &ScopeState,
|
||||||
|
init_rw: impl FnOnce() -> T,
|
||||||
|
) -> &mut UseStateSend<T> {
|
||||||
|
let hook = cx.use_hook(|| UseStateSend {
|
||||||
|
update: cx.schedule_update(),
|
||||||
|
value: Arc::new(RwLock::new(init_rw())),
|
||||||
|
});
|
||||||
|
|
||||||
|
hook
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UseStateSend<T> {
|
||||||
|
update: Arc<dyn Fn() + Send + Sync + 'static>,
|
||||||
|
value: Arc<RwLock<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for UseStateSend<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
update: self.update.clone(),
|
||||||
|
value: self.value.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UseStateSend<T> {
|
||||||
|
pub fn read(&self) -> RwLockReadGuard<'_, T> {
|
||||||
|
self.value.read().expect("Lock poisoned")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, new_value: T) {
|
||||||
|
let mut lock = self.value.write().expect("Lock poisoned");
|
||||||
|
*lock = new_value;
|
||||||
|
self.needs_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn needs_update(&self) {
|
||||||
|
(self.update)()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue