use crate::geometry::*;
use crate::widget::capture::CaptureState;
use crate::widget::placement::*;
use crate::widget::*;
pub trait Layout {
fn layout(&self, size: Point, element: usize, total: usize) -> Window;
}
pub trait LayoutElement {
fn widget<'a>(&'a self) -> &'a Widget;
fn widget_mut<'a>(&'a mut self) -> &'a mut Widget;
fn placement<'a>(&'a self) -> &'a Placement;
fn state<'a>(&'a self) -> &'a CaptureState;
fn state_mut<'a>(&'a mut self) -> &'a mut CaptureState;
}
pub trait IntoLayoutElement<T>: Sized
where
T: LayoutElement,
{
fn into_layout_element(self) -> T;
}
impl<W> IntoLayoutElement<(W, Place, CaptureState)> for W
where
W: Widget,
{
fn into_layout_element(self) -> (W, Place, CaptureState) {
(self, Place, CaptureState::default())
}
}
impl<W, P> IntoLayoutElement<(W, P, CaptureState)> for (W, P)
where
W: Widget,
P: Placement,
{
fn into_layout_element(self) -> (W, P, CaptureState) {
(self.0, self.1, CaptureState::default())
}
}
impl<L> IntoLayoutElement<L> for L
where
L: LayoutElement,
{
fn into_layout_element(self) -> L {
self
}
}
impl<W> AnchorPlaced<(W, AnchorPlacement)> for W
where
W: Widget,
{
fn anchor_left(self, anchor: u16) -> (W, AnchorPlacement) {
(self, Place.anchor_left(anchor))
}
fn left_size(self, size: u16) -> (W, AnchorPlacement) {
(self, Place.left_size(size))
}
fn anchor_right(self, anchor: u16) -> (W, AnchorPlacement) {
(self, Place.anchor_right(anchor))
}
fn right_size(self, size: u16) -> (W, AnchorPlacement) {
(self, Place.right_size(size))
}
fn anchor_top(self, anchor: u16) -> (W, AnchorPlacement) {
(self, Place.anchor_top(anchor))
}
fn top_size(self, size: u16) -> (W, AnchorPlacement) {
(self, Place.top_size(size))
}
fn anchor_bottom(self, anchor: u16) -> (W, AnchorPlacement) {
(self, Place.anchor_bottom(anchor))
}
fn bottom_size(self, size: u16) -> (W, AnchorPlacement) {
(self, Place.bottom_size(size))
}
fn fill(self) -> (W, AnchorPlacement) {
(self, Place.fill())
}
}
impl<W> AnchorPlaced<(W, AnchorPlacement)> for (W, AnchorPlacement)
where
W: Widget,
{
fn anchor_left(self, anchor: u16) -> (W, AnchorPlacement) {
(self.0, self.1.anchor_left(anchor))
}
fn left_size(self, size: u16) -> (W, AnchorPlacement) {
(self.0, self.1.left_size(size))
}
fn anchor_right(self, anchor: u16) -> (W, AnchorPlacement) {
(self.0, self.1.anchor_right(anchor))
}
fn right_size(self, size: u16) -> (W, AnchorPlacement) {
(self.0, self.1.right_size(size))
}
fn anchor_top(self, anchor: u16) -> (W, AnchorPlacement) {
(self.0, self.1.anchor_top(anchor))
}
fn top_size(self, size: u16) -> (W, AnchorPlacement) {
(self.0, self.1.top_size(size))
}
fn anchor_bottom(self, anchor: u16) -> (W, AnchorPlacement) {
(self.0, self.1.anchor_bottom(anchor))
}
fn bottom_size(self, size: u16) -> (W, AnchorPlacement) {
(self.0, self.1.bottom_size(size))
}
fn fill(self) -> (W, AnchorPlacement) {
(self.0, self.1.fill())
}
}
impl<P: Placement, W: Widget> LayoutElement for (W, P, CaptureState) {
fn widget<'a>(&'a self) -> &'a Widget {
&self.0
}
fn widget_mut<'a>(&'a mut self) -> &'a mut Widget {
&mut self.0
}
fn placement<'a>(&'a self) -> &'a Placement {
&self.1
}
fn state<'a>(&'a self) -> &'a CaptureState {
&self.2
}
fn state_mut<'a>(&'a mut self) -> &'a mut CaptureState {
&mut self.2
}
}
pub struct FreeLayout;
pub struct GridLayout {
rows: Vec<u8>,
columns: Vec<u8>,
}
impl GridLayout {
pub fn new(columns: &[u8], rows: &[u8]) -> Self {
let columns = if columns.len() == 0 {
vec![255]
} else {
columns.into()
};
let rows = if rows.len() == 0 {
vec![255]
} else {
rows.into()
};
GridLayout { rows, columns }
}
}
impl FreeLayout {
pub fn with_grid(&self, columns: &[u8], rows: &[u8]) -> GridLayout {
GridLayout::new(columns, rows)
}
}
impl Layout for FreeLayout {
fn layout(&self, size: Point, _element: usize, _total: usize) -> Window {
window(Point::default(), size)
}
}
impl Layout for GridLayout {
fn layout(&self, size: Point, element: usize, total: usize) -> Window {
let cols = self.columns.len();
let rows = self.rows.len();
if element >= cols * rows {
return FreeLayout.layout(size, element, total);
}
let row = element / cols;
let col = element % cols;
let cell_x = cell(&self.columns, col, size.x.to_primitive());
let cell_y = cell(&self.rows, row, size.y.to_primitive());
window(
point(x(cell_x.0), y(cell_y.0)),
point(x(cell_x.1), y(cell_y.1)),
)
}
}
fn cell(grid: &[u8], idx: usize, size: u16) -> (u16, u16) {
let mut total = 0u16;
let mut start = 0u16;
let mut cell = 0u16;
for i in 0..grid.len() {
let c = grid[i] as u16;
total += c;
if i < idx {
start += c;
} else if i == idx {
cell = c;
}
}
if total == 0 {
total = size;
start = (total as usize / idx) as u16;
cell = (size as usize / grid.len()) as u16;
}
if idx + 1 == grid.len() {
(size * start / total, size - size * start / total)
} else {
(size * start / total, size * cell / total)
}
}
#[test]
fn test_layout() {
let sut = GridLayout {
rows: vec![100, 100],
columns: vec![100, 100, 100],
};
let size = point(x(10), y(13));
assert_eq!(
sut.layout(size, 0usize, 3),
window(point(x(0), y(0)), point(x(3), y(6)))
);
assert_eq!(
sut.layout(size, 5usize, 3),
window(point(x(6), y(6)), point(x(4), y(7)))
);
}