use crate::{
align::{Alignment, HorizontalAlignment, VerticalAlignment},
layout::linear::{
secondary_alignment::SecondaryAlignment,
spacing::{ElementSpacing, Tight},
},
prelude::*,
};
use embedded_graphics::primitives::Rectangle;
pub trait Orientation: Copy + Clone {
type Secondary: SecondaryAlignment + Alignment;
fn destructure_size(size: Size) -> (u32, u32);
fn create_size(primary: u32, secondary: u32) -> Size;
fn adjust_size(self, size: Size, objects: u32) -> Size;
fn place_first(&self, view: &mut impl View, bounds: Rectangle, count: u32);
fn place_nth(&self, view: &mut impl View, size: Size, previous: Rectangle, n: u32, count: u32);
}
#[derive(Copy, Clone)]
pub struct Horizontal<Secondary, Spacing = Tight>
where
Secondary: SecondaryAlignment + VerticalAlignment,
Spacing: ElementSpacing,
{
pub(crate) secondary: Secondary,
pub(crate) spacing: Spacing,
}
impl<Secondary, Spacing> Horizontal<Secondary, Spacing>
where
Secondary: SecondaryAlignment + VerticalAlignment,
Spacing: ElementSpacing,
{
#[inline]
pub fn with_secondary_alignment<Sec: SecondaryAlignment + VerticalAlignment>(
self,
secondary: Sec,
) -> Horizontal<Sec, Spacing> {
Horizontal {
secondary,
spacing: self.spacing,
}
}
#[inline]
pub fn with_spacing<ElSpacing: ElementSpacing>(
self,
spacing: ElSpacing,
) -> Horizontal<Secondary, ElSpacing> {
Horizontal {
secondary: self.secondary,
spacing,
}
}
}
impl Default for Horizontal<vertical::Bottom, Tight> {
#[inline]
fn default() -> Self {
Self {
secondary: vertical::Bottom,
spacing: Tight,
}
}
}
impl<Secondary, Spacing> Orientation for Horizontal<Secondary, Spacing>
where
Secondary: SecondaryAlignment + VerticalAlignment,
Spacing: ElementSpacing,
{
type Secondary = Secondary;
#[inline]
fn destructure_size(size: Size) -> (u32, u32) {
(size.width, size.height)
}
#[inline]
fn create_size(primary: u32, secondary: u32) -> Size {
Size::new(primary, secondary)
}
#[inline]
fn place_first(&self, view: &mut impl View, bounds: Rectangle, count: u32) {
let (primary_size, _) = Self::destructure_size(bounds.size());
let view_bounds = view.bounds();
view.translate(Point::new(
self.spacing.align(
horizontal::Left,
view_bounds,
bounds,
0,
count,
primary_size,
),
Secondary::First::default().align(view_bounds, bounds),
));
}
#[inline]
fn place_nth(&self, view: &mut impl View, size: Size, previous: Rectangle, n: u32, count: u32) {
let (primary_size, _) = Self::destructure_size(size);
let view_bounds = view.bounds();
view.translate(Point::new(
self.spacing.align(
horizontal::LeftToRight,
view_bounds,
previous,
n,
count,
primary_size,
),
Secondary::default().align(view_bounds, previous),
));
}
#[inline]
fn adjust_size(self, size: Size, objects: u32) -> Size {
let (primary_size, secondary_size) = Self::destructure_size(size);
Self::create_size(
self.spacing.modify_measurement(primary_size, objects),
secondary_size,
)
}
}
#[derive(Copy, Clone)]
pub struct Vertical<Secondary, Spacing = Tight>
where
Secondary: SecondaryAlignment + HorizontalAlignment,
Spacing: ElementSpacing,
{
pub(crate) secondary: Secondary,
pub(crate) spacing: Spacing,
}
impl Default for Vertical<horizontal::Left, Tight> {
#[inline]
fn default() -> Self {
Self {
secondary: horizontal::Left,
spacing: Tight,
}
}
}
impl<Secondary, Spacing> Vertical<Secondary, Spacing>
where
Secondary: SecondaryAlignment + HorizontalAlignment,
Spacing: ElementSpacing,
{
#[inline]
pub fn with_secondary_alignment<Sec: SecondaryAlignment + HorizontalAlignment>(
self,
secondary: Sec,
) -> Vertical<Sec, Spacing> {
Vertical {
secondary,
spacing: self.spacing,
}
}
#[inline]
pub fn with_spacing<ElSpacing: ElementSpacing>(
self,
spacing: ElSpacing,
) -> Vertical<Secondary, ElSpacing> {
Vertical {
secondary: self.secondary,
spacing,
}
}
}
impl<Secondary, Spacing> Orientation for Vertical<Secondary, Spacing>
where
Secondary: SecondaryAlignment + HorizontalAlignment,
Spacing: ElementSpacing,
{
type Secondary = Secondary;
#[inline]
fn destructure_size(size: Size) -> (u32, u32) {
(size.height, size.width)
}
#[inline]
fn create_size(primary: u32, secondary: u32) -> Size {
Size::new(secondary, primary)
}
#[inline]
fn place_first(&self, view: &mut impl View, bounds: Rectangle, count: u32) {
let (primary_size, _) = Self::destructure_size(bounds.size());
let view_bounds = view.bounds();
view.translate(Point::new(
Secondary::First::default().align(view_bounds, bounds),
self.spacing
.align(vertical::Top, view_bounds, bounds, 0, count, primary_size),
));
}
#[inline]
fn place_nth(&self, view: &mut impl View, size: Size, previous: Rectangle, n: u32, count: u32) {
let (primary_size, _) = Self::destructure_size(size);
let view_bounds = view.bounds();
view.translate(Point::new(
Secondary::default().align(view_bounds, previous),
self.spacing.align(
vertical::TopToBottom,
view_bounds,
previous,
n,
count,
primary_size,
),
));
}
#[inline]
fn adjust_size(self, size: Size, objects: u32) -> Size {
let (primary_size, secondary_size) = Self::destructure_size(size);
Self::create_size(
self.spacing.modify_measurement(primary_size, objects),
secondary_size,
)
}
}