use crate::vec2; use super::*; #[derive(Clone, Copy, PartialEq)] pub struct Align { pub x: Option, pub y: Option, } impl Align { pub const TOP_LEFT: RegionAlign = RegionAlign::TOP_LEFT; pub const TOP_CENTER: RegionAlign = RegionAlign::TOP_CENTER; pub const TOP_RIGHT: RegionAlign = RegionAlign::TOP_RIGHT; pub const CENTER_LEFT: RegionAlign = RegionAlign::CENTER_LEFT; pub const CENTER: RegionAlign = RegionAlign::CENTER; pub const CENTER_RIGHT: RegionAlign = RegionAlign::CENTER_RIGHT; pub const BOT_LEFT: RegionAlign = RegionAlign::BOT_LEFT; pub const BOT_CENTER: RegionAlign = RegionAlign::BOT_CENTER; pub const BOT_RIGHT: RegionAlign = RegionAlign::BOT_RIGHT; pub const LEFT: CardinalAlign = CardinalAlign::LEFT; pub const H_CENTER: CardinalAlign = CardinalAlign::H_CENTER; pub const RIGHT: CardinalAlign = CardinalAlign::RIGHT; pub const TOP: CardinalAlign = CardinalAlign::TOP; pub const V_CENTER: CardinalAlign = CardinalAlign::V_CENTER; pub const BOT: CardinalAlign = CardinalAlign::BOT; pub fn tuple(&self) -> (Option, Option) { (self.x, self.y) } } /// Where a widget sits in a box longer than it is. The default is the middle, /// because the two edges are the ones that assume a direction: which of them /// is the near one depends on the writing system and on which way a container /// runs, and the middle is the same either way. #[derive(Debug, Clone, Copy, PartialEq)] pub struct AxisAlign(f32); impl AxisAlign { pub const NEG: Self = Self::new(0.0); pub const CENTER: Self = Self::new(0.5); pub const POS: Self = Self::new(1.0); pub const fn new(rel: f32) -> Self { Self(rel) } pub const fn rel(&self) -> f32 { self.0 } } impl Default for AxisAlign { fn default() -> Self { Self::CENTER } } pub struct CardinalAlign { axis: Axis, align: AxisAlign, } impl CardinalAlign { pub const LEFT: Self = Self::new(Axis::X, AxisAlign::NEG); pub const H_CENTER: Self = Self::new(Axis::X, AxisAlign::CENTER); pub const RIGHT: Self = Self::new(Axis::X, AxisAlign::POS); pub const TOP: Self = Self::new(Axis::Y, AxisAlign::NEG); pub const V_CENTER: Self = Self::new(Axis::Y, AxisAlign::CENTER); pub const BOT: Self = Self::new(Axis::Y, AxisAlign::POS); pub const fn new(axis: Axis, align: AxisAlign) -> Self { Self { axis, align } } } #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct RegionAlign { pub x: AxisAlign, pub y: AxisAlign, } impl RegionAlign { /// Both axes at the near edge. What a container passes as an override for /// a child it is going to position itself. pub const NEAR: Self = Self { x: AxisAlign::NEG, y: AxisAlign::NEG, }; pub fn axis(&self, axis: Axis) -> AxisAlign { match axis { Axis::X => self.x, Axis::Y => self.y, } } pub fn axis_mut(&mut self, axis: Axis) -> &mut AxisAlign { match axis { Axis::X => &mut self.x, Axis::Y => &mut self.y, } } } impl RegionAlign { pub const TOP_LEFT: Self = Self::new(AxisAlign::NEG, AxisAlign::NEG); pub const TOP_CENTER: Self = Self::new(AxisAlign::CENTER, AxisAlign::NEG); pub const TOP_RIGHT: Self = Self::new(AxisAlign::POS, AxisAlign::NEG); pub const CENTER_LEFT: Self = Self::new(AxisAlign::NEG, AxisAlign::CENTER); pub const CENTER: Self = Self::new(AxisAlign::CENTER, AxisAlign::CENTER); pub const CENTER_RIGHT: Self = Self::new(AxisAlign::POS, AxisAlign::CENTER); pub const BOT_LEFT: Self = Self::new(AxisAlign::NEG, AxisAlign::POS); pub const BOT_CENTER: Self = Self::new(AxisAlign::CENTER, AxisAlign::POS); pub const BOT_RIGHT: Self = Self::new(AxisAlign::POS, AxisAlign::POS); pub const fn new(x: AxisAlign, y: AxisAlign) -> Self { Self { x, y } } pub const fn rel(&self) -> Vec2 { vec2(self.x.rel(), self.y.rel()) } } impl UiVec2 { pub fn partial_align(&self, align: Align) -> UiRegion { UiRegion { x: if let Some(align) = align.x { self.x.align(align) } else { UiSpan::FULL }, y: if let Some(align) = align.y { self.y.align(align) } else { UiSpan::FULL }, } } pub fn align(&self, align: RegionAlign) -> UiRegion { UiRegion { x: self.x.align(align.x), y: self.y.align(align.y), } } } impl Vec2 { pub fn partial_align(&self, align: Align) -> UiRegion { let s = UiVec2::from(*self); UiRegion { x: if let Some(align) = align.x { s.x.align(align) } else { UiSpan::FULL }, y: if let Some(align) = align.y { s.y.align(align) } else { UiSpan::FULL }, } } pub fn align(&self, align: RegionAlign) -> UiRegion { let s = UiVec2::from(*self); UiRegion { x: s.x.align(align.x), y: s.y.align(align.y), } } } impl UiScalar { pub const fn align(&self, align: AxisAlign) -> UiSpan { let rel = align.rel(); let mut start = UiScalar::rel(rel); start.px -= self.px * rel; start.rel -= self.rel * rel; let mut end = UiScalar::rel(rel); end.px += self.px * (1.0 - rel); end.rel += self.rel * (1.0 - rel); UiSpan { start, end } } } impl From for Align { fn from(region: RegionAlign) -> Self { Self { x: Some(region.x), y: Some(region.y), } } } impl From for RegionAlign { fn from(align: Align) -> Self { Self { x: align.x.unwrap_or(AxisAlign::CENTER), y: align.y.unwrap_or(AxisAlign::CENTER), } } } impl From for RegionAlign { fn from(align: CardinalAlign) -> Self { Align::from(align).into() } } impl From for Align { fn from(cardinal: CardinalAlign) -> Self { let align = Some(cardinal.align); match cardinal.axis { Axis::X => Self { x: align, y: None }, Axis::Y => Self { x: None, y: align }, } } } const impl From for UiVec2 { fn from(align: RegionAlign) -> Self { Self::rel(align.rel()) } } impl RegionAlign { pub const fn pos(self) -> UiVec2 { UiVec2::from(self) } }