1use std::{future::Future, ops::Range, sync::Arc};
2
3use super::{
4 ActionId, KeyboardEvent, PointerData, UiAction, UiAsyncContext, UiEventContext, UiId,
5 WheelDelta,
6};
7
8pub type UiEventHandler = Arc<dyn Fn(&mut UiEventContext) + Send + Sync>;
9pub type UiInputEventHandler = Arc<dyn Fn(&mut UiEventContext, &UiEventPayload) + Send + Sync>;
10pub type UiActionHandler = Arc<dyn Fn(&mut UiEventContext, &UiAction) + Send + Sync>;
11pub type UiValueEventHandler<A> = Arc<dyn Fn(&mut UiEventContext, A) + Send + Sync>;
12
13pub fn async_handler<F, Fut>(handler: F) -> UiEventHandler
14where
15 F: Fn(UiAsyncContext) -> Fut + Send + Sync + 'static,
16 Fut: Future<Output = ()> + Send + 'static,
17{
18 Arc::new(move |context| {
19 let future = handler(context.async_context());
20 let _ = context.spawn(future);
21 })
22}
23
24pub fn async_handler_with<A, F, Fut>(handler: F) -> UiValueEventHandler<A>
25where
26 A: Send + 'static,
27 F: Fn(UiAsyncContext, A) -> Fut + Send + Sync + 'static,
28 Fut: Future<Output = ()> + Send + 'static,
29{
30 Arc::new(move |context, argument| {
31 let future = handler(context.async_context(), argument);
32 let _ = context.spawn(future);
33 })
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
37pub enum UiEventKind {
38 Click,
39 PointerDown,
40 PointerMove,
41 PointerUp,
42 Wheel,
43 KeyDown,
44 KeyUp,
45 Input,
46 CompositionStart,
47 CompositionUpdate,
48 CompositionEnd,
49 Focus,
50 Blur,
51 Change,
52}
53
54#[derive(Clone, Debug, PartialEq, Eq)]
55pub enum UiEventPayload {
56 Click,
57 PointerDown {
58 pointer: PointerData,
59 },
60 PointerMove {
61 pointer: PointerData,
62 },
63 PointerUp {
64 pointer: PointerData,
65 },
66 Wheel {
67 delta: WheelDelta,
68 },
69 Keyboard {
70 event: KeyboardEvent,
71 },
72 Input {
73 text: String,
74 },
75 CompositionStart,
76 CompositionUpdate {
77 text: String,
78 cursor: Option<Range<usize>>,
79 },
80 CompositionEnd,
81 Focus,
82 Blur,
83 Change {
84 value: Option<String>,
85 },
86}
87
88impl UiEventPayload {
89 pub const fn kind(&self) -> UiEventKind {
90 match self {
91 Self::Click => UiEventKind::Click,
92 Self::PointerDown { .. } => UiEventKind::PointerDown,
93 Self::PointerMove { .. } => UiEventKind::PointerMove,
94 Self::PointerUp { .. } => UiEventKind::PointerUp,
95 Self::Wheel { .. } => UiEventKind::Wheel,
96 Self::Keyboard {
97 event:
98 KeyboardEvent {
99 state: super::KeyState::Down,
100 ..
101 },
102 } => UiEventKind::KeyDown,
103 Self::Keyboard { .. } => UiEventKind::KeyUp,
104 Self::Input { .. } => UiEventKind::Input,
105 Self::CompositionStart => UiEventKind::CompositionStart,
106 Self::CompositionUpdate { .. } => UiEventKind::CompositionUpdate,
107 Self::CompositionEnd => UiEventKind::CompositionEnd,
108 Self::Focus => UiEventKind::Focus,
109 Self::Blur => UiEventKind::Blur,
110 Self::Change { .. } => UiEventKind::Change,
111 }
112 }
113}
114
115#[derive(Clone)]
116pub struct UiInputEventBinding {
117 pub kind: UiEventKind,
118 pub capture: bool,
119 pub handler: UiInputEventHandler,
120}
121
122#[derive(Clone)]
123pub struct UiHandlerEvent {
124 pub target: UiId,
125 pub payload: UiEventPayload,
126 pub capture_handlers: Vec<UiInputEventHandler>,
127 pub bubble_handlers: Vec<UiInputEventHandler>,
128}
129
130impl std::fmt::Debug for UiHandlerEvent {
131 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 formatter
133 .debug_struct("UiHandlerEvent")
134 .field("target", &self.target)
135 .field("payload", &self.payload)
136 .field("capture_handlers", &self.capture_handlers.len())
137 .field("bubble_handlers", &self.bubble_handlers.len())
138 .finish()
139 }
140}
141
142#[derive(Clone)]
143pub struct UiActionEvent {
144 pub target: UiId,
145 pub action: UiAction,
146 pub handler: UiActionHandler,
147}
148
149impl UiActionEvent {
150 pub fn dispatch(&self, context: &mut UiEventContext) {
151 (self.handler)(context, &self.action);
152 }
153}
154
155impl std::fmt::Debug for UiActionEvent {
156 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 formatter
158 .debug_struct("UiActionEvent")
159 .field("target", &self.target)
160 .field("action", &self.action)
161 .finish_non_exhaustive()
162 }
163}
164
165pub struct UiActionBinding {
166 pub id: ActionId,
167 pub handler: UiActionHandler,
168}
169
170impl Clone for UiActionBinding {
171 fn clone(&self) -> Self {
172 Self {
173 id: self.id.clone(),
174 handler: Arc::clone(&self.handler),
175 }
176 }
177}
178
179pub trait IntoUiHandler {
180 fn into_handler(self) -> UiEventHandler;
181}
182
183impl<F> IntoUiHandler for F
184where
185 F: Fn(&mut UiEventContext) + Send + Sync + 'static,
186{
187 fn into_handler(self) -> UiEventHandler {
188 Arc::new(self)
189 }
190}
191
192impl IntoUiHandler for UiEventHandler {
193 fn into_handler(self) -> UiEventHandler {
194 self
195 }
196}
197
198#[cfg(test)]
199#[path = "handler_test.rs"]
200mod tests;