use crate::*; /// Draws items from an iterator. pub struct Map where I: Iterator + Send + Sync, F: Fn() -> I + Send + Sync, { __: PhantomData<(O, B)>, /// Function that returns iterator over stacked components get_iter: F, /// Function that returns each stacked component get_item: G, } impl<'a, O, A, B, I, F, G> Map where I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, { pub const fn new (get_iter: F, get_item: G) -> Self { Self { __: PhantomData, get_iter, get_item } } } macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{ impl<'a, O, A, B, I, F> Map< O, A, Push>>>, I, F, fn(A, usize)->B > where O: Out, B: Draw + Layout, I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a { pub const fn $name ( size: O::Unit, get_iter: F, get_item: impl Fn(A, usize)->B + Send + Sync ) -> Map< O, A, Push>>, I, F, impl Fn(A, usize)->Push>> + Send + Sync > { Map { __: PhantomData, get_iter, get_item: move |item: A, index: usize|{ // FIXME: multiply let mut push: O::Unit = O::Unit::from(0u16); for _ in 0..index { push = push + size; } Push::$axis(push, Align::$align(Fixed::$axis(size, get_item(item, index)))) } } } } }); impl_map_direction!(east, x, w); impl_map_direction!(south, y, n); impl_map_direction!(west, x, e); impl_map_direction!(north, y, s); impl<'a, O, A, B, I, F, G> Layout for Map where O: Out, B: Draw + Layout, I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync { fn layout (&self, area: O::Area) -> O::Area { let Self { get_iter, get_item, .. } = self; let mut index = 0; let [mut min_x, mut min_y] = area.center(); let [mut max_x, mut max_y] = area.center(); for item in get_iter() { let [x,y,w,h] = get_item(item, index).layout(area).xywh(); min_x = min_x.min(x.into()); min_y = min_y.min(y.into()); max_x = max_x.max((x + w).into()); max_y = max_y.max((y + h).into()); index += 1; } let w = max_x - min_x; let h = max_y - min_y; //[min_x.into(), min_y.into(), w.into(), h.into()].into() area.center_xy([w.into(), h.into()].into()).into() } } impl<'a, O, A, B, I, F, G> Draw for Map where O: Out, B: Draw + Layout, I: Iterator + Send + Sync + 'a, F: Fn() -> I + Send + Sync + 'a, G: Fn(A, usize)->B + Send + Sync { fn draw (&self, to: &mut O) { let Self { get_iter, get_item, .. } = self; let mut index = 0; let area = self.layout(to.area()); for item in get_iter() { let item = get_item(item, index); //to.place_at(area.into(), &item); to.place_at(item.layout(area), &item); index += 1; } } } #[inline] pub fn map_south( item_offset: O::Unit, item_height: O::Unit, item: impl Draw + Layout ) -> impl Draw + Layout { Push::y(item_offset, Fixed::y(item_height, Fill::x(item))) } #[inline] pub fn map_south_west( item_offset: O::Unit, item_height: O::Unit, item: impl Draw + Layout ) -> impl Draw + Layout { Push::y(item_offset, Align::nw(Fixed::y(item_height, Fill::x(item)))) } #[inline] pub fn map_east( item_offset: O::Unit, item_width: O::Unit, item: impl Draw + Layout ) -> impl Draw + Layout { Push::x(item_offset, Align::w(Fixed::x(item_width, Fill::y(item)))) }