use crate::prelude::*;
use crate::ui::prelude::*;
use graphics_shapes::prelude::{Coord, Rect};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ColumnGravity {
Left,
Center,
Right,
}
#[derive(Debug, Clone)]
pub struct ColumnLayout {
pub padding: usize,
pub spacing: usize,
pub bounds: Rect,
pub gravity: ColumnGravity,
}
impl ColumnLayout {
pub fn new(padding: usize, spacing: usize, bounds: Rect, gravity: ColumnGravity) -> Self {
Self {
padding,
spacing,
bounds,
gravity,
}
}
pub fn new_from_topleft(topleft: Coord) -> Self {
Self::new(
0,
0,
Rect::new_with_size(topleft, 1000000, 100000),
ColumnGravity::Left,
)
}
pub fn new_bounded(bounds: Rect) -> Self {
Self::new(0, 0, bounds, ColumnGravity::Left)
}
}
impl ColumnLayout {
pub fn layout(&self, views: &mut [&mut dyn UiElement]) {
let mut y = self.padding;
for view in views {
let x = match self.gravity {
ColumnGravity::Left => self.padding,
ColumnGravity::Center => {
(self.bounds.width() / 2).saturating_sub(view.bounds().width() / 2)
}
ColumnGravity::Right => self
.bounds
.width()
.saturating_sub(view.bounds().width())
.saturating_sub(self.padding),
};
view.set_position(self.bounds.top_left() + (x, y));
y += view.bounds().height();
y += self.spacing;
}
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use crate::ui::prelude::*;
use graphics_shapes::coord;
#[test]
fn column_defaults() {
let style = UiStyle::default();
let mut view1 = Button::new((0, 0), "Test", None, &style.button);
let mut view2 = Button::new((0, 0), "Another", None, &style.button);
let layout = ColumnLayout {
padding: 0,
spacing: 0,
bounds: Rect::new((0, 0), (100, 100)),
gravity: ColumnGravity::Left,
};
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(0, 0));
assert_eq!(view2.bounds().top_left(), coord!(0, 16));
}
#[test]
fn column_defaults_with_padding() {
let style = UiStyle::default();
let mut view1 = Button::new((0, 0), "Test", None, &style.button);
let mut view2 = Button::new((0, 0), "Another", None, &style.button);
let layout = ColumnLayout {
padding: 10,
spacing: 0,
bounds: Rect::new((0, 0), (100, 100)),
gravity: ColumnGravity::Left,
};
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(10, 10));
assert_eq!(view2.bounds().top_left(), coord!(10, 26));
}
#[test]
fn column_defaults_with_spacing() {
let style = UiStyle::default();
let mut view1 = Button::new((0, 0), "Test", None, &style.button);
let mut view2 = Button::new((0, 0), "Another", None, &style.button);
let layout = ColumnLayout {
padding: 0,
spacing: 8,
bounds: Rect::new((0, 0), (100, 100)),
gravity: ColumnGravity::Left,
};
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(0, 0));
assert_eq!(view2.bounds().top_left(), coord!(0, 24));
}
#[test]
fn column_defaults_with_spacing_and_padding() {
let style = UiStyle::default();
let mut view1 = Button::new((0, 0), "Test", None, &style.button);
let mut view2 = Button::new((0, 0), "Another", None, &style.button);
let layout = ColumnLayout {
padding: 10,
spacing: 8,
bounds: Rect::new((0, 0), (100, 100)),
gravity: ColumnGravity::Left,
};
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(10, 10));
assert_eq!(view2.bounds().top_left(), coord!(10, 34));
}
#[test]
fn column_defaults_with_gravity_right() {
let style = UiStyle::default();
let mut view1 = Button::new((0, 0), "Test", None, &style.button);
let mut view2 = Button::new((0, 0), "Another", None, &style.button);
let layout = ColumnLayout {
padding: 0,
spacing: 0,
bounds: Rect::new((0, 0), (100, 100)),
gravity: ColumnGravity::Right,
};
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(67, 0));
assert_eq!(view2.bounds().top_left(), coord!(42, 16));
}
#[test]
fn column_defaults_with_gravity_right_and_padding() {
let style = UiStyle::default();
let mut view1 = Button::new((0, 0), "Test", None, &style.button);
let mut view2 = Button::new((0, 0), "Another", None, &style.button);
let layout = ColumnLayout {
padding: 20,
spacing: 0,
bounds: Rect::new((0, 0), (100, 100)),
gravity: ColumnGravity::Right,
};
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(47, 20));
assert_eq!(view2.bounds().top_left(), coord!(22, 36));
}
#[test]
fn column_defaults_with_gravity_center() {
let style = UiStyle::default();
let mut view1 = Button::new((0, 0), "Test", None, &style.button);
let mut view2 = Button::new((0, 0), "Another", None, &style.button);
let mut layout = ColumnLayout {
padding: 0,
spacing: 0,
bounds: Rect::new((0, 0), (100, 100)),
gravity: ColumnGravity::Center,
};
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(34, 0));
assert_eq!(view2.bounds().top_left(), coord!(21, 16));
layout.padding = 20;
layout.layout(&mut [&mut view1, &mut view2]);
assert_eq!(view1.bounds().top_left(), coord!(34, 20));
assert_eq!(view2.bounds().top_left(), coord!(21, 36));
}
}