initial commit

This commit is contained in:
2025-08-08 18:22:52 -04:00
parent eba8481bde
commit 56beeb80f3
31 changed files with 1223 additions and 1197 deletions

66
src/layout/mod.rs Normal file
View File

@@ -0,0 +1,66 @@
mod node;
pub use node::*;
use crate::primitive::{Color, Painter};
pub type UIColor = Color<u8>;
pub trait UINode: 'static {
fn draw(&self, painter: &mut Painter);
}
pub struct UI {
base: Box<dyn UINode>,
}
impl UI {
pub fn to_primitives(&self) -> Painter {
let mut painter = Painter::default();
self.base.draw(&mut painter);
painter
}
}
impl<N: UINode> From<N> for UI {
fn from(node: N) -> Self {
Self {
base: Box::new(node),
}
}
}
impl UINode for Box<dyn UINode> {
fn draw(&self, painter: &mut Painter) {
self.as_ref().draw(painter);
}
}
pub trait NodeArray<const LEN: usize> {
fn to_arr(self) -> [Box<dyn UINode>; LEN];
}
// I hate this language it's so bad why do I even use it
macro_rules! impl_node_arr {
($n:expr;$($T:tt)+) => {
impl<$($T: UINode,)*> NodeArray<$n> for ($($T,)*) {
fn to_arr(self) -> [Box<dyn UINode>; $n] {
#[allow(non_snake_case)]
let ($($T,)*) = self;
[$(Box::new($T),)*]
}
}
};
}
impl_node_arr!(1;A);
impl_node_arr!(2;A B);
impl_node_arr!(3;A B C);
impl_node_arr!(4;A B C D);
impl_node_arr!(5;A B C D E);
impl_node_arr!(6;A B C D E F);
impl_node_arr!(7;A B C D E F G);
impl_node_arr!(8;A B C D E F G H);
impl_node_arr!(9;A B C D E F G H I);
impl_node_arr!(10;A B C D E F G H I J);
impl_node_arr!(11;A B C D E F G H I J K);
impl_node_arr!(12;A B C D E F G H I J K L);

164
src/layout/node.rs Normal file
View File

@@ -0,0 +1,164 @@
use std::ops::Range;
use crate::{
primitive::{Axis, Painter, RoundedRectData, UIRegion},
NodeArray, UIColor, UINode,
};
#[derive(Clone, Copy)]
pub struct RoundedRect {
pub color: UIColor,
pub radius: f32,
pub thickness: f32,
pub inner_radius: f32,
}
impl RoundedRect {
pub fn color(mut self, color: UIColor) -> Self {
self.color = color;
self
}
}
impl UINode for RoundedRect {
fn draw(&self, painter: &mut Painter) {
painter.write(RoundedRectData {
color: self.color,
radius: self.radius,
thickness: self.thickness,
inner_radius: self.inner_radius,
});
}
}
pub struct Span {
pub elements: Vec<(Range<f32>, Box<dyn UINode>)>,
pub axis: Axis,
}
impl UINode for Span {
fn draw(&self, painter: &mut Painter) {
for (span, child) in &self.elements {
let mut sub_region = UIRegion::full();
let view = sub_region.axis_mut(self.axis);
*view.top_left.anchor = span.start;
*view.bot_right.anchor = span.end;
painter.draw_within(child, sub_region);
}
}
}
impl Span {
pub fn proportioned<const LEN: usize>(
axis: Axis,
ratios: [impl UINum; LEN],
elements: impl NodeArray<LEN>,
) -> Self {
let ratios = ratios.map(|r| r.to_f32());
let total: f32 = ratios.iter().sum();
let mut start = 0.0;
Self {
elements: elements
.to_arr()
.into_iter()
.zip(ratios)
.map(|(e, r)| {
let end = start + r / total;
let res = (start..end, e);
start = end;
res
})
.collect(),
axis,
}
}
}
pub struct Regioned<N: UINode> {
region: UIRegion,
inner: N,
}
impl<N: UINode> UINode for Regioned<N> {
fn draw(&self, painter: &mut Painter) {
painter.region.select(&self.region);
self.inner.draw(painter);
}
}
pub struct Padding {
left: f32,
right: f32,
top: f32,
bottom: f32,
}
impl Padding {
pub fn uniform(amt: f32) -> Self {
Self {
left: amt,
right: amt,
top: amt,
bottom: amt,
}
}
pub fn region(&self) -> UIRegion {
let mut region = UIRegion::full();
region.top_left.offset.x += self.left;
region.top_left.offset.y += self.top;
region.bot_right.offset.x -= self.right;
region.bot_right.offset.y -= self.bottom;
region
}
}
impl<T: UINum> From<T> for Padding {
fn from(amt: T) -> Self {
Self::uniform(amt.to_f32())
}
}
pub trait NodeUtil: Sized + UINode {
fn pad(self, padding: impl Into<Padding>) -> Regioned<Self>;
}
impl<T: UINode> NodeUtil for T {
fn pad(self, padding: impl Into<Padding>) -> Regioned<Self> {
Regioned {
region: padding.into().region(),
inner: self,
}
}
}
pub trait NodeArrayUtil<const LEN: usize> {
fn proportioned(self, axis: Axis, ratios: [impl UINum; LEN]) -> Span;
}
impl<T: NodeArray<LEN>, const LEN: usize> NodeArrayUtil<LEN> for T {
fn proportioned(self, axis: Axis, ratios: [impl UINum; LEN]) -> Span {
Span::proportioned(axis, ratios, self)
}
}
pub trait UINum {
fn to_f32(self) -> f32;
}
impl UINum for f32 {
fn to_f32(self) -> f32 {
self
}
}
impl UINum for u32 {
fn to_f32(self) -> f32 {
self as f32
}
}
impl UINum for i32 {
fn to_f32(self) -> f32 {
self as f32
}
}