zng_wgt_image/fill.rs
1//! Background/foreground image properties.
2//!
3//! Implemented on this case instead of `zng-wgt-fill` to avoid cyclic dependencies.
4
5use zng_ext_image::ImageSource;
6use zng_wgt::prelude::*;
7use zng_wgt_fill::{background, foreground};
8
9use crate::{ImageFit, ImageRepeat};
10
11/// Background image.
12///
13/// This property applies an image as [`background`].
14///
15/// The image can be configured by the same `img_*` contextual properties that affect [`Image!`] widgets,
16/// a subset of image properties have `background_img_*` equivalent that only affect background images. You
17/// can also adjust the opacity of the image using [`background_img_opacity`].
18///
19/// Note that you can use you can always set [`background`] or [`background_fn`] to an [`Image!`] widget directly to
20/// access advanced image configuration properties.
21///
22/// [`background`]: fn@background
23/// [`background_fn`]: fn@zng_wgt_fill::background
24/// [`background_img_opacity`]: fn@background_img_opacity
25/// [`Image!`]: struct@crate::Image
26#[property(FILL)]
27pub fn background_img(child: impl IntoUiNode, source: impl IntoVar<ImageSource>) -> UiNode {
28 background(
29 child,
30 fill_img_node(
31 source.into_var(),
32 BACKGROUND_IMG_FIT_VAR,
33 BACKGROUND_IMG_ALIGN_VAR,
34 BACKGROUND_IMG_OFFSET_VAR,
35 BACKGROUND_IMG_CROP_VAR,
36 BACKGROUND_IMG_REPEAT_VAR,
37 BACKGROUND_IMG_REPEAT_SPACING_VAR,
38 BACKGROUND_IMG_OPACITY_VAR,
39 ),
40 )
41}
42
43/// Sets the background image fit.
44///
45/// This property sets the [`BACKGROUND_IMG_FIT_VAR`] and overrides the [`img_fit`] value for the background images.
46///
47/// [`img_fit`]: fn@crate::img_fit
48#[property(CONTEXT, default(BACKGROUND_IMG_FIT_VAR))]
49pub fn background_img_fit(child: impl IntoUiNode, fit: impl IntoVar<ImageFit>) -> UiNode {
50 with_context_var(child, BACKGROUND_IMG_FIT_VAR, fit)
51}
52
53/// Sets the background image alignment.
54///
55/// This property sets the [`BACKGROUND_IMG_ALIGN_VAR`] and overrides the [`img_align`] value for the background images.
56///
57/// [`img_align`]: fn@crate::img_align
58#[property(CONTEXT, default(BACKGROUND_IMG_ALIGN_VAR))]
59pub fn background_img_align(child: impl IntoUiNode, align: impl IntoVar<Align>) -> UiNode {
60 with_context_var(child, BACKGROUND_IMG_ALIGN_VAR, align)
61}
62
63/// Sets the background image offset.
64///
65/// This property sets the [`BACKGROUND_IMG_OFFSET_VAR`] and overrides the [`img_offset`] value for the background images.
66///
67/// [`img_offset`]: fn@crate::img_offset
68#[property(CONTEXT, default(BACKGROUND_IMG_OFFSET_VAR))]
69pub fn background_img_offset(child: impl IntoUiNode, offset: impl IntoVar<Vector>) -> UiNode {
70 with_context_var(child, BACKGROUND_IMG_OFFSET_VAR, offset)
71}
72
73/// Sets the background image crop.
74///
75/// This property sets the [`BACKGROUND_IMG_CROP_VAR`] and overrides the [`img_crop`] value for the background images.
76///
77/// [`img_crop`]: fn@crate::img_crop
78#[property(CONTEXT, default(BACKGROUND_IMG_CROP_VAR))]
79pub fn background_img_crop(child: impl IntoUiNode, crop: impl IntoVar<Rect>) -> UiNode {
80 with_context_var(child, BACKGROUND_IMG_CROP_VAR, crop)
81}
82
83/// Sets the background image repeat.
84///
85/// This property sets the [`BACKGROUND_IMG_REPEAT_VAR`] and overrides the [`img_repeat`] value for the background images.
86///
87/// [`img_repeat`]: fn@crate::img_repeat
88#[property(CONTEXT, default(BACKGROUND_IMG_REPEAT_VAR))]
89pub fn background_img_repeat(child: impl IntoUiNode, repeat: impl IntoVar<ImageRepeat>) -> UiNode {
90 with_context_var(child, BACKGROUND_IMG_REPEAT_VAR, repeat)
91}
92
93/// Sets the background image repeat spacing.
94///
95/// This property sets the [`BACKGROUND_IMG_REPEAT_SPACING_VAR`] and overrides the [`img_repeat_spacing`] value for the background images.
96///
97/// [`img_repeat_spacing`]: fn@crate::img_repeat_spacing
98#[property(CONTEXT, default(BACKGROUND_IMG_REPEAT_SPACING_VAR))]
99pub fn background_img_repeat_spacing(child: impl IntoUiNode, spacing: impl IntoVar<Size>) -> UiNode {
100 with_context_var(child, BACKGROUND_IMG_REPEAT_SPACING_VAR, spacing)
101}
102
103/// Sets the background image opacity.
104///
105/// This property sets the [`BACKGROUND_IMG_OPACITY_VAR`].
106///
107/// [`img_repeat_spacing`]: fn@crate::img_repeat_spacing
108#[property(CONTEXT, default(BACKGROUND_IMG_OPACITY_VAR))]
109pub fn background_img_opacity(child: impl IntoUiNode, alpha: impl IntoVar<Factor>) -> UiNode {
110 with_context_var(child, BACKGROUND_IMG_OPACITY_VAR, alpha)
111}
112
113context_var! {
114 /// The background image layout mode.
115 ///
116 /// Is [`IMAGE_FIT_VAR`] by default.
117 ///
118 /// [`IMAGE_FIT_VAR`]: crate::IMAGE_FIT_VAR
119 pub static BACKGROUND_IMG_FIT_VAR: ImageFit = crate::IMAGE_FIT_VAR;
120
121 /// Align of the background image in relation to the widget final size.
122 ///
123 /// Is [`IMAGE_ALIGN_VAR`] by default.
124 ///
125 /// [`IMAGE_ALIGN_VAR`]: crate::IMAGE_ALIGN_VAR
126 pub static BACKGROUND_IMG_ALIGN_VAR: Align = crate::IMAGE_ALIGN_VAR;
127
128 /// Offset applied to the background image after all measure and arrange.
129 ///
130 /// Is [`IMAGE_OFFSET_VAR`] by default.
131 ///
132 /// [`IMAGE_OFFSET_VAR`]: crate::IMAGE_OFFSET_VAR
133 pub static BACKGROUND_IMG_OFFSET_VAR: Vector = crate::IMAGE_OFFSET_VAR;
134
135 /// Simple clip applied to the background image before layout.
136 ///
137 /// Is [`IMAGE_CROP_VAR`] by default.
138 ///
139 /// [`IMAGE_CROP_VAR`]: crate::IMAGE_CROP_VAR
140 pub static BACKGROUND_IMG_CROP_VAR: Rect = crate::IMAGE_CROP_VAR;
141
142 /// Pattern repeat applied on the final background image.
143 ///
144 /// Is [`IMAGE_REPEAT_VAR`] by default.
145 ///
146 /// [`IMAGE_REPEAT_VAR`]: crate::IMAGE_REPEAT_VAR
147 pub static BACKGROUND_IMG_REPEAT_VAR: ImageRepeat = crate::IMAGE_REPEAT_VAR;
148
149 /// Spacing between repeated background image copies.
150 ///
151 /// Is [`IMAGE_REPEAT_SPACING_VAR`] by default.
152 ///
153 /// [`IMAGE_REPEAT_SPACING_VAR`]: crate::IMAGE_REPEAT_SPACING_VAR
154 pub static BACKGROUND_IMG_REPEAT_SPACING_VAR: Size = crate::IMAGE_REPEAT_SPACING_VAR;
155
156 /// Opacity of the background image.
157 ///
158 /// Is `100.pct()` by default.
159 pub static BACKGROUND_IMG_OPACITY_VAR: Factor = 100.pct();
160}
161
162/// Foreground image.
163///
164/// This property applies an image as [`foreground`].
165///
166/// The image can be configured by the same `img_*` contextual properties that affect [`Image!`] widgets,
167/// a subset of image properties have `foreground_img_*` equivalent that only affect foreground images. You
168/// can also adjust the opacity of the image using [`foreground_img_opacity`].
169///
170/// Note that you can use you can always set [`foreground`] or [`foreground_fn`] to an [`Image!`] widget directly to
171/// access advanced image configuration properties.
172///
173/// [`foreground`]: fn@foreground
174/// [`foreground_fn`]: fn@zng_wgt_fill::foreground
175/// [`foreground_img_opacity`]: fn@foreground_img_opacity
176/// [`Image!`]: struct@crate::Image
177#[property(FILL)]
178pub fn foreground_img(child: impl IntoUiNode, source: impl IntoVar<ImageSource>) -> UiNode {
179 foreground(
180 child,
181 fill_img_node(
182 source.into_var(),
183 FOREGROUND_IMG_FIT_VAR,
184 FOREGROUND_IMG_ALIGN_VAR,
185 FOREGROUND_IMG_OFFSET_VAR,
186 FOREGROUND_IMG_CROP_VAR,
187 FOREGROUND_IMG_REPEAT_VAR,
188 FOREGROUND_IMG_REPEAT_SPACING_VAR,
189 FOREGROUND_IMG_OPACITY_VAR,
190 ),
191 )
192}
193
194/// Sets the foreground image fit.
195///
196/// This property sets the [`FOREGROUND_IMG_FIT_VAR`] and overrides the [`img_fit`] value for the foreground images.
197///
198/// [`img_fit`]: fn@crate::img_fit
199#[property(CONTEXT, default(FOREGROUND_IMG_FIT_VAR))]
200pub fn foreground_img_fit(child: impl IntoUiNode, fit: impl IntoVar<ImageFit>) -> UiNode {
201 with_context_var(child, FOREGROUND_IMG_FIT_VAR, fit)
202}
203
204/// Sets the foreground image alignment.
205///
206/// This property sets the [`FOREGROUND_IMG_ALIGN_VAR`] and overrides the [`img_align`] value for the foreground images.
207///
208/// [`img_align`]: fn@crate::img_align
209#[property(CONTEXT, default(FOREGROUND_IMG_ALIGN_VAR))]
210pub fn foreground_img_align(child: impl IntoUiNode, align: impl IntoVar<Align>) -> UiNode {
211 with_context_var(child, FOREGROUND_IMG_ALIGN_VAR, align)
212}
213
214/// Sets the foreground image offset.
215///
216/// This property sets the [`FOREGROUND_IMG_OFFSET_VAR`] and overrides the [`img_offset`] value for the foreground images.
217///
218/// [`img_offset`]: fn@crate::img_offset
219#[property(CONTEXT, default(FOREGROUND_IMG_OFFSET_VAR))]
220pub fn foreground_img_offset(child: impl IntoUiNode, offset: impl IntoVar<Vector>) -> UiNode {
221 with_context_var(child, FOREGROUND_IMG_OFFSET_VAR, offset)
222}
223
224/// Sets the foreground image crop.
225///
226/// This property sets the [`FOREGROUND_IMG_CROP_VAR`] and overrides the [`img_crop`] value for the foreground images.
227///
228/// [`img_crop`]: fn@crate::img_crop
229#[property(CONTEXT, default(FOREGROUND_IMG_CROP_VAR))]
230pub fn foreground_img_crop(child: impl IntoUiNode, crop: impl IntoVar<Rect>) -> UiNode {
231 with_context_var(child, FOREGROUND_IMG_CROP_VAR, crop)
232}
233
234/// Sets the foreground image repeat.
235///
236/// This property sets the [`FOREGROUND_IMG_REPEAT_VAR`] and overrides the [`img_repeat`] value for the foreground images.
237///
238/// [`img_repeat`]: fn@crate::img_repeat
239#[property(CONTEXT, default(FOREGROUND_IMG_REPEAT_VAR))]
240pub fn foreground_img_repeat(child: impl IntoUiNode, repeat: impl IntoVar<ImageRepeat>) -> UiNode {
241 with_context_var(child, FOREGROUND_IMG_REPEAT_VAR, repeat)
242}
243
244/// Sets the foreground image repeat spacing.
245///
246/// This property sets the [`FOREGROUND_IMG_REPEAT_SPACING_VAR`] and overrides the [`img_repeat_spacing`] value for the foreground images.
247///
248/// [`img_repeat_spacing`]: fn@crate::img_repeat_spacing
249#[property(CONTEXT, default(FOREGROUND_IMG_REPEAT_SPACING_VAR))]
250pub fn foreground_img_repeat_spacing(child: impl IntoUiNode, spacing: impl IntoVar<Size>) -> UiNode {
251 with_context_var(child, FOREGROUND_IMG_REPEAT_SPACING_VAR, spacing)
252}
253
254/// Sets the foreground image opacity.
255///
256/// This property sets the [`FOREGROUND_IMG_OPACITY_VAR`].
257///
258/// [`img_repeat_spacing`]: fn@crate::img_repeat_spacing
259#[property(CONTEXT, default(FOREGROUND_IMG_OPACITY_VAR))]
260pub fn foreground_img_opacity(child: impl IntoUiNode, alpha: impl IntoVar<Factor>) -> UiNode {
261 with_context_var(child, FOREGROUND_IMG_OPACITY_VAR, alpha)
262}
263
264context_var! {
265 /// The foreground image layout mode.
266 ///
267 /// Is [`IMAGE_FIT_VAR`] by default.
268 ///
269 /// [`IMAGE_FIT_VAR`]: crate::IMAGE_FIT_VAR
270 pub static FOREGROUND_IMG_FIT_VAR: ImageFit = crate::IMAGE_FIT_VAR;
271
272 /// Align of the foreground image in relation to the widget final size.
273 ///
274 /// Is [`IMAGE_ALIGN_VAR`] by default.
275 ///
276 /// [`IMAGE_ALIGN_VAR`]: crate::IMAGE_ALIGN_VAR
277 pub static FOREGROUND_IMG_ALIGN_VAR: Align = crate::IMAGE_ALIGN_VAR;
278
279 /// Offset applied to the foreground image after all measure and arrange.
280 ///
281 /// Is [`IMAGE_OFFSET_VAR`] by default.
282 ///
283 /// [`IMAGE_OFFSET_VAR`]: crate::IMAGE_OFFSET_VAR
284 pub static FOREGROUND_IMG_OFFSET_VAR: Vector = crate::IMAGE_OFFSET_VAR;
285
286 /// Simple clip applied to the foreground image before layout.
287 ///
288 /// Is [`IMAGE_CROP_VAR`] by default.
289 ///
290 /// [`IMAGE_CROP_VAR`]: crate::IMAGE_CROP_VAR
291 pub static FOREGROUND_IMG_CROP_VAR: Rect = crate::IMAGE_CROP_VAR;
292
293 /// Pattern repeat applied on the final foreground image.
294 ///
295 /// Is [`IMAGE_REPEAT_VAR`] by default.
296 ///
297 /// [`IMAGE_REPEAT_VAR`]: crate::IMAGE_REPEAT_VAR
298 pub static FOREGROUND_IMG_REPEAT_VAR: ImageRepeat = crate::IMAGE_REPEAT_VAR;
299
300 /// Spacing between repeated foreground image copies.
301 ///
302 /// Is [`IMAGE_REPEAT_SPACING_VAR`] by default.
303 ///
304 /// [`IMAGE_REPEAT_SPACING_VAR`]: crate::IMAGE_REPEAT_SPACING_VAR
305 pub static FOREGROUND_IMG_REPEAT_SPACING_VAR: Size = crate::IMAGE_REPEAT_SPACING_VAR;
306
307 /// Opacity of the foreground image.
308 ///
309 /// Is `100.pct()` by default.
310 pub static FOREGROUND_IMG_OPACITY_VAR: Factor = 100.pct();
311}
312
313#[allow(clippy::too_many_arguments)]
314fn fill_img_node(
315 source: impl IntoVar<ImageSource>,
316 img_fit: impl IntoVar<ImageFit>,
317 img_align: impl IntoVar<Align>,
318 img_offset: impl IntoVar<Vector>,
319 img_crop: impl IntoVar<Rect>,
320 img_repeat: impl IntoVar<ImageRepeat>,
321 img_repeat_spacing: impl IntoVar<Size>,
322 img_opacity: impl IntoVar<Factor>,
323) -> UiNode {
324 use crate::node;
325 // child
326 let child = node::image_presenter();
327 let child = node::image_error_presenter(child);
328 let child = node::image_loading_presenter(child);
329 let child = opacity_node(child, img_opacity);
330
331 // event
332 let child = node::image_source(child, source);
333
334 // context
335 let child = crate::img_fit(child, img_fit);
336 let child = crate::img_align(child, img_align);
337 let child = crate::img_offset(child, img_offset);
338 let child = crate::img_crop(child, img_crop);
339 let child = crate::img_repeat(child, img_repeat);
340 crate::img_repeat_spacing(child, img_repeat_spacing)
341}
342
343// very similar to `child_opacity`, code copied here to avoid importing the full `zng-wgt-filter`.
344fn opacity_node(child: impl IntoUiNode, alpha: impl IntoVar<Factor>) -> UiNode {
345 let frame_key = FrameValueKey::new_unique();
346 let alpha = alpha.into_var();
347
348 match_node(child, move |child, op| match op {
349 UiNodeOp::Init => {
350 WIDGET.sub_var_render_update(&alpha);
351 }
352 UiNodeOp::Render { frame } => {
353 let opacity = frame_key.bind_var(&alpha, |f| f.0);
354 frame.push_opacity(opacity, |frame| child.render(frame));
355 }
356 UiNodeOp::RenderUpdate { update } => {
357 update.update_f32_opt(frame_key.update_var(&alpha, |f| f.0));
358 child.render_update(update);
359 }
360 _ => {}
361 })
362}