Archived
179 lines
4.9 KiB
Rust
179 lines
4.9 KiB
Rust
/// FlexLayout — the underlying flex engine for VStack, HStack.
|
|
///
|
|
/// This is the power behind the stacks. Most developers use VStack/HStack
|
|
/// directly; FlexLayout is available when you need full control.
|
|
|
|
/// Direction of the flex axis.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum FlexDirection {
|
|
/// Children arranged top-to-bottom (VStack).
|
|
Column,
|
|
/// Children arranged left-to-right (HStack) — respects RTL automatically.
|
|
Row,
|
|
/// Like Column, but children wrap to new columns when they overflow.
|
|
ColumnWrap,
|
|
/// Like Row, but children wrap to new rows when they overflow.
|
|
RowWrap,
|
|
}
|
|
|
|
impl FlexDirection {
|
|
pub fn is_horizontal(&self) -> bool {
|
|
matches!(self, FlexDirection::Row | FlexDirection::RowWrap)
|
|
}
|
|
|
|
pub fn is_vertical(&self) -> bool {
|
|
matches!(self, FlexDirection::Column | FlexDirection::ColumnWrap)
|
|
}
|
|
|
|
pub fn wraps(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
FlexDirection::ColumnWrap | FlexDirection::RowWrap
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Alignment along the cross axis.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum CrossAxisAlignment {
|
|
/// Stretch children to fill the cross axis.
|
|
Stretch,
|
|
/// Align children to the start of the cross axis.
|
|
Start,
|
|
/// Center children on the cross axis.
|
|
Center,
|
|
/// Align children to the end of the cross axis.
|
|
End,
|
|
/// Align text baselines (horizontal stacks only).
|
|
Baseline,
|
|
}
|
|
|
|
/// Alignment along the main axis.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum MainAxisAlignment {
|
|
/// Pack children toward the start.
|
|
Start,
|
|
/// Center children.
|
|
Center,
|
|
/// Pack children toward the end.
|
|
End,
|
|
/// Distribute space between children.
|
|
SpaceBetween,
|
|
/// Distribute space around children.
|
|
SpaceAround,
|
|
/// Distribute space evenly around children.
|
|
SpaceEvenly,
|
|
}
|
|
|
|
/// How much space the main axis should occupy.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum MainAxisSize {
|
|
/// Shrink to minimum size needed.
|
|
Min,
|
|
/// Expand to fill all available space.
|
|
Max,
|
|
}
|
|
|
|
/// Logical horizontal alignment (RTL-aware).
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum HAlign {
|
|
/// Toward the reading-start (left in LTR, right in RTL).
|
|
Leading,
|
|
Center,
|
|
/// Toward the reading-end (right in LTR, left in RTL).
|
|
Trailing,
|
|
}
|
|
|
|
/// Vertical alignment.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum VAlign {
|
|
Top,
|
|
Center,
|
|
Bottom,
|
|
Baseline,
|
|
}
|
|
|
|
/// Full flex layout specification.
|
|
#[derive(Debug, Clone)]
|
|
pub struct FlexLayout {
|
|
pub direction: FlexDirection,
|
|
pub main_axis_alignment: MainAxisAlignment,
|
|
pub cross_axis_alignment: CrossAxisAlignment,
|
|
pub main_axis_size: MainAxisSize,
|
|
/// Gap between children in dp.
|
|
pub gap: u32,
|
|
}
|
|
|
|
impl FlexLayout {
|
|
/// VStack defaults (column, wrapping, leading-aligned).
|
|
pub fn vstack(spacing: u32, wrap: bool) -> Self {
|
|
Self {
|
|
direction: if wrap {
|
|
FlexDirection::ColumnWrap
|
|
} else {
|
|
FlexDirection::Column
|
|
},
|
|
main_axis_alignment: MainAxisAlignment::Start,
|
|
cross_axis_alignment: CrossAxisAlignment::Stretch,
|
|
main_axis_size: MainAxisSize::Max,
|
|
gap: spacing,
|
|
}
|
|
}
|
|
|
|
/// HStack defaults (row, wrapping, center-aligned vertically).
|
|
pub fn hstack(spacing: u32, wrap: bool) -> Self {
|
|
Self {
|
|
direction: if wrap {
|
|
FlexDirection::RowWrap
|
|
} else {
|
|
FlexDirection::Row
|
|
},
|
|
main_axis_alignment: MainAxisAlignment::Start,
|
|
cross_axis_alignment: CrossAxisAlignment::Center,
|
|
main_axis_size: MainAxisSize::Max,
|
|
gap: spacing,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn flex_direction_horizontal() {
|
|
assert!(FlexDirection::Row.is_horizontal());
|
|
assert!(FlexDirection::RowWrap.is_horizontal());
|
|
assert!(!FlexDirection::Column.is_horizontal());
|
|
}
|
|
|
|
#[test]
|
|
fn flex_direction_vertical() {
|
|
assert!(FlexDirection::Column.is_vertical());
|
|
assert!(!FlexDirection::Row.is_vertical());
|
|
}
|
|
|
|
#[test]
|
|
fn flex_direction_wraps() {
|
|
assert!(FlexDirection::RowWrap.wraps());
|
|
assert!(!FlexDirection::Row.wraps());
|
|
}
|
|
|
|
#[test]
|
|
fn vstack_layout_defaults() {
|
|
let layout = FlexLayout::vstack(8, true);
|
|
assert!(layout.direction.is_vertical());
|
|
assert!(layout.direction.wraps());
|
|
assert_eq!(layout.gap, 8);
|
|
}
|
|
|
|
#[test]
|
|
fn hstack_layout_defaults() {
|
|
let layout = FlexLayout::hstack(16, false);
|
|
assert!(layout.direction.is_horizontal());
|
|
assert!(!layout.direction.wraps());
|
|
assert_eq!(layout.gap, 16);
|
|
assert_eq!(layout.cross_axis_alignment, CrossAxisAlignment::Center);
|
|
}
|
|
}
|