From 50123c6e0e10571fcd5830526a6027403dec4767 Mon Sep 17 00:00:00 2001 From: Ethan Reynolds Date: Thu, 1 Oct 2026 13:19:38 -0400 Subject: [PATCH] fix(#194): an unshrunk tab is exactly its natural width tabs.width rebuilt every tab's width as least plus the rest times the shrink factor. at a factor of one that sum can land a hair short of the natural width in floating point, so the label box came out a fraction of a pixel narrower than the label and fit_box cut it with an ellipsis. a tab the bar has room for now takes its natural width directly. the test sweeps paddings that do not land on whole pixels and fails without the fix. --- src/tabs.mach | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/tabs.mach b/src/tabs.mach index 39daf3e..5316ac5 100644 --- a/src/tabs.mach +++ b/src/tabs.mach @@ -357,8 +357,11 @@ fun least(ctx: *context.Context, g: *Geom, t: *Tab) f32 { ret minf(natural(ctx, g, t), g.pad * 2.0::f32 + g.lh * 2.0::f32 + close_w(g, t)); } -# a tab's width this frame +# a tab's width this frame. a tab the bar has room for is exactly its natural +# width: rebuilt through the shrink, least plus the rest times one, it can come +# out a hair short and cut a label that fits. fun width(ctx: *context.Context, g: *Geom, t: *Tab) f32 { + if (g.fit >= 1.0::f32) { ret natural(ctx, g, t); } val lo: f32 = least(ctx, g, t); ret lo + (natural(ctx, g, t) - lo) * g.fit; } @@ -751,6 +754,34 @@ fun keys(a: *App) u64 { ret k; } +test bar__unshrunk_tabs_are_their_natural_width { + var al: allo.Allocator; + val made: err[allo.Error] = page.make(?al); + if (sel made.err) { ret 1; } + var a: App; + var d: driver.Driver; + if (!app(?d, ?al, ?a, 8, 2000.0::f32)) { ret 1; } + a.tabs[1].closable = false; + a.tabs[4].closable = false; + var g: Geom; + g.fit = 1.0::f32; + g.lh = context.line_height(?d.ctx); + # paddings that do not land on whole pixels, as a scaled theme gives + var k: u32 = 1; + for (k < 400) { + g.pad = k::f32 * 0.037::f32; + var i: usize = 0; + for (i < a.n) { + if (width(?d.ctx, ?g, ?a.tabs[i]) != natural(?d.ctx, ?g, ?a.tabs[i])) { ret 2; } + i = i + 1; + } + k = k + 1; + } + val f: err[allo.Error] = driver.free(?d); + if (sel f.err) { ret 1; } + ret 0; +} + test bar__selects_closes_and_reorders { var al: allo.Allocator; val made: err[allo.Error] = page.make(?al);