feat: port el-ui vessels — rename crates→vessels, add El source + manifests

This commit is contained in:
Will Anderson
2026-05-05 04:19:22 -05:00
parent b580a63540
commit faee6fdb25
145 changed files with 4050 additions and 12 deletions
+162
View File
@@ -0,0 +1,162 @@
/// Layout constraints — what the parent is offering the child.
///
/// A parent passes a LayoutConstraints to each child during layout.
/// The child must produce a size within these constraints.
/// Constraints flow down; sizes flow back up.
/// Constraints passed from a parent to a child during layout.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LayoutConstraints {
/// Minimum width the child must be (dp).
pub min_width: f32,
/// Maximum width available to the child (dp). f32::INFINITY = unbounded.
pub max_width: f32,
/// Minimum height the child must be (dp).
pub min_height: f32,
/// Maximum height available to the child (dp). f32::INFINITY = unbounded.
pub max_height: f32,
}
impl LayoutConstraints {
/// Unconstrained — the child can be any size.
pub fn unbounded() -> Self {
Self {
min_width: 0.0,
max_width: f32::INFINITY,
min_height: 0.0,
max_height: f32::INFINITY,
}
}
/// Constrained to a specific width, unconstrained height.
pub fn with_max_width(max_width: f32) -> Self {
Self {
min_width: 0.0,
max_width,
min_height: 0.0,
max_height: f32::INFINITY,
}
}
/// Constrained to an exact width and height.
pub fn tight(width: f32, height: f32) -> Self {
Self {
min_width: width,
max_width: width,
min_height: height,
max_height: height,
}
}
/// Return constraints loosened to allow any size up to the maximums.
pub fn loosen(&self) -> Self {
Self {
min_width: 0.0,
max_width: self.max_width,
min_height: 0.0,
max_height: self.max_height,
}
}
/// Deflate the constraints by padding amounts.
/// Useful when a parent applies its own padding before offering space to a child.
pub fn deflate(&self, horizontal: f32, vertical: f32) -> Self {
Self {
min_width: (self.min_width - horizontal).max(0.0),
max_width: (self.max_width - horizontal).max(0.0),
min_height: (self.min_height - vertical).max(0.0),
max_height: (self.max_height - vertical).max(0.0),
}
}
/// Is the width dimension bounded?
pub fn has_bounded_width(&self) -> bool {
self.max_width.is_finite()
}
/// Is the height dimension bounded?
pub fn has_bounded_height(&self) -> bool {
self.max_height.is_finite()
}
/// Clamp a proposed size to fit within these constraints.
pub fn clamp_size(&self, width: f32, height: f32) -> (f32, f32) {
(
width.clamp(self.min_width, self.max_width),
height.clamp(self.min_height, self.max_height),
)
}
}
/// The size a child reports back to its parent after layout.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Size {
pub width: f32,
pub height: f32,
}
impl Size {
pub fn new(width: f32, height: f32) -> Self {
Self { width, height }
}
pub fn zero() -> Self {
Self { width: 0.0, height: 0.0 }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unbounded_has_no_max() {
let c = LayoutConstraints::unbounded();
assert!(c.max_width.is_infinite());
assert!(c.max_height.is_infinite());
}
#[test]
fn tight_constraints() {
let c = LayoutConstraints::tight(100.0, 50.0);
assert_eq!(c.min_width, 100.0);
assert_eq!(c.max_width, 100.0);
}
#[test]
fn deflate_reduces_available_space() {
let c = LayoutConstraints::tight(200.0, 100.0);
let deflated = c.deflate(16.0, 8.0);
assert_eq!(deflated.max_width, 184.0);
assert_eq!(deflated.max_height, 92.0);
}
#[test]
fn deflate_does_not_go_negative() {
let c = LayoutConstraints::tight(10.0, 10.0);
let deflated = c.deflate(20.0, 20.0);
assert_eq!(deflated.max_width, 0.0);
assert_eq!(deflated.max_height, 0.0);
}
#[test]
fn clamp_size() {
let c = LayoutConstraints {
min_width: 50.0,
max_width: 200.0,
min_height: 30.0,
max_height: 100.0,
};
let (w, h) = c.clamp_size(250.0, 20.0);
assert_eq!(w, 200.0);
assert_eq!(h, 30.0);
}
#[test]
fn bounded_width_detection() {
let bounded = LayoutConstraints::with_max_width(400.0);
let unbounded = LayoutConstraints::unbounded();
assert!(bounded.has_bounded_width());
assert!(!unbounded.has_bounded_width());
}
}