diff --git a/ui/src/events/mod.rs b/ui/src/events/mod.rs index 072bde7..3982a8a 100644 --- a/ui/src/events/mod.rs +++ b/ui/src/events/mod.rs @@ -6,6 +6,7 @@ pub use winit::event::{TouchPhase, MouseScrollDelta, DeviceId, ModifiersState, V use crate::SharedNode; +#[derive(Clone, Debug)] pub struct NodeEvent { /// Target node of event. pub target: SharedNode, @@ -16,6 +17,7 @@ pub struct NodeEvent { } /// Different event types that can be sent to a node. +#[derive(Clone, Debug, PartialEq)] pub enum InnerEvent { Wheel { phase: TouchPhase, @@ -56,6 +58,7 @@ pub enum InnerEvent { KeyUp(KeyboardEvent), } +#[derive(Clone, Debug, PartialEq)] pub struct KeyboardEvent { /// Logical location ("it's effect") of the key pub key: Option, @@ -77,6 +80,7 @@ pub struct KeyboardEvent { pub device: DeviceId } +#[derive(Clone, Debug, PartialEq)] pub struct MouseEvent { /// The button which fired the event (if any) pub button: Option, @@ -214,14 +218,14 @@ impl MouseEvent { } } -#[derive(Default)] +#[derive(Copy, Clone, Default, Debug, PartialEq)] pub(crate) struct MouseValue { pub last_location: Location, pub buttons: u8 } impl MouseValue { - fn update_buttons(&mut self, button: MouseButton, state: ElementState) { + pub(crate) fn update_buttons(&mut self, button: MouseButton, state: ElementState) { let buttons = MouseEvent::button_to_buttons(button); match state { ElementState::Pressed => self.buttons |= buttons, diff --git a/ui/src/lib.rs b/ui/src/lib.rs index f4eac64..a21b040 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -81,15 +81,14 @@ pub fn run_event_loop(root_node: SharedNode) -> ! { WindowEvent::MouseWheel { device_id, delta, phase, .. } => {}, WindowEvent::CursorMoved { device_id, position, .. } => { let mouse_value = mouse_values.get(&device_id); - let (movement, location, buttons) = match mouse_value { + let (movement, location, mouse_value) = match mouse_value { Some(mouse_value) => { let location = (position.x, position.y).into(); let movement = location - mouse_value.last_location; - mouse_values.insert(device_id, MouseValue { + (movement, location, MouseValue { last_location: location, buttons: mouse_value.buttons - }); - (movement, location, mouse_value.buttons) + }) }, None => { let location = (position.x, position.y).into(); @@ -98,10 +97,11 @@ pub fn run_event_loop(root_node: SharedNode) -> ! { last_location: location, buttons: 0 }; - mouse_values.insert(device_id, value); - (movement, location, Default::default()) + (movement, location, value) } }; + let buttons = mouse_value.buttons; + mouse_values.insert(device_id, mouse_value); let path = get_element_at(&root, &context, location); @@ -111,7 +111,7 @@ pub fn run_event_loop(root_node: SharedNode) -> ! { Some(target_layout) => target_layout, None => { return; } }; - let target_layout = taffy.layout(target_layout.to_owned()).unwrap(); + let target_layout = context.taffy.layout(target_layout.to_owned()).unwrap(); let event = NodeEvent { target: path.last().unwrap().clone(), path: path.clone(), @@ -125,6 +125,10 @@ pub fn run_event_loop(root_node: SharedNode) -> ! { offset: location - target_layout.location.into() }) }; + + for node in path.iter().rev() { + node.write().unwrap().on_event(&event); + } } }, WindowEvent::DroppedFile(path) => {}, @@ -143,7 +147,7 @@ pub fn run_event_loop(root_node: SharedNode) -> ! { path: strong_focus_path.clone(), event: if focused { events::InnerEvent::Focus } else { events::InnerEvent::Blur } }; - strong_focus_path.last().unwrap().write().unwrap().on_event(&focus_event.event); + strong_focus_path.last().unwrap().write().unwrap().on_event(&focus_event); let focus_event = NodeEvent { target: strong_focus_path.last().unwrap().clone(), @@ -152,7 +156,7 @@ pub fn run_event_loop(root_node: SharedNode) -> ! { }; for node in strong_focus_path.iter().rev() { - node.write().unwrap().on_event(&focus_event.event); + node.write().unwrap().on_event(&focus_event); } }, None => {} @@ -162,10 +166,41 @@ pub fn run_event_loop(root_node: SharedNode) -> ! { WindowEvent::KeyboardInput { device_id, input, is_synthetic } => {}, WindowEvent::MouseInput { device_id, state, button, .. } => { let mouse_value = mouse_values.get(&device_id); - let mouse_value = match mouse_value { - Some(mouse_value) => mouse_value, + let mut mouse_value = match mouse_value { + Some(mouse_value) => mouse_value.clone(), None => { return; } // Mouse move should be fired first }; + mouse_value.update_buttons(button, state); + + let location = mouse_value.last_location; + let path = get_element_at(&root, &context, location); + + match path { + Some(path) => { + let mevent = MouseEvent { + button: Some(button), + buttons: mouse_value.buttons, + client: location, + movement: Location::new(0., 0.), + device: device_id, + modifiers, + offset: Location::new(0., 0.) + }; + let event = NodeEvent { + target: path.last().unwrap().clone(), + path: path.clone(), + event: match state { + winit::event::ElementState::Pressed => events::InnerEvent::MouseDown(mevent), + winit::event::ElementState::Released => events::InnerEvent::MouseUp(mevent) + } + }; + + for node in path.iter().rev() { + node.write().unwrap().on_event(&event); + } + }, + None => {} + } }, WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::Resized(size) => { diff --git a/ui/src/nodes/layout.rs b/ui/src/nodes/layout.rs index d95fc6d..82516f0 100644 --- a/ui/src/nodes/layout.rs +++ b/ui/src/nodes/layout.rs @@ -38,4 +38,6 @@ impl Node for Layout { self.style.layout.size.width = Dimension::Points(width); self.style.layout.size.height = Dimension::Points(height); } + + fn on_event(&mut self, event: &crate::events::NodeEvent) {} } \ No newline at end of file diff --git a/ui/src/nodes/mod.rs b/ui/src/nodes/mod.rs index b248d3d..2fcfebb 100644 --- a/ui/src/nodes/mod.rs +++ b/ui/src/nodes/mod.rs @@ -64,19 +64,21 @@ pub trait Node: Debug { /// Render the node, called after rendering it's children /// Canvas considers 0, 0 to be top left corner (for location after layouting happens) fn render_post_children(&self, _context: &mut RenderContext, _layout: Layout) {} + /// Called when an event happens on the node. This is called after the children have been called. + /// Beware! Events include a path and target with [Arc>]s, but you already have a write lock for this node! + /// Remember to check if the node is the same as self, and if it is, use self instead of the node in the path to prevent deadlocks! + fn on_event(&mut self, _event: &crate::events::NodeEvent) {} + + /// Called when the size of window changes on the root node. Layouts do implement this. /// Is an optional function instead of another trait because of missing support for trait upcasting // TODO: When rust supports trait upcasting, make this a trait fn resize(&mut self, _width: f32, _height: f32) {} - - /// Called when an event happens on the node. This is called after the children have been called. - /// Beware! Events include a path and target with [Arc>]s, but you already have a write lock for this node! - /// Remember to check if the node is the same as self, and if it is, use self instead of the node in the path to prevent deadlocks! - fn on_event(&mut self, _event: &crate::events::InnerEvent) {} } pub fn get_element_at(node: &SharedTNode, context: &RenderContext, location: Location) -> Option> { - let children = node.read().unwrap().children(); + let node_borrowed = node.read().unwrap(); + let children = node_borrowed.children(); let taffy_node = context.node_layout.get(node); let taffy_node = match taffy_node { Some(taffy_node) => taffy_node, diff --git a/ui/src/nodes/primitives.rs b/ui/src/nodes/primitives.rs index 5cec0a9..2760445 100644 --- a/ui/src/nodes/primitives.rs +++ b/ui/src/nodes/primitives.rs @@ -40,4 +40,6 @@ impl Node for Rectangle { &self.fill ); } + + fn on_event(&mut self, event: &crate::events::NodeEvent) {} } \ No newline at end of file