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
//! Content-related [`El`] modifiers: text runs, icon source, and raster image source.
use crate::image::{Image, ImageFit};
use super::color::Color;
use super::layout_types::Size;
use super::node::El;
use super::text_types::{FontFamily, FontWeight, TextAlign, TextOverflow, TextRole, TextWrap};
impl El {
// ---- Text-bearing ----
pub fn text(mut self, t: impl Into<String>) -> Self {
self.text = Some(t.into());
self
}
pub fn text_color(mut self, c: Color) -> Self {
self.text_color = Some(c);
self
}
pub fn text_align(mut self, align: TextAlign) -> Self {
self.text_align = align;
self
}
pub fn center_text(self) -> Self {
self.text_align(TextAlign::Center)
}
pub fn end_text(self) -> Self {
self.text_align(TextAlign::End)
}
pub fn text_wrap(mut self, wrap: TextWrap) -> Self {
self.text_wrap = wrap;
self
}
pub fn wrap_text(self) -> Self {
self.text_wrap(TextWrap::Wrap)
}
pub fn nowrap_text(self) -> Self {
self.text_wrap(TextWrap::NoWrap)
}
pub fn text_overflow(mut self, overflow: TextOverflow) -> Self {
self.text_overflow = overflow;
self
}
pub fn ellipsis(self) -> Self {
self.text_overflow(TextOverflow::Ellipsis)
}
pub fn max_lines(mut self, lines: usize) -> Self {
self.text_max_lines = Some(lines.max(1));
self
}
pub fn font_size(mut self, s: f32) -> Self {
self.font_size = s;
self.line_height = crate::tokens::line_height_for_size(s);
self
}
pub fn line_height(mut self, h: f32) -> Self {
self.line_height = h.max(1.0);
self
}
pub fn font_weight(mut self, w: FontWeight) -> Self {
self.font_weight = w;
self
}
pub fn font_family(mut self, family: FontFamily) -> Self {
self.font_family = family;
self.explicit_font_family = true;
self
}
pub fn inter(self) -> Self {
self.font_family(FontFamily::Inter)
}
pub fn roboto(self) -> Self {
self.font_family(FontFamily::Roboto)
}
/// Override the monospace face used when this node renders as code
/// (`font_mono = true`, `TextRole::Code`, or any descendant that
/// inherits the value through theme propagation). Setting this
/// pins the node — theme `with_mono_font_family(...)` no longer
/// stamps over it.
pub fn mono_font_family(mut self, family: FontFamily) -> Self {
self.mono_font_family = family;
self.explicit_mono_font_family = true;
self
}
/// Pin this node's monospace face to JetBrains Mono. Convenience
/// shorthand for `.mono_font_family(FontFamily::JetBrainsMono)`.
pub fn jetbrains_mono(self) -> Self {
self.mono_font_family(FontFamily::JetBrainsMono)
}
/// Set the icon for this element to either a built-in [`crate::IconName`],
/// an app-supplied [`crate::SvgIcon`], or a string-typed name from
/// the built-in vocabulary.
pub fn icon_source(mut self, source: impl crate::svg_icon::IntoIconSource) -> Self {
self.icon = Some(source.into_icon_source());
self
}
/// Convenience alias for [`Self::icon_source`] preserved for call
/// sites that want the historical name.
pub fn icon_name(self, source: impl crate::svg_icon::IntoIconSource) -> Self {
self.icon_source(source)
}
pub fn icon_stroke_width(mut self, width: f32) -> Self {
self.icon_stroke_width = width.max(0.25);
self
}
pub fn icon_size(mut self, size: f32) -> Self {
let size = size.max(1.0);
self.font_size = size;
self.line_height = size;
self.width = Size::Fixed(size);
self.height = Size::Fixed(size);
self.explicit_width = true;
self.explicit_height = true;
self
}
/// Attach a raster image. Usually you'll want the [`crate::image`]
/// free builder instead, which sets [`crate::Kind::Image`] for you; this
/// method exists for cases where you've already constructed an El
/// (e.g. through a stock widget) and want to swap in pixel art.
pub fn image(mut self, image: impl Into<Image>) -> Self {
self.image = Some(image.into());
self
}
pub fn image_fit(mut self, fit: ImageFit) -> Self {
self.image_fit = fit;
self
}
pub fn image_tint(mut self, c: Color) -> Self {
self.image_tint = Some(c);
self
}
/// Attach an app-owned GPU texture source. Typically set via the
/// [`crate::tree::surface`] builder (which also sets
/// [`crate::Kind::Surface`]); reach for this method on a stock
/// widget El whose Kind you want to keep.
pub fn surface_source(mut self, source: crate::surface::SurfaceSource) -> Self {
self.surface_source = Some(source);
self
}
/// How a [`crate::Kind::Surface`] El composes with widgets below
/// it. Default is [`crate::surface::SurfaceAlpha::Premultiplied`].
pub fn surface_alpha(mut self, alpha: crate::surface::SurfaceAlpha) -> Self {
self.surface_alpha = alpha;
self
}
/// How a [`crate::Kind::Surface`] El's texture projects into its
/// resolved rect. Defaults to [`crate::image::ImageFit::Fill`] —
/// stretch to the rect — for parity with the pre-`surface_fit`
/// behaviour. `Contain` / `Cover` / `None` mirror the modes on
/// [`crate::El::image_fit`].
pub fn surface_fit(mut self, fit: crate::image::ImageFit) -> Self {
self.surface_fit = fit;
self
}
/// Affine applied to the texture quad in destination space, around
/// the centre of the post-[`Self::surface_fit`] rect. Defaults to
/// identity. Use this for rotation, mirroring, source-dimension-
/// independent zoom/pan, or any combination thereof. The El's
/// auto-clip scissor still clamps the rendered content to the
/// resolved rect.
pub fn surface_transform(mut self, transform: crate::affine::Affine2) -> Self {
self.surface_transform = transform;
self
}
/// Attach a vector asset source. Typically set via the
/// [`crate::tree::vector`] builder (which also sets
/// [`crate::Kind::Vector`]); reach for this method on a stock
/// widget El whose Kind you want to keep.
pub fn vector_source(
mut self,
asset: impl Into<std::sync::Arc<crate::vector::VectorAsset>>,
) -> Self {
self.vector_source = Some(asset.into());
self
}
/// Select how a vector asset should render. The default is
/// [`crate::vector::VectorRenderMode::Painted`], which preserves
/// authored fills/strokes/gradients. Use [`Self::vector_mask`] when
/// the asset is intended as one-colour coverage geometry.
pub fn vector_render_mode(mut self, mode: crate::vector::VectorRenderMode) -> Self {
self.vector_render_mode = mode;
self
}
/// Treat this vector as coverage geometry and paint it with one
/// colour. Backends can render this through their MSDF path.
pub fn vector_mask(self, color: Color) -> Self {
self.vector_render_mode(crate::vector::VectorRenderMode::Mask { color })
}
/// Preserve authored vector paint. This is the default for
/// [`crate::tree::vector`].
pub fn vector_painted(self) -> Self {
self.vector_render_mode(crate::vector::VectorRenderMode::Painted)
}
/// Inside-out redraw deadline. While this El is visible (rect
/// intersects the viewport), Aetna asks the host to drive the next
/// frame within `deadline`. Aggregated across the tree via `min`,
/// so the host gets a single signal regardless of how many widgets
/// are asking. Use `Duration::ZERO` for "next frame ASAP";
/// non-zero values pace the redraw loop below the display rate.
///
/// Apps that pause / resume animation (e.g. GIF playback) just
/// stop calling this method on the relevant El — Aetna re-runs
/// the aggregation each frame, so the redraw scheduler quiets
/// automatically when no visible widget is asking.
pub fn redraw_within(mut self, deadline: std::time::Duration) -> Self {
self.redraw_within = Some(deadline);
self
}
/// Opt this node into the monospace face. Setting this flag also
/// sets [`El::explicit_mono`] so a subsequent role modifier
/// (`.caption()` / `.label()` / `.body()` / `.title()` /
/// `.heading()` / `.display()`) won't silently reset `font_mono`
/// when the role's default is non-mono. The natural reading order
/// `text(s).mono().caption()` therefore renders in mono.
pub fn mono(mut self) -> Self {
self.font_mono = true;
self.explicit_mono = true;
self
}
/// Italic styling for a text run. Honoured by the
/// [`crate::Kind::Inlines`] layout pass and (best-effort) on
/// standalone text Els.
pub fn italic(mut self) -> Self {
self.text_italic = true;
self
}
/// Inline-run background. Honoured when this El is a styled text
/// leaf inside an [`crate::Kind::Inlines`] parent: the shaped span
/// paints a solid quad behind its glyphs (per-line if the span
/// wraps). Mirrors HTML's `<mark>` / inline `background`; the rect
/// tracks the glyph extent rather than the El's layout box, so a
/// wrapped highlight follows the prose. No effect on standalone
/// text Els.
pub fn background(mut self, color: Color) -> Self {
self.text_bg = Some(color);
self
}
/// Underline styling for a text run.
pub fn underline(mut self) -> Self {
self.text_underline = true;
self
}
/// Strikethrough styling for a text run.
pub fn strikethrough(mut self) -> Self {
self.text_strikethrough = true;
self
}
/// Markdown-flavoured inline-code styling. Currently `mono`-styled;
/// a tinted background per the theme is a future addition. Authors
/// who want raw mono without code chrome should use [`Self::mono`]
/// instead.
pub fn code(self) -> Self {
self.text_role(TextRole::Code)
}
/// Mark this run as a link to `url`. Inside an
/// [`crate::Kind::Inlines`] parent the run paints with a
/// link-themed color; runs sharing the same URL group together for
/// hit-test.
pub fn link(mut self, url: impl Into<String>) -> Self {
self.text_link = Some(url.into());
self
}
pub fn math_expr(mut self, expr: impl Into<std::sync::Arc<crate::math::MathExpr>>) -> Self {
self.math = Some(expr.into());
self
}
pub fn math_display(mut self, display: crate::math::MathDisplay) -> Self {
self.math_display = display;
self
}
}