1use super::*;
4
5impl Ui {
6 pub(super) fn padded_size(&mut self, id: NodeId) -> [i32; 2] {
7 self.compute_size(id);
8 let n = &self.nodes[id];
9 let mut w = (n.size[0] + n.margins[0] + n.margins[1]).max(n.min_size[0]);
10 let mut h = (n.size[1] + n.margins[2] + n.margins[3]).max(n.min_size[1]);
11 if n.flags & flags::SCREEN_WIDTH != 0 {
12 w = self.screen[0];
13 }
14 if n.flags & flags::SCREEN_HEIGHT != 0 {
15 h = self.screen[1];
16 }
17 [w, h]
18 }
19
20 pub(super) fn begin_size_pass(&mut self) {
22 self.size_pass = self.size_pass.wrapping_add(1).max(1);
23 }
24
25 pub(super) fn compute_size(&mut self, id: NodeId) {
29 if self.nodes[id].sized_pass == self.size_pass {
30 return;
31 }
32 let children = self.nodes[id].children.clone();
33 let size = match self.nodes[id].kind.clone() {
34 Kind::Group => {
35 let mut s = [0, 0];
36 for c in children {
37 if !self.nodes[c].visible() {
38 continue;
39 }
40 let p = self.padded_size(c);
41 s = [s[0].max(p[0]), s[1].max(p[1])];
42 }
43 s
44 }
45 Kind::Ribbon {
46 vertical,
47 uniform,
48 spacing,
49 ..
50 } => {
51 let (mut max, mut sum, mut cells, mut non_empty) = ([0, 0], [0, 0], Vec::new(), 0);
52 for &c in &children {
53 if !self.nodes[c].visible() {
54 cells.push(0);
55 continue;
56 }
57 let p = self.padded_size(c);
58 max = [max[0].max(p[0]), max[1].max(p[1])];
59 sum = [sum[0] + p[0], sum[1] + p[1]];
60 cells.push(if vertical { p[1] } else { p[0] });
61 if p[0] > 0 && p[1] > 0 {
62 non_empty += 1;
63 }
64 }
65 if uniform {
66 let cell = if vertical { max[1] } else { max[0] };
67 cells.iter_mut().for_each(|c| *c = cell);
68 sum = [
69 children.len() as i32 * max[0],
70 children.len() as i32 * max[1],
71 ];
72 }
73 let gaps = spacing * (non_empty - 1).max(0);
74 if let Kind::Ribbon { cells: stored, .. } = &mut self.nodes[id].kind {
75 *stored = cells;
76 }
77 if vertical {
78 [max[0], sum[1] + gaps]
79 } else {
80 [sum[0] + gaps, max[1]]
81 }
82 }
83 Kind::Border { sprites } => {
84 let w = |i: usize| sprites[i].map_or(0, |s| s.width);
85 let h = |i: usize| sprites[i].map_or(0, |s| s.height);
86 [
87 (w(0) + w(2)).max(w(6) + w(8)),
88 (h(0) + h(6)).max(h(2) + h(8)),
89 ]
90 }
91 Kind::Lines { size, .. } => size,
92 Kind::Image { sprite, size } => [
93 if size[0] > 0 {
94 size[0]
95 } else {
96 sprite.map_or(0, |s| s.width)
97 },
98 if size[1] > 0 {
99 size[1]
100 } else {
101 sprite.map_or(0, |s| s.height)
102 },
103 ],
104 Kind::AnimatedImage {
105 sprites,
106 size,
107 frame,
108 ..
109 } => {
110 let sprite = sprites.get(frame).copied().flatten();
111 [
112 if size[0] > 0 {
113 size[0]
114 } else {
115 sprite.map_or(0, |s| s.width)
116 },
117 if size[1] > 0 {
118 size[1]
119 } else {
120 sprite.map_or(0, |s| s.height)
121 },
122 ]
123 }
124 Kind::Button {
125 states,
126 content,
127 state,
128 ..
129 } => {
130 let mut s = content.map_or([0, 0], |c| self.padded_size(c));
131 if let Some(st) = states[state].or(states[0]) {
132 let p = self.padded_size(st);
133 s = [s[0].max(p[0]), s[1].max(p[1])];
134 }
135 let n = &self.nodes[id];
136 [s[0].max(n.min_size[0]), s[1].max(n.min_size[1])]
137 }
138 Kind::Text(mut t) => {
139 self.layout_text(&mut t);
140 let s = [t.layout.width, t.layout.height];
141 self.nodes[id].kind = Kind::Text(t);
142 s
143 }
144 Kind::Label {
145 mut text,
146 icon,
147 icon_size,
148 orientation,
149 min_text_width,
150 gap,
151 ..
152 } => {
153 self.layout_text(&mut text);
154 let (tw, th) = (
155 text.layout.width.max(if text.text.is_empty() {
156 0
157 } else {
158 min_text_width
159 }),
160 text.layout.height,
161 );
162 let iw = if icon_size[0] > 0 {
163 icon_size[0]
164 } else {
165 icon.map_or(0, |s| s.width)
166 };
167 let ih = if icon_size[1] > 0 {
168 icon_size[1]
169 } else {
170 icon.map_or(0, |s| s.height)
171 };
172 if let Kind::Label { text: t, .. } = &mut self.nodes[id].kind {
173 *t = text;
174 }
175 if orientation > 1 {
176 [iw.max(tw), gap + ih + th]
177 } else {
178 [gap + iw + tw, ih.max(th)]
179 }
180 }
181 Kind::Picture { .. } | Kind::Viewport | Kind::List(_) => {
182 for c in children {
183 self.compute_size(c);
184 }
185 self.nodes[id].min_size
186 }
187 Kind::Unsupported(_) => [0, 0],
188 Kind::Control(c) => self.measure_control(id, c),
189 };
190 self.nodes[id].size = [
191 size[0].max(self.nodes[id].min_size[0]),
192 size[1].max(self.nodes[id].min_size[1]),
193 ];
194 if let Some(b) = self.nodes[id].border {
195 self.compute_size(b);
196 }
197 self.nodes[id].sized_pass = self.size_pass;
198 }
199
200 pub(super) fn layout_text(&self, t: &mut TextData) {
201 let mut display = t.text.clone();
202 if !t.wrap && t.ellipsis_width > 0 {
203 if let Some(f) = t.font {
204 if TextLayout::compute(&self.res, f, &display, None, 0).width > t.ellipsis_width {
205 while !display.is_empty()
206 && TextLayout::compute(&self.res, f, &format!("{display}..."), None, 0)
207 .width
208 > t.ellipsis_width
209 {
210 display.pop();
211 }
212 display.push_str("...");
213 }
214 }
215 }
216 t.layout = match t.font {
217 Some(f) => TextLayout::compute(
218 &self.res,
219 f,
220 &display,
221 t.wrap.then_some(t.max_width),
222 t.justify,
223 ),
224 None => TextLayout::default(),
225 };
226 }
227
228 pub(super) fn place(&mut self, id: NodeId, l: i32, t: i32, r: i32, b: i32) {
230 self.place_filling(id, l, t, r, b, 0);
231 }
232
233 pub(super) fn place_filling(
235 &mut self,
236 id: NodeId,
237 mut l: i32,
238 mut t: i32,
239 r: i32,
240 b: i32,
241 fill: u32,
242 ) {
243 let n = &mut self.nodes[id];
244 let fill = n.flags | fill;
245 let (mut w, mut h) = (n.size[0], n.size[1]);
246 if r < w + l {
247 l = r - w;
248 }
249 if b < h + t {
250 t = b - h;
251 }
252 let [ml, mr, mt, mb] = n.margins;
253 let (mut x, mut y) = (l + ml, t + mt);
254 let (aw, ah) = ((r - mr) - x, (b - mb) - y);
255 if fill & flags::FILL_WIDTH != 0 {
256 w = aw;
257 }
258 if fill & flags::FILL_HEIGHT != 0 {
259 h = ah;
260 }
261 match n.alignment % 3 {
262 1 => x += (aw >> 1) - (w >> 1),
263 2 => x = (r - mr) - w,
264 _ => {}
265 }
266 match n.alignment / 3 {
267 1 => y += (ah >> 1) - (h >> 1),
268 2 => y = (b - mb) - h,
269 _ => {}
270 }
271 n.rect = [x, y, x + w, y + h];
272 }
273
274 pub fn layout(&mut self, root: NodeId, rect: [i32; 4]) {
276 self.begin_size_pass();
277 self.compute_size(root);
278 self.compute_layout(root, rect[0], rect[1], rect[2], rect[3]);
279 }
280
281 pub fn layout_dialog(&mut self, root: NodeId, rect: [i32; 4]) {
286 self.begin_size_pass();
287 self.compute_size(root);
288 if !matches!(self.nodes[root].kind, Kind::Group) {
289 self.compute_layout(root, rect[0], rect[1], rect[2], rect[3]);
290 return;
291 }
292 self.place(root, rect[0], rect[1], rect[2], rect[3]);
293 let rc = self.nodes[root].rect;
294 if let Some(border) = self.nodes[root].border {
295 self.compute_layout(border, rc[0], rc[1], rc[2], rc[3]);
296 }
297 for c in self.nodes[root].children.clone() {
298 if self.nodes[c].visible() {
299 self.compute_layout(c, rc[0], rc[1], rc[2], rc[3]);
300 }
301 }
302 }
303
304 pub(super) fn compute_layout(&mut self, id: NodeId, l: i32, t: i32, r: i32, b: i32) {
306 let slot = [l, t, r, b];
307 if let Kind::Control(c) = &self.nodes[id].kind {
308 let fill = match c {
312 Control::Scroll { vertical: true, .. } => flags::FILL_HEIGHT,
313 Control::Scroll {
314 vertical: false, ..
315 } => flags::FILL_WIDTH,
316 _ => 0,
317 };
318 self.place_filling(id, l, t, r, b, fill);
319 self.layout_control(id);
320 } else {
321 match self.nodes[id].kind.clone() {
322 Kind::Group
323 | Kind::Viewport
324 | Kind::List(_)
325 | Kind::Picture { .. }
326 | Kind::Image { .. }
327 | Kind::Lines { .. }
328 | Kind::AnimatedImage { .. } => {
329 let n = &mut self.nodes[id];
331 let [ml, mr, mt, mb] = n.margins;
332 if matches!(n.kind, Kind::Group)
333 || n.flags & (flags::FILL_WIDTH | flags::FILL_HEIGHT) != 0
334 {
335 n.rect = [l + ml, t + mt, r - mr, b - mb];
336 if !matches!(n.kind, Kind::Group) {
337 let full = n.rect;
338 self.place(id, l, t, r, b);
339 let n = &mut self.nodes[id];
340 if n.flags & flags::FILL_WIDTH != 0 {
341 (n.rect[0], n.rect[2]) = (full[0], full[2]);
342 }
343 if n.flags & flags::FILL_HEIGHT != 0 {
344 (n.rect[1], n.rect[3]) = (full[1], full[3]);
345 }
346 }
347 } else {
348 self.place(id, l, t, r, b);
349 }
350 self.reveal_selection(id);
351 let rc = self.nodes[id].rect;
352 for c in self.nodes[id].children.clone() {
353 if self.nodes[c].visible() {
354 self.compute_layout(c, rc[0], rc[1], rc[2], rc[3]);
355 }
356 }
357 }
358 Kind::Border { .. } => {
359 let n = &mut self.nodes[id];
360 let [ml, mr, mt, mb] = n.margins;
361 n.rect = [l + ml, t + mt, r - mr, b - mb];
362 }
363 Kind::Ribbon {
364 vertical,
365 spacing,
366 cells,
367 ..
368 } => {
369 self.place(id, l, t, r, b);
370 let rc = self.nodes[id].rect;
371 let fill_last = self.nodes[id].flags
372 & if vertical {
373 flags::FILL_HEIGHT
374 } else {
375 flags::FILL_WIDTH
376 }
377 != 0;
378 let children = self.nodes[id].children.clone();
379 let mut offset = 0;
380 for (i, c) in children.iter().copied().enumerate() {
381 if !self.nodes[c].visible() {
382 continue;
383 }
384 let cell = cells.get(i).copied().unwrap_or(0);
385 let last = i + 1 == children.len();
386 let p = self.padded_size(c);
387 if vertical {
388 let bottom = if fill_last && last {
389 rc[3]
390 } else {
391 rc[1] + offset + cell
392 };
393 self.compute_layout(c, rc[0], rc[1] + offset, rc[2], bottom);
394 } else {
395 let right = if fill_last && last {
396 rc[2]
397 } else {
398 rc[0] + offset + cell
399 };
400 self.compute_layout(c, rc[0] + offset, rc[1], right, rc[3]);
401 }
402 offset += cell;
403 if p[0] > 0 && p[1] > 0 {
404 offset += spacing;
405 }
406 }
407 }
408 Kind::Button {
409 states, content, ..
410 } => {
411 self.place(id, l, t, r, b);
412 let rc = self.nodes[id].rect;
413 for c in states.iter().flatten().chain(content.iter()) {
414 self.compute_layout(*c, rc[0], rc[1], rc[2], rc[3]);
415 }
416 }
417 Kind::Text(_) | Kind::Label { .. } | Kind::Unsupported(_) => {
418 self.place(id, l, t, r, b)
419 }
420 Kind::Control(_) => unreachable!(),
421 }
422 }
423 if let Some(border) = self.nodes[id].border {
427 self.compute_layout(border, slot[0], slot[1], slot[2], slot[3]);
428 }
429 }
430}