Skip to content

Commit 8e792bf

Browse files
masonry: document widget timer lifecycle
Clarify that `request_anim_frame` and `Widget::on_anim_frame` are for frame-cadenced visual updates, while delayed one-shot UI behavior should use widget timers. Update the pass-system and widget-implementation docs to describe timer delivery through `Update::Timer`, the non-bubbling delivery model, and the usual `Option<TimerToken>` request/cancel pattern.
1 parent 7b40ad4 commit 8e792bf

4 files changed

Lines changed: 33 additions & 0 deletions

File tree

masonry/src/doc/implementing_widget.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ In the course of a frame, Masonry will run a series of passes over the widget tr
4848
- `on_pointer_event`, `on_text_event` and `on_access_event` are called once after a user-initiated event (like a mouse click or keyboard input).
4949
- `on_anim_frame` is called once per frame for animated widgets.
5050
- `update` is called many times during a frame, with various events reflecting changes in the widget's state (for instance, it gets or loses text focus).
51+
- `update` is also where timers requested by the widget are delivered as `Update::Timer`.
5152
- `measure` and `layout` are called during Masonry's layout pass.
5253
`measure` computes the preferred size of the widget on a single axis.
5354
`layout` receives a chosen size and lays out its children accordingly.
@@ -162,6 +163,12 @@ impl Widget for ColorRectangle {
162163
}
163164
```
164165

166+
Use `on_anim_frame` for visual state that should advance with frame cadence, such as continuous motion or interpolation.
167+
For delayed one-shot behavior, use a timer instead.
168+
For example, a widget can store an `Option<TimerToken>`, set it with `ctx.request_timer(delay)`, then compare it against `Update::Timer(token)` in `update`.
169+
If the delayed behavior should continue, request a new one-shot timer from that `Update::Timer` branch.
170+
Cancel the stored token with `ctx.cancel_timer(token)` when the state that made the timer relevant no longer applies.
171+
165172
### Layout
166173

167174
Next we implement layout:
@@ -351,6 +358,11 @@ Most context types include these methods for requesting future passes:
351358
- `request_accessibility_update()`
352359
- `request_layout()`
353360
- `request_anim_frame()`
361+
- `request_timer()`
362+
- `cancel_timer()`
363+
364+
Use `request_anim_frame()` for frame-cadenced animation.
365+
Use `request_timer()` for delayed one-shot UI behavior such as cursor blinking, tooltip delays, debounce, or long press recognition.
354366

355367

356368
### Using context in `ColorRectangle`

masonry_core/src/core/contexts.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,11 @@ impl_context_method!(
16671667
}
16681668

16691669
/// Requests an animation frame.
1670+
///
1671+
/// Use this for visual state that should advance with frame cadence,
1672+
/// such as continuous motion or interpolation. For delayed one-shot UI
1673+
/// behavior like cursor blinking, tooltip delays, debounce, or long
1674+
/// press recognition, prefer [`request_timer`](Self::request_timer).
16701675
pub fn request_anim_frame(&mut self) {
16711676
trace!("request_anim_frame");
16721677
self.widget_state.request_anim = true;

masonry_core/src/core/widget.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ pub trait Widget: AsDynWidget + Any {
195195
/// [`request_anim`](UpdateCtx::request_anim_frame) unless the animation
196196
/// has finished.
197197
///
198+
/// Use timers instead of animation frames for delayed one-shot UI behavior
199+
/// such as cursor blinking, tooltip delays, debounce, or long press
200+
/// recognition.
201+
///
198202
/// On the first frame when transitioning from idle to animating, `interval`
199203
/// will be 0. (This logic is presently per-window but might change to
200204
/// per-widget to make it more consistent). Otherwise it is in nanoseconds.

masonry_core/src/doc/pass_system.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ It runs in depth-first preorder on all animated widgets in the tree.
4848

4949
The animation pass may be considered as a special event pass: it's not triggered by user interaction, and it doesn't bubble, but it's also triggered externally and sets off the rewrite passes.
5050

51+
### Timer delivery
52+
53+
Widget timers are delayed callbacks requested with context methods such as [`UpdateCtx::request_timer`].
54+
When a timer expires, Masonry delivers [`Update::Timer`] to the widget that requested it.
55+
56+
Timer delivery does not bubble to ancestors.
57+
Like the animation pass, it is triggered externally by the host event loop and sets off the rewrite passes after delivery.
58+
Timers are best for delayed one-shot UI behavior such as cursor blinking, tooltip delays, debounce, and long press recognition.
59+
Use animation frames instead for visual state that should advance with frame cadence.
60+
5161

5262
## Rewrite passes
5363

@@ -255,6 +265,8 @@ They can access the layout of children if they have already been laid out.
255265
[`RegisterCtx`]: crate::core::RegisterCtx
256266
[`QueryCtx`]: crate::core::QueryCtx
257267
[`WidgetAdded`]: crate::core::Update::WidgetAdded
268+
[`Update::Timer`]: crate::core::Update::Timer
269+
[`UpdateCtx::request_timer`]: crate::core::UpdateCtx::request_timer
258270
[`Ime::Disabled`]: crate::core::Ime::Disabled
259271
[`FocusChanged`]: crate::core::Update::FocusChanged
260272
[`ChildFocusChanged`]: crate::core::Update::ChildFocusChanged

0 commit comments

Comments
 (0)