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
//! Visual, cursor, and paint-transform modifiers for [`El`].
use crate::anim::Timing;
use crate::shader::ShaderBinding;
use crate::style::StyleProfile;
use super::color::Color;
use super::geometry::{Corners, Sides};
use super::node::{El, FocusRingPlacement};
use super::semantics::SurfaceRole;
impl El {
// ---- Visual ----
pub fn fill(mut self, c: Color) -> Self {
self.fill = Some(c);
self
}
/// Fill applied when the nearest focusable ancestor isn't focused;
/// the painter lerps from `dim_fill` toward `fill` as the focus
/// envelope rises from 0 to 1. See [`Self::dim_fill`] field doc.
pub fn dim_fill(mut self, c: Color) -> Self {
self.dim_fill = Some(c);
self
}
pub fn stroke(mut self, c: Color) -> Self {
self.stroke = Some(c);
if self.stroke_width == 0.0 {
self.stroke_width = 1.0;
}
self
}
pub fn stroke_width(mut self, w: f32) -> Self {
self.stroke_width = w;
self
}
/// Set the element's corner radii. A scalar (e.g.
/// `.radius(tokens::RADIUS_MD)`) sets all four corners uniformly
/// via [`Corners::from`]; pass [`Corners::top`] / [`Corners::bottom`]
/// / [`Corners::left`] / [`Corners::right`], or a directly-built
/// [`Corners`], to round only a subset of corners.
pub fn radius(mut self, r: impl Into<Corners>) -> Self {
self.radius = r.into();
self.explicit_radius = true;
self
}
pub fn shadow(mut self, s: f32) -> Self {
self.shadow = s;
self
}
/// Tag this node with a semantic [`SurfaceRole`] so the theme can
/// route it through the appropriate paint recipe. Most app code
/// should not call this directly: the catalog widgets (`card()`,
/// `sidebar()`, `dialog()`, `popover()`, `tabs_list()`, etc.) set
/// the right role *and* the matching fill / stroke / radius /
/// shadow together, while the `.selected()` and `.current()`
/// chainables wrap the corresponding state recipes.
///
/// Reach for the raw chainable when authoring a new widget or when
/// composing a custom container that the catalog doesn't cover —
/// and remember that decorative roles (`Panel`, `Raised`, `Popover`,
/// `Danger`) require you to supply a fill yourself; see the
/// [`SurfaceRole`] doc for the per-variant contract. The bundle
/// lint pass flags `Panel` without a fill as
/// [`crate::bundle::lint::FindingKind::MissingSurfaceFill`].
pub fn surface_role(mut self, role: SurfaceRole) -> Self {
self.surface_role = role;
self
}
/// Permit paint to extend beyond this element's layout bounds by
/// `outset` on each side. Layout-neutral; siblings don't move and
/// hit-testing still uses the layout rect.
pub fn paint_overflow(mut self, outset: impl Into<Sides>) -> Self {
self.paint_overflow = outset.into();
self
}
/// Draw the stock focus ring just inside this node's layout rect.
///
/// The default focus ring is outside the rect so it does not reduce
/// usable control area. Inside rings are for dense, flush stacks such as
/// menu rows, where adding gaps would change the intended visual recipe.
pub fn focus_ring_inside(mut self) -> Self {
self.focus_ring_placement = FocusRingPlacement::Inside;
self
}
/// Draw the stock focus ring outside this node's layout rect.
pub fn focus_ring_outside(mut self) -> Self {
self.focus_ring_placement = FocusRingPlacement::Outside;
self
}
/// Attach a hover tooltip to this element. The runtime synthesizes
/// a floating tooltip layer when the pointer rests on the node for
/// the configured delay.
///
/// **The node must also have a [`key`](Self::key).** Tooltips fire
/// through the hit-test pipeline, and `crate::hit_test` only
/// returns keyed nodes — an unkeyed leaf with `.tooltip()` is
/// silently dead, because hover skips past it to the nearest
/// keyed ancestor (which has a different `computed_id` and a
/// different tooltip). The bundle lint flags this case as
/// [`crate::bundle::lint::FindingKind::DeadTooltip`].
///
/// For info-only chrome inside list rows (sha cells, timestamps,
/// chips, identicon avatars) the usual key is a synthetic one
/// like `"row:{idx}.<part>"` — its only purpose is to make the
/// tooltip's hover land. The tooltip text is snapshotted onto the
/// hit target at hit-test time, so tooltips fire correctly even
/// on `virtual_list_dyn` rows whose children are realized only
/// during layout.
pub fn tooltip(mut self, text: impl Into<String>) -> Self {
self.tooltip = Some(text.into());
self
}
/// Declare the pointer cursor when the pointer is over this
/// element.
pub fn cursor(mut self, cursor: crate::cursor::Cursor) -> Self {
self.cursor = Some(cursor);
self
}
/// Declare the cursor shown only while a press is captured at this
/// exact node.
pub fn cursor_pressed(mut self, cursor: crate::cursor::Cursor) -> Self {
self.cursor_pressed = Some(cursor);
self
}
// ---- Paint-time transforms (animatable via `.animate()`) ----
/// Multiply this element's paint alpha by `v` (clamped to `[0, 1]`).
pub fn opacity(mut self, v: f32) -> Self {
self.opacity = v.clamp(0.0, 1.0);
self
}
/// Offset this element's paint and its descendants by `(x, y)` in
/// logical pixels.
pub fn translate(mut self, x: f32, y: f32) -> Self {
self.translate = (x, y);
self
}
/// Uniformly scale this element's paint around its rect centre.
pub fn scale(mut self, v: f32) -> Self {
self.scale = v.max(0.0);
self
}
/// Opt this element into app-driven prop interpolation.
pub fn animate(mut self, timing: Timing) -> Self {
self.animate = Some(timing);
self
}
/// Bind a shader for the surface paint, replacing the implicit
/// `stock::rounded_rect`.
pub fn shader(mut self, binding: ShaderBinding) -> Self {
self.shader_override = Some(binding);
self
}
// ---- Internal: style profile ----
pub fn style_profile(mut self, p: StyleProfile) -> Self {
self.style_profile = p;
self
}
pub(crate) fn default_radius(mut self, r: impl Into<Corners>) -> Self {
self.radius = r.into();
self.explicit_radius = false;
self
}
}