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}