From 5785352ac0d8892c3c7abca2ef9673d426871483 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Fri, 21 Nov 2025 02:44:59 -0500 Subject: [PATCH] max size + better scrolling size fn --- TODO | 4 +++ src/bin/test/main.rs | 2 +- src/core/position/max_size.rs | 48 +++++++++++++++++++++++++++++++++++ src/core/position/mod.rs | 2 ++ src/core/position/scroll.rs | 8 +++--- src/core/trait_fns.rs | 20 +++++++++++++++ src/layout/painter.rs | 16 +++++++----- 7 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 src/core/position/max_size.rs diff --git a/TODO b/TODO index 0bf54ce..69b55c6 100644 --- a/TODO +++ b/TODO @@ -4,6 +4,7 @@ images text figure out ways to speed up / what costs the most resizing (per frame) is really slow (assuming painter isn't griefing) + j is weird / fix x offset masks r just made to bare minimum work @@ -29,6 +30,9 @@ really weird limitation: but the child gets drawn during that, so it will think the child is still active !!! or something like that idk, maybe I need a special enum for parent that includes a undecided state where it may or may not get redrawn by the parent or just do ref counting and ensure all drawn things == 1 afterwards (seems like best way) + ok so I'm removing the limit for now + +don't forget I'm streaming tags vecs for each widget type? diff --git a/src/bin/test/main.rs b/src/bin/test/main.rs index b3c9b1c..707d619 100644 --- a/src/bin/test/main.rs +++ b/src/bin/test/main.rs @@ -151,7 +151,7 @@ impl Client { }) .add(&mut ui); let text_edit_scroll = ( - msg_area, + msg_area.height(rest(1)), ( Rect::new(Color::WHITE.darker(0.9)), ( diff --git a/src/core/position/max_size.rs b/src/core/position/max_size.rs new file mode 100644 index 0000000..30e3ca9 --- /dev/null +++ b/src/core/position/max_size.rs @@ -0,0 +1,48 @@ +use crate::prelude::*; + +pub struct MaxSize { + pub inner: WidgetId, + pub x: Option, + pub y: Option, +} + +impl MaxSize { + fn apply_to_outer(&self, ctx: &mut SizeCtx) { + if let Some(x) = self.x { + ctx.outer.x.select_len(x.apply_rest()); + } + if let Some(y) = self.y { + ctx.outer.y.select_len(y.apply_rest()); + } + } +} + +impl Widget for MaxSize { + fn draw(&mut self, painter: &mut Painter) { + painter.widget(&self.inner); + } + + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + self.apply_to_outer(ctx); + let width = ctx.width(&self.inner); + if let Some(x) = self.x { + let width_px = width.apply_rest().to_abs(ctx.output_size().x); + let x_px = x.apply_rest().to_abs(ctx.output_size().x); + if width_px > x_px { x } else { width } + } else { + width + } + } + + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + self.apply_to_outer(ctx); + let height = ctx.height(&self.inner); + if let Some(y) = self.y { + let height_px = height.apply_rest().to_abs(ctx.output_size().y); + let y_px = y.apply_rest().to_abs(ctx.output_size().y); + if height_px > y_px { y } else { height } + } else { + height + } + } +} diff --git a/src/core/position/mod.rs b/src/core/position/mod.rs index 5349a66..159c1f0 100644 --- a/src/core/position/mod.rs +++ b/src/core/position/mod.rs @@ -1,4 +1,5 @@ mod align; +mod max_size; mod offset; mod pad; mod scroll; @@ -7,6 +8,7 @@ mod span; mod stack; pub use align::*; +pub use max_size::*; pub use offset::*; pub use pad::*; pub use scroll::*; diff --git a/src/core/position/scroll.rs b/src/core/position/scroll.rs index c61ac1a..38ca0b5 100644 --- a/src/core/position/scroll.rs +++ b/src/core/position/scroll.rs @@ -28,12 +28,12 @@ impl Widget for Scroll { painter.widget_within(&self.inner, region); } - fn desired_width(&mut self, _: &mut SizeCtx) -> Len { - Len::default() + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + ctx.width(&self.inner) } - fn desired_height(&mut self, _: &mut SizeCtx) -> Len { - Len::default() + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + ctx.height(&self.inner) } } diff --git a/src/core/trait_fns.rs b/src/core/trait_fns.rs index fd61ec4..d5b771b 100644 --- a/src/core/trait_fns.rs +++ b/src/core/trait_fns.rs @@ -9,6 +9,8 @@ pub trait CoreWidget { fn sized(self, size: impl Into) -> impl WidgetFn; fn width(self, len: impl Into) -> impl WidgetFn; fn height(self, len: impl Into) -> impl WidgetFn; + fn max_width(self, width: impl Into) -> impl WidgetFn; + fn max_height(self, height: impl Into) -> impl WidgetFn; fn offset(self, amt: impl Into) -> impl WidgetFn; fn scroll(self) -> impl WidgetIdFn; fn masked(self) -> impl WidgetFn; @@ -52,6 +54,24 @@ impl, Tag> CoreWidget for W { } } + fn max_width(self, len: impl Into) -> impl WidgetFn { + let len = len.into(); + move |ui| MaxSize { + inner: self.add(ui).any(), + x: Some(len), + y: None, + } + } + + fn max_height(self, len: impl Into) -> impl WidgetFn { + let len = len.into(); + move |ui| MaxSize { + inner: self.add(ui).any(), + x: None, + y: Some(len), + } + } + fn width(self, len: impl Into) -> impl WidgetFn { let len = len.into(); move |ui| Sized { diff --git a/src/layout/painter.rs b/src/layout/painter.rs index 970fc0f..bc14650 100644 --- a/src/layout/painter.rs +++ b/src/layout/painter.rs @@ -184,12 +184,12 @@ impl<'a> PainterCtx<'a> { // but this has a very weird issue where you can't move widgets unless u remove first // so swapping is impossible rn I think? // there's definitely better solutions like a counter (>1 = panic) but don't care rn - if self.draw_started.contains(&id) { - panic!( - "Cannot draw the same widget ({}) twice (1)", - self.widgets.data(&id).unwrap().label - ); - } + // if self.draw_started.contains(&id) { + // panic!( + // "Cannot draw the same widget ({}) twice (1)", + // self.widgets.data(&id).unwrap().label + // ); + // } let mut old_children = old_children.unwrap_or_default(); let mut resize = ResizeRef::default(); if let Some(active) = self.active.get_mut(&id) @@ -580,6 +580,10 @@ impl SizeCtx<'_> { self.outer.to_abs(self.output_size) } + pub fn output_size(&mut self) -> Vec2 { + self.output_size + } + pub fn draw_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> TextTexture { self.text.draw(buffer, attrs, self.textures) }