the great orientation refactor (move to x & y UiScalars/Spans) + don't call full size in align

This commit is contained in:
2025-11-20 15:44:39 -05:00
parent 96ef0c529b
commit 6251c23d37
20 changed files with 832 additions and 578 deletions

View File

@@ -7,8 +7,32 @@ pub struct Aligned {
impl Widget for Aligned {
fn draw(&mut self, painter: &mut Painter) {
let region =
UiRegion::from_ui_size_align(painter.size(&self.inner).to_uivec2(), self.align);
let region = match self.align {
Align {
x: Some(x),
y: Some(y),
} => {
painter
.size(&self.inner)
.to_uivec2()
.align(RegionAlign { x, y })
}
Align {
x: Some(x),
y: None,
} => {
let x = painter.size_ctx().width(&self.inner).apply_rest().align(x);
UiRegion::new(x, UiSpan::FULL)
}
Align {
x: None,
y: Some(y),
} => {
let y = painter.size_ctx().height(&self.inner).apply_rest().align(y);
UiRegion::new(UiSpan::FULL, y)
}
Align { x: None, y: None } => UiRegion::FULL,
};
painter.widget_within(&self.inner, region);
}

View File

@@ -7,7 +7,7 @@ pub struct Offset {
impl Widget for Offset {
fn draw(&mut self, painter: &mut Painter) {
let region = UiRegion::full().offset(self.amt);
let region = UiRegion::FULL.offset(self.amt);
painter.widget_within(&self.inner, region);
}

View File

@@ -13,8 +13,8 @@ impl Widget for Pad {
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len {
let width = self.padding.left + self.padding.right;
let height = self.padding.top + self.padding.bottom;
ctx.outer.abs.x -= width;
ctx.outer.abs.y -= height;
ctx.outer.x.abs -= width;
ctx.outer.y.abs -= height;
let mut size = ctx.width(&self.inner);
size.abs += width;
size
@@ -23,8 +23,8 @@ impl Widget for Pad {
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len {
let width = self.padding.left + self.padding.right;
let height = self.padding.top + self.padding.bottom;
ctx.outer.abs.x -= width;
ctx.outer.abs.y -= height;
ctx.outer.x.abs -= width;
ctx.outer.y.abs -= height;
let mut size = ctx.height(&self.inner);
size.abs += height;
size
@@ -49,11 +49,11 @@ impl Padding {
}
}
pub fn region(&self) -> UiRegion {
let mut region = UiRegion::full();
region.top_left.abs.x += self.left;
region.top_left.abs.y += self.top;
region.bot_right.abs.x -= self.right;
region.bot_right.abs.y -= self.bottom;
let mut region = UiRegion::FULL;
region.x.start.abs += self.left;
region.y.start.abs += self.top;
region.x.end.abs -= self.right;
region.y.end.abs -= self.bottom;
region
}
pub fn x(amt: impl UiNum) -> Self {

View File

@@ -9,16 +9,10 @@ pub struct Sized {
impl Sized {
fn apply_to_outer(&self, ctx: &mut SizeCtx) {
if let Some(x) = self.x {
let outer = ctx.outer.axis(Axis::X);
ctx.outer
.axis_mut(Axis::X)
.set(x.apply_rest().within_len(outer));
ctx.outer.x.select_len(x.apply_rest());
}
if let Some(y) = self.y {
let outer = ctx.outer.axis(Axis::Y);
ctx.outer
.axis_mut(Axis::Y)
.set(y.apply_rest().within_len(outer));
ctx.outer.y.select_len(y.apply_rest());
}
}
}

View File

@@ -1,6 +1,5 @@
use std::marker::PhantomData;
use crate::prelude::*;
use std::marker::PhantomData;
pub struct Span {
pub children: Vec<WidgetId>,
@@ -13,18 +12,19 @@ impl Widget for Span {
let total = self.len_sum(&mut painter.size_ctx());
let mut start = UiScalar::rel_min();
for child in &self.children {
let mut child_region = UiRegion::full();
let mut axis = child_region.axis_mut(self.dir.axis);
axis.top_left.set(start);
let mut span = UiSpan::FULL;
span.start = start;
let len = painter.len_axis(child, self.dir.axis);
if len.rest > 0.0 {
let offset = UiScalar::new(total.rel, total.abs);
let rel_end = UiScalar::from_anchor(len.rest / total.rest);
start = rel_end.within(start, (UiScalar::rel_max() + start) - offset);
let rel_end = UiScalar::rel(len.rest / total.rest);
let end = (UiScalar::rel_max() + start) - offset;
start = rel_end.within(&start.to(end));
}
start.abs += len.abs;
start.rel += len.rel;
axis.bot_right.set(start);
span.end = start;
let mut child_region = UiRegion::from_axis(self.dir.axis, span, UiSpan::FULL);
if self.dir.sign == Sign::Neg {
child_region.flip(self.dir.axis);
}
@@ -89,33 +89,29 @@ impl Span {
fn desired_ortho(&mut self, ctx: &mut SizeCtx) -> Len {
// this is an awful hack to get text wrapping to work properly when in a downward span
let outer = ctx.outer.axis(self.dir.axis);
if self.dir.axis == Axis::X {
// so....... this literally copies draw so that the lengths are correctly set in the
// context, which makes this slow and not cool
let total = self.len_sum(ctx);
let mut start = UiScalar::rel_min();
let outer = ctx.outer.axis(self.dir.axis);
let mut ortho_len = Len::ZERO;
for child in &self.children {
let mut child_region = UiRegion::full();
let mut axis = child_region.axis_mut(self.dir.axis);
axis.top_left.set(start);
let mut span = UiSpan::FULL;
span.start = start;
let len = ctx.len_axis(child, self.dir.axis);
if len.rest > 0.0 {
let offset = UiScalar::new(total.rel, total.abs);
let rel_end = UiScalar::from_anchor(len.rest / total.rest);
start = rel_end.within(start, (UiScalar::rel_max() + start) - offset);
let rel_end = UiScalar::rel(len.rest / total.rest);
let end = (UiScalar::rel_max() + start) - offset;
start = rel_end.within(&start.to(end));
}
start.abs += len.abs;
start.rel += len.rel;
axis.bot_right.set(start);
// if self.dir.sign == Sign::Neg {
// child_region.flip(self.dir.axis);
// }
let scalar = child_region.size().axis(self.dir.axis);
ctx.outer
.axis_mut(self.dir.axis)
.set(scalar.within_len(outer));
span.end = start;
let scalar = span.len();
*ctx.outer.axis_mut(self.dir.axis) = outer.select_len(scalar);
let ortho = ctx.len_axis(child, !self.dir.axis);
// TODO: rel shouldn't do this, but no easy way before actually calculating pixels
if ortho.rel > 0.0 || ortho.rest > 0.0 {

View File

@@ -32,8 +32,8 @@ impl<O> TextBuilder<O> {
self.attrs.line_height = height;
self
}
pub fn text_align(mut self, align: Align) -> Self {
self.attrs.align = align;
pub fn text_align(mut self, align: impl Into<RegionAlign>) -> Self {
self.attrs.align = align.into();
self
}
pub fn wrap(mut self, wrap: bool) -> Self {

View File

@@ -15,10 +15,10 @@ pub struct TextEdit {
impl TextEdit {
pub fn region(&self) -> UiRegion {
UiRegion::from_size_align(
self.tex().map(|t| t.size()).unwrap_or(Vec2::ZERO),
self.align,
)
self.tex()
.map(|t| t.size())
.unwrap_or(Vec2::ZERO)
.align(self.align)
}
pub fn content(&self) -> String {
@@ -44,7 +44,7 @@ impl Widget for TextEdit {
let size = vec2(1, self.attrs.line_height);
painter.primitive_within(
RectPrimitive::color(Color::WHITE),
UiRegion::from_size_align(size, Align::TopLeft)
size.align(Align::TOP_LEFT)
.offset(offset)
.within(&region),
);
@@ -205,7 +205,7 @@ impl<'a> TextEditCtx<'a> {
}
pub fn select(&mut self, pos: Vec2, size: Vec2) {
let pos = pos - self.text.region().top_left.to_abs(size);
let pos = pos - self.text.region().top_left().to_abs(size);
self.text.cursor = self.text.buf.hit(pos.x, pos.y);
}

View File

@@ -100,11 +100,13 @@ impl Widget for Text {
}
}
pub fn text_region(tex: &TextTexture, align: Align) -> UiRegion {
pub fn text_region(tex: &TextTexture, align: RegionAlign) -> UiRegion {
let tex_dims = tex.handle.size();
let mut region = UiRegion::from_size_align(tex.size(), align);
region.top_left.abs += tex.top_left;
region.bot_right.abs = region.top_left.abs + tex_dims;
let mut region = tex.size().align(align);
region.x.start.abs += tex.top_left.x;
region.y.start.abs += tex.top_left.y;
region.x.end.abs = region.x.start.abs + tex_dims.x;
region.y.end.abs = region.y.start.abs + tex_dims.y;
region
}

View File

@@ -3,7 +3,7 @@ use crate::prelude::*;
pub trait CoreWidget<W, Tag> {
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad>;
fn align(self, align: Align) -> impl WidgetFn<Aligned>;
fn align(self, align: impl Into<Align>) -> impl WidgetFn<Aligned>;
fn center(self) -> impl WidgetFn<Aligned>;
fn label(self, label: impl Into<String>) -> impl WidgetIdFn<W>;
fn sized(self, size: impl Into<Size>) -> impl WidgetFn<Sized>;
@@ -24,15 +24,15 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
}
}
fn align(self, align: Align) -> impl WidgetFn<Aligned> {
fn align(self, align: impl Into<Align>) -> impl WidgetFn<Aligned> {
move |ui| Aligned {
inner: self.add(ui).any(),
align,
align: align.into(),
}
}
fn center(self) -> impl WidgetFn<Aligned> {
self.align(Align::Center)
self.align(Align::CENTER)
}
fn label(self, label: impl Into<String>) -> impl WidgetIdFn<W::Widget> {