1use sequoia_core::{Color, Edges, Length};
2use sequoia_layout::{
3 Align, Dock, DockStyle, Indents, Inset, LayoutStyle, Overflow, Position, sanitize_gap,
4};
5use sequoia_style::BoxStyle;
6
7use crate::any::AnyView;
8use crate::view::{PaintCtx, View};
9use crate::views::{IntoChildren, Unit};
10
11#[derive(Clone, Default)]
12pub struct DockArea {
13 children: Vec<AnyView>,
14 docks: Vec<Dock>,
15 style: LayoutStyle,
16 gap: f32,
17 last_child_fill: bool,
18 ordered: bool,
19 deco: BoxStyle,
20}
21
22impl DockArea {
23 pub fn new() -> Self {
24 Self {
25 children: Vec::new(),
26 docks: Vec::new(),
27 style: LayoutStyle {
28 width: Length::Fit,
29 height: Length::Fit,
30 ..LayoutStyle::default()
31 },
32 gap: 0.0,
33 last_child_fill: false,
34 ordered: false,
35 deco: BoxStyle::new(),
36 }
37 }
38
39 pub fn dock<V: View + 'static>(mut self, child: V, dock: Dock) -> Self {
40 self.children.push(AnyView::new(child));
41 self.docks.push(dock);
42 self.debug_check_fill_order();
43 self
44 }
45
46 pub fn dock_if<V: View + 'static>(
47 self,
48 cond: bool,
49 make: impl FnOnce() -> V,
50 dock: Dock,
51 ) -> Self {
52 if cond { self.dock(make(), dock) } else { self }
53 }
54
55 pub fn dock_opt<V: View + 'static>(self, child: Option<V>, dock: Dock) -> Self {
56 match child {
57 Some(v) => self.dock(v, dock),
58 None => self,
59 }
60 }
61
62 pub fn children(mut self, children: impl IntoChildren, dock: Dock) -> Self {
63 for child in children.into_children() {
64 self.children.push(child);
65 self.docks.push(dock);
66 }
67 self.debug_check_fill_order();
68 self
69 }
70
71 pub fn len(&self) -> usize {
72 self.children.len()
73 }
74
75 pub fn is_empty(&self) -> bool {
76 self.children.is_empty()
77 }
78
79 pub fn docks(&self) -> &[Dock] {
80 &self.docks
81 }
82
83 pub fn get_dock(&self, index: usize) -> Option<Dock> {
84 self.docks.get(index).copied()
85 }
86
87 pub fn is_ordered(&self) -> bool {
88 self.ordered
89 }
90
91 pub fn is_border(&self) -> bool {
92 !self.ordered
93 }
94
95 pub fn dock_at<V: View + 'static>(mut self, index: usize, child: V, dock: Dock) -> Self {
96 let i = index.min(self.children.len());
97 self.children.insert(i, AnyView::new(child));
98 self.docks.insert(i, dock);
99 self.debug_check_fill_order();
100 self
101 }
102
103 pub fn remove(mut self, index: usize) -> Self {
104 if index < self.children.len() {
105 self.children.remove(index);
106 self.docks.remove(index);
107 }
108 self
109 }
110
111 pub fn move_child(mut self, from: usize, slot: usize) -> Self {
112 crate::dnd::move_item(&mut self.children, from, slot);
113
114 crate::dnd::move_item(&mut self.docks, from, slot);
115 self.debug_check_fill_order();
116 self
117 }
118
119 pub fn set_dock(mut self, index: usize, dock: Dock) -> Self {
120 if let Some(d) = self.docks.get_mut(index) {
121 *d = dock;
122 }
123 self.debug_check_fill_order();
124 self
125 }
126
127 pub fn clear(mut self) -> Self {
128 self.children.clear();
129 self.docks.clear();
130 self
131 }
132
133 pub fn dock_mut<V: View + 'static>(&mut self, child: V, dock: Dock) {
134 self.children.push(AnyView::new(child));
135 self.docks.push(dock);
136 self.debug_check_fill_order();
137 }
138
139 pub fn dock_at_mut<V: View + 'static>(&mut self, index: usize, child: V, dock: Dock) {
140 let i = index.min(self.children.len());
141 self.children.insert(i, AnyView::new(child));
142 self.docks.insert(i, dock);
143 self.debug_check_fill_order();
144 }
145
146 pub fn remove_mut(&mut self, index: usize) {
147 if index < self.children.len() {
148 self.children.remove(index);
149 self.docks.remove(index);
150 }
151 }
152
153 pub fn move_child_mut(&mut self, from: usize, slot: usize) {
154 crate::dnd::move_item(&mut self.children, from, slot);
155 crate::dnd::move_item(&mut self.docks, from, slot);
156 self.debug_check_fill_order();
157 }
158
159 pub fn set_dock_mut(&mut self, index: usize, dock: Dock) {
160 if let Some(d) = self.docks.get_mut(index) {
161 *d = dock;
162 }
163 self.debug_check_fill_order();
164 }
165
166 pub fn clear_mut(&mut self) {
167 self.children.clear();
168 self.docks.clear();
169 }
170
171 fn debug_check_fill_order(&self) {
172 #[cfg(debug_assertions)]
173 {
174 let n = self.docks.len();
175 if n == 0 {
176 return;
177 }
178 if !self.ordered && self.last_child_fill {
179 log::warn!(
180 "sequoia-view::DockArea: .last_child_fill(true) is ignored in Border mode - remove it or set it to .ordered(true)"
181 );
182 }
183 if self.ordered {
184 for i in 0..n {
185 let effective =
186 sequoia_layout::effective_dock(&self.docks, self.last_child_fill, i, n);
187 if effective == Dock::Fill && i + 1 != n {
188 log::warn!(
189 "sequoia-view::DockArea(ordered): Fill at position {i}/{n} - children after it will get 0x0; put Fill last or use Border mode"
190 );
191 break;
192 }
193 }
194 } else {
195 let fills = self.docks.iter().filter(|d| **d == Dock::Fill).count();
196 if fills > 1 {
197 log::warn!(
198 "sequoia-view::DockArea: {fills}× Fill - the first one takes the rest, the next ones will get 0x0"
199 );
200 }
201 }
202 }
203 }
204
205 pub fn left<V: View + 'static>(self, child: V) -> Self {
206 self.dock(child, Dock::Left)
207 }
208
209 pub fn right<V: View + 'static>(self, child: V) -> Self {
210 self.dock(child, Dock::Right)
211 }
212
213 pub fn top<V: View + 'static>(self, child: V) -> Self {
214 self.dock(child, Dock::Top)
215 }
216
217 pub fn bottom<V: View + 'static>(self, child: V) -> Self {
218 self.dock(child, Dock::Bottom)
219 }
220
221 pub fn fill<V: View + 'static>(self, child: V) -> Self {
222 self.dock(child, Dock::Fill)
223 }
224
225 pub fn center<V: View + 'static>(self, child: V) -> Self {
226 self.fill(child)
227 }
228
229 pub fn left_if<V: View + 'static>(self, cond: bool, make: impl FnOnce() -> V) -> Self {
230 self.dock_if(cond, make, Dock::Left)
231 }
232
233 pub fn right_if<V: View + 'static>(self, cond: bool, make: impl FnOnce() -> V) -> Self {
234 self.dock_if(cond, make, Dock::Right)
235 }
236
237 pub fn top_if<V: View + 'static>(self, cond: bool, make: impl FnOnce() -> V) -> Self {
238 self.dock_if(cond, make, Dock::Top)
239 }
240
241 pub fn bottom_if<V: View + 'static>(self, cond: bool, make: impl FnOnce() -> V) -> Self {
242 self.dock_if(cond, make, Dock::Bottom)
243 }
244
245 pub fn fill_if<V: View + 'static>(self, cond: bool, make: impl FnOnce() -> V) -> Self {
246 self.dock_if(cond, make, Dock::Fill)
247 }
248
249 pub fn center_if<V: View + 'static>(self, cond: bool, make: impl FnOnce() -> V) -> Self {
250 self.dock_if(cond, make, Dock::Fill)
251 }
252
253 pub fn left_opt<V: View + 'static>(self, child: Option<V>) -> Self {
254 self.dock_opt(child, Dock::Left)
255 }
256
257 pub fn right_opt<V: View + 'static>(self, child: Option<V>) -> Self {
258 self.dock_opt(child, Dock::Right)
259 }
260
261 pub fn top_opt<V: View + 'static>(self, child: Option<V>) -> Self {
262 self.dock_opt(child, Dock::Top)
263 }
264
265 pub fn bottom_opt<V: View + 'static>(self, child: Option<V>) -> Self {
266 self.dock_opt(child, Dock::Bottom)
267 }
268
269 pub fn fill_opt<V: View + 'static>(self, child: Option<V>) -> Self {
270 self.dock_opt(child, Dock::Fill)
271 }
272
273 pub fn center_opt<V: View + 'static>(self, child: Option<V>) -> Self {
274 self.dock_opt(child, Dock::Fill)
275 }
276
277 pub fn last_child_fill(mut self, fill: bool) -> Self {
278 self.last_child_fill = fill;
279 self.debug_check_fill_order();
280 self
281 }
282
283 pub fn ordered(mut self, ordered: bool) -> Self {
284 self.ordered = ordered;
285 self.debug_check_fill_order();
286 self
287 }
288
289 pub fn border_layout(mut self, border: bool) -> Self {
290 self.ordered = !border;
291 self.debug_check_fill_order();
292 self
293 }
294
295 pub fn gap(mut self, gap: f32) -> Self {
296 self.gap = sanitize_gap(gap);
297 self
298 }
299
300 pub fn padding(mut self, padding: impl Into<Edges>) -> Self {
301 self.style = self.style.padding(padding);
302 self
303 }
304
305 pub fn pad(self, padding: impl Into<Edges>) -> Self {
306 self.padding(padding)
307 }
308
309 pub fn padding_xy(mut self, x: f32, y: f32) -> Self {
310 self.style = self.style.padding_xy(x, y);
311 self
312 }
313
314 pub fn padding_x(mut self, x: f32) -> Self {
315 self.style = self.style.padding_x(x);
316 self
317 }
318
319 pub fn padding_y(mut self, y: f32) -> Self {
320 self.style = self.style.padding_y(y);
321 self
322 }
323
324 pub fn padding_left(mut self, v: f32) -> Self {
325 self.style = self.style.padding_left(v);
326 self
327 }
328
329 pub fn padding_right(mut self, v: f32) -> Self {
330 self.style = self.style.padding_right(v);
331 self
332 }
333
334 pub fn padding_top(mut self, v: f32) -> Self {
335 self.style = self.style.padding_top(v);
336 self
337 }
338
339 pub fn padding_bottom(mut self, v: f32) -> Self {
340 self.style = self.style.padding_bottom(v);
341 self
342 }
343
344 pub fn margin(mut self, margin: impl Into<Edges>) -> Self {
345 self.style = self.style.margin(margin);
346 self
347 }
348
349 pub fn margin_xy(mut self, x: f32, y: f32) -> Self {
350 self.style = self.style.margin_xy(x, y);
351 self
352 }
353
354 pub fn margin_x(mut self, x: f32) -> Self {
355 self.style = self.style.margin_x(x);
356 self
357 }
358
359 pub fn margin_y(mut self, y: f32) -> Self {
360 self.style = self.style.margin_y(y);
361 self
362 }
363
364 pub fn margin_left(mut self, v: f32) -> Self {
365 self.style = self.style.margin_left(v);
366 self
367 }
368
369 pub fn margin_right(mut self, v: f32) -> Self {
370 self.style = self.style.margin_right(v);
371 self
372 }
373
374 pub fn margin_top(mut self, v: f32) -> Self {
375 self.style = self.style.margin_top(v);
376 self
377 }
378
379 pub fn margin_bottom(mut self, v: f32) -> Self {
380 self.style = self.style.margin_bottom(v);
381 self
382 }
383
384 pub fn indent_top(mut self, v: f32) -> Self {
385 self.style = self.style.indent_top(v);
386 self
387 }
388
389 pub fn indent_bottom(mut self, v: f32) -> Self {
390 self.style = self.style.indent_bottom(v);
391 self
392 }
393
394 pub fn indent_left(mut self, v: f32) -> Self {
395 self.style = self.style.indent_left(v);
396 self
397 }
398
399 pub fn indent_right(mut self, v: f32) -> Self {
400 self.style = self.style.indent_right(v);
401 self
402 }
403
404 pub fn clear_indents(mut self) -> Self {
405 self.style = self.style.clear_indents();
406 self
407 }
408
409 pub fn indent(mut self, indents: Indents) -> Self {
410 self.style = self.style.indent(indents);
411 self
412 }
413
414 pub fn indent_all(mut self, v: f32) -> Self {
415 self.style = self.style.indent_all(v);
416 self
417 }
418
419 pub fn indent_xy(mut self, x: f32, y: f32) -> Self {
420 self.style = self.style.indent_xy(x, y);
421 self
422 }
423
424 pub fn indent_axes(mut self, horizontal: f32, vertical: f32) -> Self {
425 self.style = self.style.indent_axes(horizontal, vertical);
426 self
427 }
428
429 pub fn width(mut self, width: impl Into<Length>) -> Self {
430 self.style = self.style.width(width.into());
431 self
432 }
433
434 pub fn height(mut self, height: impl Into<Length>) -> Self {
435 self.style = self.style.height(height.into());
436 self
437 }
438
439 pub fn size(mut self, width: impl Into<Length>, height: impl Into<Length>) -> Self {
440 self.style = self.style.width(width.into()).height(height.into());
441 self
442 }
443
444 pub fn square(mut self, side: impl Into<Length>) -> Self {
445 let side = side.into();
446 self.style = self.style.width(side).height(side);
447 self
448 }
449
450 pub fn min_width(mut self, v: f32) -> Self {
451 self.style = self.style.min_width(v);
452 self
453 }
454
455 pub fn max_width(mut self, v: f32) -> Self {
456 self.style = self.style.max_width(v);
457 self
458 }
459
460 pub fn min_height(mut self, v: f32) -> Self {
461 self.style = self.style.min_height(v);
462 self
463 }
464
465 pub fn max_height(mut self, v: f32) -> Self {
466 self.style = self.style.max_height(v);
467 self
468 }
469
470 pub fn overflow(mut self, overflow: Overflow) -> Self {
471 self.style = self.style.overflow(overflow);
472 self
473 }
474
475 pub fn flex(mut self, weight: f32) -> Self {
476 self.style = self.style.flex(weight);
477 self
478 }
479
480 pub fn flex_grow(mut self, weight: f32) -> Self {
481 self.style = self.style.flex_grow(weight);
482 self
483 }
484
485 pub fn flex_shrink(mut self, shrink: f32) -> Self {
486 self.style = self.style.flex_shrink(shrink);
487 self
488 }
489
490 pub fn flex_basis(mut self, basis: Option<Length>) -> Self {
491 self.style = self.style.flex_basis(basis);
492 self
493 }
494
495 pub fn align_self(mut self, align: Option<Align>) -> Self {
496 self.style = self.style.align_self(align);
497 self
498 }
499
500 pub fn align_self_value(mut self, align: Align) -> Self {
501 self.style = self.style.align_self_value(align);
502 self
503 }
504
505 pub fn aspect_ratio(mut self, ratio: Option<f32>) -> Self {
506 self.style = self.style.aspect_ratio(ratio);
507 self
508 }
509
510 pub fn aspect(mut self, ratio: f32) -> Self {
511 self.style = self.style.aspect(ratio);
512 self
513 }
514
515 pub fn position(mut self, position: Position) -> Self {
516 self.style = self.style.position(position);
517 self
518 }
519
520 pub fn absolute(mut self) -> Self {
521 self.style = self.style.absolute();
522 self
523 }
524
525 pub fn absolute_at(mut self, left: f32, top: f32) -> Self {
526 self.style = self.style.absolute_at(left, top);
527 self
528 }
529
530 pub fn absolute_inset(mut self, inset: Inset) -> Self {
531 self.style = self.style.absolute_inset(inset);
532 self
533 }
534
535 pub fn fit(mut self) -> Self {
536 self.style = self.style.fit();
537 self
538 }
539
540 pub fn hit_testable(mut self, on: bool) -> Self {
541 self.style = self.style.hit_testable(on);
542 self
543 }
544
545 pub fn expand(self) -> Self {
546 self.flex(1.0)
547 }
548
549 pub fn fill_width(mut self) -> Self {
550 self.style = self.style.width(Length::Fill(1.0));
551 self
552 }
553
554 pub fn fill_height(mut self) -> Self {
555 self.style = self.style.height(Length::Fill(1.0));
556 self
557 }
558
559 pub fn fill_size(self) -> Self {
560 self.fill_width().fill_height()
561 }
562
563 pub fn background(mut self, color: Color) -> Self {
564 self.deco = self.deco.background(color);
565 self
566 }
567
568 pub fn border(mut self, width: f32, color: Color) -> Self {
569 self.deco = self.deco.border(width, color);
570 self
571 }
572
573 pub fn border_left(mut self, width: f32, color: Color) -> Self {
574 self.deco = self.deco.border_left(width, color);
575 self
576 }
577
578 pub fn border_right(mut self, width: f32, color: Color) -> Self {
579 self.deco = self.deco.border_right(width, color);
580 self
581 }
582
583 pub fn border_top(mut self, width: f32, color: Color) -> Self {
584 self.deco = self.deco.border_top(width, color);
585 self
586 }
587
588 pub fn border_bottom(mut self, width: f32, color: Color) -> Self {
589 self.deco = self.deco.border_bottom(width, color);
590 self
591 }
592
593 pub fn border_x(mut self, width: f32, color: Color) -> Self {
594 self.deco = self.deco.border_x(width, color);
595 self
596 }
597
598 pub fn border_y(mut self, width: f32, color: Color) -> Self {
599 self.deco = self.deco.border_y(width, color);
600 self
601 }
602
603 pub fn radius(mut self, radius: f32) -> Self {
604 self.deco = self.deco.radius(radius);
605 self
606 }
607
608 pub fn box_style(mut self, style: BoxStyle) -> Self {
609 self.deco = style;
610 self
611 }
612
613 pub fn style(self, style: BoxStyle) -> Self {
614 self.box_style(style)
615 }
616}
617
618impl View for DockArea {
619 fn body(&self) -> impl View + 'static {
620 Unit
621 }
622 fn children_override(&self) -> Option<Vec<AnyView>> {
623 Some(self.children.clone())
624 }
625 fn layout_style(&self) -> LayoutStyle {
626 self.style
627 }
628 fn dock(&self) -> Option<DockStyle> {
629 Some(DockStyle {
630 docks: self.docks.clone(),
631 gap: self.gap,
632 last_child_fill: self.last_child_fill,
633 ordered: self.ordered,
634 })
635 }
636 fn paint_self(&self, ctx: &mut PaintCtx) {
637 ctx.paint_box(self.deco);
638 }
639}