fltk_float/
overlay.rs

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}