1use linear_map::{LinearMap, set::LinearSet};
9use smallvec::SmallVec;
10use std::any::TypeId;
11use std::collections::{HashMap, VecDeque};
12use std::fmt::Debug;
13use std::future::Future;
14use std::ops::{Deref, DerefMut};
15use std::pin::Pin;
16use std::time::Instant;
17
18use super::*;
19use crate::cast::{Cast, Conv};
20use crate::config::{ConfigMsg, WindowConfig};
21use crate::draw::DrawShared;
22use crate::geom::{Offset, Vec2};
23use crate::messages::Erased;
24use crate::runner::{Platform, RunnerT, WindowDataErased};
25#[allow(unused)] use crate::theme::SizeCx;
26use crate::theme::ThemeSize;
27use crate::window::{PopupDescriptor, WindowId};
28use crate::{ActionClose, ActionMoved, ActionRedraw, ActionResize, ConfigAction, HasId, Id, Node};
29use key::Input;
30use nav::NavFocus;
31
32#[cfg(feature = "accesskit")] mod accessibility;
33mod key;
34mod nav;
35mod press;
36mod send;
37mod timer;
38mod window;
39
40pub use nav::NavAdvance;
41pub use press::{GrabBuilder, GrabMode, Press, PressSource, PressStart};
42pub(crate) use press::{Mouse, Touch};
43pub use timer::TimerHandle;
44
45struct PopupState {
46 id: WindowId,
47 desc: PopupDescriptor,
48 old_nav_focus: Option<Id>,
49 is_sized: bool,
50}
51
52pub struct EventState {
70 pub(crate) window_id: WindowId,
71 pub(crate) config: WindowConfig,
72 platform: Platform,
73 disabled: Vec<Id>,
74 window_has_focus: bool,
75 #[cfg(feature = "accesskit")]
76 accesskit_is_enabled: bool,
77 modifiers: ModifiersState,
78 input: Input,
79 nav: NavFocus,
80 key_depress: LinearMap<PhysicalKey, Id>,
81 mouse: Mouse,
82 touch: Touch,
83 access_keys: HashMap<Key, Id>,
84 popups: SmallVec<[PopupState; 16]>,
85 popup_removed: SmallVec<[(Id, WindowId); 16]>,
86 time_updates: Vec<(Instant, Id, TimerHandle)>,
87 frame_updates: LinearSet<(Id, TimerHandle)>,
88 need_frame_update: bool,
89 send_queue: VecDeque<(Id, Erased)>,
91 fut_messages: Vec<(Id, Pin<Box<dyn Future<Output = Erased>>>)>,
93 pub(super) pending_send_targets: Vec<(TypeId, Id)>,
94 action_moved: Option<ActionMoved>,
95 pub(crate) action_redraw: Option<ActionRedraw>,
96 action_close: Option<ActionClose>,
97}
98
99impl EventState {
100 #[inline]
102 pub(crate) fn new(window_id: WindowId, config: WindowConfig, platform: Platform) -> Self {
103 EventState {
104 window_id,
105 config,
106 platform,
107 disabled: vec![],
108 window_has_focus: false,
109 #[cfg(feature = "accesskit")]
110 accesskit_is_enabled: false,
111 modifiers: ModifiersState::empty(),
112 input: Input::default(),
113 nav: NavFocus::default(),
114 key_depress: Default::default(),
115 mouse: Default::default(),
116 touch: Default::default(),
117 access_keys: Default::default(),
118 popups: Default::default(),
119 popup_removed: Default::default(),
120 time_updates: vec![],
121 frame_updates: Default::default(),
122 need_frame_update: false,
123 send_queue: Default::default(),
124 pending_send_targets: vec![],
125 fut_messages: vec![],
126 action_moved: None,
127 action_redraw: None,
128 action_close: None,
129 }
130 }
131
132 pub(crate) fn update_config(&mut self, scale_factor: f32) {
134 self.config.update(scale_factor);
135 }
136
137 #[must_use]
147 pub(crate) fn full_configure(
148 &mut self,
149 sizer: &dyn ThemeSize,
150 node: Node,
151 ) -> Option<ActionResize> {
152 let id = Id::ROOT.make_child(self.window_id.get().cast());
153
154 log::debug!(target: "kas_core::event", "full_configure of Window{id}");
155
156 self.nav.fallback = None;
158
159 let mut cx = ConfigCx::new(sizer, self);
160 cx.configure(node, id);
161 let resize = cx.resize;
162 self.action_moved = Some(ActionMoved);
164 resize
165 }
166
167 #[inline]
171 #[must_use]
172 pub(crate) fn with<'a, F: FnOnce(&mut EventCx)>(
173 &'a mut self,
174 runner: &'a mut dyn RunnerT,
175 theme: &'a dyn ThemeSize,
176 window: &'a dyn WindowDataErased,
177 f: F,
178 ) -> Option<ActionResize> {
179 let mut cx = EventCx {
180 runner,
181 window,
182 cx: ConfigCx::new(theme, self),
183 target_is_disabled: false,
184 last_child: None,
185 scroll: Scroll::None,
186 resize_window: None,
187 };
188 f(&mut cx);
189 let resize = cx.resize.or(cx.resize_window);
190 let redraw = cx.redraw;
191 self.action_redraw = self.action_redraw.or(redraw);
192 resize
193 }
194
195 fn cancel_event_focus(&mut self, target: &Id) {
197 self.input.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]
221 pub fn config(&self) -> &WindowConfig {
222 &self.config
223 }
224
225 #[inline]
227 pub fn config_enable_pan(&self, source: PressSource) -> bool {
228 source.is_touch()
229 || source.is_primary()
230 && self
231 .config
232 .event()
233 .mouse_pan()
234 .is_enabled_with(self.modifiers())
235 }
236
237 #[inline]
239 pub fn config_enable_mouse_text_pan(&self) -> bool {
240 self.config
241 .event()
242 .mouse_text_pan()
243 .is_enabled_with(self.modifiers())
244 }
245
246 #[inline]
250 pub fn config_test_pan_thresh(&self, dist: Offset) -> bool {
251 Vec2::conv(dist).abs().max_comp() >= self.config.event().pan_dist_thresh()
252 }
253
254 #[inline]
259 pub fn redraw(&mut self, id: impl HasId) {
260 let _ = id;
262
263 self.action_redraw = Some(ActionRedraw);
264 }
265
266 #[inline]
268 pub(crate) fn opt_redraw(&mut self, id: Option<Id>) {
269 if let Some(id) = id {
270 self.redraw(id);
271 }
272 }
273
274 #[inline]
278 pub fn region_moved(&mut self) {
279 self.action_moved = Some(ActionMoved);
280 }
281
282 #[inline]
284 pub fn close_own_window(&mut self) {
285 self.action_close = Some(ActionClose);
286 }
287
288 #[inline]
290 pub fn action_moved(&mut self, action: impl Into<Option<ActionMoved>>) {
291 self.action_moved = self.action_moved.or(action.into());
292 }
293
294 #[inline]
298 pub fn action_redraw(&mut self, action: impl Into<Option<ActionRedraw>>) {
299 self.action_redraw = self.action_redraw.or(action.into());
300 }
301}
302
303#[must_use]
308pub struct ConfigCx<'a> {
309 theme: &'a dyn ThemeSize,
310 state: &'a mut EventState,
311 resize: Option<ActionResize>,
312 redraw: Option<ActionRedraw>,
313}
314
315impl<'a> Deref for ConfigCx<'a> {
316 type Target = EventState;
317 fn deref(&self) -> &EventState {
318 self.state
319 }
320}
321impl<'a> DerefMut for ConfigCx<'a> {
322 fn deref_mut(&mut self) -> &mut EventState {
323 self.state
324 }
325}
326
327impl<'a> ConfigCx<'a> {
328 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
330 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
331 pub fn new(sh: &'a dyn ThemeSize, ev: &'a mut EventState) -> Self {
332 ConfigCx {
333 theme: sh,
334 state: ev,
335 resize: None,
336 redraw: None,
337 }
338 }
339
340 #[inline]
342 pub fn size_cx<'b>(&'b mut self) -> SizeCx<'b>
343 where
344 'a: 'b,
345 {
346 SizeCx::new(self.state, self.theme)
347 }
348
349 #[inline]
359 pub fn configure(&mut self, mut widget: Node<'_>, id: Id) {
360 let start_resize = std::mem::take(&mut self.resize);
363 widget._configure(self, id);
364 self.resize = self.resize.or(start_resize);
365 }
366
367 #[inline]
372 pub fn update(&mut self, mut widget: Node<'_>) {
373 let start_resize = std::mem::take(&mut self.resize);
376 widget._update(self);
377 self.resize = self.resize.or(start_resize);
378 }
379
380 pub fn set_disabled(&mut self, target: Id, disable: bool) {
389 if disable {
390 self.cancel_event_focus(&target);
391 }
392
393 for (i, id) in self.disabled.iter().enumerate() {
394 if target == id {
395 if !disable {
396 self.redraw();
397 self.disabled.remove(i);
398 }
399 return;
400 }
401 }
402 if disable {
403 self.redraw();
404 self.disabled.push(target);
405 }
406 }
407
408 pub fn set_send_target_for<M: Debug + 'static>(&mut self, id: Id) {
413 let type_id = TypeId::of::<M>();
414 self.pending_send_targets.push((type_id, id));
415 }
416
417 #[inline]
423 pub fn redraw(&mut self) {
424 self.redraw = Some(ActionRedraw);
425 }
426
427 #[inline]
433 pub fn resize(&mut self) {
434 self.resize = Some(ActionResize);
435 }
436
437 #[inline]
438 pub(crate) fn needs_redraw(&self) -> bool {
439 self.redraw.is_some()
440 }
441
442 #[inline]
443 pub(crate) fn needs_resize(&self) -> bool {
444 self.resize.is_some()
445 }
446
447 #[inline]
448 pub(crate) fn set_resize(&mut self, resize: Option<ActionResize>) {
449 self.resize = resize;
450 }
451}
452
453#[must_use]
458pub struct EventCx<'a> {
459 runner: &'a mut dyn RunnerT,
460 window: &'a dyn WindowDataErased,
461 cx: ConfigCx<'a>,
462 pub(crate) target_is_disabled: bool,
463 last_child: Option<usize>,
464 scroll: Scroll,
465 resize_window: Option<ActionResize>,
466}
467
468impl<'a> Deref for EventCx<'a> {
469 type Target = ConfigCx<'a>;
470 fn deref(&self) -> &Self::Target {
471 &self.cx
472 }
473}
474impl<'a> DerefMut for EventCx<'a> {
475 fn deref_mut(&mut self) -> &mut Self::Target {
476 &mut self.cx
477 }
478}
479
480impl<'a> EventCx<'a> {
481 pub fn draw_shared(&mut self) -> &mut dyn DrawShared {
483 self.runner.draw_shared()
484 }
485
486 #[inline]
488 pub fn change_config(&mut self, msg: ConfigMsg) {
489 let action = self.config.change_config(msg);
490 if !action.is_empty() {
491 self.runner.config_update(action);
492 }
493 }
494
495 pub fn with_config(&mut self, f: impl FnOnce(&WindowConfig) -> ConfigAction) {
497 let action = f(&self.config);
498 if !action.is_empty() {
499 self.runner.config_update(action);
500 }
501 }
502
503 #[inline]
505 pub fn exit(&mut self) {
506 self.runner.exit();
507 }
508
509 fn pre_recursion(&self) {
511 debug_assert!(self.resize.is_none());
512 debug_assert!(self.scroll == Scroll::None);
513 debug_assert!(self.last_child.is_none());
514 }
515
516 fn post_recursion(&mut self) {
518 self.last_child = None;
519 self.scroll = Scroll::None;
520 self.resize_window = self.resize_window.or(self.resize);
521 self.resize = None;
522 }
523}