use crate::ui::{ component::{Component, Event, EventCtx}, geometry::{Alignment, Alignment2D, Axis, Grid, GridCellSpan, Insets, Offset, Rect}, shape::Renderer, }; pub struct GridPlaced { inner: T, grid: Grid, cells: GridCellSpan, } impl GridPlaced { pub fn new(inner: T) -> Self { Self { inner, grid: Grid::new(Rect::zero(), 0, 0), cells: GridCellSpan { from: (0, 0), to: (0, 0), }, } } pub fn with_grid(mut self, rows: usize, cols: usize) -> Self { self.grid.rows = rows; self.grid.cols = cols; self } pub fn with_spacing(mut self, spacing: i16) -> Self { self.grid.spacing = spacing; self } pub fn with_row_col(mut self, row: usize, col: usize) -> Self { self.cells.from = (row, col); self.cells.to = (row, col); self } pub fn with_from_to(mut self, from: (usize, usize), to: (usize, usize)) -> Self { self.cells.from = from; self.cells.to = to; self } } impl Component for GridPlaced where T: Component, { type Msg = T::Msg; fn place(&mut self, bounds: Rect) -> Rect { self.grid.area = bounds; self.inner.place(self.grid.cells(self.cells)) } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { self.inner.event(ctx, event) } fn paint(&mut self) { self.inner.paint() } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { self.inner.render(target); } } #[cfg(feature = "ui_debug")] impl crate::trace::Trace for GridPlaced where T: Component, T: crate::trace::Trace, { fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.component("GridPlaced"); t.child("inner", &self.inner); } } pub struct FixedHeightBar { inner: T, height: i16, } impl FixedHeightBar { pub const fn bottom(inner: T, height: i16) -> Self { Self { inner, height } } } impl Component for FixedHeightBar where T: Component, { type Msg = T::Msg; fn place(&mut self, bounds: Rect) -> Rect { let (_, bar) = bounds.split_bottom(self.height); self.inner.place(bar) } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { self.inner.event(ctx, event) } fn paint(&mut self) { self.inner.paint() } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { self.inner.render(target); } } #[cfg(feature = "ui_debug")] impl crate::trace::Trace for FixedHeightBar where T: Component, T: crate::trace::Trace, { fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.component("FixedHeightBar"); t.child("inner", &self.inner); } } pub struct Floating { inner: T, size: Offset, border: Offset, align: Alignment2D, } impl Floating { pub const fn new(size: Offset, border: Offset, align: Alignment2D, inner: T) -> Self { Self { inner, size, border, align, } } pub const fn top_right(side: i16, border: i16, inner: T) -> Self { let size = Offset::uniform(side); let border = Offset::uniform(border); Self::new(size, border, Alignment2D::TOP_RIGHT, inner) } } impl Component for Floating where T: Component, { type Msg = T::Msg; fn place(&mut self, bounds: Rect) -> Rect { let mut border = self.border; let area = match self.align.0 { Alignment::Start => bounds.split_left(self.size.x).0, Alignment::Center => panic!("alignment not supported"), Alignment::End => { border.x = -border.x; bounds.split_right(self.size.x).1 } }; let area = match self.align.1 { Alignment::Start => area.split_top(self.size.y).0, Alignment::Center => panic!("alignment not supported"), Alignment::End => { border.y = -border.y; area.split_bottom(self.size.y).1 } }; self.inner.place(area.translate(border)) } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { self.inner.event(ctx, event) } fn paint(&mut self) { self.inner.paint() } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { self.inner.render(target); } } #[cfg(feature = "ui_debug")] impl crate::trace::Trace for Floating where T: Component, T: crate::trace::Trace, { fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.component("Floating"); t.child("inner", &self.inner); } } pub struct Split { first: T, second: U, axis: Axis, size: i16, spacing: i16, } impl Split { pub const fn new(axis: Axis, size: i16, spacing: i16, first: T, second: U) -> Self { Self { first, second, axis, size, spacing, } } pub const fn left(size: i16, spacing: i16, first: T, second: U) -> Self { Self::new(Axis::Vertical, size, spacing, first, second) } pub const fn right(size: i16, spacing: i16, first: T, second: U) -> Self { Self::new(Axis::Vertical, -size, spacing, first, second) } pub const fn top(size: i16, spacing: i16, first: T, second: U) -> Self { Self::new(Axis::Horizontal, size, spacing, first, second) } pub const fn bottom(size: i16, spacing: i16, first: T, second: U) -> Self { Self::new(Axis::Horizontal, -size, spacing, first, second) } } impl Component for Split where T: Component, U: Component, { type Msg = M; fn place(&mut self, bounds: Rect) -> Rect { let size = if self.size == 0 { (bounds.size().axis(self.axis.cross()) - self.spacing) / 2 } else { self.size }; let (first, second) = match self.axis { Axis::Vertical if size > 0 => bounds.split_left(size), Axis::Vertical => bounds.split_right(-size), Axis::Horizontal if size > 0 => bounds.split_top(size), Axis::Horizontal => bounds.split_bottom(-size), }; let (first, second) = match self.axis { Axis::Vertical if size > 0 => (first, second.inset(Insets::left(self.spacing))), Axis::Vertical => (first.inset(Insets::right(self.spacing)), second), Axis::Horizontal if size > 0 => (first, second.inset(Insets::top(self.spacing))), Axis::Horizontal => (first.inset(Insets::bottom(self.spacing)), second), }; self.first.place(first); self.second.place(second); bounds } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { self.first .event(ctx, event) .or_else(|| self.second.event(ctx, event)) } fn paint(&mut self) { self.first.paint(); self.second.paint(); } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { self.first.render(target); self.second.render(target); } } #[cfg(feature = "ui_debug")] impl crate::trace::Trace for Split where T: crate::trace::Trace, U: crate::trace::Trace, { fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.component("Split"); t.child("first", &self.first); t.child("second", &self.second); } }