From f4aef3a9837bdbbd507b4015c9f95a721ed83c18 Mon Sep 17 00:00:00 2001 From: Shadow Cat Date: Fri, 15 Aug 2025 22:59:58 -0400 Subject: [PATCH] idek stuff like stack --- src/core/frame.rs | 4 +-- src/core/mod.rs | 2 ++ src/core/num.rs | 8 ++--- src/core/rect.rs | 6 +++- src/core/sense.rs | 4 +-- src/core/span.rs | 10 +++---- src/core/stack.rs | 13 ++++++++ src/core/trait_fns.rs | 24 +++++++++++---- src/layout/color.rs | 4 ++- src/layout/painter.rs | 2 +- src/layout/region.rs | 70 +++++++++++++++++++++++++++++++++++-------- src/layout/ui.rs | 2 +- src/layout/vec2.rs | 11 ++++--- src/testing/mod.rs | 16 +++++++++- src/util/math.rs | 4 +-- 15 files changed, 138 insertions(+), 42 deletions(-) create mode 100644 src/core/stack.rs diff --git a/src/core/frame.rs b/src/core/frame.rs index 7b9bd15..fc9f7fb 100644 --- a/src/core/frame.rs +++ b/src/core/frame.rs @@ -1,4 +1,4 @@ -use crate::{Painter, UINum, UiRegion, Widget, WidgetId}; +use crate::{Painter, UiNum, UiRegion, Widget, WidgetId}; pub struct Regioned { pub region: UiRegion, @@ -38,7 +38,7 @@ impl Padding { } } -impl From for Padding { +impl From for Padding { fn from(amt: T) -> Self { Self::uniform(amt.to_f32()) } diff --git a/src/core/mod.rs b/src/core/mod.rs index 2136c32..cc63fa6 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -3,6 +3,7 @@ mod num; mod rect; mod sense; mod span; +mod stack; mod trait_fns; pub use frame::*; @@ -10,4 +11,5 @@ pub use num::*; pub use rect::*; pub use sense::*; pub use span::*; +pub use stack::*; pub use trait_fns::*; diff --git a/src/core/num.rs b/src/core/num.rs index 788aa73..b690cfd 100644 --- a/src/core/num.rs +++ b/src/core/num.rs @@ -1,20 +1,20 @@ -pub trait UINum { +pub trait UiNum { fn to_f32(self) -> f32; } -impl UINum for f32 { +impl UiNum for f32 { fn to_f32(self) -> f32 { self } } -impl UINum for u32 { +impl UiNum for u32 { fn to_f32(self) -> f32 { self as f32 } } -impl UINum for i32 { +impl UiNum for i32 { fn to_f32(self) -> f32 { self as f32 } diff --git a/src/core/rect.rs b/src/core/rect.rs index e27510e..f0b25e2 100644 --- a/src/core/rect.rs +++ b/src/core/rect.rs @@ -1,4 +1,4 @@ -use crate::{Painter, UiColor, Widget, primitive::RoundedRectData}; +use crate::{primitive::RoundedRectData, Painter, UiNum, UiColor, Widget}; #[derive(Clone, Copy)] pub struct Rect { @@ -21,6 +21,10 @@ impl Rect { self.color = color; self } + pub fn radius(mut self, radius: impl UiNum) -> Self { + self.radius = radius.to_f32(); + self + } } impl Widget for Rect { diff --git a/src/core/sense.rs b/src/core/sense.rs index f47162d..2d695d5 100644 --- a/src/core/sense.rs +++ b/src/core/sense.rs @@ -4,7 +4,7 @@ pub trait SenseCtx: 'static { fn active(&mut self, trigger: &SenseTrigger) -> bool; } -pub trait Sensable { +pub trait Sensable { fn sense( self, sense: Sense, @@ -21,7 +21,7 @@ pub trait Sensable { W: Widget; } -impl, Ctx: SenseCtx, Tag> Sensable for W { +impl, Ctx, Tag> Sensable for W { fn sense(self, sense: Sense, f: impl SenseFn + Clone) -> impl WidgetIdFn { move |ui| { let id = self.add(ui); diff --git a/src/core/span.rs b/src/core/span.rs index 67d7fd5..67f49d5 100644 --- a/src/core/span.rs +++ b/src/core/span.rs @@ -1,4 +1,4 @@ -use crate::{Dir, Painter, Sign, UINum, UiRegion, UIScalar, Widget, WidgetId}; +use crate::{Dir, Painter, Sign, UiNum, UiRegion, UIScalar, Widget, WidgetId}; pub struct Span { pub children: Vec<(WidgetId, SpanLen)>, @@ -80,19 +80,19 @@ pub enum SpanLen { Relative(f32), } -pub fn fixed(x: N) -> SpanLen { +pub fn fixed(x: N) -> SpanLen { SpanLen::Fixed(x.to_f32()) } -pub fn ratio(x: N) -> SpanLen { +pub fn ratio(x: N) -> SpanLen { SpanLen::Ratio(x.to_f32()) } -pub fn rel(x: N) -> SpanLen { +pub fn rel(x: N) -> SpanLen { SpanLen::Relative(x.to_f32()) } -impl From for SpanLen { +impl From for SpanLen { fn from(value: N) -> Self { Self::Ratio(value.to_f32()) } diff --git a/src/core/stack.rs b/src/core/stack.rs new file mode 100644 index 0000000..855c7ea --- /dev/null +++ b/src/core/stack.rs @@ -0,0 +1,13 @@ +use crate::{Widget, WidgetId}; + +pub struct Stack { + pub children: Vec, +} + +impl Widget for Stack { + fn draw(&self, painter: &mut crate::Painter) { + for child in &self.children { + painter.draw(child); + } + } +} diff --git a/src/core/trait_fns.rs b/src/core/trait_fns.rs index e81e26a..0ea66d7 100644 --- a/src/core/trait_fns.rs +++ b/src/core/trait_fns.rs @@ -1,12 +1,13 @@ use super::*; use crate::{UiRegion, Vec2, WidgetArrLike, WidgetFn, WidgetLike}; -pub trait CoreWidget { +pub trait CoreWidget { fn pad(self, padding: impl Into) -> impl WidgetFn; fn center(self, size: impl Into) -> impl WidgetFn; + fn region(self, region: UiRegion) -> impl WidgetFn; } -impl, Ctx: 'static, Tag> CoreWidget for W { +impl, Ctx: 'static, Tag> CoreWidget for W { fn pad(self, padding: impl Into) -> impl WidgetFn { |ui| Regioned { region: padding.into().region(), @@ -16,7 +17,14 @@ impl, Ctx: 'static, Tag> CoreWidget for W { fn center(self, size: impl Into) -> impl WidgetFn { |ui| Regioned { - region: UiRegion::center(size.into()), + region: UiRegion::center().size(size.into()), + inner: self.add(ui).erase_type(), + } + } + + fn region(self, region: UiRegion) -> impl WidgetFn { + move |ui| Regioned { + region, inner: self.add(ui).erase_type(), } } @@ -24,10 +32,11 @@ impl, Ctx: 'static, Tag> CoreWidget for W { pub trait CoreWidgetArr { fn span(self, dir: Dir, lengths: [impl Into; LEN]) -> impl WidgetFn; + fn stack(self) -> impl WidgetFn; } -impl, Ctx: 'static, Tag> CoreWidgetArr - for Wa +impl, Ctx: 'static, Tag> + CoreWidgetArr for Wa { fn span(self, dir: Dir, lengths: [impl Into; LEN]) -> impl WidgetFn { let lengths = lengths.map(Into::into); @@ -36,4 +45,9 @@ impl, Ctx: 'static, Tag> Core children: self.ui(ui).arr.into_iter().zip(lengths).collect(), } } + fn stack(self) -> impl WidgetFn { + move |ui| Stack { + children: self.ui(ui).arr.to_vec(), + } + } } diff --git a/src/layout/color.rs b/src/layout/color.rs index 5909711..215348d 100644 --- a/src/layout/color.rs +++ b/src/layout/color.rs @@ -18,9 +18,11 @@ impl Color { pub const YELLOW: Self = Self::rgb(T::MAX, T::MAX, T::MIN); pub const LIME: Self = Self::rgb(T::MID, T::MAX, T::MIN); pub const GREEN: Self = Self::rgb(T::MIN, T::MAX, T::MIN); + pub const TURQUOISE: Self = Self::rgb(T::MIN, T::MAX, T::MID); pub const CYAN: Self = Self::rgb(T::MIN, T::MAX, T::MAX); + pub const SKY: Self = Self::rgb(T::MIN, T::MID, T::MAX); pub const BLUE: Self = Self::rgb(T::MIN, T::MIN, T::MAX); - pub const INDIGO: Self = Self::rgb(T::MIN, T::MID, T::MAX); + pub const PURPLE: Self = Self::rgb(T::MID, T::MIN, T::MAX); pub const MAGENTA: Self = Self::rgb(T::MAX, T::MIN, T::MAX); pub const fn new(r: T, g: T, b: T, a: T) -> Self { diff --git a/src/layout/painter.rs b/src/layout/painter.rs index a5ed1ba..d8900fe 100644 --- a/src/layout/painter.rs +++ b/src/layout/painter.rs @@ -40,7 +40,7 @@ impl<'a, Ctx> Painter<'a, Ctx> { .extend_from_slice(bytemuck::cast_slice::<_, u32>(&[data])); } - pub fn draw(&mut self, id: &WidgetId) + pub fn draw(&mut self, id: &WidgetId) where Ctx: 'static, { diff --git a/src/layout/region.rs b/src/layout/region.rs index b7431b5..7d9ec56 100644 --- a/src/layout/region.rs +++ b/src/layout/region.rs @@ -6,12 +6,12 @@ use crate::{ #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, Default)] -pub struct UIPos { +pub struct UiPos { pub anchor: Vec2, pub offset: Vec2, } -impl UIPos { +impl UiPos { pub const fn anchor_offset(anchor_x: f32, anchor_y: f32, offset_x: f32, offset_y: f32) -> Self { Self { anchor: vec2(anchor_x, anchor_y), @@ -23,6 +23,10 @@ impl UIPos { Self::anchor_offset(0.5, 0.5, 0.0, 0.0) } + pub const fn anchor(anchor: Vec2) -> Self { + Self::anchor_offset(anchor.x, anchor.y, 0.0, 0.0) + } + pub const fn top_left() -> Self { Self::anchor_offset(0.0, 0.0, 0.0, 0.0) } @@ -31,12 +35,16 @@ impl UIPos { Self::anchor_offset(1.0, 1.0, 0.0, 0.0) } - pub const fn offset(mut self, offset: Vec2) -> Self { - self.offset = offset; + pub const fn shift(&mut self, offset: Vec2) { + self.offset += offset; + } + + pub const fn shifted(mut self, offset: Vec2) -> Self { + self.shift(offset); self } - pub const fn within(&self, region: &UiRegion) -> UIPos { + pub const fn within(&self, region: &UiRegion) -> UiPos { let anchor = self .anchor .lerp(region.top_left.anchor, region.bot_right.anchor); @@ -44,7 +52,7 @@ impl UIPos { + self .anchor .lerp(region.top_left.offset, region.bot_right.offset); - UIPos { anchor, offset } + UiPos { anchor, offset } } pub fn axis_mut(&mut self, axis: Axis) -> UIScalarView<'_> { @@ -111,23 +119,32 @@ impl UIScalar { #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct UiRegion { - pub top_left: UIPos, - pub bot_right: UIPos, + pub top_left: UiPos, + pub bot_right: UiPos, } impl UiRegion { pub const fn full() -> Self { Self { - top_left: UIPos::top_left(), - bot_right: UIPos::bottom_right(), + top_left: UiPos::top_left(), + bot_right: UiPos::bottom_right(), } } - pub fn center(size: Vec2) -> Self { + pub fn center() -> Self { + Self::anchor(Vec2::new(0.5, 0.5)) + } + pub fn anchor(anchor: Vec2) -> Self { Self { - top_left: UIPos::center().offset(-size / 2.0), - bot_right: UIPos::center().offset(size / 2.0), + top_left: UiPos::anchor(anchor), + bot_right: UiPos::anchor(anchor), } } + pub fn size(mut self, size: impl Into) -> Self { + let size = size.into(); + self.top_left = self.top_left.shifted(-size / 2.0); + self.bot_right = self.bot_right.shifted(size / 2.0); + self + } pub fn within(&self, parent: &Self) -> Self { Self { top_left: self.top_left.within(parent), @@ -150,6 +167,33 @@ impl UiRegion { std::mem::swap(&mut self.top_left, &mut self.bot_right); } + pub fn shift(&mut self, offset: impl Into) { + let offset = offset.into(); + self.top_left.shift(offset); + self.bot_right.shift(offset); + } + + pub fn shifted(mut self, offset: impl Into) -> Self { + println!("before {:?}", self); + self.shift(offset); + println!("after {:?}", self); + self + } + + pub fn top_left() -> Self { + Self { + top_left: UiPos::top_left(), + bot_right: UiPos::top_left(), + } + } + + pub fn bottom_right() -> Self { + Self { + top_left: UiPos::bottom_right(), + bot_right: UiPos::bottom_right(), + } + } + pub fn to_screen(&self, size: Vec2) -> ScreenRect { ScreenRect { top_left: self.top_left.anchor * size + self.top_left.offset, diff --git a/src/layout/ui.rs b/src/layout/ui.rs index 0e60e8f..0ff8b11 100644 --- a/src/layout/ui.rs +++ b/src/layout/ui.rs @@ -147,7 +147,7 @@ impl Widgets { Self(HashMap::new()) } - pub fn get_dyn(&self, id: &WidgetId) -> &dyn Widget { + pub fn get_dyn(&self, id: &WidgetId) -> &dyn Widget { self.0.get(&id.id).unwrap().as_ref() } diff --git a/src/layout/vec2.rs b/src/layout/vec2.rs index f2b645c..c3c1468 100644 --- a/src/layout/vec2.rs +++ b/src/layout/vec2.rs @@ -1,4 +1,4 @@ -use crate::util::{F32Util, impl_op}; +use crate::{util::{impl_op, F32Util}, UiNum}; use std::ops::*; #[repr(C)] @@ -52,8 +52,11 @@ impl Neg for Vec2 { } } -impl From<(f32, f32)> for Vec2 { - fn from((x, y): (f32, f32)) -> Self { - Self { x, y } +impl From<(T, U)> for Vec2 { + fn from((x, y): (T, U)) -> Self { + Self { + x: x.to_f32(), + y: y.to_f32(), + } } } diff --git a/src/testing/mod.rs b/src/testing/mod.rs index 14560c6..8569a45 100644 --- a/src/testing/mod.rs +++ b/src/testing/mod.rs @@ -106,7 +106,21 @@ impl Client { ) .span(Dir::RIGHT, [1, 1, 1]), ); - ui.set_base((buttons, pad_test.pad(10).id(&main)).span(Dir::DOWN, [fixed(40), ratio(1)])); + ui.set_base( + ( + buttons, + ( + pad_test.pad(10).id(&main), + Rect::new(Color::PURPLE).radius(30).region( + UiRegion::bottom_right() + .size((150, 150)) + .shifted((-75, -75)), + ), + ) + .stack(), + ) + .span(Dir::DOWN, [fixed(40), ratio(1)]), + ); (ui, UiIds { test }) } diff --git a/src/util/math.rs b/src/util/math.rs index fdf7189..5a7a28a 100644 --- a/src/util/math.rs +++ b/src/util/math.rs @@ -26,7 +26,7 @@ macro_rules! impl_op { } } } - impl $opa for $T { + impl const $opa for $T { fn $fna(&mut self, rhs: Self) { $(self.$field.$fna(rhs.$field);)* } @@ -49,7 +49,7 @@ macro_rules! impl_op { } } } - impl $opa for $T { + impl const $opa for $T { fn $fna(&mut self, rhs: f32) { $(self.$field.$fna(rhs);)* }