Archived
feat: port el-ui vessels — rename crates→vessels, add El source + manifests
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user