GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
fix(group): count a labelled member's strip once
A widget's rect is its content plus its detached-label strip (the
WidgetHost::label_strip contract; `layout` lands the block a strip above
the content origin). Group::hull subtracted the strip from that rect again,
so every labelled member lifted the hull — and the frame and its title tab —
one strip too high. In the gallery the Flat lasso's tab landed on the
exhibit above its first member. The hull now takes the rect as is; a test
with a labelled Slider pins it.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
src/widget/container/group.rs | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/src/widget/container/group.rs b/src/widget/container/group.rs
index f05ed80..2654c17 100644
--- a/src/widget/container/group.rs
+++ b/src/widget/container/group.rs
@@ -111,15 +111,15 @@ impl Group {
if !w.visible() {
continue;
}
- let (x, mut y, ww, mut hh) = w.rect();
+ let (x, y, ww, hh) = w.rect();
if ww <= 0.0 || hh <= 0.0 || x + ww <= 0.0 || y + hh <= 0.0 {
continue;
}
- // A labelled control's detached label hangs in the strip above its
- // rect: the lasso wraps the label too.
- let strip = w.label_strip();
- y -= strip;
- hh += strip;
+ // The rect IS the block — a labelled control's detached label strip
+ // is already in it (`WidgetHost::label_strip`: "a widget's rect is
+ // always its content plus this strip"), so the lasso wraps the label
+ // by taking the rect as is. Subtracting the strip here again pushed
+ // every labelled member's hull one strip too high, and the tab with it.
hull = Some(match hull {
None => (x, y, x + ww, y + hh),
Some((x0, y0, x1, y1)) => (x0.min(x), y0.min(y), x1.max(x + ww), y1.max(y + hh)),
@@ -277,7 +277,7 @@ impl Input for Group {
#[cfg(test)]
mod tests {
use super::*;
- use crate::widget::{Button, WidgetHost};
+ use crate::widget::{Button, Slider, WidgetHost};
fn register(ctx: &mut UiContext, w: &mut dyn WidgetHost) -> WidgetId {
let id = w.base().id();
@@ -303,6 +303,23 @@ mod tests {
assert!(f.tab.is_none(), "no label, no tab");
}
+ /// A labelled member's rect already holds its label strip; the hull takes the
+ /// rect as it is, not the rect less another strip.
+ #[test]
+ fn a_labelled_members_strip_is_counted_once() {
+ let mut ctx = UiContext::new();
+ let mut s = Slider::new().with_label("Amount");
+ let strip = s.label_strip();
+ assert!(strip > 0.0, "a detached label has a strip");
+ // The block: strip + control, as `layout` lands it.
+ WidgetHost::set_rect(&mut s, 100.0, 50.0, 160.0, 16.0 + strip);
+ let ids = vec![register(&mut ctx, &mut s)];
+ let g = Group::new(ids).with_padding(10.0);
+ let f = g.inner().frame(&ctx).unwrap();
+ assert_eq!(f.body.y, 40.0, "one padding above the block, not a strip more");
+ assert_eq!(f.body.height, 16.0 + strip + 20.0);
+ }
+
/// Fit to plate: a side near the plate's edge takes it (one padding in), a
/// far side keeps the hull, and a corner on the plate's corner is concentric.
#[test]