`Len` is `Px` beside `Rel` beside `Weight`, so the seam `4e28f10` left in `Span` -- a float length added to a fixed-point cursor -- is gone, and the sum a span compares against its box is exact. `Weight` is its own scale, `Fixed<16>`, because a share of what is left over is not a fraction of anything: a list divides its room by the total of them, so the range has to hold a whole list's worth while the precision only has to tell two weights apart. `Rel::ratio` turns two weights into a share on the finer grid, which is what a span needs and what dividing them on their own grid would round away. `AxisAlign` holds a `Rel` rather than a float, which is what the layout was reading out of it anyway. `Padding` and `Span::gap` hold `Px`, converted where they are built instead of on every frame. `RegionAlign::rel` is gone; its one caller wanted a position, and now builds one. `Fixed` gains `from_num` for a number as it is written in source, `mul_int` for a length repeated a whole number of times, and `ratio`. Checked: fmt, clippy, 101 tests, 100 generated seeds in 86 s, all five shrinker cases at 300 seeds, and all five examples byte-identical at 1920x1200 against `4e28f10`. With the fuzzer comparing for equality rather than within 0.05 px, four of the five cases now pass 100 seeds -- `resize-repaint` joins the other three. `reorder` still fails one seed by one step, so the last of it is in what a box is measured *in*: `px_len` and the window are still floats. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
125 lines
2.7 KiB
Rust
125 lines
2.7 KiB
Rust
use crate::prelude::*;
|
|
|
|
pub struct Pad {
|
|
pub padding: Padding,
|
|
pub inner: StrongWidget,
|
|
}
|
|
|
|
impl Widget for Pad {
|
|
fn draw(&mut self, painter: &mut Painter) -> Size {
|
|
let inner = painter
|
|
.widget_aligned(&self.inner, self.padding.region(), RegionAlign::NEAR)
|
|
.size();
|
|
Size {
|
|
x: Len {
|
|
px: inner.x.px + self.padding.left + self.padding.right,
|
|
..inner.x
|
|
},
|
|
y: Len {
|
|
px: inner.y.px + self.padding.top + self.padding.bottom,
|
|
..inner.y
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Padding {
|
|
pub left: Px,
|
|
pub right: Px,
|
|
pub top: Px,
|
|
pub bottom: Px,
|
|
}
|
|
|
|
impl Padding {
|
|
pub const ZERO: Self = Self {
|
|
left: Px::ZERO,
|
|
right: Px::ZERO,
|
|
top: Px::ZERO,
|
|
bottom: Px::ZERO,
|
|
};
|
|
|
|
pub fn uniform(amt: impl UiNum) -> Self {
|
|
let amt = Px::from_num(amt);
|
|
Self {
|
|
left: amt,
|
|
right: amt,
|
|
top: amt,
|
|
bottom: amt,
|
|
}
|
|
}
|
|
pub fn region(&self) -> UiRegion {
|
|
let mut region = UiRegion::FULL;
|
|
region.x.start.px += self.left;
|
|
region.y.start.px += self.top;
|
|
region.x.end.px -= self.right;
|
|
region.y.end.px -= self.bottom;
|
|
region
|
|
}
|
|
pub fn x(amt: impl UiNum) -> Self {
|
|
let amt = Px::from_num(amt);
|
|
Self {
|
|
left: amt,
|
|
right: amt,
|
|
..Self::ZERO
|
|
}
|
|
}
|
|
pub fn y(amt: impl UiNum) -> Self {
|
|
let amt = Px::from_num(amt);
|
|
Self {
|
|
top: amt,
|
|
bottom: amt,
|
|
..Self::ZERO
|
|
}
|
|
}
|
|
|
|
pub fn top(amt: impl UiNum) -> Self {
|
|
let mut s = Self::ZERO;
|
|
s.top = Px::from_num(amt);
|
|
s
|
|
}
|
|
|
|
pub fn bottom(amt: impl UiNum) -> Self {
|
|
let mut s = Self::ZERO;
|
|
s.bottom = Px::from_num(amt);
|
|
s
|
|
}
|
|
|
|
pub fn left(amt: impl UiNum) -> Self {
|
|
let mut s = Self::ZERO;
|
|
s.left = Px::from_num(amt);
|
|
s
|
|
}
|
|
|
|
pub fn right(amt: impl UiNum) -> Self {
|
|
let mut s = Self::ZERO;
|
|
s.right = Px::from_num(amt);
|
|
s
|
|
}
|
|
|
|
pub fn with_top(mut self, amt: impl UiNum) -> Self {
|
|
self.top = Px::from_num(amt);
|
|
self
|
|
}
|
|
|
|
pub fn with_bottom(mut self, amt: impl UiNum) -> Self {
|
|
self.bottom = Px::from_num(amt);
|
|
self
|
|
}
|
|
|
|
pub fn with_left(mut self, amt: impl UiNum) -> Self {
|
|
self.left = Px::from_num(amt);
|
|
self
|
|
}
|
|
|
|
pub fn with_right(mut self, amt: impl UiNum) -> Self {
|
|
self.right = Px::from_num(amt);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<T: UiNum> From<T> for Padding {
|
|
fn from(amt: T) -> Self {
|
|
Self::uniform(amt)
|
|
}
|
|
}
|