Fix event dispatch
This commit is contained in:
parent
9bb8a27bb7
commit
17f963e4cc
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
116
src/events.rs
116
src/events.rs
|
@ -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)>,
|
||||
|
|
27
src/tick.rs
27
src/tick.rs
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue