agg_gui/widgets/
container.rs1use crate::color::Color;
9use crate::device_scale::device_scale;
10use crate::event::{Event, EventResult};
11use crate::geometry::{Rect, Size};
12use crate::draw_ctx::DrawCtx;
13use crate::layout_props::{HAnchor, Insets, VAnchor, WidgetBase};
14use crate::widget::Widget;
15
16pub struct Container {
22 bounds: Rect,
23 children: Vec<Box<dyn Widget>>,
24 base: WidgetBase,
25 pub background: Color,
26 pub border_color: Option<Color>,
27 pub border_width: f64,
28 pub corner_radius: f64,
29 pub inner_padding: Insets,
30}
31
32impl Container {
33 pub fn new() -> Self {
35 Self {
36 bounds: Rect::default(),
37 children: Vec::new(),
38 base: WidgetBase::new(),
39 background: Color::rgba(0.0, 0.0, 0.0, 0.0),
40 border_color: None,
41 border_width: 1.0,
42 corner_radius: 0.0,
43 inner_padding: Insets::ZERO,
44 }
45 }
46
47 pub fn add(mut self, child: Box<dyn Widget>) -> Self {
49 self.children.push(child);
50 self
51 }
52
53 pub fn with_background(mut self, color: Color) -> Self {
54 self.background = color;
55 self
56 }
57
58 pub fn with_border(mut self, color: Color, width: f64) -> Self {
59 self.border_color = Some(color);
60 self.border_width = width;
61 self
62 }
63
64 pub fn with_corner_radius(mut self, r: f64) -> Self {
65 self.corner_radius = r;
66 self
67 }
68
69 pub fn with_padding(mut self, p: f64) -> Self {
70 self.inner_padding = Insets::all(p);
71 self
72 }
73
74 pub fn with_inner_padding(mut self, p: Insets) -> Self {
75 self.inner_padding = p;
76 self
77 }
78
79 pub fn with_margin(mut self, m: Insets) -> Self { self.base.margin = m; self }
80 pub fn with_h_anchor(mut self, h: HAnchor) -> Self { self.base.h_anchor = h; self }
81 pub fn with_v_anchor(mut self, v: VAnchor) -> Self { self.base.v_anchor = v; self }
82 pub fn with_min_size(mut self, s: Size) -> Self { self.base.min_size = s; self }
83 pub fn with_max_size(mut self, s: Size) -> Self { self.base.max_size = s; self }
84}
85
86impl Default for Container {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92impl Widget for Container {
93 fn type_name(&self) -> &'static str { "Container" }
94 fn bounds(&self) -> Rect { self.bounds }
95 fn set_bounds(&mut self, bounds: Rect) { self.bounds = bounds; }
96
97 fn children(&self) -> &[Box<dyn Widget>] { &self.children }
98 fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> { &mut self.children }
99
100 fn margin(&self) -> Insets { self.base.margin }
101 fn h_anchor(&self) -> HAnchor { self.base.h_anchor }
102 fn v_anchor(&self) -> VAnchor { self.base.v_anchor }
103 fn min_size(&self) -> Size { self.base.min_size }
104 fn max_size(&self) -> Size { self.base.max_size }
105
106 fn layout(&mut self, available: Size) -> Size {
107 let pad_l = self.inner_padding.left;
108 let pad_r = self.inner_padding.right;
109 let pad_t = self.inner_padding.top;
110 let pad_b = self.inner_padding.bottom;
111 let inner_w = (available.width - pad_l - pad_r).max(0.0);
112
113 let scale = device_scale();
119 let mut cursor_y = available.height - pad_t;
120
121 for child in self.children.iter_mut() {
122 let m = child.margin().scale(scale);
123 let avail_w = (inner_w - m.left - m.right).max(0.0);
124 let avail_h = (cursor_y - pad_b - m.top - m.bottom).max(0.0);
125 let desired = child.layout(Size::new(avail_w, avail_h));
126
127 cursor_y -= m.top;
129 let child_y = cursor_y - desired.height;
130 let child_bounds = Rect::new(
131 pad_l + m.left,
132 child_y,
133 desired.width.min(avail_w),
134 desired.height,
135 );
136 child.set_bounds(child_bounds);
137 cursor_y = child_y - m.bottom;
139 }
140
141 Size::new(available.width, available.height)
143 }
144
145 fn paint(&mut self, ctx: &mut dyn DrawCtx) {
146 let w = self.bounds.width;
147 let h = self.bounds.height;
148 let r = self.corner_radius;
149
150 if self.background.a > 0.001 {
152 ctx.set_fill_color(self.background);
153 ctx.begin_path();
154 ctx.rounded_rect(0.0, 0.0, w, h, r);
155 ctx.fill();
156 }
157
158 if let Some(bc) = self.border_color {
160 ctx.set_stroke_color(bc);
161 ctx.set_line_width(self.border_width);
162 ctx.begin_path();
163 ctx.rounded_rect(0.0, 0.0, w, h, r);
164 ctx.stroke();
165 }
166 }
167
168 fn on_event(&mut self, _event: &Event) -> EventResult {
169 EventResult::Ignored
170 }
171}