feather_ui/layout/
leaf.rs1use super::base::Empty;
5use super::{Concrete, Desc, Layout, Renderable, Staged, base, map_unsized_area};
6use crate::{DRect, PxDim, PxRect, SourceID, rtree};
7use std::marker::PhantomData;
8use std::rc::Rc;
9
10pub trait Prop: base::Area + base::Limits + base::Anchor {}
11
12crate::gen_from_to_dyn!(Prop);
13
14impl Prop for DRect {}
15
16pub trait Padded: Prop + base::Padding {}
20
21crate::gen_from_to_dyn!(Padded);
22
23impl Padded for DRect {}
24
25impl Desc for dyn Prop {
26 type Props = dyn Prop;
27 type Child = dyn Empty;
28 type Children = PhantomData<dyn Layout<Self::Child>>;
29
30 fn stage<'a>(
31 props: &Self::Props,
32 outer_area: PxRect,
33 outer_limits: crate::PxLimits,
34 _: &Self::Children,
35 id: std::sync::Weak<SourceID>,
36 renderable: Option<Rc<dyn Renderable>>,
37 window: &mut crate::component::window::WindowState,
38 ) -> Box<dyn Staged + 'a> {
39 let limits = outer_limits + props.limits().resolve(window.dpi);
40 let evaluated_area = super::limit_area(
41 map_unsized_area(props.area().resolve(window.dpi), PxDim::zero())
42 * super::nuetralize_unsized(outer_area),
43 limits,
44 );
45
46 let anchor = props.anchor().resolve(window.dpi) * evaluated_area.dim();
47 let evaluated_area = evaluated_area - anchor;
48
49 debug_assert!(evaluated_area.v.is_finite().all());
50 Box::new(Concrete {
51 area: evaluated_area,
52 renderable,
53 rtree: rtree::Node::new(
54 evaluated_area.to_untyped(),
55 None,
56 Default::default(),
57 id,
58 window,
59 ),
60 children: Default::default(),
61 layer: None,
62 })
63 }
64}
65
66#[derive_where::derive_where(Clone)]
71pub struct Sized<T> {
72 pub id: std::sync::Weak<SourceID>,
73 pub props: Rc<T>,
74 pub size: crate::PxDim,
75 pub renderable: Option<Rc<dyn Renderable>>,
76}
77
78impl<T: Padded> Layout<T> for Sized<T> {
79 fn get_props(&self) -> &T {
80 &self.props
81 }
82 fn stage<'a>(
83 &self,
84 outer_area: crate::PxRect,
85 outer_limits: crate::PxLimits,
86 window: &mut crate::component::window::WindowState,
87 ) -> Box<dyn super::Staged + 'a> {
88 let limits = outer_limits + self.props.limits().resolve(window.dpi);
89 let padding = self.props.padding().as_perimeter(window.dpi);
90 let area = self.props.area().resolve(window.dpi);
91 let aspect_ratio = self.size.width / self.size.height; let (unsized_x, unsized_y) = super::check_unsized(area);
98 let outer_area = super::nuetralize_unsized(outer_area);
99 let mapped_area = match (unsized_x, unsized_y, aspect_ratio.is_finite()) {
100 (true, false, false) => {
101 let mut presize = map_unsized_area(area, PxDim::zero()) * outer_area;
102 let adjust = presize.dim().height * aspect_ratio;
103 let v = presize.v.as_array_mut();
104 v[2] += adjust;
105 presize
106 }
107 (false, true, false) => {
108 let mut presize = map_unsized_area(area, PxDim::zero()) * outer_area;
109 let adjust = presize.dim().width / aspect_ratio;
111 let v = presize.v.as_array_mut();
112 v[3] += adjust;
113 presize
114 }
115 _ => {
116 map_unsized_area(area, self.size + padding.topleft() + padding.bottomright())
117 * outer_area
118 }
119 };
120
121 let evaluated_area = super::limit_area(mapped_area, limits);
122
123 let anchor = self.props.anchor().resolve(window.dpi) * evaluated_area.dim();
124 let evaluated_area = evaluated_area - anchor;
125
126 debug_assert!(
127 evaluated_area.v.is_finite().all(),
128 "non-finite evaluated area!"
129 );
130 debug_assert!(evaluated_area.v.is_finite().all());
131 Box::new(Concrete {
132 area: evaluated_area,
133 renderable: self.renderable.clone(),
134 rtree: rtree::Node::new(
135 evaluated_area.to_untyped(),
136 None,
137 Default::default(),
138 self.id.clone(),
139 window,
140 ),
141 children: Default::default(),
142 layer: None,
143 })
144 }
145}