Files
pulse-trader/pulse-ui/src/layout.rs
T
2026-07-14 11:35:12 -04:00

145 lines
3.7 KiB
Rust

#[derive(Debug, Clone, Copy)]
pub enum Size {
Fixed(u16),
Flex(u16),
Percent(u16),
}
#[derive(Debug, Clone, Copy)]
pub struct Rect {
pub x: u16,
pub y: u16,
pub width: u16,
pub height: u16,
}
#[derive(Debug, Clone)]
pub enum LayoutItem {
Rows { unit: Size, items: Vec<LayoutItem> },
Columns { unit: Size, items: Vec<LayoutItem> },
Widget(Size),
}
#[derive(Debug, Clone)]
pub struct Allocation {
pub widget_alloc: Vec<Rect>,
pub frame_alloc: Vec<Rect>,
}
impl LayoutItem {
pub fn allocate(&self, alloc: &Rect, frame: &mut Vec<Rect>, widgets: &mut Vec<Rect>) {
match self {
Self::Rows { items, .. } | Self::Columns { items, .. } => {
frame.push(*alloc);
let is_row = matches!(self, Self::Rows { .. });
let allocation = if is_row { alloc.height } else { alloc.width };
let remaining = allocation
- items
.iter()
.map(|item| item.get_size().get_fixed(alloc.height))
.sum::<u16>();
let total_weight = items
.iter()
.map(|item| item.get_size().get_flex())
.sum::<u16>();
let mut curr = if is_row { alloc.y } else { alloc.x };
for item in items {
let size = item.get_size();
let unit_alloc = size.get(allocation, remaining, total_weight);
let item_alloc = if is_row {
Rect {
width: alloc.width,
height: unit_alloc,
x: alloc.x,
y: curr,
}
} else {
Rect {
width: unit_alloc,
height: alloc.height,
x: curr,
y: alloc.y,
}
};
curr += unit_alloc;
item.allocate(&item_alloc, frame, widgets);
}
}
Self::Widget(_) => {
widgets.push(*alloc);
}
}
}
pub fn get_size<'a>(&'a self) -> &'a Size {
match self {
Self::Rows { unit, .. } => unit,
Self::Columns { unit, .. } => unit,
Self::Widget(unit) => unit,
}
}
}
impl Size {
pub fn get_fixed(&self, alloc: u16) -> u16 {
match self {
Self::Fixed(v) => *v,
Self::Percent(v) => alloc * (*v) / 100,
Self::Flex(_) => 0,
}
}
pub fn get_flex(&self) -> u16 {
match self {
Self::Flex(f) => *f,
_ => 0,
}
}
pub fn get(&self, alloc: u16, remaining: u16, total_weight: u16) -> u16 {
match self {
Self::Fixed(v) => *v,
Self::Percent(v) => alloc * (*v) / 100,
Self::Flex(v) => {
if total_weight == 0 {
0
} else {
remaining * v / total_weight
}
}
}
}
}
impl Rect {
pub fn allocate(&self, layout: &LayoutItem) -> Allocation {
let mut widget_alloc = Vec::new();
let mut frame_alloc = Vec::new();
layout.allocate(self, &mut frame_alloc, &mut widget_alloc);
Allocation {
widget_alloc,
frame_alloc,
}
}
}
pub fn layout(rows: Vec<LayoutItem>) -> LayoutItem {
LayoutItem::Rows {
unit: Size::Percent(100),
items: rows,
}
}