1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
11
12use zng_wgt::prelude::gradient::{GradientRadius, GradientStops, LinearGradientAxis, stops};
13use zng_wgt::{HitTestMode, hit_test_mode, node::interactive_node, prelude::*};
14
15pub mod node;
16
17#[property(FILL)]
26pub fn background(child: impl IntoUiNode, background: impl IntoUiNode) -> UiNode {
27 let background = interactive_node(background, false);
28 let background = fill_node(background);
29
30 match_node(ui_vec![background, child], |children, op| match op {
31 UiNodeOp::Measure { wm, desired_size } => {
32 children.delegated();
33 *desired_size = children.node().with_child(1, |n| n.measure(wm));
34 }
35 UiNodeOp::Layout { wl, final_size } => {
36 children.delegated();
37 let size = children.node().with_child(1, |n| n.layout(wl));
38
39 LAYOUT.with_constraints(PxConstraints2d::new_exact_size(size), || {
40 children.node().with_child(0, |n| n.layout(wl));
41 });
42 *final_size = size;
43 }
44 _ => {}
45 })
46}
47
48#[property(FILL, default(WidgetFn::nil()))]
58pub fn background_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<()>>) -> UiNode {
59 background(child, presenter((), wgt_fn))
60}
61
62#[property(FILL, default(colors::BLACK.transparent()))]
68pub fn background_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode {
69 background(child, node::flood(color))
70}
71
72#[property(FILL, default(0.deg(), {
78 let c = colors::BLACK.transparent();
79 stops![c, c]
80}))]
81pub fn background_gradient(child: impl IntoUiNode, axis: impl IntoVar<LinearGradientAxis>, stops: impl IntoVar<GradientStops>) -> UiNode {
82 background(child, node::linear_gradient(axis, stops))
83}
84
85#[property(FILL, default((50.pct(), 50.pct()), 100.pct(), {
91 let c = colors::BLACK.transparent();
92 stops![c, c]
93}))]
94pub fn background_radial(
95 child: impl IntoUiNode,
96 center: impl IntoVar<Point>,
97 radius: impl IntoVar<GradientRadius>,
98 stops: impl IntoVar<GradientStops>,
99) -> UiNode {
100 background(child, node::radial_gradient(center, radius, stops))
101}
102
103#[property(FILL, default((50.pct(), 50.pct()), 0.deg(), {
109 let c = colors::BLACK.transparent();
110 stops![c, c]
111}))]
112pub fn background_conic(
113 child: impl IntoUiNode,
114 center: impl IntoVar<Point>,
115 angle: impl IntoVar<AngleRadian>,
116 stops: impl IntoVar<GradientStops>,
117) -> UiNode {
118 background(child, node::conic_gradient(center, angle, stops))
119}
120
121#[property(FILL, default(UiNode::nil()))]
132pub fn foreground(child: impl IntoUiNode, foreground: impl IntoUiNode) -> UiNode {
133 let foreground = interactive_node(foreground, false);
134 let foreground = fill_node(foreground);
135 let foreground = hit_test_mode(foreground, HitTestMode::Disabled);
136
137 match_node(ui_vec![child, foreground], |children, op| match op {
138 UiNodeOp::Measure { wm, desired_size } => {
139 children.delegated();
140 *desired_size = children.node().with_child(0, |n| n.measure(wm));
141 }
142 UiNodeOp::Layout { wl, final_size } => {
143 children.delegated();
144 let size = children.node().with_child(0, |n| n.layout(wl));
145 LAYOUT.with_constraints(PxConstraints2d::new_exact_size(size), || {
146 children.node().with_child(1, |n| n.layout(wl));
147 });
148 *final_size = size;
149 }
150 _ => {}
151 })
152}
153
154#[property(FILL, default(WidgetFn::nil()))]
164pub fn foreground_fn(child: impl IntoUiNode, wgt_fn: impl IntoVar<WidgetFn<()>>) -> UiNode {
165 foreground(child, presenter((), wgt_fn))
166}
167
168#[property(FILL, default(0, 0, BorderStyle::Hidden))]
172pub fn foreground_highlight(
173 child: impl IntoUiNode,
174 offsets: impl IntoVar<SideOffsets>,
175 widths: impl IntoVar<SideOffsets>,
176 sides: impl IntoVar<BorderSides>,
177) -> UiNode {
178 let offsets = offsets.into_var();
179 let widths = widths.into_var();
180 let sides = sides.into_var();
181
182 let mut render_bounds = PxRect::zero();
183 let mut render_widths = PxSideOffsets::zero();
184 let mut render_radius = PxCornerRadius::zero();
185
186 match_node(child, move |child, op| match op {
187 UiNodeOp::Init => {
188 WIDGET.sub_var_layout(&offsets).sub_var_layout(&widths).sub_var_render(&sides);
189 }
190 UiNodeOp::Layout { wl, final_size } => {
191 let size = child.layout(wl);
192
193 let radius = BORDER.inner_radius();
194 let offsets = offsets.layout();
195 let radius = radius.deflate(offsets);
196
197 let mut bounds = PxRect::zero();
198 if let Some(inline) = wl.inline()
199 && let Some(first) = inline.rows.iter().find(|r| !r.size.is_empty())
200 {
201 bounds = *first;
202 }
203 if bounds.size.is_empty() {
204 let border_offsets = BORDER.inner_offsets();
205
206 bounds = PxRect::new(
207 PxPoint::new(offsets.left + border_offsets.left, offsets.top + border_offsets.top),
208 size - PxSize::new(offsets.horizontal(), offsets.vertical()),
209 );
210 }
211
212 let widths = LAYOUT.with_constraints(PxConstraints2d::new_exact_size(size), || widths.layout());
213
214 if render_bounds != bounds || render_widths != widths || render_radius != radius {
215 render_bounds = bounds;
216 render_widths = widths;
217 render_radius = radius;
218 WIDGET.render();
219 }
220
221 *final_size = size;
222 }
223 UiNodeOp::Render { frame } => {
224 child.render(frame);
225 frame.push_border(render_bounds, render_widths, sides.get(), render_radius);
226 }
227 _ => {}
228 })
229}
230
231#[property(FILL, default(colors::BLACK.transparent()))]
237pub fn foreground_color(child: impl IntoUiNode, color: impl IntoVar<Rgba>) -> UiNode {
238 foreground(child, node::flood(color))
239}
240
241#[property(FILL, default(0.deg(), {
247 let c = colors::BLACK.transparent();
248 stops![c, c]
249}))]
250pub fn foreground_gradient(child: impl IntoUiNode, axis: impl IntoVar<LinearGradientAxis>, stops: impl IntoVar<GradientStops>) -> UiNode {
251 foreground(child, node::linear_gradient(axis, stops))
252}
253
254#[property(FILL, default((50.pct(), 50.pct()), 100.pct(), {
260 let c = colors::BLACK.transparent();
261 stops![c, c]
262}))]
263pub fn foreground_radial(
264 child: impl IntoUiNode,
265 center: impl IntoVar<Point>,
266 radius: impl IntoVar<GradientRadius>,
267 stops: impl IntoVar<GradientStops>,
268) -> UiNode {
269 foreground(child, node::radial_gradient(center, radius, stops))
270}
271
272#[property(FILL, default((50.pct(), 50.pct()), 0.deg(), {
278 let c = colors::BLACK.transparent();
279 stops![c, c]
280}))]
281pub fn foreground_conic(
282 child: impl IntoUiNode,
283 center: impl IntoVar<Point>,
284 angle: impl IntoVar<AngleRadian>,
285 stops: impl IntoVar<GradientStops>,
286) -> UiNode {
287 foreground(child, node::conic_gradient(center, angle, stops))
288}