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::{
|
use bevy::{
|
||||||
ecs::{entity::Entity, system::Command, world::World},
|
ecs::{entity::Entity, system::Command, world::World},
|
||||||
hierarchy::{BuildWorldChildren, Children, DespawnRecursive, Parent},
|
hierarchy::{BuildWorldChildren, Children, DespawnRecursive, Parent},
|
||||||
|
|
@ -75,7 +78,6 @@ pub fn apply_mutations(
|
||||||
TextLayoutInfo::default(),
|
TextLayoutInfo::default(),
|
||||||
TextFlags::default(),
|
TextFlags::default(),
|
||||||
ContentSize::default(),
|
ContentSize::default(),
|
||||||
IntrinsicTextNode,
|
|
||||||
));
|
));
|
||||||
element_id_to_bevy_ui_entity.insert(id, entity);
|
element_id_to_bevy_ui_entity.insert(id, entity);
|
||||||
bevy_ui_entity_to_element_id.insert(entity, id);
|
bevy_ui_entity_to_element_id.insert(entity, id);
|
||||||
|
|
@ -184,21 +186,10 @@ pub fn apply_mutations(
|
||||||
.insert(Text::from_section(value, TextStyle::default()));
|
.insert(Text::from_section(value, TextStyle::default()));
|
||||||
}
|
}
|
||||||
Mutation::NewEventListener { name, id } => {
|
Mutation::NewEventListener { name, id } => {
|
||||||
if !is_supported_event(name) {
|
insert_event_listener(name, world.entity_mut(element_id_to_bevy_ui_entity[&id]));
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Mutation::RemoveEventListener { name, id } => {
|
Mutation::RemoveEventListener { name, id } => {
|
||||||
if name == "mouse_enter" || name == "mouse_exit" {
|
remove_event_listener(name, world.entity_mut(element_id_to_bevy_ui_entity[&id]));
|
||||||
world
|
|
||||||
.entity_mut(element_id_to_bevy_ui_entity[&id])
|
|
||||||
.remove::<RelativeCursorPosition>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Mutation::Remove { id } => {
|
Mutation::Remove { id } => {
|
||||||
let entity = element_id_to_bevy_ui_entity[&id];
|
let entity = element_id_to_bevy_ui_entity[&id];
|
||||||
|
|
@ -336,13 +327,10 @@ impl BevyTemplateNode {
|
||||||
.id()
|
.id()
|
||||||
}
|
}
|
||||||
Self::IntrinsicTextNode(text) => world
|
Self::IntrinsicTextNode(text) => world
|
||||||
.spawn((
|
.spawn(TextBundle {
|
||||||
TextBundle {
|
|
||||||
text: text.clone(),
|
text: text.clone(),
|
||||||
..default()
|
..default()
|
||||||
},
|
})
|
||||||
IntrinsicTextNode,
|
|
||||||
))
|
|
||||||
.id(),
|
.id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
116
src/events.rs
116
src/events.rs
|
|
@ -1,9 +1,13 @@
|
||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::{
|
ecs::{
|
||||||
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
event::{Event, EventWriter, Events, ManualEventReader},
|
event::{Event, EventWriter, Events, ManualEventReader},
|
||||||
system::{Local, Query, Resource},
|
system::{Local, Query, Resource},
|
||||||
|
world::World,
|
||||||
},
|
},
|
||||||
|
hierarchy::Parent,
|
||||||
|
prelude::EntityWorldMut,
|
||||||
ui::RelativeCursorPosition,
|
ui::RelativeCursorPosition,
|
||||||
utils::EntityHashSet,
|
utils::EntityHashSet,
|
||||||
};
|
};
|
||||||
|
|
@ -12,6 +16,18 @@ use dioxus::core::ScopeState;
|
||||||
use std::{any::Any, mem, rc::Rc};
|
use std::{any::Any, mem, rc::Rc};
|
||||||
|
|
||||||
// TODO: Other events
|
// 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)]
|
#[derive(Resource, Default)]
|
||||||
pub struct EventReaders {
|
pub struct EventReaders {
|
||||||
|
|
@ -25,7 +41,7 @@ pub struct EventReaders {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventReaders {
|
impl EventReaders {
|
||||||
pub fn get_dioxus_events(
|
pub fn read_events(
|
||||||
&mut self,
|
&mut self,
|
||||||
click: &Events<Pointer<Click>>,
|
click: &Events<Pointer<Click>>,
|
||||||
click_down: &Events<Pointer<Down>>,
|
click_down: &Events<Pointer<Down>>,
|
||||||
|
|
@ -61,31 +77,85 @@ impl EventReaders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_supported_event(event: &str) -> bool {
|
pub fn insert_event_listener(name: &str, mut entity: EntityWorldMut<'_>) {
|
||||||
match event {
|
match name {
|
||||||
"click" => true,
|
"click" => entity.insert(HasClickEventListener),
|
||||||
"click_down" => true,
|
"click_down" => entity.insert(HasClickDownEventListener),
|
||||||
"click_up" => true,
|
"click_up" => entity.insert(HasClickUpEventListener),
|
||||||
"mouse_over" => true,
|
"mouse_over" => &mut entity,
|
||||||
"mouse_out" => true,
|
"mouse_out" => &mut entity,
|
||||||
"mouse_enter" => true,
|
"mouse_enter" => entity.insert((
|
||||||
"mouse_exit" => true,
|
HasMouseEnterEventListener,
|
||||||
_ => false,
|
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(
|
pub fn generate_mouse_enter_leave_events(
|
||||||
entities: Query<(Entity, &RelativeCursorPosition)>,
|
entities: Query<(Entity, &RelativeCursorPosition)>,
|
||||||
|
|
|
||||||
27
src/tick.rs
27
src/tick.rs
|
|
@ -1,14 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
apply_mutations::apply_mutations, deferred_system::DeferredSystemRegistry,
|
apply_mutations::apply_mutations,
|
||||||
ecs_hooks::EcsContext, events::EventReaders, DioxusUiRoot, UiContext, UiRoot,
|
deferred_system::DeferredSystemRegistry,
|
||||||
|
ecs_hooks::EcsContext,
|
||||||
|
events::{bubble_event, EventReaders},
|
||||||
|
DioxusUiRoot, UiContext, UiRoot,
|
||||||
};
|
};
|
||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::{
|
ecs::{
|
||||||
component::Component,
|
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
world::{Mut, World},
|
world::{Mut, World},
|
||||||
},
|
},
|
||||||
hierarchy::Parent,
|
|
||||||
utils::HashMap,
|
utils::HashMap,
|
||||||
};
|
};
|
||||||
use std::{any::Any, mem, rc::Rc, sync::Arc};
|
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);
|
run_deferred_systems(world);
|
||||||
|
|
||||||
let ui_events = world.resource_scope(|world, mut event_readers: Mut<EventReaders>| {
|
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(),
|
world.resource(),
|
||||||
world.resource(),
|
world.resource(),
|
||||||
|
|
@ -75,20 +76,13 @@ fn dispatch_ui_events(
|
||||||
world: &World,
|
world: &World,
|
||||||
) {
|
) {
|
||||||
for (mut target, name, data, bubbles) in events {
|
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 {
|
if *bubbles {
|
||||||
while target_element_id.is_none()
|
bubble_event(name, &mut target, world);
|
||||||
|| 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();
|
|
||||||
}
|
}
|
||||||
}
|
if let Some(target_element_id) = ui_root.bevy_ui_entity_to_element_id.get(&target) {
|
||||||
|
|
||||||
if let Some(target_element_id) = target_element_id {
|
|
||||||
ui_root
|
ui_root
|
||||||
.virtual_dom
|
.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,
|
world,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub struct IntrinsicTextNode;
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue