I love control flow

This commit is contained in:
2025-11-20 22:48:08 -05:00
parent f6f9ebbe51
commit dff72d2c43
19 changed files with 126 additions and 63 deletions

View File

@@ -29,6 +29,12 @@ impl<Nx: UiNum, Ny: UiNum> From<(Nx, Ny)> for Size {
}
}
impl From<Len> for Size {
fn from(value: Len) -> Self {
Self { x: value, y: value }
}
}
impl Size {
pub const ZERO: Self = Self {
x: Len::ZERO,
@@ -171,10 +177,10 @@ impl std::fmt::Display for Len {
write!(f, "{} abs;", self.abs)?;
}
if self.rel != 0.0 {
write!(f, "{} rel;", self.abs)?;
write!(f, "{} rel;", self.rel)?;
}
if self.rest != 0.0 {
write!(f, "{} leftover;", self.abs)?;
write!(f, "{} rest;", self.rest)?;
}
Ok(())
}

View File

@@ -78,7 +78,10 @@ impl UiVec2 {
}
pub fn to_abs(&self, rel: Vec2) -> Vec2 {
self.get_rel() * rel + self.get_abs()
Vec2 {
x: self.x.to_abs(rel.x),
y: self.y.to_abs(rel.y),
}
}
pub const FULL_SIZE: Self = Self::rel(Vec2::ONE);
@@ -231,6 +234,10 @@ impl UiScalar {
pub const fn to(&self, end: Self) -> UiSpan {
UiSpan { start: *self, end }
}
pub const fn to_abs(&self, rel: f32) -> f32 {
self.rel * rel + self.abs
}
}
#[repr(C)]
@@ -323,6 +330,14 @@ impl UiRegion {
y: self.y.outside(&parent.y),
}
}
pub const fn axis(&mut self, axis: Axis) -> &UiSpan {
match axis {
Axis::X => &self.x,
Axis::Y => &self.y,
}
}
pub const fn axis_mut(&mut self, axis: Axis) -> &mut UiSpan {
match axis {
Axis::X => &mut self.x,

View File

@@ -29,19 +29,20 @@ pub struct PainterCtx<'a> {
pub textures: &'a mut Textures,
pub masks: &'a mut TrackedArena<Mask, u32>,
pub text: &'a mut TextData,
pub screen_size: Vec2,
pub output_size: Vec2,
pub modules: &'a mut Modules,
pub cache_width: HashMap<Id, (UiVec2, Len)>,
pub cache_height: HashMap<Id, (UiVec2, Len)>,
draw_started: HashSet<Id>,
}
#[derive(Default)]
#[derive(Clone, Copy, Debug, Default)]
pub struct ResizeRef {
x: Option<(Id, (UiVec2, Len))>,
y: Option<(Id, (UiVec2, Len))>,
}
#[derive(Debug)]
pub struct WidgetInstance {
pub id: Id,
pub region: UiRegion,
@@ -75,7 +76,7 @@ impl<'a> PainterCtx<'a> {
layers: &mut data.layers,
textures: &mut data.textures,
text: &mut data.text,
screen_size: data.output_size,
output_size: data.output_size,
modules: &mut data.modules,
masks: &mut data.masks,
cache_width: Default::default(),
@@ -91,9 +92,16 @@ impl<'a> PainterCtx<'a> {
let Some(active) = self.active.get(&id) else {
return;
};
let mut resize = active.resize;
// TODO: this is stupid having 2 of these
if let Some((rid, (outer, old_desired))) = active.resize.x {
let finish = |s: &mut Self, resize| {
if let Some(active) = s.active.get_mut(&id) {
active.resize = resize;
}
};
// TODO: this is stupid having 2 of these, don't ask me what the consequences are
if let Some((rid, (outer, old_desired))) = &mut resize.x {
let new_desired = SizeCtx {
source: id,
cache_width: &mut self.cache_width,
@@ -101,25 +109,23 @@ impl<'a> PainterCtx<'a> {
text: self.text,
textures: self.textures,
widgets: self.widgets,
outer,
output_size: self.screen_size,
outer: *outer,
output_size: self.output_size,
checked_width: &mut Default::default(),
checked_height: &mut Default::default(),
id,
}
.width_inner(id);
if new_desired != old_desired {
self.redraw(rid);
if new_desired != *old_desired {
self.redraw(*rid);
*old_desired = new_desired;
if self.draw_started.contains(&id) {
return;
return finish(self, resize);
}
}
}
let Some(active) = self.active.get(&id) else {
return;
};
if let Some((rid, (outer, old_desired))) = active.resize.y {
if let Some((rid, (outer, old_desired))) = &mut resize.y {
let new_desired = SizeCtx {
source: id,
cache_width: &mut self.cache_width,
@@ -127,17 +133,18 @@ impl<'a> PainterCtx<'a> {
text: self.text,
textures: self.textures,
widgets: self.widgets,
outer,
output_size: self.screen_size,
outer: *outer,
output_size: self.output_size,
checked_width: &mut Default::default(),
checked_height: &mut Default::default(),
id,
}
.height_inner(id);
if new_desired != old_desired {
self.redraw(rid);
if new_desired != *old_desired {
self.redraw(*rid);
*old_desired = new_desired;
if self.draw_started.contains(&id) {
return;
return finish(self, resize);
}
}
}
@@ -154,7 +161,7 @@ impl<'a> PainterCtx<'a> {
active.mask,
Some(active.children),
);
self.active.get_mut(&id).unwrap().resize = active.resize;
finish(self, resize);
}
pub fn draw(&mut self, id: Id) {
@@ -399,7 +406,7 @@ impl<'a, 'c> Painter<'a, 'c> {
text: self.ctx.text,
textures: self.ctx.textures,
widgets: self.ctx.widgets,
output_size: self.ctx.screen_size,
output_size: self.ctx.output_size,
checked_width: &mut self.children_width,
checked_height: &mut self.children_height,
cache_width: &mut self.ctx.cache_width,
@@ -410,8 +417,12 @@ impl<'a, 'c> Painter<'a, 'c> {
}
}
pub fn output_size(&self) -> Vec2 {
self.ctx.output_size
}
pub fn px_size(&mut self) -> Vec2 {
self.region.size().to_abs(self.ctx.screen_size)
self.region.size().to_abs(self.ctx.output_size)
}
pub fn text_data(&mut self) -> &mut TextData {

View File

@@ -7,7 +7,7 @@ use image::{DynamicImage, GenericImageView};
use crate::{layout::Vec2, render::TexturePrimitive, util::RefCounter};
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct TextureHandle {
inner: TexturePrimitive,
size: Vec2,

View File

@@ -4,7 +4,7 @@ use crate::{
core::{TextEdit, TextEditCtx},
layout::{
IdLike, PainterCtx, PainterData, PixelRegion, StaticWidgetId, TextureHandle, Vec2, Widget,
WidgetId, WidgetLike,
WidgetId, WidgetInstance, WidgetLike,
},
util::{HashSet, Id},
};
@@ -184,20 +184,11 @@ impl Ui {
Some(region.to_px(self.data.output_size))
}
pub fn debug(&self, label: &str) {
for (id, inst) in &self.data.active {
let l = &self.data.widgets.data(id).unwrap().label;
if l != label {
continue;
}
println!("\"{label}\" {{");
println!(" region: {}", inst.region);
println!(
" pixel region: {}",
inst.region.to_px(self.data.output_size)
);
println!("}}");
}
pub fn debug(&self, label: &str) -> impl Iterator<Item = &WidgetInstance> {
self.data.active.iter().filter_map(move |(id, inst)| {
let l = &self.data.widgets.label(id);
if *l == label { Some(inst) } else { None }
})
}
}