1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/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 UiNode, background: impl UiNode) -> impl UiNode {
27 let background = interactive_node(background, false);
28 let background = fill_node(background);
29
30 match_node_list(ui_vec![background, child], |children, op| match op {
31 UiNodeOp::Measure { wm, desired_size } => {
32 *desired_size = children.with_node(1, |n| n.measure(wm));
33 }
34 UiNodeOp::Layout { wl, final_size } => {
35 let size = children.with_node(1, |n| n.layout(wl));
36
37 LAYOUT.with_constraints(PxConstraints2d::new_exact_size(size), || {
38 children.with_node(0, |n| n.layout(wl));
39 });
40 *final_size = size;
41 }
42 _ => {}
43 })
44}
45
46#[property(FILL, default(WidgetFn::nil()))]
56pub fn background_fn(child: impl UiNode, wgt_fn: impl IntoVar<WidgetFn<()>>) -> impl UiNode {
57 background(child, presenter((), wgt_fn))
58}
59
60#[property(FILL, default(colors::BLACK.transparent()))]
66pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
67 background(child, node::flood(color))
68}
69
70#[property(FILL, default(0.deg(), {
76 let c = colors::BLACK.transparent();
77 stops![c, c]
78}))]
79pub fn background_gradient(child: impl UiNode, axis: impl IntoVar<LinearGradientAxis>, stops: impl IntoVar<GradientStops>) -> impl UiNode {
80 background(child, node::linear_gradient(axis, stops))
81}
82
83#[property(FILL, default((50.pct(), 50.pct()), 100.pct(), {
89 let c = colors::BLACK.transparent();
90 stops![c, c]
91}))]
92pub fn background_radial(
93 child: impl UiNode,
94 center: impl IntoVar<Point>,
95 radius: impl IntoVar<GradientRadius>,
96 stops: impl IntoVar<GradientStops>,
97) -> impl UiNode {
98 background(child, node::radial_gradient(center, radius, stops))
99}
100
101#[property(FILL, default((50.pct(), 50.pct()), 0.deg(), {
107 let c = colors::BLACK.transparent();
108 stops![c, c]
109}))]
110pub fn background_conic(
111 child: impl UiNode,
112 center: impl IntoVar<Point>,
113 angle: impl IntoVar<AngleRadian>,
114 stops: impl IntoVar<GradientStops>,
115) -> impl UiNode {
116 background(child, node::conic_gradient(center, angle, stops))
117}
118
119#[property(FILL, default(NilUiNode))]
130pub fn foreground(child: impl UiNode, foreground: impl UiNode) -> impl UiNode {
131 let foreground = interactive_node(foreground, false);
132 let foreground = fill_node(foreground);
133 let foreground = hit_test_mode(foreground, HitTestMode::Disabled);
134
135 match_node_list(ui_vec![child, foreground], |children, op| match op {
136 UiNodeOp::Measure { wm, desired_size } => {
137 *desired_size = children.with_node(0, |n| n.measure(wm));
138 }
139 UiNodeOp::Layout { wl, final_size } => {
140 let size = children.with_node(0, |n| n.layout(wl));
141 LAYOUT.with_constraints(PxConstraints2d::new_exact_size(size), || {
142 children.with_node(1, |n| n.layout(wl));
143 });
144 *final_size = size;
145 }
146 _ => {}
147 })
148}
149
150#[property(FILL, default(WidgetFn::nil()))]
160pub fn foreground_fn(child: impl UiNode, wgt_fn: impl IntoVar<WidgetFn<()>>) -> impl UiNode {
161 foreground(child, presenter((), wgt_fn))
162}
163
164#[property(FILL, default(0, 0, BorderStyle::Hidden))]
168pub fn foreground_highlight(
169 child: impl UiNode,
170 offsets: impl IntoVar<SideOffsets>,
171 widths: impl IntoVar<SideOffsets>,
172 sides: impl IntoVar<BorderSides>,
173) -> impl UiNode {
174 let offsets = offsets.into_var();
175 let widths = widths.into_var();
176 let sides = sides.into_var();
177
178 let mut render_bounds = PxRect::zero();
179 let mut render_widths = PxSideOffsets::zero();
180 let mut render_radius = PxCornerRadius::zero();
181
182 match_node(child, move |child, op| match op {
183 UiNodeOp::Init => {
184 WIDGET.sub_var_layout(&offsets).sub_var_layout(&widths).sub_var_render(&sides);
185 }
186 UiNodeOp::Layout { wl, final_size } => {
187 let size = child.layout(wl);
188
189 let radius = BORDER.inner_radius();
190 let offsets = offsets.layout();
191 let radius = radius.deflate(offsets);
192
193 let mut bounds = PxRect::zero();
194 if let Some(inline) = wl.inline() {
195 if let Some(first) = inline.rows.iter().find(|r| !r.size.is_empty()) {
196 bounds = *first;
197 }
198 }
199 if bounds.size.is_empty() {
200 let border_offsets = BORDER.inner_offsets();
201
202 bounds = PxRect::new(
203 PxPoint::new(offsets.left + border_offsets.left, offsets.top + border_offsets.top),
204 size - PxSize::new(offsets.horizontal(), offsets.vertical()),
205 );
206 }
207
208 let widths = LAYOUT.with_constraints(PxConstraints2d::new_exact_size(size), || widths.layout());
209
210 if render_bounds != bounds || render_widths != widths || render_radius != radius {
211 render_bounds = bounds;
212 render_widths = widths;
213 render_radius = radius;
214 WIDGET.render();
215 }
216
217 *final_size = size;
218 }
219 UiNodeOp::Render { frame } => {
220 child.render(frame);
221 frame.push_border(render_bounds, render_widths, sides.get(), render_radius);
222 }
223 _ => {}
224 })
225}
226
227#[property(FILL, default(colors::BLACK.transparent()))]
233pub fn foreground_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
234 foreground(child, node::flood(color))
235}
236
237#[property(FILL, default(0.deg(), {
243 let c = colors::BLACK.transparent();
244 stops![c, c]
245}))]
246pub fn foreground_gradient(child: impl UiNode, axis: impl IntoVar<LinearGradientAxis>, stops: impl IntoVar<GradientStops>) -> impl UiNode {
247 foreground(child, node::linear_gradient(axis, stops))
248}
249
250#[property(FILL, default((50.pct(), 50.pct()), 100.pct(), {
256 let c = colors::BLACK.transparent();
257 stops![c, c]
258}))]
259pub fn foreground_radial(
260 child: impl UiNode,
261 center: impl IntoVar<Point>,
262 radius: impl IntoVar<GradientRadius>,
263 stops: impl IntoVar<GradientStops>,
264) -> impl UiNode {
265 foreground(child, node::radial_gradient(center, radius, stops))
266}
267
268#[property(FILL, default((50.pct(), 50.pct()), 0.deg(), {
274 let c = colors::BLACK.transparent();
275 stops![c, c]
276}))]
277pub fn foreground_conic(
278 child: impl UiNode,
279 center: impl IntoVar<Point>,
280 angle: impl IntoVar<AngleRadian>,
281 stops: impl IntoVar<GradientStops>,
282) -> impl UiNode {
283 foreground(child, node::conic_gradient(center, angle, stops))
284}