#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
Left,
Center,
Right,
Top,
Bottom,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HorizontalAlignment {
Left,
Center,
Right,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerticalAlignment {
Top,
Center,
Bottom,
}
impl HorizontalAlignment {
pub const fn from_alignment(alignment: Alignment) -> Option<Self> {
match alignment {
Alignment::Left => Some(Self::Left),
Alignment::Center => Some(Self::Center),
Alignment::Right => Some(Self::Right),
Alignment::Top | Alignment::Bottom => None,
}
}
}
impl VerticalAlignment {
pub const fn from_alignment(alignment: Alignment) -> Option<Self> {
match alignment {
Alignment::Top => Some(Self::Top),
Alignment::Center => Some(Self::Center),
Alignment::Bottom => Some(Self::Bottom),
Alignment::Left | Alignment::Right => None,
}
}
}
impl HorizontalAlignment {
pub fn parse_str(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"left" | "l" => Some(Self::Left),
"center" | "centre" | "c" => Some(Self::Center),
"right" | "r" => Some(Self::Right),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Left => "left",
Self::Center => "center",
Self::Right => "right",
}
}
pub const fn is_left(&self) -> bool {
matches!(self, Self::Left)
}
pub const fn is_center(&self) -> bool {
matches!(self, Self::Center)
}
pub const fn is_right(&self) -> bool {
matches!(self, Self::Right)
}
}
impl VerticalAlignment {
pub fn parse_str(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"top" | "t" => Some(Self::Top),
"center" | "centre" | "c" => Some(Self::Center),
"bottom" | "b" => Some(Self::Bottom),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Top => "top",
Self::Center => "center",
Self::Bottom => "bottom",
}
}
pub const fn is_top(&self) -> bool {
matches!(self, Self::Top)
}
pub const fn is_center(&self) -> bool {
matches!(self, Self::Center)
}
pub const fn is_bottom(&self) -> bool {
matches!(self, Self::Bottom)
}
}
impl Alignment {
pub fn parse_str(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"left" | "l" => Some(Self::Left),
"center" | "centre" | "c" => Some(Self::Center),
"right" | "r" => Some(Self::Right),
"top" | "t" => Some(Self::Top),
"bottom" | "b" => Some(Self::Bottom),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Left => "left",
Self::Center => "center",
Self::Right => "right",
Self::Top => "top",
Self::Bottom => "bottom",
}
}
pub const fn is_horizontal(&self) -> bool {
matches!(self, Self::Left | Self::Center | Self::Right)
}
pub const fn is_vertical(&self) -> bool {
matches!(self, Self::Top | Self::Center | Self::Bottom)
}
pub const fn to_horizontal(&self) -> Option<HorizontalAlignment> {
match self {
Self::Left => Some(HorizontalAlignment::Left),
Self::Center => Some(HorizontalAlignment::Center),
Self::Right => Some(HorizontalAlignment::Right),
Self::Top | Self::Bottom => None,
}
}
pub const fn to_vertical(&self) -> Option<VerticalAlignment> {
match self {
Self::Top => Some(VerticalAlignment::Top),
Self::Center => Some(VerticalAlignment::Center),
Self::Bottom => Some(VerticalAlignment::Bottom),
Self::Left | Self::Right => None,
}
}
pub const fn is_left(&self) -> bool {
matches!(self, Self::Left)
}
pub const fn is_center(&self) -> bool {
matches!(self, Self::Center)
}
pub const fn is_right(&self) -> bool {
matches!(self, Self::Right)
}
pub const fn is_top(&self) -> bool {
matches!(self, Self::Top)
}
pub const fn is_bottom(&self) -> bool {
matches!(self, Self::Bottom)
}
pub fn from_components(
horizontal: HorizontalAlignment,
vertical: VerticalAlignment,
) -> (Self, Self) {
(horizontal.into(), vertical.into())
}
pub const fn opposite(&self) -> Self {
match self {
Self::Left => Self::Right,
Self::Center => Self::Center,
Self::Right => Self::Left,
Self::Top => Self::Bottom,
Self::Bottom => Self::Top,
}
}
pub fn css_text_align(&self) -> Option<&'static str> {
match self {
Self::Left => Some("left"),
Self::Center => Some("center"),
Self::Right => Some("right"),
_ => None,
}
}
pub fn css_vertical_align(&self) -> Option<&'static str> {
match self {
Self::Top => Some("top"),
Self::Center => Some("middle"),
Self::Bottom => Some("bottom"),
_ => None,
}
}
}
impl From<HorizontalAlignment> for Alignment {
fn from(value: HorizontalAlignment) -> Self {
match value {
HorizontalAlignment::Left => Self::Left,
HorizontalAlignment::Center => Self::Center,
HorizontalAlignment::Right => Self::Right,
}
}
}
impl From<VerticalAlignment> for Alignment {
fn from(value: VerticalAlignment) -> Self {
match value {
VerticalAlignment::Top => Self::Top,
VerticalAlignment::Center => Self::Center,
VerticalAlignment::Bottom => Self::Bottom,
}
}
}
impl TryFrom<Alignment> for HorizontalAlignment {
type Error = ();
fn try_from(value: Alignment) -> Result<Self, Self::Error> {
match value {
Alignment::Left => Ok(Self::Left),
Alignment::Center => Ok(Self::Center),
Alignment::Right => Ok(Self::Right),
_ => Err(()),
}
}
}
impl TryFrom<Alignment> for VerticalAlignment {
type Error = ();
fn try_from(value: Alignment) -> Result<Self, Self::Error> {
match value {
Alignment::Top => Ok(Self::Top),
Alignment::Center => Ok(Self::Center),
Alignment::Bottom => Ok(Self::Bottom),
_ => Err(()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn axis_alignment_mapping_is_explicit() {
assert_eq!(
HorizontalAlignment::from_alignment(Alignment::Left),
Some(HorizontalAlignment::Left)
);
assert_eq!(HorizontalAlignment::from_alignment(Alignment::Top), None);
assert_eq!(
VerticalAlignment::from_alignment(Alignment::Bottom),
Some(VerticalAlignment::Bottom)
);
assert_eq!(VerticalAlignment::from_alignment(Alignment::Right), None);
}
}