Fix event dispatch

This commit is contained in:
JMS55 2023-12-23 12:09:09 -08:00
parent 9bb8a27bb7
commit 17f963e4cc
3 changed files with 112 additions and 63 deletions

View File

@ -1,4 +1,7 @@
use crate::{events::is_supported_event, parse_attributes::set_attribute, tick::IntrinsicTextNode};
use crate::{
events::{insert_event_listener, remove_event_listener},
parse_attributes::set_attribute,
};
use bevy::{
ecs::{entity::Entity, system::Command, world::World},
hierarchy::{BuildWorldChildren, Children, DespawnRecursive, Parent},
@ -75,7 +78,6 @@ pub fn apply_mutations(
TextLayoutInfo::default(),
TextFlags::default(),
ContentSize::default(),
IntrinsicTextNode,
));
element_id_to_bevy_ui_entity.insert(id, entity);
bevy_ui_entity_to_element_id.insert(entity, id);
@ -184,21 +186,10 @@ pub fn apply_mutations(
.insert(Text::from_section(value, TextStyle::default()));
}
Mutation::NewEventListener { name, id } => {
if !is_supported_event(name) {
panic!("Encountered unsupported bevy_dioxus event `{name}`.");
}
if name == "mouse_enter" || name == "mouse_exit" {
world
.entity_mut(element_id_to_bevy_ui_entity[&id])
.insert(RelativeCursorPosition::default());
}
insert_event_listener(name, world.entity_mut(element_id_to_bevy_ui_entity[&id]));
}
Mutation::RemoveEventListener { name, id } => {
if name == "mouse_enter" || name == "mouse_exit" {
world
.entity_mut(element_id_to_bevy_ui_entity[&id])
.remove::<RelativeCursorPosition>();
}
remove_event_listener(name, world.entity_mut(element_id_to_bevy_ui_entity[&id]));
}
Mutation::Remove { id } => {
let entity = element_id_to_bevy_ui_entity[&id];
@ -336,13 +327,10 @@ impl BevyTemplateNode {
.id()
}
Self::IntrinsicTextNode(text) => world
.spawn((
TextBundle {
text: text.clone(),
..default()
},
IntrinsicTextNode,
))
.spawn(TextBundle {
text: text.clone(),
..default()
})
.id(),
}
}

View File

@ -1,9 +1,13 @@
use bevy::{
ecs::{
component::Component,
entity::Entity,
event::{Event, EventWriter, Events, ManualEventReader},
system::{Local, Query, Resource},
world::World,
},
hierarchy::Parent,
prelude::EntityWorldMut,
ui::RelativeCursorPosition,
utils::EntityHashSet,
};
@ -12,6 +16,18 @@ use dioxus::core::ScopeState;
use std::{any::Any, mem, rc::Rc};
// TODO: Other events
pub mod events {
super::impl_event! [
();
onclick
onclick_down
onclick_up
onmouse_over
onmouse_out
onmouse_enter
onmouse_exit
];
}
#[derive(Resource, Default)]
pub struct EventReaders {
@ -25,7 +41,7 @@ pub struct EventReaders {
}
impl EventReaders {
pub fn get_dioxus_events(
pub fn read_events(
&mut self,
click: &Events<Pointer<Click>>,
click_down: &Events<Pointer<Down>>,
@ -61,31 +77,85 @@ impl EventReaders {
}
}
pub fn is_supported_event(event: &str) -> bool {
match event {
"click" => true,
"click_down" => true,
"click_up" => true,
"mouse_over" => true,
"mouse_out" => true,
"mouse_enter" => true,
"mouse_exit" => true,
_ => false,
pub fn insert_event_listener(name: &str, mut entity: EntityWorldMut<'_>) {
match name {
"click" => entity.insert(HasClickEventListener),
"click_down" => entity.insert(HasClickDownEventListener),
"click_up" => entity.insert(HasClickUpEventListener),
"mouse_over" => &mut entity,
"mouse_out" => &mut entity,
"mouse_enter" => entity.insert((
HasMouseEnterEventListener,
RelativeCursorPosition::default(),
)),
"mouse_exit" => {
entity.insert((HasMouseExitEventListener, RelativeCursorPosition::default()))
}
_ => panic!("Encountered unsupported bevy_dioxus event `{name}`."),
};
}
pub fn remove_event_listener(name: &str, mut entity: EntityWorldMut<'_>) {
match name {
"click" => entity.remove::<HasClickEventListener>(),
"click_down" => entity.remove::<HasClickDownEventListener>(),
"click_up" => entity.remove::<HasClickUpEventListener>(),
"mouse_over" => &mut entity,
"mouse_out" => &mut entity,
"mouse_enter" => {
entity.remove::<HasMouseEnterEventListener>();
if !entity.contains::<HasMouseExitEventListener>() {
entity.remove::<RelativeCursorPosition>();
}
&mut entity
}
"mouse_exit" => {
entity.remove::<HasMouseExitEventListener>();
if !entity.contains::<HasMouseEnterEventListener>() {
entity.remove::<RelativeCursorPosition>();
}
&mut entity
}
_ => unreachable!(),
};
}
#[derive(Component)]
pub struct HasClickEventListener;
#[derive(Component)]
pub struct HasClickDownEventListener;
#[derive(Component)]
pub struct HasClickUpEventListener;
#[derive(Component)]
pub struct HasMouseEnterEventListener;
#[derive(Component)]
pub struct HasMouseExitEventListener;
// ----------------------------------------------------------------------------
pub fn bubble_event(event_name: &str, target_entity: &mut Entity, world: &World) {
match event_name {
"click" => bubble_event_helper::<HasClickEventListener>(target_entity, world),
"click_down" => bubble_event_helper::<HasClickDownEventListener>(target_entity, world),
"click_up" => bubble_event_helper::<HasClickUpEventListener>(target_entity, world),
_ => unreachable!(),
};
}
fn bubble_event_helper<T: Component>(target_entity: &mut Entity, world: &World) {
while !world.entity(*target_entity).contains::<T>() {
*target_entity = match world.entity(*target_entity).get::<Parent>() {
Some(parent) => parent.get(),
None => return,
};
}
}
pub mod events {
super::impl_event! [
();
onclick
onclick_down
onclick_up
onmouse_over
onmouse_out
onmouse_enter
onmouse_exit
];
}
// ----------------------------------------------------------------------------
pub fn generate_mouse_enter_leave_events(
entities: Query<(Entity, &RelativeCursorPosition)>,

View File

@ -1,14 +1,15 @@
use crate::{
apply_mutations::apply_mutations, deferred_system::DeferredSystemRegistry,
ecs_hooks::EcsContext, events::EventReaders, DioxusUiRoot, UiContext, UiRoot,
apply_mutations::apply_mutations,
deferred_system::DeferredSystemRegistry,
ecs_hooks::EcsContext,
events::{bubble_event, EventReaders},
DioxusUiRoot, UiContext, UiRoot,
};
use bevy::{
ecs::{
component::Component,
entity::Entity,
world::{Mut, World},
},
hierarchy::Parent,
utils::HashMap,
};
use std::{any::Any, mem, rc::Rc, sync::Arc};
@ -17,7 +18,7 @@ pub fn tick_dioxus_ui(world: &mut World) {
run_deferred_systems(world);
let ui_events = world.resource_scope(|world, mut event_readers: Mut<EventReaders>| {
event_readers.get_dioxus_events(
event_readers.read_events(
world.resource(),
world.resource(),
world.resource(),
@ -75,20 +76,13 @@ fn dispatch_ui_events(
world: &World,
) {
for (mut target, name, data, bubbles) in events {
let mut target_element_id = ui_root.bevy_ui_entity_to_element_id.get(&target).copied();
if *bubbles {
while target_element_id.is_none()
|| world.entity(target).contains::<IntrinsicTextNode>()
{
target = world.entity(target).get::<Parent>().unwrap().get();
target_element_id = ui_root.bevy_ui_entity_to_element_id.get(&target).copied();
}
bubble_event(name, &mut target, world);
}
if let Some(target_element_id) = target_element_id {
if let Some(target_element_id) = ui_root.bevy_ui_entity_to_element_id.get(&target) {
ui_root
.virtual_dom
.handle_event(name, Rc::clone(data), target_element_id, *bubbles);
.handle_event(name, Rc::clone(data), *target_element_id, *bubbles);
}
}
}
@ -139,6 +133,3 @@ fn render_ui(root_entity: Entity, ui_root: &mut UiRoot, world: &mut World) {
world,
);
}
#[derive(Component)]
pub struct IntrinsicTextNode;