Skip to content

Commit 63f3071

Browse files
authored
Merge pull request #482 from kas-gui/work3
Fixes
2 parents 59ead15 + 800b8e1 commit 63f3071

File tree

24 files changed

+431
-273
lines changed

24 files changed

+431
-273
lines changed

crates/kas-core/src/core/impls.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::event::{ConfigCx, Event, EventCx, FocusSource, IsUsed, Scroll, Unused
99
use crate::{Events, Id, NavAdvance, Node, Tile, Widget};
1010

1111
/// Generic implementation of [`Widget::_send`]
12+
#[inline(always)]
1213
pub fn _send<W: Events>(
1314
widget: &mut W,
1415
cx: &mut EventCx,
@@ -76,6 +77,7 @@ pub fn _send<W: Events>(
7677
}
7778

7879
/// Generic implementation of [`Widget::_replay`]
80+
#[inline(always)]
7981
pub fn _replay<W: Events>(widget: &mut W, cx: &mut EventCx, data: &<W as Widget>::Data, id: Id) {
8082
if let Some(index) = widget.find_child_index(&id) {
8183
let mut _found = false;
@@ -112,6 +114,7 @@ pub fn _replay<W: Events>(widget: &mut W, cx: &mut EventCx, data: &<W as Widget>
112114
}
113115

114116
/// Generic implementation of [`Widget::_nav_next`]
117+
#[inline(always)]
115118
pub fn _nav_next<W: Events>(
116119
widget: &mut W,
117120
cx: &mut ConfigCx,
@@ -142,9 +145,10 @@ fn nav_next(
142145
let mut child = focus.and_then(|id| widget.find_child_index(id));
143146

144147
if let Some(index) = child {
145-
if let Some(Some(id)) =
146-
widget.for_child(index, |mut node| node._nav_next(cx, focus, advance))
147-
{
148+
let mut opt_id = None;
149+
let out = &mut opt_id;
150+
widget.for_child(index, |mut node| *out = node._nav_next(cx, focus, advance));
151+
if let Some(id) = opt_id {
148152
return Some(id);
149153
}
150154
}
@@ -168,11 +172,13 @@ fn nav_next(
168172
};
169173

170174
while let Some(index) = widget.nav_next(rev, child) {
171-
if let Some(Some(id)) =
172-
widget.for_child(index, |mut node| node._nav_next(cx, focus, advance))
173-
{
175+
let mut opt_id = None;
176+
let out = &mut opt_id;
177+
widget.for_child(index, |mut node| *out = node._nav_next(cx, focus, advance));
178+
if let Some(id) = opt_id {
174179
return Some(id);
175180
}
181+
176182
child = Some(index);
177183
}
178184

crates/kas-core/src/core/node.rs

+12-17
Original file line numberDiff line numberDiff line change
@@ -214,34 +214,26 @@ impl<'a> Node<'a> {
214214
self.0.num_children()
215215
}
216216

217-
/// Run `f` on some child by index and, if valid, return the result.
217+
/// Run `f` on some child by index.
218218
///
219-
/// Calls the closure and returns `Some(result)` exactly when
220-
/// `index < self.num_children()`.
221-
pub fn for_child<R>(&mut self, index: usize, f: impl FnOnce(Node<'_>) -> R) -> Option<R> {
222-
let mut result = None;
223-
let out = &mut result;
224-
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(|node| {
225-
*out = Some(f(node));
226-
});
219+
/// Calls the closure exactly when `index < self.num_children()`.
220+
#[inline(always)]
221+
pub fn for_child(&mut self, index: usize, f: impl FnOnce(Node<'_>)) {
222+
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(f);
227223
cfg_if::cfg_if! {
228224
if #[cfg(feature = "unsafe_node")] {
229225
self.0.for_child_node(self.1, index, f);
230226
} else {
231227
self.0.for_child_node(index, f);
232228
}
233229
}
234-
result
235230
}
236231

237232
/// Run a `f` on all children
233+
#[inline(always)]
238234
pub fn for_children(&mut self, mut f: impl FnMut(Node<'_>)) {
239235
for index in 0..self.0.num_children() {
240-
// NOTE: for_child_node takes FnOnce hence we must wrap the closure
241-
let f = &mut f;
242-
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(|node| {
243-
f(node);
244-
});
236+
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(&mut f);
245237
cfg_if::cfg_if! {
246238
if #[cfg(feature = "unsafe_node")] {
247239
self.0.for_child_node(self.1, index, f);
@@ -264,10 +256,13 @@ impl<'a> Node<'a> {
264256
/// Find the descendant with this `id`, if any, and call `cb` on it
265257
///
266258
/// Returns `Some(result)` if and only if node `id` was found.
259+
#[inline(always)]
267260
pub fn find_node<F: FnOnce(Node<'_>) -> T, T>(&mut self, id: &Id, cb: F) -> Option<T> {
268261
if let Some(index) = self.find_child_index(id) {
269-
self.for_child(index, |mut node| node.find_node(id, cb))
270-
.unwrap()
262+
let mut result = None;
263+
let out = &mut result;
264+
self.for_child(index, |mut node| *out = node.find_node(id, cb));
265+
result
271266
} else if self.eq_id(id) {
272267
Some(cb(self.re()))
273268
} else {

crates/kas-core/src/event/components.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use std::time::{Duration, Instant};
1717

1818
const TIMER_SELECT: TimerHandle = TimerHandle::new(1 << 60, true);
1919
const TIMER_GLIDE: TimerHandle = TimerHandle::new((1 << 60) + 1, true);
20-
const GLIDE_POLL_MS: u64 = 3;
2120
const GLIDE_MAX_SAMPLES: usize = 8;
2221

2322
#[derive(Clone, Debug)]
@@ -318,7 +317,7 @@ impl ScrollComponent {
318317
if self.max_offset != Offset::ZERO && cx.config_enable_pan(*press) =>
319318
{
320319
let _ = press
321-
.grab(id.clone())
320+
.grab(id.clone(), GrabMode::Grab)
322321
.with_icon(CursorIcon::Grabbing)
323322
.with_cx(cx);
324323
self.glide.press_start();
@@ -336,21 +335,20 @@ impl ScrollComponent {
336335
let timeout = cx.config().event().scroll_flick_timeout();
337336
let pan_dist_thresh = cx.config().event().pan_dist_thresh();
338337
if self.glide.press_end(timeout, pan_dist_thresh) {
339-
cx.request_timer(id.clone(), TIMER_GLIDE, Duration::ZERO);
338+
cx.request_frame_timer(id.clone(), TIMER_GLIDE);
340339
}
341340
}
342-
Event::Timer(pl) if pl == TIMER_GLIDE => {
341+
Event::Timer(TIMER_GLIDE) => {
343342
// Momentum/glide scrolling: update per arbitrary step time until movment stops.
344343
let timeout = cx.config().event().scroll_flick_timeout();
345344
let decay = cx.config().event().scroll_flick_decay();
346345
if let Some(delta) = self.glide.step(timeout, decay) {
347346
action = self.scroll_by_delta(cx, delta);
347+
cx.set_scroll(Scroll::Scrolled);
348+
}
348349

349-
if self.glide.vel != Vec2::ZERO {
350-
let dur = Duration::from_millis(GLIDE_POLL_MS);
351-
cx.request_timer(id.clone(), TIMER_GLIDE, dur);
352-
cx.set_scroll(Scroll::Scrolled);
353-
}
350+
if self.glide.vel != Vec2::ZERO {
351+
cx.request_frame_timer(id.clone(), TIMER_GLIDE);
354352
}
355353
}
356354
_ => return (false, Unused),
@@ -444,7 +442,10 @@ impl TextInput {
444442
None
445443
}
446444
};
447-
press.grab(w_id).with_opt_icon(icon).with_cx(cx);
445+
press
446+
.grab(w_id, GrabMode::Grab)
447+
.with_opt_icon(icon)
448+
.with_cx(cx);
448449
self.glide.press_start();
449450
action
450451
}
@@ -484,11 +485,11 @@ impl TextInput {
484485
|| matches!(press.source, PressSource::Mouse(..) if cx.config_enable_mouse_text_pan()))
485486
{
486487
self.touch_phase = TouchPhase::None;
487-
cx.request_timer(w_id, TIMER_GLIDE, Duration::ZERO);
488+
cx.request_frame_timer(w_id, TIMER_GLIDE);
488489
}
489490
Action::None
490491
}
491-
Event::Timer(pl) if pl == TIMER_SELECT => match self.touch_phase {
492+
Event::Timer(TIMER_SELECT) => match self.touch_phase {
492493
TouchPhase::Start(touch_id, coord) => {
493494
self.touch_phase = TouchPhase::Cursor(touch_id);
494495
Action::Focus {
@@ -498,13 +499,12 @@ impl TextInput {
498499
}
499500
_ => Action::None,
500501
},
501-
Event::Timer(pl) if pl == TIMER_GLIDE => {
502+
Event::Timer(TIMER_GLIDE) => {
502503
// Momentum/glide scrolling: update per arbitrary step time until movment stops.
503504
let timeout = cx.config().event().scroll_flick_timeout();
504505
let decay = cx.config().event().scroll_flick_decay();
505506
if let Some(delta) = self.glide.step(timeout, decay) {
506-
let dur = Duration::from_millis(GLIDE_POLL_MS);
507-
cx.request_timer(w_id, TIMER_GLIDE, dur);
507+
cx.request_frame_timer(w_id, TIMER_GLIDE);
508508
Action::Pan(delta)
509509
} else {
510510
Action::None

crates/kas-core/src/event/cx/cx_pub.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl EventState {
166166
/// target is disabled, and also cancels press/pan grabs.
167167
pub fn set_disabled(&mut self, target: Id, disable: bool) {
168168
if disable {
169-
self.clear_events(&target);
169+
self.cancel_event_focus(&target);
170170
}
171171

172172
for (i, id) in self.disabled.iter().enumerate() {
@@ -186,8 +186,9 @@ impl EventState {
186186

187187
/// Schedule a timed update
188188
///
189-
/// Widget updates may be used for animation and timed responses. See also
190-
/// [`Draw::animate`](crate::draw::Draw::animate) for animation.
189+
/// Widget updates may be used for delayed action. For animation, prefer to
190+
/// use [`Draw::animate`](crate::draw::Draw::animate) or
191+
/// [`Self::request_frame_timer`].
191192
///
192193
/// Widget `id` will receive [`Event::Timer`] with this `handle` at
193194
/// approximately `time = now + delay` (or possibly a little later due to
@@ -223,6 +224,21 @@ impl EventState {
223224
self.time_updates.sort_by(|a, b| b.0.cmp(&a.0)); // reverse sort
224225
}
225226

227+
/// Schedule a frame timer update
228+
///
229+
/// Widget `id` will receive [`Event::Timer`] with this `handle` either
230+
/// before or soon after the next frame is drawn.
231+
///
232+
/// This may be useful for animations which mutate widget state. Animations
233+
/// which don't mutate widget state may use
234+
/// [`Draw::animate`](crate::draw::Draw::animate) instead.
235+
///
236+
/// It is expected that `handle.earliest() == true` (style guide).
237+
pub fn request_frame_timer(&mut self, id: Id, handle: TimerHandle) {
238+
debug_assert!(handle.earliest());
239+
self.frame_updates.insert((id, handle));
240+
}
241+
226242
/// Notify that a widget must be redrawn
227243
///
228244
/// This is equivalent to calling [`Self::action`] with [`Action::REDRAW`].

crates/kas-core/src/event/cx/mod.rs

+7-22
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// Without winit, several things go unused
99
#![cfg_attr(not(winit), allow(unused))]
1010

11-
use linear_map::LinearMap;
11+
use linear_map::{set::LinearSet, LinearMap};
1212
use smallvec::SmallVec;
1313
use std::collections::{BTreeMap, HashMap, VecDeque};
1414
use std::future::Future;
@@ -60,7 +60,7 @@ impl GrabMode {
6060

6161
#[derive(Clone, Debug)]
6262
enum GrabDetails {
63-
Click { cur_id: Option<Id> },
63+
Click,
6464
Grab,
6565
Pan((u16, u16)),
6666
}
@@ -81,24 +81,6 @@ struct MouseGrab {
8181
cancel: bool,
8282
}
8383

84-
impl<'a> EventCx<'a> {
85-
fn flush_mouse_grab_motion(&mut self) {
86-
if let Some(grab) = self.mouse_grab.as_mut() {
87-
if let GrabDetails::Click { ref cur_id } = grab.details {
88-
if grab.start_id == cur_id {
89-
if grab.depress != *cur_id {
90-
grab.depress = cur_id.clone();
91-
self.action |= Action::REDRAW;
92-
}
93-
} else if grab.depress.is_some() {
94-
grab.depress = None;
95-
self.action |= Action::REDRAW;
96-
}
97-
}
98-
}
99-
}
100-
}
101-
10284
#[derive(Clone, Debug)]
10385
struct TouchGrab {
10486
id: u64,
@@ -210,6 +192,7 @@ pub struct EventState {
210192
popups: SmallVec<[(WindowId, crate::PopupDescriptor, Option<Id>); 16]>,
211193
popup_removed: SmallVec<[(Id, WindowId); 16]>,
212194
time_updates: Vec<(Instant, Id, TimerHandle)>,
195+
frame_updates: LinearSet<(Id, TimerHandle)>,
213196
// Set of messages awaiting sending
214197
send_queue: VecDeque<(Id, Erased)>,
215198
// Set of futures of messages together with id of sending widget
@@ -380,14 +363,16 @@ impl EventState {
380363
window_id
381364
}
382365

383-
/// Clear all active events on `target`
384-
fn clear_events(&mut self, target: &Id) {
366+
/// Clear all focus and grabs on `target`
367+
fn cancel_event_focus(&mut self, target: &Id) {
385368
if let Some(id) = self.sel_focus.as_ref() {
386369
if target.is_ancestor_of(id) {
387370
if let Some(pending) = self.pending_sel_focus.as_mut() {
388371
if pending.target.as_ref() == Some(id) {
389372
pending.target = None;
390373
pending.key_focus = false;
374+
} else {
375+
// We have a new focus target, hence the old one will be cleared
391376
}
392377
} else {
393378
self.pending_sel_focus = Some(PendingSelFocus {

0 commit comments

Comments
 (0)