zng_wgt_size_offset/
max.rs1use zng_wgt::prelude::*;
2
3#[property(SIZE-1, default(PxSize::default()))]
18pub fn max_size(child: impl IntoUiNode, max_size: impl IntoVar<Size>) -> UiNode {
19 let max_size = max_size.into_var();
20 match_node(child, move |child, op| match op {
21 UiNodeOp::Init => {
22 WIDGET.sub_var_layout(&max_size);
23 }
24 UiNodeOp::Measure { wm, desired_size } => {
25 child.delegated();
26 *desired_size = MaxSizeLayout::new(&max_size).measure(&max_size, child.node(), wm);
27 }
28 UiNodeOp::Layout { wl, final_size } => {
29 child.delegated();
30 *final_size = MaxSizeLayout::new(&max_size).layout(&max_size, child.node(), wl);
31 }
32 _ => {}
33 })
34}
35struct MaxSizeLayout {
36 parent_constraints: PxConstraints2d,
37 constraints: PxConstraints2d,
38 max: PxSize,
39 is_default: bool,
40}
41impl MaxSizeLayout {
42 pub fn new(max_size: &Var<Size>) -> Self {
44 let parent_constraints = LAYOUT.constraints();
45 let mut constraints = parent_constraints;
46 let mut max = PxSize::splat(Px::MAX);
47 let mut is_default = true;
48 max_size.with(|s| {
49 if !s.width.is_default() {
50 is_default = false;
51 let dft = parent_constraints.x.max_bounded();
52 max.width = LAYOUT.with_constraints(parent_constraints.with_fill_x(parent_constraints.x.is_bounded()), || {
53 s.width.layout_dft_x(dft)
54 });
55 constraints.x = constraints.x.with_max(max.width);
56 }
57 if !s.height.is_default() {
58 is_default = false;
59 let dft = parent_constraints.y.max_bounded();
60 max.height = LAYOUT.with_constraints(parent_constraints.with_fill_y(parent_constraints.y.is_bounded()), || {
61 s.height.layout_dft_y(dft)
62 });
63 constraints.y = constraints.y.with_max(max.height);
64 }
65 });
66 Self {
67 parent_constraints,
68 constraints,
69 max,
70 is_default,
71 }
72 }
73
74 pub fn measure(&self, max_size: &Var<Size>, child: &mut UiNode, wm: &mut WidgetMeasure) -> PxSize {
75 if self.is_default {
76 return child.measure(wm);
78 }
79 let size = LAYOUT.with_constraints(self.constraints, || wm.measure_block(child));
80 self.clamp_outer_bounds(max_size, size)
81 }
82
83 pub fn layout(&self, max_size: &Var<Size>, child: &mut UiNode, wl: &mut WidgetLayout) -> PxSize {
84 if self.is_default {
85 return child.layout(wl);
86 }
87 let size = LAYOUT.with_constraints(self.constraints, || child.layout(wl));
88 self.clamp_outer_bounds(max_size, size)
89 }
90
91 fn clamp_outer_bounds(&self, max_size: &Var<Size>, mut size: PxSize) -> PxSize {
93 size = size.min(self.max);
94 max_size.with(|s| {
95 if !s.width.is_default() {
96 size.width = Align::TOP_LEFT.measure_x(size.width, self.parent_constraints.x);
97 }
98 if !s.height.is_default() {
99 size.height = Align::TOP_LEFT.measure_y(size.height, self.parent_constraints.y);
100 }
101 });
102 size
103 }
104}
105
106#[property(SIZE-1, default(Length::Default))]
120pub fn max_width(child: impl IntoUiNode, max_width: impl IntoVar<Length>) -> UiNode {
121 let max_width = max_width.into_var();
122 match_node(child, move |child, op| match op {
123 UiNodeOp::Init => {
124 WIDGET.sub_var_layout(&max_width);
125 }
126 UiNodeOp::Measure { wm, desired_size } => {
127 child.delegated();
128 *desired_size = MaxWidthLayout::new(&max_width).measure(child.node(), wm);
129 }
130 UiNodeOp::Layout { wl, final_size } => {
131 child.delegated();
132 *final_size = MaxWidthLayout::new(&max_width).layout(child.node(), wl);
133 }
134 _ => {}
135 })
136}
137struct MaxWidthLayout {
138 parent_constraints: PxConstraints2d,
139 constraints: PxConstraints2d,
140 max: Px,
141 is_default: bool,
142}
143impl MaxWidthLayout {
144 pub fn new(max_width: &Var<Length>) -> Self {
145 let parent_constraints = LAYOUT.constraints();
146 let mut constraints = parent_constraints;
147 let mut max = Px::MAX;
148 let mut is_default = true;
149
150 max_width.with(|w| {
151 if !w.is_default() {
152 is_default = false;
153 let dft = parent_constraints.x.max_bounded();
154 max = LAYOUT.with_constraints(parent_constraints.with_fill_x(parent_constraints.x.is_bounded()), || {
155 w.layout_dft_x(dft)
156 });
157 constraints.x = constraints.x.with_max(max);
158 }
159 });
160
161 Self {
162 parent_constraints,
163 constraints,
164 max,
165 is_default,
166 }
167 }
168
169 pub fn measure(&self, child: &mut UiNode, wm: &mut WidgetMeasure) -> PxSize {
170 if self.is_default {
171 return child.measure(wm);
173 }
174 let size = LAYOUT.with_constraints(self.constraints, || wm.measure_block(child));
175 self.clamp_outer_bounds(size)
176 }
177
178 pub fn layout(&self, child: &mut UiNode, wl: &mut WidgetLayout) -> PxSize {
179 if self.is_default {
180 return child.layout(wl);
181 }
182 let size = LAYOUT.with_constraints(self.constraints, || child.layout(wl));
183 self.clamp_outer_bounds(size)
184 }
185
186 fn clamp_outer_bounds(&self, mut size: PxSize) -> PxSize {
188 size.width = size.width.min(self.max);
189 size.width = Align::TOP_LEFT.measure_x(size.width, self.parent_constraints.x);
190 size
191 }
192}
193
194#[property(SIZE-1, default(Length::Default))]
208pub fn max_height(child: impl IntoUiNode, max_height: impl IntoVar<Length>) -> UiNode {
209 let max_height = max_height.into_var();
210 match_node(child, move |child, op| match op {
211 UiNodeOp::Init => {
212 WIDGET.sub_var_layout(&max_height);
213 }
214 UiNodeOp::Measure { wm, desired_size } => {
215 child.delegated();
216 *desired_size = MaxHeightLayout::new(&max_height).measure(child.node(), wm);
217 }
218 UiNodeOp::Layout { wl, final_size } => {
219 child.delegated();
220 *final_size = MaxHeightLayout::new(&max_height).layout(child.node(), wl);
221 }
222 _ => {}
223 })
224}
225struct MaxHeightLayout {
226 parent_constraints: PxConstraints2d,
227 constraints: PxConstraints2d,
228 max: Px,
229 is_default: bool,
230}
231impl MaxHeightLayout {
232 pub fn new(max_height: &Var<Length>) -> Self {
233 let parent_constraints = LAYOUT.constraints();
234 let mut constraints = parent_constraints;
235 let mut max = Px::MAX;
236 let mut is_default = true;
237
238 max_height.with(|h| {
239 if !h.is_default() {
240 is_default = false;
241 let dft = parent_constraints.y.max_bounded();
242 max = LAYOUT.with_constraints(parent_constraints.with_fill_y(parent_constraints.y.is_bounded()), || {
243 h.layout_dft_y(dft)
244 });
245 constraints.y = constraints.y.with_max(max);
246 }
247 });
248
249 Self {
250 parent_constraints,
251 constraints,
252 max,
253 is_default,
254 }
255 }
256
257 pub fn measure(&self, child: &mut UiNode, wm: &mut WidgetMeasure) -> PxSize {
258 if self.is_default {
259 return child.measure(wm);
261 }
262 let size = LAYOUT.with_constraints(self.constraints, || wm.measure_block(child));
263 self.clamp_outer_bounds(size)
264 }
265
266 pub fn layout(&self, child: &mut UiNode, wl: &mut WidgetLayout) -> PxSize {
267 if self.is_default {
268 return child.layout(wl);
269 }
270 let size = LAYOUT.with_constraints(self.constraints, || child.layout(wl));
271 self.clamp_outer_bounds(size)
272 }
273
274 fn clamp_outer_bounds(&self, mut size: PxSize) -> PxSize {
276 size.height = size.height.min(self.max);
277 size.height = Align::TOP_LEFT.measure_y(size.height, self.parent_constraints.y);
278 size
279 }
280}