1use linear_map::{LinearMap, set::LinearSet};
9use smallvec::SmallVec;
10use std::any::TypeId;
11use std::collections::{HashMap, VecDeque};
12use std::future::Future;
13use std::ops::{Deref, DerefMut};
14use std::pin::Pin;
15use std::time::Instant;
16
17use super::*;
18use crate::cast::{Cast, Conv};
19use crate::config::{ConfigMsg, WindowConfig};
20use crate::draw::DrawShared;
21use crate::geom::{Offset, Rect, Vec2};
22use crate::messages::Erased;
23use crate::runner::{Platform, RunnerT, WindowDataErased};
24use crate::theme::{SizeCx, ThemeSize};
25use crate::window::{PopupDescriptor, WindowId};
26use crate::{Action, HasId, Id, Node};
27use key::PendingSelFocus;
28use nav::PendingNavFocus;
29
30#[cfg(feature = "accesskit")] mod accessibility;
31mod key;
32mod nav;
33mod press;
34mod send;
35mod timer;
36mod window;
37
38pub use nav::NavAdvance;
39pub use press::{GrabBuilder, GrabMode, Press, PressSource, PressStart};
40pub(crate) use press::{Mouse, Touch};
41pub use timer::TimerHandle;
42
43struct PopupState {
44 id: WindowId,
45 desc: PopupDescriptor,
46 old_nav_focus: Option<Id>,
47 is_sized: bool,
48}
49
50pub struct EventState {
68 pub(crate) window_id: WindowId,
69 pub(crate) config: WindowConfig,
70 platform: Platform,
71 disabled: Vec<Id>,
72 window_has_focus: bool,
73 #[cfg(feature = "accesskit")]
74 accesskit_is_enabled: bool,
75 modifiers: ModifiersState,
76 key_focus: bool,
78 ime: Option<ImePurpose>,
79 old_ime_target: Option<Id>,
80 ime_cursor_area: Rect,
82 last_ime_rect: Rect,
83 sel_focus: Option<Id>,
84 nav_focus: Option<Id>,
85 nav_fallback: Option<Id>,
86 key_depress: LinearMap<PhysicalKey, Id>,
87 mouse: Mouse,
88 touch: Touch,
89 access_keys: HashMap<Key, Id>,
90 popups: SmallVec<[PopupState; 16]>,
91 popup_removed: SmallVec<[(Id, WindowId); 16]>,
92 time_updates: Vec<(Instant, Id, TimerHandle)>,
93 frame_updates: LinearSet<(Id, TimerHandle)>,
94 need_frame_update: bool,
95 send_queue: VecDeque<(Id, Erased)>,
97 fut_messages: Vec<(Id, Pin<Box<dyn Future<Output = Erased>>>)>,
99 pub(super) pending_send_targets: Vec<(TypeId, Id)>,
100 pending_update: Option<Id>,
102 pending_sel_focus: Option<PendingSelFocus>,
104 pending_nav_focus: PendingNavFocus,
105 pub(crate) action: Action,
106}
107
108impl EventState {
109 #[inline]
111 pub(crate) fn new(window_id: WindowId, config: WindowConfig, platform: Platform) -> Self {
112 EventState {
113 window_id,
114 config,
115 platform,
116 disabled: vec![],
117 window_has_focus: false,
118 #[cfg(feature = "accesskit")]
119 accesskit_is_enabled: false,
120 modifiers: ModifiersState::empty(),
121 key_focus: false,
122 ime: None,
123 old_ime_target: None,
124 ime_cursor_area: Rect::ZERO,
125 last_ime_rect: Rect::ZERO,
126 sel_focus: None,
127 nav_focus: None,
128 nav_fallback: None,
129 key_depress: Default::default(),
130 mouse: Default::default(),
131 touch: Default::default(),
132 access_keys: Default::default(),
133 popups: Default::default(),
134 popup_removed: Default::default(),
135 time_updates: vec![],
136 frame_updates: Default::default(),
137 need_frame_update: false,
138 send_queue: Default::default(),
139 pending_send_targets: vec![],
140 fut_messages: vec![],
141 pending_update: None,
142 pending_sel_focus: None,
143 pending_nav_focus: PendingNavFocus::None,
144 action: Action::empty(),
145 }
146 }
147
148 pub(crate) fn update_config(&mut self, scale_factor: f32) {
150 self.config.update(scale_factor);
151 }
152
153 pub(crate) fn full_configure(&mut self, sizer: &dyn ThemeSize, node: Node) {
163 let id = Id::ROOT.make_child(self.window_id.get().cast());
164
165 log::debug!(target: "kas_core::event", "full_configure of Window{id}");
166
167 self.nav_fallback = None;
169
170 ConfigCx::new(sizer, self).configure(node, id);
171 self.action |= Action::REGION_MOVED;
172 }
173
174 #[inline]
178 pub(crate) fn with<'a, F: FnOnce(&mut EventCx)>(
179 &'a mut self,
180 runner: &'a mut dyn RunnerT,
181 window: &'a dyn WindowDataErased,
182 f: F,
183 ) {
184 let mut cx = EventCx {
185 state: self,
186 runner,
187 window,
188 target_is_disabled: false,
189 last_child: None,
190 scroll: Scroll::None,
191 };
192 f(&mut cx);
193 }
194
195 fn cancel_event_focus(&mut self, target: &Id) {
197 self.clear_sel_socus_on(target);
198 self.clear_nav_focus_on(target);
199 self.mouse.cancel_event_focus(target);
200 self.touch.cancel_event_focus(target);
201 }
202
203 #[inline]
207 pub fn is_disabled(&self, w_id: &Id) -> bool {
208 for id in &self.disabled {
210 if id.is_ancestor_of(w_id) {
211 return true;
212 }
213 }
214 false
215 }
216
217 #[inline]
219 pub fn config(&self) -> &WindowConfig {
220 &self.config
221 }
222
223 #[inline]
225 pub fn config_enable_pan(&self, source: PressSource) -> bool {
226 source.is_touch()
227 || source.is_primary()
228 && self
229 .config
230 .event()
231 .mouse_pan()
232 .is_enabled_with(self.modifiers())
233 }
234
235 #[inline]
237 pub fn config_enable_mouse_text_pan(&self) -> bool {
238 self.config
239 .event()
240 .mouse_text_pan()
241 .is_enabled_with(self.modifiers())
242 }
243
244 #[inline]
248 pub fn config_test_pan_thresh(&self, dist: Offset) -> bool {
249 Vec2::conv(dist).abs().max_comp() >= self.config.event().pan_dist_thresh()
250 }
251
252 #[inline]
254 pub fn change_config(&mut self, msg: ConfigMsg) {
255 self.action |= self.config.change_config(msg);
256 }
257
258 pub fn set_disabled(&mut self, target: Id, disable: bool) {
267 if disable {
268 self.cancel_event_focus(&target);
269 }
270
271 for (i, id) in self.disabled.iter().enumerate() {
272 if target == id {
273 if !disable {
274 self.redraw(target);
275 self.disabled.remove(i);
276 }
277 return;
278 }
279 }
280 if disable {
281 self.action(&target, Action::REDRAW);
282 self.disabled.push(target);
283 }
284 }
285
286 #[inline]
290 pub fn redraw(&mut self, id: impl HasId) {
291 self.action(id, Action::REDRAW);
292 }
293
294 #[inline]
298 pub fn resize(&mut self, id: impl HasId) {
299 self.action(id, Action::RESIZE);
300 }
301
302 #[inline]
304 pub fn region_moved(&mut self) {
305 self.action |= Action::REGION_MOVED;
307 }
308
309 #[inline]
311 pub fn exit(&mut self) {
312 self.send(Id::ROOT, Command::Exit);
313 }
314
315 #[inline]
323 pub fn action(&mut self, id: impl HasId, action: Action) {
324 fn inner(cx: &mut EventState, id: Id, mut action: Action) {
325 if action.contains(Action::UPDATE) {
326 cx.request_update(id);
327 action.remove(Action::UPDATE);
328 }
329
330 cx.action |= action;
336 }
337 inner(self, id.has_id(), action)
338 }
339
340 #[inline]
342 pub(crate) fn opt_action(&mut self, id: Option<Id>, action: Action) {
343 if let Some(id) = id {
344 self.action(id, action);
345 }
346 }
347
348 #[inline]
354 pub fn window_action(&mut self, action: Action) {
355 self.action |= action;
356 }
357
358 pub fn request_update(&mut self, id: Id) {
362 self.pending_update = if let Some(id2) = self.pending_update.take() {
363 Some(id.common_ancestor(&id2))
364 } else {
365 Some(id)
366 };
367 }
368}
369
370#[must_use]
375pub struct EventCx<'a> {
376 state: &'a mut EventState,
377 runner: &'a mut dyn RunnerT,
378 window: &'a dyn WindowDataErased,
379 pub(crate) target_is_disabled: bool,
380 last_child: Option<usize>,
381 scroll: Scroll,
382}
383
384impl<'a> Deref for EventCx<'a> {
385 type Target = EventState;
386 fn deref(&self) -> &Self::Target {
387 self.state
388 }
389}
390impl<'a> DerefMut for EventCx<'a> {
391 fn deref_mut(&mut self) -> &mut Self::Target {
392 self.state
393 }
394}
395
396impl<'a> EventCx<'a> {
397 #[inline]
401 pub fn configure(&mut self, mut widget: Node<'_>, id: Id) {
402 widget._configure(&mut self.config_cx(), id);
403 }
404
405 #[inline]
411 pub fn update(&mut self, mut widget: Node<'_>) {
412 widget._update(&mut self.config_cx());
413 }
414
415 pub fn size_cx(&self) -> SizeCx<'_> {
422 SizeCx::new(self.window.theme_size())
423 }
424
425 pub fn config_cx(&mut self) -> ConfigCx<'_> {
427 let size = self.window.theme_size();
428 ConfigCx::new(size, self.state)
429 }
430
431 pub fn draw_shared(&mut self) -> &mut dyn DrawShared {
433 self.runner.draw_shared()
434 }
435}