2024-02-20 10:30:26 -06:00
|
|
|
//! Layout related types and functions
|
|
|
|
|
|
|
|
use glam::Vec2;
|
|
|
|
|
2024-02-20 12:48:32 -06:00
|
|
|
/// Alignment along a single axis
|
2024-02-20 10:30:26 -06:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, PartialOrd, Ord)]
|
|
|
|
pub enum Alignment {
|
2024-02-20 12:48:32 -06:00
|
|
|
/// Put the element at the beginning of the axis\
|
|
|
|
/// (left for horizontal, top for vertical alignment)
|
2024-02-20 10:30:26 -06:00
|
|
|
#[default]
|
|
|
|
Begin = 0,
|
2024-02-20 12:57:02 -06:00
|
|
|
|
|
|
|
/// Put the element in the center
|
2024-02-20 10:30:26 -06:00
|
|
|
Center = 1,
|
2024-02-20 12:57:02 -06:00
|
|
|
|
2024-02-20 12:48:32 -06:00
|
|
|
/// Put the element at the end of the axis\
|
|
|
|
/// (right for horizontal, bottom for vertical alignment)
|
2024-02-20 10:30:26 -06:00
|
|
|
End = 2,
|
|
|
|
}
|
|
|
|
|
2024-02-20 12:48:32 -06:00
|
|
|
/// Represents alignment in 2D space
|
|
|
|
///
|
|
|
|
/// - `horizontal` - alignment *along* x-axis (horizontal)\
|
|
|
|
/// - `vertical` - alignment *along* y-axis (vertical)
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, PartialOrd, Ord)]
|
|
|
|
pub struct Alignment2d {
|
|
|
|
/// Alignment *along* horizontal axis (X)
|
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// ├───────[ ]──────┤
|
|
|
|
/// ↑↑ ↑↑ ↑↑
|
|
|
|
/// Begin Center End
|
|
|
|
/// ```
|
|
|
|
pub horizontal: Alignment,
|
|
|
|
|
|
|
|
/// Alignment *along* vertical axis (Y)
|
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// ┬ ←─ Begin
|
|
|
|
/// │
|
|
|
|
/// [ ] ←─ Center
|
|
|
|
/// │
|
|
|
|
/// ┴ ←─ End
|
|
|
|
/// ```
|
|
|
|
pub vertical: Alignment,
|
|
|
|
}
|
|
|
|
|
2024-02-20 12:57:02 -06:00
|
|
|
impl Alignment2d {
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Create a new `Alignment2d` with the same alignment for both axes
|
2024-02-20 12:57:02 -06:00
|
|
|
#[inline]
|
|
|
|
pub const fn all(alignment: Alignment) -> Self {
|
|
|
|
Self {
|
|
|
|
horizontal: alignment,
|
|
|
|
vertical: alignment,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-20 12:48:32 -06:00
|
|
|
impl From<(Alignment, Alignment)> for Alignment2d {
|
2024-02-20 12:57:02 -06:00
|
|
|
#[inline]
|
2024-02-20 12:48:32 -06:00
|
|
|
fn from((horizontal, vertical): (Alignment, Alignment)) -> Self {
|
|
|
|
Self { horizontal, vertical }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<[Alignment; 2]> for Alignment2d {
|
2024-02-20 12:57:02 -06:00
|
|
|
#[inline]
|
2024-02-20 12:48:32 -06:00
|
|
|
fn from([horizontal, vertical]: [Alignment; 2]) -> Self {
|
|
|
|
Self { horizontal, vertical }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Alignment> for Alignment2d {
|
2024-02-20 12:57:02 -06:00
|
|
|
#[inline]
|
2024-02-20 12:48:32 -06:00
|
|
|
fn from(alignment: Alignment) -> Self {
|
2024-02-20 12:57:02 -06:00
|
|
|
Self::all(alignment)
|
2024-02-20 12:48:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Represents a single size dimension of an UI element.\
|
|
|
|
/// Can be either a static size in pixels, a fraction the parent size or auto-calculated\
|
|
|
|
/// (Meaning of `auto` is entirely dependent on the element).
|
2024-02-26 09:33:55 -06:00
|
|
|
#[derive(Default, Debug, Clone, Copy, PartialEq)]
|
2024-02-20 10:30:26 -06:00
|
|
|
pub enum UiSize {
|
|
|
|
#[default]
|
2024-02-26 09:33:55 -06:00
|
|
|
/// Automatically calculate size based on content
|
2024-02-20 10:30:26 -06:00
|
|
|
Auto,
|
2024-02-26 09:33:55 -06:00
|
|
|
/// Size as a ratio of parent size\
|
|
|
|
/// Valid range: 0.0-1.0 (0-100%)
|
2024-02-27 10:56:46 -06:00
|
|
|
///
|
|
|
|
/// Out of range values are allowed, but are not guaranteed to work as expected\
|
|
|
|
/// (especially with negative values)
|
2024-02-20 10:30:26 -06:00
|
|
|
Fraction(f32),
|
2024-02-26 09:33:55 -06:00
|
|
|
/// Static size in pixels
|
2024-02-20 10:30:26 -06:00
|
|
|
Static(f32),
|
|
|
|
}
|
|
|
|
|
2024-02-26 09:33:55 -06:00
|
|
|
impl From<f32> for UiSize {
|
|
|
|
#[inline]
|
|
|
|
fn from(value: f32) -> Self {
|
|
|
|
Self::Static(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default, Debug, Clone, Copy, PartialEq)]
|
|
|
|
pub struct UiSize2d {
|
|
|
|
pub width: UiSize,
|
|
|
|
pub height: UiSize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<(UiSize, UiSize)> for UiSize2d {
|
|
|
|
#[inline]
|
|
|
|
fn from((width, height): (UiSize, UiSize)) -> Self {
|
|
|
|
Self { width, height }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//XXX: should this exist?
|
|
|
|
impl From<UiSize> for UiSize2d {
|
|
|
|
#[inline]
|
|
|
|
fn from(size: UiSize) -> Self {
|
|
|
|
Self {
|
|
|
|
width: size,
|
|
|
|
height: size,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO?: add `UiSize2d` from `(Into<UiSize>, Into<UiSize>)` or Into<UiSize> conversion
|
|
|
|
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Constructs a `UiSize` or `UiSize2d` from a literal or expression
|
|
|
|
///
|
2024-02-26 09:33:55 -06:00
|
|
|
/// # Syntax:
|
|
|
|
/// - `auto` - `UiSize::Auto`
|
|
|
|
/// - `x` - `UiSize::Static(x)`
|
2024-02-27 10:56:46 -06:00
|
|
|
/// - `x%` - `UiSize::Fraction(x / 100.)` *(literal only)*
|
|
|
|
/// - `x/` - `UiSize::Fraction(x)`
|
|
|
|
///
|
|
|
|
/// ...where `x` is a literal, identifier or an expression wrapped in parentheses
|
2024-02-26 09:33:55 -06:00
|
|
|
///
|
2024-02-27 10:56:46 -06:00
|
|
|
/// # Note:
|
|
|
|
/// - If a single argument is provided, it creates a `UiSize` using the rules specified above\
|
|
|
|
/// - If two arguments are provided, it creates a `UiSize2d` with the first value as width and the second as height\
|
|
|
|
/// Example: `size!(100, 50%)` creates a `UiSize2d` with width `100` (`UiSize::Static(100.)`) and height `50%` (`UiSize::Fraction(0.5)`)
|
|
|
|
/// - `%` syntax is only valid for literals (`50%`), not expressions or identidiers.\
|
|
|
|
/// Use `/` instead (`(0.5 * x)/`, `x/`), but be aware of the different range (0.0-1.0) \
|
|
|
|
/// - Expressions must be wrapped in parentheses (for example: `(x + 5)`).\
|
|
|
|
/// This does not apply to single identifiers (`x`) or literals (`5`)
|
2024-02-26 09:33:55 -06:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! size {
|
|
|
|
(auto) => {
|
|
|
|
$crate::layout::UiSize::Auto
|
|
|
|
};
|
2024-02-27 10:56:46 -06:00
|
|
|
|
2024-02-26 09:33:55 -06:00
|
|
|
($x:literal) => {
|
|
|
|
$crate::layout::UiSize::Static($x as f32)
|
|
|
|
};
|
|
|
|
($x:literal %) => {
|
|
|
|
$crate::layout::UiSize::Fraction($x as f32 / 100.)
|
|
|
|
};
|
2024-02-27 10:56:46 -06:00
|
|
|
($x:literal /) => {
|
|
|
|
$crate::layout::UiSize::Fraction($x as f32)
|
|
|
|
};
|
|
|
|
|
|
|
|
($x:ident) => {
|
|
|
|
$crate::layout::UiSize::Static($x as f32)
|
|
|
|
};
|
|
|
|
($x:ident /) => {
|
|
|
|
$crate::layout::UiSize::Fraction($x as f32)
|
|
|
|
};
|
|
|
|
|
|
|
|
(($x:expr)) => {
|
|
|
|
$crate::layout::UiSize::Static(($x) as f32)
|
|
|
|
};
|
|
|
|
(($x:expr) /) => {
|
|
|
|
$crate::layout::UiSize::Fraction(($x) as f32)
|
|
|
|
};
|
|
|
|
|
|
|
|
($x:tt , $y:tt $($ys:tt)?) => {
|
2024-02-26 09:33:55 -06:00
|
|
|
$crate::layout::UiSize2d {
|
|
|
|
width: $crate::layout::size!($x),
|
|
|
|
height: $crate::layout::size!($y $($ys)?),
|
|
|
|
}
|
|
|
|
};
|
2024-02-27 10:56:46 -06:00
|
|
|
($x:tt $($xs:tt)? , $y:tt $($ys:tt)?) => {
|
2024-02-26 09:33:55 -06:00
|
|
|
$crate::layout::UiSize2d {
|
|
|
|
width: $crate::layout::size!($x $($xs)?),
|
|
|
|
height: $crate::layout::size!($y $($ys)?),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
pub use size;
|
|
|
|
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Represents the direction of the layout\
|
|
|
|
/// (for example, the direction of a container's children)\
|
|
|
|
///
|
|
|
|
/// - `Vertical` - Children are laid out from top to bottom\
|
|
|
|
/// - `Horizontal` - Children are laid out from left to right
|
2024-02-20 10:30:26 -06:00
|
|
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
pub enum UiDirection {
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Children are laid out from top to bottom
|
2024-02-20 10:30:26 -06:00
|
|
|
#[default]
|
|
|
|
Vertical,
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Children are laid out from left to right
|
2024-02-20 10:30:26 -06:00
|
|
|
Horizontal,
|
|
|
|
}
|
|
|
|
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Represents the layout information required to measure, layout and render an element.\
|
|
|
|
/// Includes the position, maximum size, direction of the layout and other information
|
2024-02-20 10:30:26 -06:00
|
|
|
pub struct LayoutInfo {
|
2024-02-27 10:56:46 -06:00
|
|
|
/// Screen-space coordinates of the top-left corner of the element.\
|
|
|
|
/// Use this value during the layout step to render the element
|
|
|
|
///
|
|
|
|
/// Not available during the measure step (will be set to zero)
|
2024-02-20 10:30:26 -06:00
|
|
|
pub position: Vec2,
|
2024-02-27 10:56:46 -06:00
|
|
|
|
|
|
|
/// Maximum size the element is allowed to take up
|
2024-02-20 10:30:26 -06:00
|
|
|
pub max_size: Vec2,
|
2024-02-27 10:56:46 -06:00
|
|
|
|
|
|
|
/// Current direction of the layout\
|
|
|
|
/// (Usually matches direction of the parent container)
|
2024-02-20 10:30:26 -06:00
|
|
|
pub direction: UiDirection,
|
|
|
|
}
|