1use std::borrow::Borrow;
2use std::rc::Rc;
3
4use fltk::group::Group;
5use fltk::prelude::{GroupExt, WidgetBase};
6
7use crate::{IntoWidget, LayoutElement, Padding, Size, WrapperFactory};
8
9pub struct Overlay<G: GroupExt + Clone = Group> {
10 props: OverlayProperties<G>,
11 min_size: Size,
12}
13
14pub struct OverlayBuilder<G: GroupExt + Clone = Group, F: Borrow<WrapperFactory> = WrapperFactory> {
15 props: OverlayProperties<G>,
16 factory: F,
17}
18
19struct OverlayProperties<G: GroupExt + Clone> {
20 group: G,
21 padding: Padding,
22 children: Vec<Rc<dyn LayoutElement>>,
23}
24
25impl<G: GroupExt + Clone> LayoutElement for Overlay<G> {
26 fn min_size(&self) -> Size {
27 self.min_size
28 }
29
30 fn layout(&self, x: i32, y: i32, width: i32, height: i32) {
31 self.props.group.clone().resize(x, y, width, height);
32 self.layout_children();
33 }
34}
35
36impl Overlay {
37 pub fn builder() -> OverlayBuilder<Group, WrapperFactory> {
38 OverlayBuilder::new(Group::default_fill())
39 }
40
41 pub fn builder_with_factory<F: Borrow<WrapperFactory>>(factory: F) -> OverlayBuilder<Group, F> {
42 OverlayBuilder::with_factory(Group::default_fill(), factory)
43 }
44}
45
46impl<G: GroupExt + Clone> Overlay<G> {
47 pub fn group(&self) -> G {
48 self.props.group.clone()
49 }
50
51 pub fn layout_children(&self) {
52 let x = self.props.group.x() + self.props.padding.left;
53 let y = self.props.group.y() + self.props.padding.top;
54 let width = self.props.group.width() - (self.props.padding.left + self.props.padding.right);
55 let height =
56 self.props.group.height() - (self.props.padding.top + self.props.padding.bottom);
57
58 for child in self.props.children.iter() {
59 child.layout(x, y, width, height);
60 }
61 }
62
63 fn new(props: OverlayProperties<G>) -> Self {
64 let mut min_size = props.children.iter().map(|child| child.min_size()).fold(
65 Default::default(),
66 |lhs: Size, rhs: Size| Size {
67 width: std::cmp::max(lhs.width, rhs.width),
68 height: std::cmp::max(lhs.height, rhs.height),
69 },
70 );
71 min_size.width += props.padding.left + props.padding.right;
72 min_size.height += props.padding.top + props.padding.bottom;
73
74 Self { props, min_size }
75 }
76}
77
78impl<G: GroupExt + Clone> OverlayBuilder<G> {
79 pub fn new(group: G) -> Self {
80 Self::with_factory(group, WrapperFactory::new())
81 }
82}
83
84impl<G: GroupExt + Clone, F: Borrow<WrapperFactory>> OverlayBuilder<G, F> {
85 pub fn with_factory(group: G, factory: F) -> Self {
86 Self {
87 props: OverlayProperties {
88 group,
89 padding: Default::default(),
90 children: Vec::new(),
91 },
92 factory,
93 }
94 }
95
96 pub fn with_left_padding(mut self, padding: i32) -> Self {
97 self.props.padding.left = padding;
98 self
99 }
100
101 pub fn with_top_padding(mut self, padding: i32) -> Self {
102 self.props.padding.top = padding;
103 self
104 }
105
106 pub fn with_right_padding(mut self, padding: i32) -> Self {
107 self.props.padding.right = padding;
108 self
109 }
110
111 pub fn with_bottom_padding(mut self, padding: i32) -> Self {
112 self.props.padding.bottom = padding;
113 self
114 }
115
116 pub fn with_padding(mut self, left: i32, top: i32, right: i32, bottom: i32) -> Self {
117 self.props.padding = Padding {
118 left,
119 top,
120 right,
121 bottom,
122 };
123 self
124 }
125
126 pub fn add<E: LayoutElement + 'static>(&mut self, element: E) {
127 self.add_shared(Rc::new(element));
128 }
129
130 pub fn add_shared(&mut self, element: Rc<dyn LayoutElement>) {
131 self.props.children.push(element);
132 }
133
134 pub fn wrap<W: IntoWidget + 'static>(&mut self, widget: W) -> W {
135 let element = self.factory.borrow().wrap(widget.clone());
136 self.add_shared(element);
137 widget
138 }
139
140 pub fn end(self) -> Overlay<G> {
141 self.props.group.end();
142 Overlay::new(self.props)
143 }
144}