Skip to main content

embedded_gui/
input.rs

1use crate::widget::{EventPhase, WidgetId};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum PointerButton {
5    Primary,
6    Secondary,
7}
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum PointerState {
11    Pressed,
12    Released,
13    Moved,
14}
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum InputEvent {
18    Up,
19    Down,
20    Left,
21    Right,
22    SelectLeft,
23    SelectRight,
24    Home,
25    End,
26    SelectHome,
27    SelectEnd,
28    WordLeft,
29    WordRight,
30    SelectWordLeft,
31    SelectWordRight,
32    Undo,
33    Redo,
34    Select,
35    SelectPressed,
36    SelectReleased,
37    Back,
38    BackPressed,
39    BackReleased,
40    Encoder {
41        delta: i8,
42    },
43    Pointer {
44        x: i32,
45        y: i32,
46        state: PointerState,
47        button: PointerButton,
48    },
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub enum UiEvent {
53    FocusChanged {
54        old: Option<WidgetId>,
55        new: Option<WidgetId>,
56    },
57    Activate(WidgetId),
58    Back,
59    Pressed(WidgetId),
60    Released(WidgetId),
61    Clicked(WidgetId),
62    DoubleClicked(WidgetId),
63    LongPressed(WidgetId),
64    Opened(WidgetId),
65    Closed(WidgetId),
66    PointerPressed(WidgetId),
67    PointerReleased(WidgetId),
68    Gesture(WidgetId),
69    ValueChanged(WidgetId),
70    TextInput {
71        id: WidgetId,
72        ch: char,
73    },
74    Focused(WidgetId),
75    Defocused(WidgetId),
76    Scroll {
77        id: WidgetId,
78        delta: i32,
79    },
80    LayoutChanged(WidgetId),
81    StyleChanged(WidgetId),
82}
83
84#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
85pub struct UiEventFilter(u16);
86
87impl UiEventFilter {
88    pub const FOCUS: Self = Self(1 << 0);
89    pub const ACTIVATE: Self = Self(1 << 1);
90    pub const BACK: Self = Self(1 << 2);
91    pub const POINTER: Self = Self(1 << 3);
92    pub const VALUE: Self = Self(1 << 4);
93    pub const SCROLL: Self = Self(1 << 5);
94    pub const LAYOUT: Self = Self(1 << 6);
95    pub const STYLE: Self = Self(1 << 7);
96
97    pub const ALL: Self = Self(
98        Self::FOCUS.0
99            | Self::ACTIVATE.0
100            | Self::BACK.0
101            | Self::POINTER.0
102            | Self::VALUE.0
103            | Self::SCROLL.0
104            | Self::LAYOUT.0
105            | Self::STYLE.0,
106    );
107
108    pub const fn empty() -> Self {
109        Self(0)
110    }
111
112    pub const fn contains(self, other: Self) -> bool {
113        self.0 & other.0 == other.0
114    }
115
116    pub fn insert(&mut self, other: Self) {
117        self.0 |= other.0;
118    }
119
120    pub fn remove(&mut self, other: Self) {
121        self.0 &= !other.0;
122    }
123}
124
125impl core::ops::BitOr for UiEventFilter {
126    type Output = Self;
127
128    fn bitor(self, rhs: Self) -> Self::Output {
129        Self(self.0 | rhs.0)
130    }
131}
132
133impl UiEvent {
134    pub const fn target(self) -> Option<WidgetId> {
135        match self {
136            Self::FocusChanged { new, .. } => new,
137            Self::Activate(id)
138            | Self::Pressed(id)
139            | Self::Released(id)
140            | Self::Clicked(id)
141            | Self::DoubleClicked(id)
142            | Self::LongPressed(id)
143            | Self::Opened(id)
144            | Self::Closed(id)
145            | Self::PointerPressed(id)
146            | Self::PointerReleased(id)
147            | Self::Gesture(id)
148            | Self::ValueChanged(id)
149            | Self::TextInput { id, .. }
150            | Self::Focused(id)
151            | Self::Defocused(id)
152            | Self::LayoutChanged(id)
153            | Self::StyleChanged(id) => Some(id),
154            Self::Scroll { id, .. } => Some(id),
155            Self::Back => None,
156        }
157    }
158
159    pub const fn filter(self) -> UiEventFilter {
160        match self {
161            Self::FocusChanged { .. } | Self::Focused(_) | Self::Defocused(_) => {
162                UiEventFilter::FOCUS
163            }
164            Self::Activate(_)
165            | Self::Pressed(_)
166            | Self::Released(_)
167            | Self::Clicked(_)
168            | Self::DoubleClicked(_)
169            | Self::LongPressed(_)
170            | Self::Opened(_)
171            | Self::Closed(_) => UiEventFilter::ACTIVATE,
172            Self::Back => UiEventFilter::BACK,
173            Self::PointerPressed(_) | Self::PointerReleased(_) | Self::Gesture(_) => {
174                UiEventFilter::POINTER
175            }
176            Self::ValueChanged(_) | Self::TextInput { .. } => UiEventFilter::VALUE,
177            Self::Scroll { .. } => UiEventFilter::SCROLL,
178            Self::LayoutChanged(_) => UiEventFilter::LAYOUT,
179            Self::StyleChanged(_) => UiEventFilter::STYLE,
180        }
181    }
182}
183
184#[derive(Clone, Copy, Debug, PartialEq, Eq)]
185pub enum WidgetEventKind {
186    Pressed,
187    Released,
188    Clicked,
189    DoubleClicked,
190    LongPressed,
191    Opened,
192    Closed,
193    ValueChanged,
194    Focused,
195    Defocused,
196    Scroll { delta: i32 },
197    Gesture,
198    LayoutChanged,
199    StyleChanged,
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub struct WidgetEvent {
204    pub target: WidgetId,
205    pub current: WidgetId,
206    pub phase: EventPhase,
207    pub kind: WidgetEventKind,
208}
209
210#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
211pub struct WidgetEventFilter(u16);
212
213impl WidgetEventFilter {
214    pub const POINTER: Self = Self(1 << 0);
215    pub const ACTIVATE: Self = Self(1 << 1);
216    pub const VALUE: Self = Self(1 << 2);
217    pub const FOCUS: Self = Self(1 << 3);
218    pub const SCROLL: Self = Self(1 << 4);
219    pub const LAYOUT: Self = Self(1 << 5);
220    pub const STYLE: Self = Self(1 << 6);
221
222    pub const ALL: Self = Self(
223        Self::POINTER.0
224            | Self::ACTIVATE.0
225            | Self::VALUE.0
226            | Self::FOCUS.0
227            | Self::SCROLL.0
228            | Self::LAYOUT.0
229            | Self::STYLE.0,
230    );
231
232    pub const fn contains(self, other: Self) -> bool {
233        self.0 & other.0 == other.0
234    }
235}
236
237impl core::ops::BitOr for WidgetEventFilter {
238    type Output = Self;
239
240    fn bitor(self, rhs: Self) -> Self::Output {
241        Self(self.0 | rhs.0)
242    }
243}
244
245impl WidgetEventKind {
246    pub const fn filter(self) -> WidgetEventFilter {
247        match self {
248            Self::Pressed | Self::Released | Self::Gesture => WidgetEventFilter::POINTER,
249            Self::Clicked
250            | Self::DoubleClicked
251            | Self::LongPressed
252            | Self::Opened
253            | Self::Closed => WidgetEventFilter::ACTIVATE,
254            Self::ValueChanged => WidgetEventFilter::VALUE,
255            Self::Focused | Self::Defocused => WidgetEventFilter::FOCUS,
256            Self::Scroll { .. } => WidgetEventFilter::SCROLL,
257            Self::LayoutChanged => WidgetEventFilter::LAYOUT,
258            Self::StyleChanged => WidgetEventFilter::STYLE,
259        }
260    }
261}
262
263#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
264pub struct EventPhaseMask(u8);
265
266impl EventPhaseMask {
267    pub const CAPTURE: Self = Self(1 << 0);
268    pub const TARGET: Self = Self(1 << 1);
269    pub const BUBBLE: Self = Self(1 << 2);
270    pub const ALL: Self = Self(Self::CAPTURE.0 | Self::TARGET.0 | Self::BUBBLE.0);
271
272    pub const fn contains(self, phase: EventPhase) -> bool {
273        let bit = match phase {
274            EventPhase::Capture => Self::CAPTURE.0,
275            EventPhase::Target => Self::TARGET.0,
276            EventPhase::Bubble => Self::BUBBLE.0,
277        };
278        self.0 & bit == bit
279    }
280}
281
282#[derive(Clone, Copy, Debug, PartialEq, Eq)]
283pub struct WidgetDispatchPolicy {
284    pub kinds: WidgetEventFilter,
285    pub phases: EventPhaseMask,
286    pub stop: bool,
287}
288
289impl WidgetDispatchPolicy {
290    pub const fn stop(kinds: WidgetEventFilter, phases: EventPhaseMask) -> Self {
291        Self {
292            kinds,
293            phases,
294            stop: true,
295        }
296    }
297
298    pub const fn allows(self, kind: WidgetEventKind, phase: EventPhase) -> bool {
299        self.kinds.contains(kind.filter()) && self.phases.contains(phase)
300    }
301}