Skip to main content

lgui_core/core/input/
handler.rs

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;