bevy_dioxus/src/tick.rs

140 lines
4.4 KiB
Rust
Raw Normal View History

2023-12-07 02:46:50 +00:00
use crate::{
2023-12-12 08:12:06 +00:00
apply_mutations::apply_mutations, deferred_system::DeferredSystemRegistry,
2023-12-13 00:22:54 +00:00
events::EventReaders, hooks::EcsSubscriptions, DioxusUiRoot,
2023-12-07 02:46:50 +00:00
};
use bevy::{
2023-12-07 20:25:02 +00:00
ecs::{
entity::Entity,
2023-12-07 20:57:34 +00:00
system::{CommandQueue, Commands},
2023-12-07 20:25:02 +00:00
world::{Mut, World},
},
2023-12-07 02:46:50 +00:00
prelude::{Deref, DerefMut},
utils::synccell::SyncCell,
};
use dioxus::core::{Element, Scope, ScopeState, VirtualDom};
2023-12-12 08:12:06 +00:00
use std::{mem, rc::Rc, sync::Arc};
2023-12-07 02:46:50 +00:00
pub fn tick_dioxus_ui(world: &mut World) {
let world_ptr: *mut World = world;
let world_cell = world.as_unsafe_world_cell();
2023-12-13 00:22:54 +00:00
let ecs_subscriptions = unsafe { world_cell.get_resource::<EcsSubscriptions>().unwrap() };
2023-12-12 08:12:06 +00:00
let events = unsafe {
world_cell
.get_resource_mut::<EventReaders>()
.unwrap()
.get_dioxus_events(world_cell.get_resource().unwrap())
};
2023-12-07 20:57:34 +00:00
let mut command_queue = CommandQueue::default();
let mut commands = Commands::new_from_entities(&mut command_queue, world_cell.entities());
2023-12-07 02:46:50 +00:00
for (root_entity, mut dioxus_ui_root) in unsafe {
world_cell
.world_mut()
.query::<(Entity, &mut DioxusUiRoot)>()
.iter_mut(world_cell.world_mut())
} {
let DioxusUiRoot {
virtual_dom,
parent_to_children,
children_to_parent,
2023-12-07 19:17:42 +00:00
element_id_to_bevy_ui_entity,
2023-12-12 08:12:06 +00:00
bevy_ui_entity_to_element_id,
2023-12-07 19:17:42 +00:00
templates,
2023-12-10 21:50:10 +00:00
needs_rebuild,
2023-12-07 02:46:50 +00:00
} = &mut *dioxus_ui_root;
let virtual_dom = virtual_dom.get();
2023-12-13 00:22:54 +00:00
let schedule_update = virtual_dom.base_scope().schedule_update_any();
for scope_id in &*ecs_subscriptions.world_and_queries {
schedule_update(*scope_id);
}
for (resource_id, scope_ids) in &*ecs_subscriptions.resources {
if unsafe { world_cell.world() }.is_resource_changed_by_id(*resource_id) {
for scope_id in scope_ids {
schedule_update(*scope_id);
}
2023-12-13 00:22:54 +00:00
}
}
2023-12-07 02:46:50 +00:00
virtual_dom
.base_scope()
.provide_context(EcsContext { world: world_ptr });
for (mut target, name, data) in &events {
let mut target_element_id = bevy_ui_entity_to_element_id.get(&target);
while target_element_id.is_none() {
target = children_to_parent[&target];
target_element_id = bevy_ui_entity_to_element_id.get(&target);
2023-12-12 08:12:06 +00:00
}
virtual_dom.handle_event(name, Rc::clone(data), *target_element_id.unwrap(), true);
2023-12-12 08:12:06 +00:00
}
2023-12-07 20:57:34 +00:00
2023-12-07 02:46:50 +00:00
if *needs_rebuild {
2023-12-07 19:17:42 +00:00
apply_mutations(
virtual_dom.rebuild(),
parent_to_children,
children_to_parent,
2023-12-07 19:17:42 +00:00
element_id_to_bevy_ui_entity,
2023-12-12 08:12:06 +00:00
bevy_ui_entity_to_element_id,
2023-12-07 19:17:42 +00:00
templates,
root_entity,
2023-12-07 20:57:34 +00:00
&mut commands,
2023-12-07 19:17:42 +00:00
);
2023-12-07 02:46:50 +00:00
*needs_rebuild = false;
}
2023-12-07 19:17:42 +00:00
apply_mutations(
virtual_dom.render_immediate(),
parent_to_children,
children_to_parent,
2023-12-07 19:17:42 +00:00
element_id_to_bevy_ui_entity,
2023-12-12 08:12:06 +00:00
bevy_ui_entity_to_element_id,
2023-12-07 19:17:42 +00:00
templates,
root_entity,
2023-12-07 20:57:34 +00:00
&mut commands,
2023-12-07 19:17:42 +00:00
);
2023-12-07 02:46:50 +00:00
}
2023-12-07 20:57:34 +00:00
command_queue.apply(world);
2023-12-07 20:25:02 +00:00
for system_id in mem::take(&mut *world.resource_mut::<DeferredSystemRegistry>().run_queue) {
let _ = world.run_system(system_id);
2023-12-07 02:46:50 +00:00
}
2023-12-07 20:25:02 +00:00
world.resource_scope(|world, mut system_registry: Mut<DeferredSystemRegistry>| {
system_registry.ref_counts.retain(|system_id, ref_count| {
let cleanup = Arc::strong_count(ref_count) == 1;
if cleanup {
world.remove_system(*system_id).unwrap();
}
!cleanup
});
});
2023-12-07 02:46:50 +00:00
}
#[derive(Clone)]
pub(crate) struct EcsContext {
world: *mut World,
}
impl EcsContext {
pub fn get_world(cx: &ScopeState) -> &mut World {
unsafe {
&mut *cx
.consume_context::<EcsContext>()
.expect("Must be used from a dioxus component within a DioxusUiRoot bevy component")
.world
}
}
}
#[derive(Deref, DerefMut)]
pub struct VirtualDomUnsafe(pub SyncCell<VirtualDom>);
unsafe impl Send for VirtualDomUnsafe {}
impl VirtualDomUnsafe {
pub fn new(root_component: fn(Scope) -> Element) -> Self {
Self(SyncCell::new(VirtualDom::new(root_component)))
}
}