1use crate::{Layout, Painter, Pos2, Rect, Region, Vec2, grid, vec2};
2
3#[cfg(debug_assertions)]
4use crate::{Align2, Color32, Stroke};
5
6pub(crate) struct Placer {
7 grid: Option<grid::GridLayout>,
9 layout: Layout,
10 region: Region,
11}
12
13impl Placer {
14 pub(crate) fn new(max_rect: Rect, layout: Layout) -> Self {
15 let region = layout.region_from_max_rect(max_rect);
16 Self {
17 grid: None,
18 layout,
19 region,
20 }
21 }
22
23 #[inline(always)]
24 pub(crate) fn set_grid(&mut self, grid: grid::GridLayout) {
25 self.grid = Some(grid);
26 }
27
28 pub(crate) fn save_grid(&mut self) {
29 if let Some(grid) = &mut self.grid {
30 grid.save();
31 }
32 }
33
34 #[inline(always)]
35 pub(crate) fn grid(&self) -> Option<&grid::GridLayout> {
36 self.grid.as_ref()
37 }
38
39 #[inline(always)]
40 pub(crate) fn is_grid(&self) -> bool {
41 self.grid.is_some()
42 }
43
44 #[inline(always)]
45 pub(crate) fn layout(&self) -> &Layout {
46 &self.layout
47 }
48
49 #[inline(always)]
50 pub(crate) fn prefer_right_to_left(&self) -> bool {
51 self.layout.prefer_right_to_left()
52 }
53
54 #[inline(always)]
55 pub(crate) fn min_rect(&self) -> Rect {
56 self.region.min_rect
57 }
58
59 #[inline(always)]
60 pub(crate) fn max_rect(&self) -> Rect {
61 self.region.max_rect
62 }
63
64 #[inline(always)]
65 pub(crate) fn force_set_min_rect(&mut self, min_rect: Rect) {
66 self.region.min_rect = min_rect;
67 }
68
69 #[inline(always)]
70 pub(crate) fn cursor(&self) -> Rect {
71 self.region.cursor
72 }
73
74 #[inline(always)]
75 pub(crate) fn set_cursor(&mut self, cursor: Rect) {
76 self.region.cursor = cursor;
77 }
78}
79
80impl Placer {
81 pub(crate) fn align_size_within_rect(&self, size: Vec2, outer: Rect) -> Rect {
82 if let Some(grid) = &self.grid {
83 grid.align_size_within_rect(size, outer)
84 } else {
85 self.layout.align_size_within_rect(size, outer)
86 }
87 }
88
89 pub(crate) fn available_rect_before_wrap(&self) -> Rect {
90 if let Some(grid) = &self.grid {
91 grid.available_rect(&self.region)
92 } else {
93 self.layout.available_rect_before_wrap(&self.region)
94 }
95 }
96
97 pub(crate) fn available_size(&self) -> Vec2 {
100 if let Some(grid) = &self.grid {
101 grid.available_rect(&self.region).size()
102 } else {
103 self.layout.available_size(&self.region)
104 }
105 }
106
107 pub(crate) fn next_space(&self, child_size: Vec2, item_spacing: Vec2) -> Rect {
112 debug_assert!(
113 0.0 <= child_size.x && 0.0 <= child_size.y,
114 "Negative child size: {child_size:?}"
115 );
116 self.region.sanity_check();
117 if let Some(grid) = &self.grid {
118 grid.next_cell(self.region.cursor, child_size)
119 } else {
120 self.layout
121 .next_frame(&self.region, child_size, item_spacing)
122 }
123 }
124
125 pub(crate) fn next_widget_position(&self) -> Pos2 {
127 if let Some(grid) = &self.grid {
128 grid.next_cell(self.region.cursor, Vec2::ZERO).center()
129 } else {
130 self.layout.next_widget_position(&self.region)
131 }
132 }
133
134 pub(crate) fn justify_and_align(&self, rect: Rect, child_size: Vec2) -> Rect {
136 debug_assert!(!rect.any_nan(), "rect: {rect:?}");
137 debug_assert!(!child_size.any_nan(), "child_size is NaN: {child_size:?}");
138
139 if let Some(grid) = &self.grid {
140 grid.justify_and_align(rect, child_size)
141 } else {
142 self.layout.justify_and_align(rect, child_size)
143 }
144 }
145
146 pub(crate) fn advance_cursor(&mut self, amount: f32) {
149 debug_assert!(
150 self.grid.is_none(),
151 "You cannot advance the cursor when in a grid layout"
152 );
153 self.layout.advance_cursor(&mut self.region, amount);
154 }
155
156 pub(crate) fn advance_after_rects(
162 &mut self,
163 frame_rect: Rect,
164 widget_rect: Rect,
165 item_spacing: Vec2,
166 ) {
167 debug_assert!(!frame_rect.any_nan(), "frame_rect: {frame_rect:?}");
168 debug_assert!(
169 !widget_rect.any_nan(),
170 "widget_rect is NaN: {widget_rect:?}"
171 );
172 self.region.sanity_check();
173
174 if let Some(grid) = &mut self.grid {
175 grid.advance(&mut self.region.cursor, frame_rect, widget_rect);
176 } else {
177 self.layout.advance_after_rects(
178 &mut self.region.cursor,
179 frame_rect,
180 widget_rect,
181 item_spacing,
182 );
183 }
184
185 self.expand_to_include_rect(frame_rect); self.region.sanity_check();
188 }
189
190 pub(crate) fn end_row(&mut self, item_spacing: Vec2, painter: &Painter) {
193 if let Some(grid) = &mut self.grid {
194 grid.end_row(&mut self.region.cursor, painter);
195 } else {
196 self.layout.end_row(&mut self.region, item_spacing);
197 }
198 }
199
200 pub(crate) fn set_row_height(&mut self, height: f32) {
202 self.layout.set_row_height(&mut self.region, height);
203 }
204}
205
206impl Placer {
207 pub(crate) fn expand_to_include_rect(&mut self, rect: Rect) {
209 self.region.expand_to_include_rect(rect);
210 }
211
212 pub(crate) fn expand_to_include_x(&mut self, x: f32) {
214 self.region.expand_to_include_x(x);
215 }
216
217 pub(crate) fn expand_to_include_y(&mut self, y: f32) {
219 self.region.expand_to_include_y(y);
220 }
221
222 fn next_widget_space_ignore_wrap_justify(&self, size: Vec2) -> Rect {
223 self.layout
224 .next_widget_space_ignore_wrap_justify(&self.region, size)
225 }
226
227 pub(crate) fn set_max_width(&mut self, width: f32) {
230 let rect = self.next_widget_space_ignore_wrap_justify(vec2(width, 0.0));
231 let region = &mut self.region;
232 region.max_rect.min.x = rect.min.x;
233 region.max_rect.max.x = rect.max.x;
234 region.max_rect |= region.min_rect; region.cursor.min.x = region.max_rect.min.x;
237 region.cursor.max.x = region.max_rect.max.x;
238
239 region.sanity_check();
240 }
241
242 pub(crate) fn set_max_height(&mut self, height: f32) {
245 let rect = self.next_widget_space_ignore_wrap_justify(vec2(0.0, height));
246 let region = &mut self.region;
247 region.max_rect.min.y = rect.min.y;
248 region.max_rect.max.y = rect.max.y;
249 region.max_rect |= region.min_rect; region.cursor.min.y = region.max_rect.min.y;
252 region.cursor.max.y = region.max_rect.max.y;
253
254 region.sanity_check();
255 }
256
257 pub(crate) fn set_min_width(&mut self, width: f32) {
260 if width <= 0.0 {
261 return;
262 }
263 let rect = self.next_widget_space_ignore_wrap_justify(vec2(width, 0.0));
264 self.region.expand_to_include_x(rect.min.x);
265 self.region.expand_to_include_x(rect.max.x);
266 }
267
268 pub(crate) fn set_min_height(&mut self, height: f32) {
271 if height <= 0.0 {
272 return;
273 }
274 let rect = self.next_widget_space_ignore_wrap_justify(vec2(0.0, height));
275 self.region.expand_to_include_y(rect.min.y);
276 self.region.expand_to_include_y(rect.max.y);
277 }
278}
279
280impl Placer {
281 #[cfg(debug_assertions)]
282 pub(crate) fn debug_paint_cursor(&self, painter: &crate::Painter, text: impl ToString) {
283 let stroke = Stroke::new(1.0, Color32::DEBUG_COLOR);
284
285 if let Some(grid) = &self.grid {
286 let rect = grid.next_cell(self.cursor(), Vec2::splat(0.0));
287 painter.rect_stroke(rect, 1.0, stroke, epaint::StrokeKind::Inside);
288 let align = Align2::CENTER_CENTER;
289 painter.debug_text(align.pos_in_rect(&rect), align, stroke.color, text);
290 } else {
291 self.layout
292 .paint_text_at_cursor(painter, &self.region, stroke, text);
293 }
294 }
295}