Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
use bevy::prelude::{Entity, Resource, World};
use crate::{
cursor::{CursorEvent, ScrollEvent},
keyboard_event::KeyboardEvent,
prelude::{KayakWidgetContext, OnChange},
};
/// An event type sent to widgets
#[derive(Resource, Clone, Debug)]
pub struct KEvent {
/// The node targeted by this event
pub target: Entity,
/// The current target of this event
pub current_target: Entity,
/// The type of event
pub event_type: EventType,
/// Indicates whether this event should propagate or not
pub(crate) should_propagate: bool,
/// Indicates whether the default action of this event (if any) has been prevented
pub(crate) default_prevented: bool,
/// OnChange systems to call afterwards
pub(crate) on_change_systems: Vec<OnChange>,
}
impl PartialEq for KEvent {
fn eq(&self, other: &Self) -> bool {
self.target == other.target
&& self.current_target == other.current_target
&& self.event_type == other.event_type
&& self.should_propagate == other.should_propagate
&& self.default_prevented == other.default_prevented
}
}
impl Default for KEvent {
fn default() -> Self {
Self {
target: Entity::from_raw(0),
current_target: Entity::from_raw(0),
event_type: EventType::Click(CursorEvent::default()),
should_propagate: true,
default_prevented: false,
on_change_systems: Vec::new(),
}
}
}
impl KEvent {
/// Create a new event
///
/// This is the preferred method for creating an event as it automatically sets up
/// propagation and other event metadata in a standardized manner
pub fn new(target: Entity, event_type: EventType) -> Self {
Self {
target,
current_target: target,
should_propagate: event_type.propagates(),
event_type,
default_prevented: false,
on_change_systems: Vec::new(),
}
}
/// Returns whether this event is currently set to propagate
pub fn propagates(&self) -> bool {
self.should_propagate
}
/// If called, prevents this event from propagating up the hierarchy
pub fn stop_propagation(&mut self) {
if matches!(
self.event_type,
EventType::Click(..)
| EventType::MouseIn(..)
| EventType::MouseDown(..)
| EventType::Scroll(..)
| EventType::Focus
| EventType::Hover(..)
) {
self.should_propagate = false;
}
}
/// Returns whether this event's default action has been prevented or not
pub fn is_default_prevented(&self) -> bool {
self.default_prevented
}
/// Prevents this event's default action (if any) from being executed
pub fn prevent_default(&mut self) {
self.default_prevented = true;
}
pub fn add_system(&mut self, system: OnChange) {
self.on_change_systems.push(system);
}
pub(crate) fn run_on_change(&mut self, world: &mut World, widget_context: KayakWidgetContext) {
for system in self.on_change_systems.drain(..) {
system.try_call(self.current_target, world, widget_context.clone());
}
}
}
/// The type of event
///
/// __Note:__ This type implements `PartialEq` and `Hash` in a way that only considers the variant itself,
/// not the underlying data. If full comparisons are needed, they should be done with the inner data or
/// with a custom wrapper.
#[derive(Debug, Clone)]
pub enum EventType {
/// An event that occurs when the user clicks a widget
Click(CursorEvent),
/// An event that occurs when the user hovers the cursor over a widget
Hover(CursorEvent),
/// An event that occurs when the user moves the cursor into a widget
MouseIn(CursorEvent),
/// An event that occurs when the user moves the cursor out of a widget
MouseOut(CursorEvent),
/// An event that occurs when the user presses down on the cursor over a widget
MouseDown(CursorEvent),
/// An event that occurs when the user releases the cursor over a widget
MouseUp(CursorEvent),
/// An event that occurs when the user scrolls over a widget
Scroll(ScrollEvent),
/// An event that occurs when a widget receives focus
Focus,
/// An event that occurs when a widget loses focus
Blur,
/// An event that occurs when the user types in a character within a _focused_ widget
CharInput { c: smol_str::SmolStr },
/// An event that occurs when the user releases a key within a _focused_ widget
KeyUp(KeyboardEvent),
/// An event that occurs when the user presses a key down within a _focused_ widget
KeyDown(KeyboardEvent),
}
impl Eq for EventType {}
/// __Note:__ Only checks if the two event types are the same discriminant
impl PartialEq for EventType {
fn eq(&self, other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(other)
}
}
/// __Note:__ Only uses the discriminant for hashing
impl std::hash::Hash for EventType {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(&std::mem::discriminant(self), state);
}
}
/// The various categories an event can belong to
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EventCategory {
/// A category for events related to the mouse/cursor
Mouse,
/// A category for events related to the keyboard
Keyboard,
/// A category for events related to focus
Focus,
}
impl EventType {
/// Returns whether this event type should propagate by default
///
/// For more details on what should and shouldn't propagate, check out the
/// [W3 specifications](https://www.w3.org/TR/uievents/#event-types), upon which this is based.
pub fn propagates(&self) -> bool {
match self {
// Propagates
Self::Hover(..) => true,
Self::Click(..) => true,
Self::MouseDown(..) => true,
Self::MouseUp(..) => true,
Self::Scroll(..) => true,
Self::CharInput { .. } => true,
Self::KeyUp(..) => true,
Self::KeyDown(..) => true,
// Doesn't Propagate
Self::MouseIn(..) => false,
Self::MouseOut(..) => false,
Self::Focus => false,
Self::Blur => false,
}
}
/// Get the category of this event
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::Scroll(..) => EventCategory::Mouse,
// Keyboard
Self::CharInput { .. } => EventCategory::Keyboard,
Self::KeyUp(..) => EventCategory::Keyboard,
Self::KeyDown(..) => EventCategory::Keyboard,
// Focus
Self::Focus => EventCategory::Focus,
Self::Blur => EventCategory::Focus,
}
}
}