iris: make span compaction explicit

This commit is contained in:
iris committed 2026-09-12 21:18:09 -04:00
1 parent 54e6765a1d
commit 5f4975285d
4 files changed
+90 -19

No files matched your search

+2
View File
@@ -100,10 +100,12 @@ where
rect(PaintId::PURPLE).sized((50, 50)).align(Align::TOP), rect(PaintId::PURPLE).sized((50, 50)).align(Align::TOP),
) )
.span(Dir::RIGHT) .span(Dir::RIGHT)
.compact()
.center(), .center(),
wtext("pretty cool right?").size(50), wtext("pretty cool right?").size(50),
) )
.span(Dir::DOWN) .span(Dir::DOWN)
.compact()
.add(rsc); .add(rsc);
let texts = Span::empty(Dir::DOWN).gap(10).add(rsc); let texts = Span::empty(Dir::DOWN).gap(10).add(rsc);
+10 -18
View File
@@ -38,24 +38,17 @@ where
.add(Srgba8::new(53, 57, 66, 255).to_linear()); .add(Srgba8::new(53, 57, 66, 255).to_linear());
let styled = "Bold, italic, underlined, and colored spans"; let styled = "Bold, italic, underlined, and colored spans";
let styled = wtext(styled) let styled = wtext(styled).size(20).spans(vec![
.size(20) SpanStyle::new(0..4).bold(),
.spans(vec![ SpanStyle::new(6..12).italic(),
SpanStyle::new(0..4).bold(), SpanStyle::new(14..24).underline(),
SpanStyle::new(6..12).italic(), SpanStyle::new(30..37).color(PaintId::SKY),
SpanStyle::new(14..24).underline(), ]);
SpanStyle::new(30..37).color(PaintId::SKY),
])
.width(rest(1));
let aligned = ( let aligned = (
wtext("Left aligned") wtext("Left aligned").text_align(Align::CENTER_LEFT),
.text_align(Align::CENTER_LEFT) wtext("Centered").text_align(Align::CENTER),
.width(rest(1)), wtext("Right aligned").text_align(Align::CENTER_RIGHT),
wtext("Centered").text_align(Align::CENTER).width(rest(1)),
wtext("Right aligned")
.text_align(Align::CENTER_RIGHT)
.width(rest(1)),
) )
.span(Dir::DOWN) .span(Dir::DOWN)
.gap(dp(4)) .gap(dp(4))
@@ -84,8 +77,7 @@ where
.spans(vec![SpanStyle::new(0..9).bold()]), .spans(vec![SpanStyle::new(0..9).bold()]),
wtext("Drag across display text to select it. The overflow markers select hidden source text, but are never copied.") wtext("Drag across display text to select it. The overflow markers select hidden source text, but are never copied.")
.overflow(TextOverflow::Wrap) .overflow(TextOverflow::Wrap)
.color(PaintId::GRAY) .color(PaintId::GRAY),
.width(rest(1)),
) )
.span(Dir::DOWN) .span(Dir::DOWN)
.gap(dp(6)) .gap(dp(6))
+57
View File
@@ -204,6 +204,7 @@ fn a_span_reuses_unchanged_sibling_sizes_when_only_its_along_extent_changes() {
children: vec![changed.any(), sibling.any()], children: vec![changed.any(), sibling.any()],
dir: Dir::DOWN, dir: Dir::DOWN,
gap: LayoutLen::ZERO, gap: LayoutLen::ZERO,
compact_orthogonal: false,
}); });
let root = rsc let root = rsc
.ui .ui
@@ -231,6 +232,61 @@ fn a_span_reuses_unchanged_sibling_sizes_when_only_its_along_extent_changes() {
); );
} }
#[test]
fn a_span_leaves_children_in_its_offered_orthogonal_axis_by_default() {
let mut rsc = TestRsc { ui: Ui::default() };
let short = wtext("short").add(&mut rsc);
let root = (short, wtext("a much wider line"))
.span(Dir::DOWN)
.add_strong(&mut rsc);
let root_id = root.id();
let root = root.any();
let mut render = UiRenderState::new();
render.resize((200.0, 100.0));
render.update(&root, &mut rsc);
let width = render.active[&root_id].size.x;
assert_eq!(width.rel, 0.0);
assert_eq!(width.rest, 0.0);
assert!(width.abs > 0.0 && width.abs < 200.0);
assert_eq!(
render.active[&short.id()]
.region
.to_px(vec2(200.0, 100.0))
.size()
.x,
200.0,
);
}
#[test]
fn a_compact_span_shrinks_its_orthogonal_axis_to_its_widest_child() {
let mut rsc = TestRsc { ui: Ui::default() };
let short = wtext("short").add(&mut rsc);
let root = (short, wtext("a much wider line"))
.span(Dir::DOWN)
.compact()
.add_strong(&mut rsc);
let root_id = root.id();
let root = root.any();
let mut render = UiRenderState::new();
render.resize((200.0, 100.0));
render.update(&root, &mut rsc);
let width = render.active[&root_id].size.x;
assert_eq!(width.rel, 0.0);
assert_eq!(width.rest, 0.0);
assert!(width.abs > 0.0 && width.abs < 200.0);
assert_eq!(
render.active[&short.id()]
.region
.to_px(vec2(200.0, 100.0))
.size()
.x,
width.abs,
);
}
#[test] #[test]
fn a_child_coordinate_offset_moves_only_the_child_subtree() { fn a_child_coordinate_offset_moves_only_the_child_subtree() {
let mut rsc = TestRsc { ui: Ui::default() }; let mut rsc = TestRsc { ui: Ui::default() };
@@ -1077,6 +1133,7 @@ fn a_span_of_padded_children_inside_a_span_draws_each_where_its_box_is() {
children: vec![header.any(), inner.any()], children: vec![header.any(), inner.any()],
dir: Dir::DOWN, dir: Dir::DOWN,
gap: LayoutLen::ZERO, gap: LayoutLen::ZERO,
compact_orthogonal: false,
}); });
let mut list = LazySpan::new(Dir::DOWN, Pin::End); let mut list = LazySpan::new(Dir::DOWN, Pin::End);
list.push_back(LazyItem::new(0, outer.any())); list.push_back(LazyItem::new(0, outer.any()));
+21 -1
View File
@@ -5,6 +5,7 @@ pub struct Span {
pub children: Vec<StrongWidget>, pub children: Vec<StrongWidget>,
pub dir: Dir, pub dir: Dir,
pub gap: LayoutLen, pub gap: LayoutLen,
pub compact_orthogonal: bool,
} }
impl Widget for Span { impl Widget for Span {
@@ -85,7 +86,7 @@ impl Widget for Span {
} }
if ortho_mixed { if ortho_mixed {
ortho_len = LayoutLen::default(); ortho_len = LayoutLen::default();
} else { } else if self.compact_orthogonal {
let ortho = ortho_len let ortho = ortho_len
.apply_rest(painter.density()) .apply_rest(painter.density())
.align(AxisAlign::Neg); .align(AxisAlign::Neg);
@@ -111,9 +112,18 @@ impl Span {
children: Vec::new(), children: Vec::new(),
dir, dir,
gap: LayoutLen::ZERO, gap: LayoutLen::ZERO,
compact_orthogonal: false,
} }
} }
/// Shrink the span and its children to the widest orthogonal child
/// instead of leaving children in the orthogonal space offered by its
/// parent.
pub fn compact(mut self) -> Self {
self.compact_orthogonal = true;
self
}
pub fn gap(mut self, gap: impl Into<LayoutLen>) -> Self { pub fn gap(mut self, gap: impl Into<LayoutLen>) -> Self {
self.gap = gap.into(); self.gap = gap.into();
self self
@@ -132,6 +142,7 @@ pub struct SpanBuilder<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Ta
pub children: Wa, pub children: Wa,
pub dir: Dir, pub dir: Dir,
pub gap: LayoutLen, pub gap: LayoutLen,
pub compact_orthogonal: bool,
_pd: PhantomData<(State, Tag)>, _pd: PhantomData<(State, Tag)>,
} }
@@ -146,6 +157,7 @@ impl<Rsc, const LEN: usize, Wa: WidgetArrLike<Rsc, LEN, Tag>, Tag> WidgetFnTrait
children: self.children.add(rsc).arr.into_iter().collect(), children: self.children.add(rsc).arr.into_iter().collect(),
dir: self.dir, dir: self.dir,
gap: self.gap, gap: self.gap,
compact_orthogonal: self.compact_orthogonal,
} }
} }
} }
@@ -158,6 +170,7 @@ impl<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Tag>, Tag>
children, children,
dir, dir,
gap: LayoutLen::ZERO, gap: LayoutLen::ZERO,
compact_orthogonal: false,
_pd: PhantomData, _pd: PhantomData,
} }
} }
@@ -166,6 +179,13 @@ impl<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Tag>, Tag>
self.gap = gap.into(); self.gap = gap.into();
self self
} }
/// Shrink the span and its children to the widest orthogonal child
/// instead of filling the orthogonal space offered by its parent.
pub fn compact(mut self) -> Self {
self.compact_orthogonal = true;
self
}
} }
impl std::ops::Deref for Span { impl std::ops::Deref for Span {