1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
// SPDX-FileCopyrightText: Copyright (c) 2026 Mike Li/Mikewolfli/Wei Li(mikewolfli@163.com)
// SPDX-License-Identifier: MIT
//! The painting bridge that connects a self-painting widget to `dyn Widget`.
//!
//! # Why this module exists
//!
//! `crate::widget::runtime::render_frame` holds widgets as `&mut dyn Widget` and
//! needs to reach [`Draw::draw`]. `Widget` deliberately does not *require* `Draw`
//! (a widget may paint nothing and lay out children instead), so `Widget` exposes
//! `as_draw_mut() -> Option<&mut dyn Draw>`, defaulting to `None`.
//!
//! That default was silently wrong. An audit found **168** types implementing
//! `Draw`, but only **6** overriding `as_draw_mut` — so mounting any of the other
//! **162** produced an empty surface and reported no error. The failure was
//! invisible: `render_frame` asked the bridge, got `None`, and concluded there was
//! nothing to paint.
//!
//! # Why the fix is a macro invoked inside each `impl Widget`
//!
//! The ideal `impl<T: Draw> Paintable for T` compiles but is unusable here: trait
//! selection needs the concrete type, and `&mut dyn Widget` has erased it. A
//! blanket impl is only reachable behind a generic bound like `W: Draw + Widget`,
//! which no `Box<dyn Widget>` satisfies — that is precisely why `as_draw_mut`
//! exists at all.
//!
//! The override therefore has to be emitted **where the concrete type is visible**:
//! inside the widget's own `impl Widget` block. [`crate::impl_draw_bridge!`] emits
//! exactly that one method. It is a *generated* line rather than a remembered one,
//! and the coverage test in `crate::widget::runtime` fails by name if a painting
//! widget is missing it — so the silent-blank failure cannot ship.
//!
//! The macro is zero-cost (principle #28): it expands to the same `Some(self)` the
//! six hand-written bridges already use, with no table and no lookup.
use crateDraw;
use crateWidget;
/// Emits the [`Widget::as_draw_mut`] override for a self-painting widget.
///
/// Invoke **inside** the widget's `impl Widget` block:
///
/// ```ignore
/// impl Widget for Button {
/// fn base(&self) -> &BaseWidget { &self.base }
/// fn base_mut(&mut self) -> &mut BaseWidget { &mut self.base }
///
/// impl_draw_bridge!();
/// }
/// ```
///
/// # Why this is a macro and not a blanket impl
///
/// The obvious `impl<T: Draw> Widget for T` is impossible — it would overlap the
/// per-type `impl Widget for X` every control already has (coherence). An
/// `impl<T: Draw> Paintable for T` helper does compile, but a `&mut dyn Widget`
/// cannot *select* it: trait selection needs the concrete type, and the trait
/// object has erased it. That is the whole reason `as_draw_mut` exists.
///
/// So the override is generated where the concrete type is still visible — inside
/// its own impl — and the macro makes the intent (`this type paints itself`)
/// explicit and uniform, instead of a line each author must remember to copy.
///
/// The coverage test in `crate::widget::runtime` fails by name when a painting
/// widget lacks this call, which is what the previous hand-written approach had no
/// way to detect: it had silently fallen to 6 of 168.
/// Implements `Default` by delegating to a type's `new()`.
///
/// # Why this exists
///
/// A type whose `new()` takes its geometry has no universal default — but many
/// types in this crate have a zero-argument `new()`, and for those the impl is
/// always the identical five lines:
///
/// ```ignore
/// impl Default for Thing {
/// fn default() -> Self {
/// Self::new()
/// }
/// }
/// ```
///
/// That block appeared **117 times**, which is 117 copies of one fact. It is also
/// the kind of boilerplate that silently drifts: a `new()` that gains a required
/// argument leaves a `Default` impl that no longer describes it, because nothing
/// forces the two to be read together.
///
/// # Usage
///
/// ```ignore
/// impl Thing {
/// pub fn new() -> Self { /* … */ }
/// }
///
/// crate::impl_default_via_new!(Thing);
/// ```
///
/// The macro generates an inherent-free impl, so it can be invoked anywhere in the
/// module that defines the type — normally immediately after the type's own `impl`
/// block, so the two are read together.
/// Returns the painting channel for `widget`, or `None` when it paints nothing.
///
/// The single entry point the render loop should use. It asks the widget itself,
/// so a wrapper that paints through a child keeps working, and a widget that
/// implements `Draw` answers `Some(self)` through [`crate::impl_draw_bridge!`].
///
/// # Painting is also where a **host-owned** control is advanced
///
/// [`crate::widget::runtime::tick_animations`] sweeps the mounted registry. A control held as a
/// `Box<dyn Widget>` is not in it, so nothing advanced it and nothing knew it was in flight: a
/// `Switch` set to ON and then painted showed its thumb at the off end every frame, forever, and
/// reported no error. That is not a hypothetical host — it is how `census`,
/// `examples/export_control_svgs.rs` and this function's own callers hold their controls, and it is
/// the pattern the crate's front-page example documents.
///
/// So the paint path advances such a control and records the fact. Both halves are needed:
/// advancing is what makes the picture move, and recording is what lets
/// [`crate::widget::runtime::animation_bus_needs_another_frame`] answer `true`, so a loop learns
/// the frame it would otherwise never schedule is needed.
///
/// # The two exclusions, and why each is load-bearing
///
/// **A mounted control is not advanced here.** It reaches this function every frame too, and
/// advancing it would run its animation once for `tick_animations` and once for its own paint —
/// twice per frame, the exact failure `tick_animations`' documentation warns about ("the same
/// button advanced twice in one frame"). [`crate::widget::runtime::is_mounted`] keeps the two
/// populations disjoint.
///
/// **A control that manages its own repaint is not advanced here either.** Such a control's
/// `tick` calls [`crate::widget::BaseWidget::request_redraw`], so advancing it on every paint
/// would make every advance ask for the next paint: a feedback loop with no way to stop, and
/// nothing outside this function can see that the owner is already choosing when to repaint.
/// [`crate::widget::Widget::manages_own_repaint`] reports that fact and defaults to "no", so an
/// ordinary control — a hovered `Button`, a toggled `Switch`, the case that made this necessary —
/// is advanced, while a free-running `Spinner` draws whatever frame it is on and keeps its own
/// cadence. The observable consequence for the snapshots is that two consecutive renders of the
/// same control are identical, which the exporter's reproducibility depends on.
///
/// A resting owned control costs one `is_animating()` call, which is what keeps the "a still
/// window pays nothing" property of the bus intact.
/// Advances an owned control that owes frames, and tells the bus so.
///
/// Split from [`draw_of`] so the **whole** of the animation-bus interaction — the frame step, the
/// `is_mounted` question and the two bus calls — is one call site that a build without the runtime
/// can compile out. `mini` and `embedded` are `alloc_frugal`: they have no `widget::runtime` (the
/// module is `#[cfg(not(alloc_frugal))]`), no registry to ask, and no frame bus to answer. Those
/// builds paint whole frames on demand, so there is nothing for this to drive and no host loop to
/// keep awake — the honest behaviour is to do nothing, not to carry a stub of a mechanism that
/// does not exist in the profile.
/// The frame advance where the profile has no frame bus.
///
/// `mini`/`embedded` have no `widget::runtime`, so there is no registry to distinguish a mounted
/// control from an owned one and no bus to report to. Nothing is advanced, which is what those
/// profiles already did: they repaint whole frames from their own host loop.
/// The delta one frame of the paint path is worth, in milliseconds.
///
/// # Why a constant and not a measured frame time
///
/// At this entry point the crate has no clock and will not grow one: a wrong frame delta is worse
/// than a fixed one — a single long frame (the host loaded a font, the window was occluded) would
/// otherwise teleport every in-flight animation to its end. `Switch::tick` and the other control
/// `tick`s accumulate against a *target* rather than a deadline, so a fixed step simply paces the
/// movement and cannot overshoot. 16 ms is the step a 60 Hz host would use, so an animation takes
/// the same time here as it would on that host.
///
/// # Why it is shared rather than copied
///
/// `Carousel`'s legacy `Event::Timer` arm steps its autoplay clock by one nominal frame, which is
/// the *same* quantity this paint path hands a control. A second `16` there would be a copy of a
/// policy with nothing linking the copy to it — the drift the duration gate exists to stop — so
/// the value is published from here and both readers name it. It is deliberately **not** a
/// `theme.motion` token: it is a sample size, not a duration, which is why
/// `tools/transition_duration_exemptions.txt` records the reason rather than the value being
/// folded into a tempo (BLUE22 §6.7's distinction, and BLUE24 §2.4 gate A).
pub const ANIMATION_FRAME_DELTA_MS: u32 = 16;
/// Reports whether `widget` is a control the frame sweep does **not** own but which is in flight.
///
/// Split out so the two independent facts — "is this mounted?" and "does it owe frames?" — are
/// asked of one named place rather than as a compound condition inside the paint path. The
/// `is_animating()` read is second, so a control that is mounted (the common case) or resting pays
/// nothing for the question.
/// Maps "has this control settled?" onto the bus fact.
///
/// A named translation rather than a bare negation at the call site: the bus speaks in
/// "a host-owned control is animating", while `tick` speaks in "it needs another frame", and
/// conflating the two is how the two halves of the animation contract drift apart.