Add use_state_send()

This commit is contained in:
JMS55 2023-12-26 15:00:35 -08:00
parent 5a4b1d60e9
commit 9776f179f9
3 changed files with 66 additions and 14 deletions

View File

@ -28,7 +28,7 @@ fn main() {
#[component]
fn Editor(cx: Scope) -> Element {
// 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! {
node {
@ -42,19 +42,23 @@ fn Editor(cx: Scope) -> Element {
}
#[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 = entities.query();
let mut entities = entities.into_iter().collect::<Vec<_>>();
entities.sort_by_key(|(entity, _)| *entity);
let spawn_entity = use_system(cx, |world: &mut World| {
world.spawn_empty();
let spawn_entity = use_system(cx, {
let selected_entity = (*selected_entity).clone();
move |world: &mut World| {
let new_entity = world.spawn_empty();
selected_entity.write(Some(new_entity.id()));
}
});
render! {
node {
onclick: move |_| selected_entity.set(None),
onclick: move |_| selected_entity.write(None),
flex_direction: "column",
if entities.is_empty() {
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 {
Button {
onclick: move |event: Event<PointerButton>| if *event.data == PointerButton::Primary {
if Some(entity) == ***selected_entity {
selected_entity.set(None);
if Some(entity) == *selected_entity.read() {
selected_entity.write(None);
} else {
selected_entity.set(Some(entity));
selected_entity.write(Some(entity));
}
event.stop_propagation();
},
base_color: if Some(entity) == ***selected_entity { Some(VIOLET_700) } else { None },
click_color: if Some(entity) == ***selected_entity { Some(VIOLET_400) } else { None },
hover_color: if Some(entity) == ***selected_entity { Some(VIOLET_500) } else { None },
base_color: if Some(entity) == *selected_entity.read() { Some(VIOLET_700) } else { None },
click_color: if Some(entity) == *selected_entity.read() { Some(VIOLET_400) } else { None },
hover_color: if Some(entity) == *selected_entity.read() { Some(VIOLET_500) } else { None },
match name.name {
Some(name) => format!("{name}"),
_ => format!("Entity ({:?})", name.entity)
@ -93,11 +97,11 @@ fn SceneTree<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>) -> El
}
#[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 type_registry = use_resource::<AppTypeRegistry>(cx).read();
let components = selected_entity
.get()
.read()
.map(|selected_entity| {
let entity_ref = world.get_entity(selected_entity).unwrap();
let mut components = entity_ref
@ -118,7 +122,7 @@ fn EntityInspector<'a>(cx: Scope, selected_entity: &'a UseState<Option<Entity>>)
.unwrap_or_default();
render! {
if selected_entity.is_none() {
if selected_entity.read().is_none() {
rsx! {
node {
margin: "8",

View File

@ -9,6 +9,7 @@ mod events;
mod hot_reload;
mod parse_attributes;
mod tick;
mod use_state_send;
use self::{
apply_mutations::BevyTemplate,
@ -29,6 +30,7 @@ use dioxus::core::{Element, ElementId, Scope, VirtualDom};
pub mod prelude {
pub use super::ecs_hooks::*;
pub use super::elements::*;
pub use super::use_state_send::*;
pub use super::{DioxusUiBundle, DioxusUiPlugin, DioxusUiRoot};
pub use bevy_mod_picking::pointer::PointerButton;
pub use dioxus;

46
src/use_state_send.rs Normal file
View 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)()
}
}