use super::base::Empty;
use super::{Concrete, Desc, Layout, Renderable, Staged, base, map_unsized_area};
use crate::{DRect, PxDim, PxRect, SourceID, rtree};
use std::marker::PhantomData;
use std::rc::Rc;
pub trait Prop: base::Area + base::Limits + base::Anchor {}
crate::gen_from_to_dyn!(Prop);
impl Prop for DRect {}
pub trait Padded: Prop + base::Padding {}
crate::gen_from_to_dyn!(Padded);
impl Padded for DRect {}
impl Desc for dyn Prop {
type Props = dyn Prop;
type Child = dyn Empty;
type Children = PhantomData<dyn Layout<Self::Child>>;
fn stage<'a>(
props: &Self::Props,
outer_area: PxRect,
outer_limits: crate::PxLimits,
_: &Self::Children,
id: std::sync::Weak<SourceID>,
renderable: Option<Rc<dyn Renderable>>,
window: &mut crate::component::window::WindowState,
) -> Box<dyn Staged + 'a> {
let limits = outer_limits + props.limits().resolve(window.dpi);
let evaluated_area = super::limit_area(
map_unsized_area(props.area().resolve(window.dpi), PxDim::zero())
* super::nuetralize_unsized(outer_area),
limits,
);
let anchor = props.anchor().resolve(window.dpi) * evaluated_area.dim();
let evaluated_area = evaluated_area - anchor;
debug_assert!(evaluated_area.v.is_finite().all());
Box::new(Concrete {
area: evaluated_area,
renderable,
rtree: rtree::Node::new(
evaluated_area.to_untyped(),
None,
Default::default(),
id,
window,
),
children: Default::default(),
layer: None,
})
}
}
#[derive_where::derive_where(Clone)]
pub struct Sized<T> {
pub id: std::sync::Weak<SourceID>,
pub props: Rc<T>,
pub size: crate::PxDim,
pub renderable: Option<Rc<dyn Renderable>>,
}
impl<T: Padded> Layout<T> for Sized<T> {
fn get_props(&self) -> &T {
&self.props
}
fn stage<'a>(
&self,
outer_area: crate::PxRect,
outer_limits: crate::PxLimits,
window: &mut crate::component::window::WindowState,
) -> Box<dyn super::Staged + 'a> {
let limits = outer_limits + self.props.limits().resolve(window.dpi);
let padding = self.props.padding().as_perimeter(window.dpi);
let area = self.props.area().resolve(window.dpi);
let aspect_ratio = self.size.width / self.size.height;
let (unsized_x, unsized_y) = super::check_unsized(area);
let outer_area = super::nuetralize_unsized(outer_area);
let mapped_area = match (unsized_x, unsized_y, aspect_ratio.is_finite()) {
(true, false, false) => {
let mut presize = map_unsized_area(area, PxDim::zero()) * outer_area;
let adjust = presize.dim().height * aspect_ratio;
let v = presize.v.as_array_mut();
v[2] += adjust;
presize
}
(false, true, false) => {
let mut presize = map_unsized_area(area, PxDim::zero()) * outer_area;
let adjust = presize.dim().width / aspect_ratio;
let v = presize.v.as_array_mut();
v[3] += adjust;
presize
}
_ => {
map_unsized_area(area, self.size + padding.topleft() + padding.bottomright())
* outer_area
}
};
let evaluated_area = super::limit_area(mapped_area, limits);
let anchor = self.props.anchor().resolve(window.dpi) * evaluated_area.dim();
let evaluated_area = evaluated_area - anchor;
debug_assert!(
evaluated_area.v.is_finite().all(),
"non-finite evaluated area!"
);
debug_assert!(evaluated_area.v.is_finite().all());
Box::new(Concrete {
area: evaluated_area,
renderable: self.renderable.clone(),
rtree: rtree::Node::new(
evaluated_area.to_untyped(),
None,
Default::default(),
self.id.clone(),
window,
),
children: Default::default(),
layer: None,
})
}
}