1use crate::draw_ctx::DrawCtx;
4use crate::event::{Event, EventResult};
5use crate::geometry::{Rect, Size};
6use crate::layout_props::{resolve_fit_or_stretch, HAnchor, Insets, VAnchor, WidgetBase};
7use crate::widget::Widget;
8
9pub struct Stack {
27 bounds: Rect,
28 children: Vec<Box<dyn Widget>>,
29 aligned: Vec<bool>,
32 base: WidgetBase,
33 hit_children_only: bool,
37}
38
39impl Stack {
40 pub fn new() -> Self {
41 Self {
42 bounds: Rect::default(),
43 children: Vec::new(),
44 aligned: Vec::new(),
45 base: WidgetBase::new(),
46 hit_children_only: false,
47 }
48 }
49
50 pub fn with_hit_children_only(mut self, v: bool) -> Self {
58 self.hit_children_only = v;
59 self
60 }
61
62 pub fn add(mut self, child: Box<dyn Widget>) -> Self {
64 self.children.push(child);
65 self.aligned.push(false);
66 self
67 }
68
69 pub fn add_aligned(mut self, child: Box<dyn Widget>) -> Self {
73 self.children.push(child);
74 self.aligned.push(true);
75 self
76 }
77
78 pub fn with_margin(mut self, m: Insets) -> Self {
79 self.base.margin = m;
80 self
81 }
82 pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
83 self.base.h_anchor = h;
84 self
85 }
86 pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
87 self.base.v_anchor = v;
88 self
89 }
90 pub fn with_min_size(mut self, s: Size) -> Self {
91 self.base.min_size = s;
92 self
93 }
94 pub fn with_max_size(mut self, s: Size) -> Self {
95 self.base.max_size = s;
96 self
97 }
98}
99
100impl Default for Stack {
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106impl Widget for Stack {
107 fn type_name(&self) -> &'static str {
108 "Stack"
109 }
110 fn bounds(&self) -> Rect {
111 self.bounds
112 }
113 fn set_bounds(&mut self, b: Rect) {
114 self.bounds = b;
115 }
116 fn children(&self) -> &[Box<dyn Widget>] {
117 &self.children
118 }
119 fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
120 &mut self.children
121 }
122
123 fn margin(&self) -> Insets {
124 self.base.margin
125 }
126 fn widget_base(&self) -> Option<&WidgetBase> {
127 Some(&self.base)
128 }
129 fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
130 Some(&mut self.base)
131 }
132 fn h_anchor(&self) -> HAnchor {
133 self.base.h_anchor
134 }
135 fn v_anchor(&self) -> VAnchor {
136 self.base.v_anchor
137 }
138 fn min_size(&self) -> Size {
139 self.base.min_size
140 }
141 fn max_size(&self) -> Size {
142 self.base.max_size
143 }
144
145 fn layout(&mut self, available: Size) -> Size {
146 for idx in 0..self.children.len() {
147 if self.aligned.get(idx).copied().unwrap_or(false) {
148 let child = &mut self.children[idx];
149 let desired = child.layout(available);
153 let m = child.margin();
156 let slot_w = (available.width - m.left - m.right).max(0.0);
160 let slot_h = (available.height - m.top - m.bottom).max(0.0);
161 let w = desired
162 .width
163 .clamp(child.min_size().width, child.max_size().width)
164 .min(slot_w);
165 let h = desired
166 .height
167 .clamp(child.min_size().height, child.max_size().height)
168 .min(slot_h);
169 child.layout(Size::new(w, h));
170
171 let ha = child.h_anchor();
172 let x = if ha.contains(HAnchor::RIGHT) && !ha.contains(HAnchor::LEFT) {
173 (available.width - m.right - w).max(0.0)
174 } else if ha.contains(HAnchor::CENTER) && !ha.is_stretch() {
175 m.left + (available.width - m.left - m.right - w) * 0.5
176 } else {
177 m.left
178 };
179
180 let va = child.v_anchor();
182 let y = if va.contains(VAnchor::TOP) && !va.contains(VAnchor::BOTTOM) {
183 (available.height - m.top - h).max(0.0)
184 } else if va.contains(VAnchor::CENTER) && !va.is_stretch() {
185 m.bottom + (available.height - m.bottom - m.top - h) * 0.5
186 } else {
187 m.bottom
188 };
189
190 child.set_bounds(Rect::new(x, y, w, h));
191 } else {
192 let child = &mut self.children[idx];
193 child.layout(available);
194 child.set_bounds(Rect::new(0.0, 0.0, available.width, available.height));
195 }
196 }
197
198 let mut i = 0;
217 let mut raised: Vec<(Box<dyn Widget>, bool)> = Vec::new();
218 while i < self.children.len() {
219 if self.children[i].take_raise_request() {
220 let child = self.children.remove(i);
221 let aligned = if i < self.aligned.len() {
229 self.aligned.remove(i)
230 } else {
231 false
232 };
233 raised.push((child, aligned));
234 } else {
236 i += 1;
237 }
238 }
239 for (r, a) in raised {
240 self.children.push(r);
241 self.aligned.push(a);
242 }
243
244 available
245 }
246
247 fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
248
249 fn hit_test(&self, local_pos: crate::geometry::Point) -> bool {
250 if !self.hit_children_only {
251 let b = self.bounds();
252 return local_pos.x >= 0.0
253 && local_pos.x <= b.width
254 && local_pos.y >= 0.0
255 && local_pos.y <= b.height;
256 }
257 self.children.iter().any(|child| {
258 let b = child.bounds();
259 child.is_visible()
260 && child.hit_test(crate::geometry::Point::new(
261 local_pos.x - b.x,
262 local_pos.y - b.y,
263 ))
264 })
265 }
266
267 fn on_event(&mut self, _: &Event) -> EventResult {
268 EventResult::Ignored
269 }
270}
271
272pub struct Padding {
278 bounds: Rect,
279 children: Vec<Box<dyn Widget>>,
280 base: WidgetBase,
281 insets: Insets,
282}
283
284impl Padding {
285 pub fn new(insets: Insets, child: Box<dyn Widget>) -> Self {
287 Self {
288 bounds: Rect::default(),
289 children: vec![child],
290 base: WidgetBase::new(),
291 insets,
292 }
293 }
294
295 pub fn uniform(amount: f64, child: Box<dyn Widget>) -> Self {
297 Self::new(Insets::all(amount), child)
298 }
299
300 pub fn with_margin(mut self, m: Insets) -> Self {
301 self.base.margin = m;
302 self
303 }
304 pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
305 self.base.h_anchor = h;
306 self
307 }
308 pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
309 self.base.v_anchor = v;
310 self
311 }
312 pub fn with_min_size(mut self, s: Size) -> Self {
313 self.base.min_size = s;
314 self
315 }
316 pub fn with_max_size(mut self, s: Size) -> Self {
317 self.base.max_size = s;
318 self
319 }
320}
321
322impl Widget for Padding {
323 fn type_name(&self) -> &'static str {
324 "Padding"
325 }
326 fn bounds(&self) -> Rect {
327 self.bounds
328 }
329 fn set_bounds(&mut self, b: Rect) {
330 self.bounds = b;
331 }
332 fn children(&self) -> &[Box<dyn Widget>] {
333 &self.children
334 }
335 fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
336 &mut self.children
337 }
338
339 fn margin(&self) -> Insets {
340 self.base.margin
341 }
342 fn widget_base(&self) -> Option<&WidgetBase> {
343 Some(&self.base)
344 }
345 fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
346 Some(&mut self.base)
347 }
348 fn h_anchor(&self) -> HAnchor {
349 self.base.h_anchor
350 }
351 fn v_anchor(&self) -> VAnchor {
352 self.base.v_anchor
353 }
354 fn min_size(&self) -> Size {
355 self.base.min_size
356 }
357 fn max_size(&self) -> Size {
358 self.base.max_size
359 }
360
361 fn layout(&mut self, available: Size) -> Size {
362 let p = &self.insets;
363 let inner = Size::new(
364 (available.width - p.left - p.right).max(0.0),
365 (available.height - p.top - p.bottom).max(0.0),
366 );
367 if let Some(child) = self.children.first_mut() {
368 let desired = child.layout(inner);
369 child.set_bounds(Rect::new(p.left, p.bottom, desired.width, desired.height));
371 }
372 let content_w = self.children.first().map_or(0.0, |c| c.bounds().width);
374 let content_h = self.children.first().map_or(0.0, |c| c.bounds().height);
375 Size::new(content_w + p.left + p.right, content_h + p.top + p.bottom)
376 }
377
378 fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
379
380 fn on_event(&mut self, _: &Event) -> EventResult {
381 EventResult::Ignored
382 }
383}
384
385pub struct SizedBox {
395 bounds: Rect,
396 children: Vec<Box<dyn Widget>>,
397 base: WidgetBase,
398 pub width: Option<f64>,
399 pub height: Option<f64>,
400}
401
402impl SizedBox {
403 pub fn new() -> Self {
404 Self {
405 bounds: Rect::default(),
406 children: Vec::new(),
407 base: WidgetBase::new(),
408 width: None,
409 height: None,
410 }
411 }
412
413 pub fn with_width(mut self, w: f64) -> Self {
414 self.width = Some(w);
415 self
416 }
417 pub fn with_height(mut self, h: f64) -> Self {
418 self.height = Some(h);
419 self
420 }
421
422 pub fn with_child(mut self, child: Box<dyn Widget>) -> Self {
423 self.children.clear();
424 self.children.push(child);
425 self
426 }
427
428 pub fn fixed(width: f64, height: f64) -> Self {
430 Self::new().with_width(width).with_height(height)
431 }
432
433 pub fn with_margin(mut self, m: Insets) -> Self {
434 self.base.margin = m;
435 self
436 }
437 pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
438 self.base.h_anchor = h;
439 self
440 }
441 pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
442 self.base.v_anchor = v;
443 self
444 }
445 pub fn with_min_size(mut self, s: Size) -> Self {
446 self.base.min_size = s;
447 self
448 }
449 pub fn with_max_size(mut self, s: Size) -> Self {
450 self.base.max_size = s;
451 self
452 }
453}
454
455impl Default for SizedBox {
456 fn default() -> Self {
457 Self::new()
458 }
459}
460
461impl Widget for SizedBox {
462 fn type_name(&self) -> &'static str {
463 "SizedBox"
464 }
465 fn bounds(&self) -> Rect {
466 self.bounds
467 }
468 fn set_bounds(&mut self, b: Rect) {
469 self.bounds = b;
470 }
471 fn children(&self) -> &[Box<dyn Widget>] {
472 &self.children
473 }
474 fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
475 &mut self.children
476 }
477
478 fn margin(&self) -> Insets {
479 self.base.margin
480 }
481 fn widget_base(&self) -> Option<&WidgetBase> {
482 Some(&self.base)
483 }
484 fn widget_base_mut(&mut self) -> Option<&mut WidgetBase> {
485 Some(&mut self.base)
486 }
487 fn h_anchor(&self) -> HAnchor {
488 self.base.h_anchor
489 }
490 fn v_anchor(&self) -> VAnchor {
491 self.base.v_anchor
492 }
493 fn min_size(&self) -> Size {
494 self.base.min_size
495 }
496 fn max_size(&self) -> Size {
497 self.base.max_size
498 }
499
500 fn measure_min_height(&self, available_w: f64) -> f64 {
507 if let Some(h) = self.height {
508 return h;
509 }
510 if let Some(child) = self.children.first() {
511 let m = child.margin();
512 let w = self.width.unwrap_or(available_w);
513 let slot_w = (w - m.left - m.right).max(0.0);
514 return (child.measure_min_height(slot_w) + m.vertical())
515 .clamp(self.base.min_size.height, self.base.max_size.height);
516 }
517 self.base.min_size.height
518 }
519
520 fn layout(&mut self, available: Size) -> Size {
521 let w = self.width.unwrap_or(available.width);
532 let mut h = self.height.unwrap_or_else(|| {
533 if self.children.is_empty() {
534 0.0
535 } else {
536 available.height
537 }
538 });
539
540 if let Some(child) = self.children.first_mut() {
541 let m = child.margin();
542 let slot_w = (w - m.left - m.right).max(0.0);
543 let slot_h = (h - m.top - m.bottom).max(0.0);
544
545 let desired = child.layout(Size::new(slot_w, slot_h));
546
547 if self.height.is_none() {
550 h = (desired.height + m.vertical())
551 .clamp(self.base.min_size.height, self.base.max_size.height);
552 }
553
554 let h_anchor = child.h_anchor();
556 let min_w = child.min_size().width;
557 let max_w = child.max_size().width;
558 let child_w = if h_anchor.is_stretch() {
559 slot_w.clamp(min_w, max_w)
560 } else if h_anchor == HAnchor::MAX_FIT_OR_STRETCH {
561 resolve_fit_or_stretch(desired.width, slot_w, true).clamp(min_w, max_w)
562 } else if h_anchor == HAnchor::MIN_FIT_OR_STRETCH {
563 resolve_fit_or_stretch(desired.width, slot_w, false).clamp(min_w, max_w)
564 } else {
565 desired.width.clamp(min_w, max_w)
566 };
567
568 let child_x = if h_anchor.contains(HAnchor::RIGHT) && !h_anchor.contains(HAnchor::LEFT)
569 {
570 (w - m.right - child_w).max(0.0)
571 } else if h_anchor.contains(HAnchor::CENTER) && !h_anchor.is_stretch() {
572 m.left + (slot_w - child_w) * 0.5
573 } else {
574 m.left
575 };
576
577 let v_anchor = child.v_anchor();
579 let min_h = child.min_size().height;
580 let max_h = child.max_size().height;
581 let child_h = if v_anchor.is_stretch() {
582 slot_h.clamp(min_h, max_h)
583 } else if v_anchor == VAnchor::MAX_FIT_OR_STRETCH {
584 resolve_fit_or_stretch(desired.height, slot_h, true).clamp(min_h, max_h)
585 } else if v_anchor == VAnchor::MIN_FIT_OR_STRETCH {
586 resolve_fit_or_stretch(desired.height, slot_h, false).clamp(min_h, max_h)
587 } else {
588 desired.height.clamp(min_h, max_h)
589 };
590
591 let child_w = if self.width.is_some() {
598 child_w.min(slot_w)
599 } else {
600 child_w
601 };
602 let child_h = if self.height.is_some() {
603 child_h.min(slot_h)
604 } else {
605 child_h
606 };
607
608 let child_y = if v_anchor.contains(VAnchor::TOP) && !v_anchor.contains(VAnchor::BOTTOM)
609 {
610 (h - m.top - child_h).max(0.0)
611 } else if v_anchor.contains(VAnchor::CENTER) && !v_anchor.is_stretch() {
612 m.bottom + (slot_h - child_h) * 0.5
613 } else {
614 m.bottom
615 };
616
617 child.set_bounds(Rect::new(child_x, child_y, child_w, child_h));
618 }
619
620 Size::new(w, h)
621 }
622
623 fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
624
625 fn on_event(&mut self, _: &Event) -> EventResult {
626 EventResult::Ignored
627 }
628}