use bevy_ecs::prelude::*;
use crate::keys::Key;
use crate::layout::RenderedLayout;
use crate::point::Point;
use crate::runtime::MousePosition;
use crate::widget::WidgetNode;
#[derive(Event, Debug)]
pub struct Click(pub MousePosition);
#[derive(Event, Debug)]
pub struct DoubleClick(pub MousePosition);
#[derive(Event, Debug)]
pub struct Scroll(pub MousePosition, pub Point);
#[derive(Event, Debug)]
pub struct KeyPress(pub Key);
#[derive(Event)]
pub struct EntityMessage<M>(pub M);
pub trait MessageTypeTrait: Send + Sync + 'static {
fn position(&self) -> Option<MousePosition> {
None
}
}
impl MessageTypeTrait for Click {
fn position(&self) -> Option<MousePosition> {
Some(self.0)
}
}
impl MessageTypeTrait for DoubleClick {
fn position(&self) -> Option<MousePosition> {
Some(self.0)
}
}
impl MessageTypeTrait for Scroll {
fn position(&self) -> Option<MousePosition> {
Some(self.0)
}
}
impl MessageTypeTrait for KeyPress {}
#[derive(Component)]
pub struct Message<E: MessageTypeTrait, M> {
message_type: std::marker::PhantomData<E>,
pub producer: Box<dyn Fn(&E) -> Option<M> + Send + Sync>,
}
impl<E: MessageTypeTrait, M: Clone + Send + Sync + 'static> Message<E, M> {
pub fn new(content: M) -> Message<E, M> {
Message {
message_type: std::marker::PhantomData,
producer: Box::new(move |_| Some(content.clone())),
}
}
}
impl<E: MessageTypeTrait, M: Send + Sync + 'static> Message<E, M> {
pub fn from_event(content: impl Fn(&E) -> Option<M> + Send + Sync + 'static) -> Message<E, M> {
Message {
message_type: std::marker::PhantomData,
producer: Box::new(content),
}
}
}
fn on_event<E: MessageTypeTrait + Event + std::fmt::Debug, M: Send + Sync + 'static>(
event: On<E>,
mut commands: Commands,
q: Query<(Entity, &Message<E, M>, &RenderedLayout), With<WidgetNode>>,
) {
for (_entity, message, layout) in &q {
if let Some(mouse_position) = event.position()
&& !layout.0.contains_point(&mouse_position.0)
{
continue;
}
if let Some(content) = (message.producer)(&*event) {
commands.trigger(EntityMessage(content));
}
}
}
pub fn message_setup<M: Clone + Send + Sync + 'static>(world: &mut World) {
world.add_observer(on_event::<Click, M>);
world.add_observer(on_event::<DoubleClick, M>);
world.add_observer(on_event::<Scroll, M>);
world.add_observer(on_event::<KeyPress, M>);
}