Skip to main content

aetna_core/tree/
content.rs

1//! Content-related [`El`] modifiers: text runs, icon source, and raster image source.
2
3use crate::image::{Image, ImageFit};
4
5use super::color::Color;
6use super::layout_types::Size;
7use super::node::El;
8use super::text_types::{FontFamily, FontWeight, TextAlign, TextOverflow, TextRole, TextWrap};
9
10impl El {
11    // ---- Text-bearing ----
12    pub fn text(mut self, t: impl Into<String>) -> Self {
13        self.text = Some(t.into());
14        self
15    }
16
17    pub fn text_color(mut self, c: Color) -> Self {
18        self.text_color = Some(c);
19        self
20    }
21
22    pub fn text_align(mut self, align: TextAlign) -> Self {
23        self.text_align = align;
24        self
25    }
26
27    pub fn center_text(self) -> Self {
28        self.text_align(TextAlign::Center)
29    }
30
31    pub fn end_text(self) -> Self {
32        self.text_align(TextAlign::End)
33    }
34
35    pub fn text_wrap(mut self, wrap: TextWrap) -> Self {
36        self.text_wrap = wrap;
37        self
38    }
39
40    pub fn wrap_text(self) -> Self {
41        self.text_wrap(TextWrap::Wrap)
42    }
43
44    pub fn nowrap_text(self) -> Self {
45        self.text_wrap(TextWrap::NoWrap)
46    }
47
48    pub fn text_overflow(mut self, overflow: TextOverflow) -> Self {
49        self.text_overflow = overflow;
50        self
51    }
52
53    pub fn ellipsis(self) -> Self {
54        self.text_overflow(TextOverflow::Ellipsis)
55    }
56
57    pub fn max_lines(mut self, lines: usize) -> Self {
58        self.text_max_lines = Some(lines.max(1));
59        self
60    }
61
62    pub fn font_size(mut self, s: f32) -> Self {
63        self.font_size = s;
64        self.line_height = crate::tokens::line_height_for_size(s);
65        self
66    }
67
68    pub fn line_height(mut self, h: f32) -> Self {
69        self.line_height = h.max(1.0);
70        self
71    }
72
73    pub fn font_weight(mut self, w: FontWeight) -> Self {
74        self.font_weight = w;
75        self
76    }
77
78    pub fn font_family(mut self, family: FontFamily) -> Self {
79        self.font_family = family;
80        self.explicit_font_family = true;
81        self
82    }
83
84    pub fn inter(self) -> Self {
85        self.font_family(FontFamily::Inter)
86    }
87
88    pub fn roboto(self) -> Self {
89        self.font_family(FontFamily::Roboto)
90    }
91
92    /// Override the monospace face used when this node renders as code
93    /// (`font_mono = true`, `TextRole::Code`, or any descendant that
94    /// inherits the value through theme propagation). Setting this
95    /// pins the node — theme `with_mono_font_family(...)` no longer
96    /// stamps over it.
97    pub fn mono_font_family(mut self, family: FontFamily) -> Self {
98        self.mono_font_family = family;
99        self.explicit_mono_font_family = true;
100        self
101    }
102
103    /// Pin this node's monospace face to JetBrains Mono. Convenience
104    /// shorthand for `.mono_font_family(FontFamily::JetBrainsMono)`.
105    pub fn jetbrains_mono(self) -> Self {
106        self.mono_font_family(FontFamily::JetBrainsMono)
107    }
108
109    /// Set the icon for this element to either a built-in [`crate::IconName`],
110    /// an app-supplied [`crate::SvgIcon`], or a string-typed name from
111    /// the built-in vocabulary.
112    pub fn icon_source(mut self, source: impl crate::svg_icon::IntoIconSource) -> Self {
113        self.icon = Some(source.into_icon_source());
114        self
115    }
116
117    /// Convenience alias for [`Self::icon_source`] preserved for call
118    /// sites that want the historical name.
119    pub fn icon_name(self, source: impl crate::svg_icon::IntoIconSource) -> Self {
120        self.icon_source(source)
121    }
122
123    pub fn icon_stroke_width(mut self, width: f32) -> Self {
124        self.icon_stroke_width = width.max(0.25);
125        self
126    }
127
128    pub fn icon_size(mut self, size: f32) -> Self {
129        let size = size.max(1.0);
130        self.font_size = size;
131        self.line_height = size;
132        self.width = Size::Fixed(size);
133        self.height = Size::Fixed(size);
134        self.explicit_width = true;
135        self.explicit_height = true;
136        self
137    }
138
139    /// Attach a raster image. Usually you'll want the [`crate::image`]
140    /// free builder instead, which sets [`crate::Kind::Image`] for you; this
141    /// method exists for cases where you've already constructed an El
142    /// (e.g. through a stock widget) and want to swap in pixel art.
143    pub fn image(mut self, image: impl Into<Image>) -> Self {
144        self.image = Some(image.into());
145        self
146    }
147
148    pub fn image_fit(mut self, fit: ImageFit) -> Self {
149        self.image_fit = fit;
150        self
151    }
152
153    pub fn image_tint(mut self, c: Color) -> Self {
154        self.image_tint = Some(c);
155        self
156    }
157
158    /// Attach an app-owned GPU texture source. Typically set via the
159    /// [`crate::tree::surface`] builder (which also sets
160    /// [`crate::Kind::Surface`]); reach for this method on a stock
161    /// widget El whose Kind you want to keep.
162    pub fn surface_source(mut self, source: crate::surface::SurfaceSource) -> Self {
163        self.surface_source = Some(source);
164        self
165    }
166
167    /// How a [`crate::Kind::Surface`] El composes with widgets below
168    /// it. Default is [`crate::surface::SurfaceAlpha::Premultiplied`].
169    pub fn surface_alpha(mut self, alpha: crate::surface::SurfaceAlpha) -> Self {
170        self.surface_alpha = alpha;
171        self
172    }
173
174    /// How a [`crate::Kind::Surface`] El's texture projects into its
175    /// resolved rect. Defaults to [`crate::image::ImageFit::Fill`] —
176    /// stretch to the rect — for parity with the pre-`surface_fit`
177    /// behaviour. `Contain` / `Cover` / `None` mirror the modes on
178    /// [`crate::El::image_fit`].
179    pub fn surface_fit(mut self, fit: crate::image::ImageFit) -> Self {
180        self.surface_fit = fit;
181        self
182    }
183
184    /// Affine applied to the texture quad in destination space, around
185    /// the centre of the post-[`Self::surface_fit`] rect. Defaults to
186    /// identity. Use this for rotation, mirroring, source-dimension-
187    /// independent zoom/pan, or any combination thereof. The El's
188    /// auto-clip scissor still clamps the rendered content to the
189    /// resolved rect.
190    pub fn surface_transform(mut self, transform: crate::affine::Affine2) -> Self {
191        self.surface_transform = transform;
192        self
193    }
194
195    /// Attach a vector asset source. Typically set via the
196    /// [`crate::tree::vector`] builder (which also sets
197    /// [`crate::Kind::Vector`]); reach for this method on a stock
198    /// widget El whose Kind you want to keep.
199    pub fn vector_source(
200        mut self,
201        asset: impl Into<std::sync::Arc<crate::vector::VectorAsset>>,
202    ) -> Self {
203        self.vector_source = Some(asset.into());
204        self
205    }
206
207    /// Select how a vector asset should render. The default is
208    /// [`crate::vector::VectorRenderMode::Painted`], which preserves
209    /// authored fills/strokes/gradients. Use [`Self::vector_mask`] when
210    /// the asset is intended as one-colour coverage geometry.
211    pub fn vector_render_mode(mut self, mode: crate::vector::VectorRenderMode) -> Self {
212        self.vector_render_mode = mode;
213        self
214    }
215
216    /// Treat this vector as coverage geometry and paint it with one
217    /// colour. Backends can render this through their MSDF path.
218    pub fn vector_mask(self, color: Color) -> Self {
219        self.vector_render_mode(crate::vector::VectorRenderMode::Mask { color })
220    }
221
222    /// Preserve authored vector paint. This is the default for
223    /// [`crate::tree::vector`].
224    pub fn vector_painted(self) -> Self {
225        self.vector_render_mode(crate::vector::VectorRenderMode::Painted)
226    }
227
228    /// Inside-out redraw deadline. While this El is visible (rect
229    /// intersects the viewport), Aetna asks the host to drive the next
230    /// frame within `deadline`. Aggregated across the tree via `min`,
231    /// so the host gets a single signal regardless of how many widgets
232    /// are asking. Use `Duration::ZERO` for "next frame ASAP";
233    /// non-zero values pace the redraw loop below the display rate.
234    ///
235    /// Apps that pause / resume animation (e.g. GIF playback) just
236    /// stop calling this method on the relevant El — Aetna re-runs
237    /// the aggregation each frame, so the redraw scheduler quiets
238    /// automatically when no visible widget is asking.
239    pub fn redraw_within(mut self, deadline: std::time::Duration) -> Self {
240        self.redraw_within = Some(deadline);
241        self
242    }
243
244    /// Opt this node into the monospace face. Setting this flag also
245    /// sets [`El::explicit_mono`] so a subsequent role modifier
246    /// (`.caption()` / `.label()` / `.body()` / `.title()` /
247    /// `.heading()` / `.display()`) won't silently reset `font_mono`
248    /// when the role's default is non-mono. The natural reading order
249    /// `text(s).mono().caption()` therefore renders in mono.
250    pub fn mono(mut self) -> Self {
251        self.font_mono = true;
252        self.explicit_mono = true;
253        self
254    }
255
256    /// Italic styling for a text run. Honoured by the
257    /// [`crate::Kind::Inlines`] layout pass and (best-effort) on
258    /// standalone text Els.
259    pub fn italic(mut self) -> Self {
260        self.text_italic = true;
261        self
262    }
263
264    /// Inline-run background. Honoured when this El is a styled text
265    /// leaf inside an [`crate::Kind::Inlines`] parent: the shaped span
266    /// paints a solid quad behind its glyphs (per-line if the span
267    /// wraps). Mirrors HTML's `<mark>` / inline `background`; the rect
268    /// tracks the glyph extent rather than the El's layout box, so a
269    /// wrapped highlight follows the prose. No effect on standalone
270    /// text Els.
271    pub fn background(mut self, color: Color) -> Self {
272        self.text_bg = Some(color);
273        self
274    }
275
276    /// Underline styling for a text run.
277    pub fn underline(mut self) -> Self {
278        self.text_underline = true;
279        self
280    }
281
282    /// Strikethrough styling for a text run.
283    pub fn strikethrough(mut self) -> Self {
284        self.text_strikethrough = true;
285        self
286    }
287
288    /// Markdown-flavoured inline-code styling. Currently `mono`-styled;
289    /// a tinted background per the theme is a future addition. Authors
290    /// who want raw mono without code chrome should use [`Self::mono`]
291    /// instead.
292    pub fn code(self) -> Self {
293        self.text_role(TextRole::Code)
294    }
295
296    /// Mark this run as a link to `url`. Inside an
297    /// [`crate::Kind::Inlines`] parent the run paints with a
298    /// link-themed color; runs sharing the same URL group together for
299    /// hit-test.
300    pub fn link(mut self, url: impl Into<String>) -> Self {
301        self.text_link = Some(url.into());
302        self
303    }
304
305    pub fn math_expr(mut self, expr: impl Into<std::sync::Arc<crate::math::MathExpr>>) -> Self {
306        self.math = Some(expr.into());
307        self
308    }
309
310    pub fn math_display(mut self, display: crate::math::MathDisplay) -> Self {
311        self.math_display = display;
312        self
313    }
314}