Skip to content
Snippets Groups Projects
Commit 4dec9831 authored by MrGVSV's avatar MrGVSV
Browse files

Added CursorEvent

Added the CursorEvent struct to the cursor-related enum variants on
EventType

Also changed how PartialEq and Hash work for EventType. They no longer
consider the inner variant data
parent 8ceca4d3
No related branches found
No related tags found
No related merge requests found
Showing
with 161 additions and 79 deletions
......@@ -90,7 +90,7 @@ Widget's can create their own state and will re-render when that state changes.
fn Counter(context: &mut KayakContext) {
let (count, set_count, ..) = use_state!(0i32);
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => set_count(count + 1),
EventType::Click(..) => set_count(count + 1),
_ => {}
});
......
......@@ -31,7 +31,7 @@ fn Counter(context: &mut KayakContext) {
let (count, set_count, ..) = use_state!(0i32);
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => set_count(count + 1),
EventType::Click(..) => set_count(count + 1),
_ => {}
});
......
......@@ -63,12 +63,12 @@ fn FolderTree(context: &mut KayakContext) {
let (is_b_open, set_b_open, ..) = use_state!(false);
let set_close_b = set_b_open.clone();
let close_b = Some(OnEvent::new(move |_, event| match event.event_type {
EventType::Click => set_close_b(false),
EventType::Click(..) => set_close_b(false),
_ => {}
}));
let set_open_b = set_b_open.clone();
let open_b = Some(OnEvent::new(move |_, event| match event.event_type {
EventType::Click => set_open_b(true),
EventType::Click(..) => set_open_b(true),
_ => {}
}));
......
......@@ -53,10 +53,10 @@ fn BlueButton(context: KayakContext, children: Children, styles: Option<Style>)
let cloned_current_button_handle = current_button_handle.clone();
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::MouseIn => {
EventType::MouseIn(..) => {
cloned_current_button_handle.set(blue_button_hover_handle);
}
EventType::MouseOut => {
EventType::MouseOut(..) => {
cloned_current_button_handle.set(blue_button_handle);
}
_ => (),
......
......@@ -39,7 +39,7 @@ fn StateCounter() {
// both implement `Copy`. For other types, you may have to clone the state to pass it into a closure like this.
// (You can also clone the setter as well if you need to use it in multiple places.)
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => set_count(count + 1),
EventType::Click(..) => set_count(count + 1),
_ => {}
});
......@@ -64,7 +64,7 @@ fn EffectCounter() {
// the third field in the tuple returned from the `use_state` macro.
let (count, set_count, raw_count) = use_state!(0);
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => set_count(count + 1),
EventType::Click(..) => set_count(count + 1),
_ => {}
});
......
......@@ -24,7 +24,7 @@ fn Removal(context: &mut KayakContext) {
let is_visible = context.create_state(true).unwrap();
let cloned_is_visible = is_visible.clone();
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => {
EventType::Click(..) => {
cloned_is_visible.set(!cloned_is_visible.get());
}
_ => {}
......
......@@ -89,7 +89,7 @@ fn ThemeButton(context: &mut KayakContext, theme: Theme) {
let theme_clone = Arc::new(theme);
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => {
EventType::Click(..) => {
// Update the shared state
// This will cause the ThemeProvider to re-render along with all of the other consumers
consumer.set((*theme_clone).clone());
......
......@@ -30,14 +30,14 @@ pub fn Tab(context: &mut KayakContext, content: String, selected: bool) {
};
let event_handler = OnEvent::new(move |_, event| match event.event_type {
EventType::Hover => {
EventType::Hover(..) => {
if selected {
set_hover_state(TabHoverState::Active);
} else {
set_hover_state(TabHoverState::Inactive);
}
}
EventType::MouseOut => {
EventType::MouseOut(..) => {
set_hover_state(TabHoverState::None);
}
EventType::Focus => {
......
......@@ -24,7 +24,7 @@ pub fn TabBar(
let on_select = on_select_tab.clone();
let tab_event_handler = OnEvent::new(move |_, event| {
match event.event_type {
EventType::Click => {
EventType::Click(..) => {
on_select.call(index);
}
EventType::KeyDown(evt) => {
......
......@@ -29,10 +29,10 @@ pub fn AddButton(children: Children, styles: Option<Style>) {
});
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::MouseIn => {
EventType::MouseIn(..) => {
set_color(Color::new(0.0791, 0.0998, 0.201, 1.0));
}
EventType::MouseOut => {
EventType::MouseOut(..) => {
set_color(Color::new(0.0781, 0.0898, 0.101, 1.0));
}
_ => {}
......
......@@ -24,7 +24,7 @@ pub fn Card(card_id: usize, name: String, on_delete: Handler<usize>) {
let on_delete = on_delete.clone();
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => {
EventType::Click(..) => {
on_delete.call(card_id);
}
_ => (),
......
......@@ -29,10 +29,10 @@ pub fn DeleteButton(children: Children, styles: Option<Style>) {
});
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::MouseIn => {
EventType::MouseIn(..) => {
set_color(Color::new(0.0791, 0.0998, 0.201, 1.0));
}
EventType::MouseOut => {
EventType::MouseOut(..) => {
set_color(Color::new(0.0781, 0.0898, 0.101, 1.0));
}
_ => {}
......
......@@ -61,7 +61,7 @@ fn TodoApp() {
let mut todos_cloned = todos.clone();
let cloned_set_todos = set_todos.clone();
let add_events = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => {
EventType::Click(..) => {
if !new_todo_value_cloned.is_empty() {
todos_cloned.push(Todo {
name: new_todo_value_cloned.clone(),
......
......@@ -97,7 +97,7 @@ fn ControlPanel() {
}
let on_change_color = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => {
EventType::Click(..) => {
// Cycle the color
set_color_index((color_index + 1) % COLORS.len());
}
......
......@@ -16,3 +16,11 @@ impl Default for PointerEvents {
Self::All
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct CursorEvent {
pub(crate) pressed: bool,
pub(crate) just_pressed: bool,
pub(crate) just_released: bool,
pub(crate) position: (f32, f32)
}
\ No newline at end of file
use derivative::Derivative;
use crate::{Index, KeyboardEvent};
use crate::cursor::CursorEvent;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Event {
......@@ -19,7 +21,7 @@ impl Default for Event {
Self {
target: Default::default(),
current_target: Default::default(),
event_type: EventType::Click,
event_type: EventType::Click(CursorEvent::default()),
should_propagate: true,
default_prevented: false,
}
......@@ -62,19 +64,52 @@ impl Event {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, Derivative)]
#[derivative(PartialEq, Hash, Eq)]
pub enum EventType {
Click,
Hover,
MouseIn,
MouseOut,
MouseDown,
MouseUp,
Click(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
CursorEvent
),
Hover(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
CursorEvent
),
MouseIn(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
CursorEvent
),
MouseOut(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
CursorEvent
),
MouseDown(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
CursorEvent
),
MouseUp(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
CursorEvent
),
Focus,
Blur,
CharInput { c: char },
KeyUp(KeyboardEvent),
KeyDown(KeyboardEvent),
KeyUp(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
KeyboardEvent
),
KeyDown(
#[derivative(PartialEq = "ignore")]
#[derivative(Hash = "ignore")]
KeyboardEvent
),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
......@@ -92,16 +127,16 @@ impl EventType {
pub fn propagates(&self) -> bool {
match self {
// Propagates
Self::Hover => true,
Self::Click => true,
Self::MouseDown => true,
Self::MouseUp => true,
Self::Hover(..) => true,
Self::Click(..) => true,
Self::MouseDown(..) => true,
Self::MouseUp(..) => true,
Self::CharInput { .. } => true,
Self::KeyUp(..) => true,
Self::KeyDown(..) => true,
// Doesn't Propagate
Self::MouseIn => false,
Self::MouseOut => false,
Self::MouseIn(..) => false,
Self::MouseOut(..) => false,
Self::Focus => false,
Self::Blur => false,
}
......@@ -111,12 +146,12 @@ impl EventType {
pub fn event_category(&self) -> EventCategory {
match self {
// Mouse
Self::Hover => EventCategory::Mouse,
Self::Click => EventCategory::Mouse,
Self::MouseDown => EventCategory::Mouse,
Self::MouseUp => EventCategory::Mouse,
Self::MouseIn => EventCategory::Mouse,
Self::MouseOut => EventCategory::Mouse,
Self::Hover(..) => EventCategory::Mouse,
Self::Click(..) => EventCategory::Mouse,
Self::MouseDown(..) => EventCategory::Mouse,
Self::MouseUp(..) => EventCategory::Mouse,
Self::MouseIn(..) => EventCategory::Mouse,
Self::MouseOut(..) => EventCategory::Mouse,
// Keyboard
Self::CharInput { .. } => EventCategory::Keyboard,
Self::KeyUp(..) => EventCategory::Keyboard,
......
......@@ -8,6 +8,7 @@ use crate::{
KeyboardModifiers, PointerEvents, Widget,
};
use std::collections::{HashMap, HashSet};
use crate::cursor::CursorEvent;
type EventMap = HashMap<Index, HashSet<EventType>>;
type TreeNode = (
......@@ -37,6 +38,7 @@ impl Default for EventState {
#[derive(Debug, Clone)]
pub(crate) struct EventDispatcher {
is_mouse_pressed: bool,
next_mouse_pressed: bool,
current_mouse_position: (f32, f32),
next_mouse_position: (f32, f32),
previous_events: EventMap,
......@@ -52,6 +54,7 @@ impl EventDispatcher {
Self {
last_clicked: Binding::new(Index::default()),
is_mouse_pressed: Default::default(),
next_mouse_pressed: Default::default(),
current_mouse_position: Default::default(),
next_mouse_position: Default::default(),
previous_events: Default::default(),
......@@ -163,17 +166,17 @@ impl EventDispatcher {
// Events that need to be maintained without re-firing between event updates should be managed here
for (index, events) in &self.previous_events {
// Mouse is currently pressed for this node
if self.is_mouse_pressed && events.contains(&EventType::MouseDown) {
if self.is_mouse_pressed && events.contains(&EventType::MouseDown(Default::default())) {
// Make sure this event isn't removed while mouse is still held down
Self::insert_event(&mut next_events, index, EventType::MouseDown);
Self::insert_event(&mut next_events, index, EventType::MouseDown(Default::default()));
}
// Mouse is currently within this node
if events.contains(&EventType::MouseIn)
&& !Self::contains_event(&next_events, index, &EventType::MouseOut)
if events.contains(&EventType::MouseIn(Default::default()))
&& !Self::contains_event(&next_events, index, &EventType::MouseOut(Default::default()))
{
// Make sure this event isn't removed while mouse is still within node
Self::insert_event(&mut next_events, index, EventType::MouseIn);
Self::insert_event(&mut next_events, index, EventType::MouseIn(Default::default()));
}
}
......@@ -201,6 +204,30 @@ impl EventDispatcher {
let old_wants_cursor = self.wants_cursor;
self.contains_cursor = None;
self.wants_cursor = None;
self.next_mouse_position = self.current_mouse_position;
self.next_mouse_pressed = self.is_mouse_pressed;
// --- Pre-Process --- //
// We pre-process some events so that we can provide accurate event data (such as if the mouse is pressed)
// This is faster than resolving data after the fact since `input_events` is generally very small
for input_event in input_events {
if let InputEvent::MouseMoved(point) = input_event {
// Reset next global mouse position
self.next_mouse_position = *point;
}
if matches!(input_event, InputEvent::MouseLeftPress) {
// Reset next global mouse pressed
self.next_mouse_pressed = true;
break;
} else if matches!(input_event, InputEvent::MouseLeftRelease) {
// Reset next global mouse pressed
self.next_mouse_pressed = false;
// Reset global cursor container
self.has_cursor = None;
break;
}
}
// === Mouse Events === //
let mut stack: Vec<TreeNode> = vec![(root, 0)];
......@@ -212,12 +239,7 @@ impl EventDispatcher {
// --- Process Event --- //
if matches!(input_event.category(), InputEventCategory::Mouse) {
// A widget's PointerEvents style will determine how it and its children are processed
let mut pointer_events = PointerEvents::default();
if let Some(widget) = widget_manager.current_widgets.get(current).unwrap() {
if let Some(styles) = widget.get_styles() {
pointer_events = styles.pointer_events.resolve();
}
}
let pointer_events = Self::resolve_pointer_events(current, widget_manager);
match pointer_events {
PointerEvents::All | PointerEvents::SelfOnly => {
......@@ -226,6 +248,7 @@ impl EventDispatcher {
(current, depth),
&mut states,
widget_manager,
false,
);
event_stream.extend(events);
......@@ -290,6 +313,7 @@ impl EventDispatcher {
// === Process Cursor States === //
self.current_mouse_position = self.next_mouse_position;
self.is_mouse_pressed = self.next_mouse_pressed;
if self.contains_cursor.is_none() {
// No change -> revert
......@@ -309,6 +333,7 @@ impl EventDispatcher {
tree_node: TreeNode,
states: &mut HashMap<EventType, EventState>,
widget_manager: &WidgetManager,
ignore_layout: bool
) -> Vec<Event> {
let mut event_stream = Vec::<Event>::new();
let (node, depth) = tree_node;
......@@ -316,19 +341,20 @@ impl EventDispatcher {
match input_event {
InputEvent::MouseMoved(point) => {
if let Some(layout) = widget_manager.get_layout(&node) {
let cursor_event = self.get_cursor_event(*point);
let was_contained = layout.contains(&self.current_mouse_position);
let is_contained = layout.contains(point);
if was_contained != is_contained {
if !ignore_layout && was_contained != is_contained {
if was_contained {
event_stream.push(Event::new(node, EventType::MouseOut));
event_stream.push(Event::new(node, EventType::MouseOut(cursor_event)));
} else {
event_stream.push(Event::new(node, EventType::MouseIn));
event_stream.push(Event::new(node, EventType::MouseIn(cursor_event)));
}
}
if self.contains_cursor.is_none() || !self.contains_cursor.unwrap_or_default() {
if let Some(widget) = widget_manager.current_widgets.get(node).unwrap() {
// Check if the cursor moved onto a widget that qualifies as one that can contain it
if Self::can_contain_cursor(widget) {
if ignore_layout || Self::can_contain_cursor(widget) {
self.contains_cursor = Some(is_contained);
}
}
......@@ -343,21 +369,16 @@ impl EventDispatcher {
}
// Check for hover eligibility
if is_contained {
Self::update_state(states, (node, depth), layout, EventType::Hover);
if ignore_layout || is_contained {
Self::update_state(states, (node, depth), layout, EventType::Hover(cursor_event));
}
}
// Reset global mouse position
self.next_mouse_position = *point;
}
InputEvent::MouseLeftPress => {
// Reset global mouse pressed
self.is_mouse_pressed = true;
if let Some(layout) = widget_manager.get_layout(&node) {
if layout.contains(&self.current_mouse_position) {
event_stream.push(Event::new(node, EventType::MouseDown));
if ignore_layout || layout.contains(&self.current_mouse_position) {
let cursor_event = self.get_cursor_event(self.current_mouse_position);
event_stream.push(Event::new(node, EventType::MouseDown(cursor_event)));
if let Some(focusable) = widget_manager.get_focusable(node) {
if focusable {
......@@ -378,18 +399,15 @@ impl EventDispatcher {
}
}
InputEvent::MouseLeftRelease => {
// Reset global mouse pressed
self.is_mouse_pressed = false;
self.has_cursor = None;
if let Some(layout) = widget_manager.get_layout(&node) {
if layout.contains(&self.current_mouse_position) {
event_stream.push(Event::new(node, EventType::MouseUp));
if ignore_layout || layout.contains(&self.current_mouse_position) {
let cursor_event = self.get_cursor_event(self.current_mouse_position);
event_stream.push(Event::new(node, EventType::MouseUp(cursor_event)));
self.last_clicked.set(node);
if Self::contains_event(&self.previous_events, &node, &EventType::MouseDown)
if Self::contains_event(&self.previous_events, &node, &EventType::MouseDown(cursor_event))
{
Self::update_state(states, (node, depth), layout, EventType::Click);
Self::update_state(states, (node, depth), layout, EventType::Click(cursor_event));
}
}
}
......@@ -400,6 +418,27 @@ impl EventDispatcher {
event_stream
}
fn resolve_pointer_events(index: Index, widget_manager: &WidgetManager) -> PointerEvents {
let mut pointer_events = PointerEvents::default();
if let Some(widget) = widget_manager.current_widgets.get(index).unwrap() {
if let Some(styles) = widget.get_styles() {
pointer_events = styles.pointer_events.resolve();
}
}
pointer_events
}
fn get_cursor_event(&self, position: (f32, f32)) -> CursorEvent {
let change = self.next_mouse_pressed != self.is_mouse_pressed;
let pressed = self.next_mouse_pressed;
CursorEvent {
position,
pressed,
just_pressed: change && pressed,
just_released: change && !pressed,
}
}
fn process_keyboard_events(
&mut self,
input_event: &InputEvent,
......
......@@ -137,7 +137,7 @@ pub fn dyn_partial_eq(_: TokenStream, input: TokenStream) -> TokenStream {
/// let (count, set_count, ..) = use_state!(0);
///
/// let on_event = OnEvent::new(move |_, event| match event.event_type {
/// EventType::Click => {
/// EventType::Click(..) => {
/// set_count(foo + 1);
/// }
/// _ => {}
......@@ -215,7 +215,7 @@ pub fn use_state(initial_state: TokenStream) -> TokenStream {
/// }, [count_state]);
///
/// let on_event = OnEvent::new(move |_, event| match event.event_type {
/// EventType::Click => {
/// EventType::Click(..) => {
/// set_count(foo + 1);
/// }
/// _ => {}
......
......@@ -54,7 +54,7 @@ pub fn Fold(
}
let handler = OnEvent::new(move |_, event| match event.event_type {
EventType::Click => {
EventType::Click(..) => {
if open.is_none() {
// This is an internally-managed state
set_is_open(!is_open);
......
......@@ -72,7 +72,7 @@ pub fn Inspector() {
}
let handle_button_events = Some(OnEvent::new(move |_, event| match event.event_type {
EventType::Click => last_clicked.set(parent_id_move.unwrap()),
EventType::Click(..) => last_clicked.set(parent_id_move.unwrap()),
_ => {}
}));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment