fix(ui): keep flexible children inside their parent, and let weight win - #104
Merged
Conversation
Checkpoint before further work.
The geometry a caller reads back is now the distance between two rounded edges, never a rounded size. A stack divides its width exactly (96.5 + 6 + 97 + 6 + 96.5 fills a 302px row), but rounding each child's size on its own reported 97/97/97 for a total of 303, so the last child looked like it hung a pixel past the row and "every widget fits inside its parent", the one invariant a layout audit wants to trust, was false by a pixel and compounded with nesting. Edge rounding makes adjacent children tile: one child's trailing edge is the next one's leading edge, so a 302px row reads back as 97 + 97 + 96. This covers get_width and get_height and the /widgets and /widget/N geometry the driver reports, on AppKit and on GTK4, where the same independent rounding truncated instead and under-reported. Win32 already derived its sizes from integer edges. Found while confirming the weighted half of the same report: weight() on buttons was silently overridden by the equal-width chain a row of buttons gets by default. That chain is a required constraint and the proportional shares are not, so weights of 16 / 62 / 22 came out 500/500/500 in a 1500px row. A weight is an explicit instruction to divide space unevenly, so it now retracts the chain for that child exactly as an explicit width() already did, and the same weights now give 240/930/330, summing to the row exactly. ui.timer also keeps firing while a slider or scrollbar is being dragged, a menu is open, or a window is resized live. scheduledTimer registers in the default run-loop mode alone, and AppKit runs all of that tracking in NSEventTrackingRunLoopMode, where a default-mode timer never fires, so an animation or a clock stopped dead for as long as the mouse was held down. flexround_demo and its driver spec assert the invariant rather than per-backend pixel counts, so they mean the same thing on AppKit and GTK4. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The new spec claimed the three buttons end up within a pixel of each other. That is AppKit behaviour: an equal-width chain is what gives a row of buttons its grid-like look there, while GTK4 sizes each button to its own label, so the row came out 60 / 71 and the assertion failed on Linux while the three real invariants passed on both backends. Replaced with the property the fix actually delivers, which is true on either backend: adjacent children's reported edges are separated by exactly the stack's spacing. Rounding each width on its own pushed the remainder into the gaps, so a 6px gap read back as 5 or 7 depending on where the fractions fell; edge-rounded geometry makes it 6 every time, because both edges are offset by the same whole number before rounding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two reported bugs, plus a third found while confirming the second.
ui.timerstops during modal tracking (#97)scheduledTimerregisters in the default run-loop mode alone, and AppKit runsslider drags, scrollbar drags, menu tracking and live window resize in
NSEventTrackingRunLoopMode, where a default-mode timer does not fire. Ananimation or a clock stopped dead for as long as the mouse was held down and
jumped on release. The timer now goes into the common modes.
Flexible children overflow their parent by the rounding remainder (#101)
The layout was never wrong. Auto Layout divides a 302px row exactly:
The readback was wrong. It rounded each child's SIZE on its own, so those
three frames reported as 97 / 97 / 96.5 rounded up to 97, a total of 303 in a
302px parent. The report's own numbers show it:
x=206 w=97where the trueframe is
205.5 + 96.5. Positions already rounded consistently, sizes did not.A reported size is now the distance between two ROUNDED EDGES, so adjacent
children tile: one child's trailing edge is the next one's leading edge, and
the row reads back as 97 + 97 + 96 = 290, plus 12 of gaps, exactly 302. The
remainder is spread rather than dumped on the last child, so the widest and
narrowest differ by at most a pixel, which is the distribution the issue asks
for.
Fixed in
get_width/get_heightand in the/widgetsand/widget/Ngeometry the driver reports, on AppKit and on GTK4. GTK4 had the same
independent rounding by truncation, which under-reports rather than overflows,
but breaks tiling the same way. Win32 already derived its sizes from integer
edges and needed no change.
weight()silently overridden on buttonsConfirming the weighted-pane half of #101 turned up a separate bug. A row of
buttons gets an equal-width chain by default, which is what gives the
calculator its grid-like rows. That chain is a required constraint and the
proportional shares from
weight()are not, so weights of 16 / 62 / 22 cameout 500 / 500 / 500 in a 1500px row, with no diagnostic.
set_widthalreadyretracted the chain for exactly this reason;
weightnow does too.Before and after, same program:
240 / 930 / 330 is 16% / 62% / 22% of 1500, and it sums to the row exactly, so
this also settles the "237 + 918 + 326 = 1481" case in the report.
Verification
aeb .all.aebuilds clean, zero warnings.flexround_demoreportsbuttons=97/97/96in a 302px row andweighted=240/930/330in a 1500px row. Both sum to their parent exactly.numbers, which is what showed the layout was already correct and moved the
fix to the readback instead of to the constraints. An earlier attempt that
lowered the equal-width constraint's priority changed nothing and was
dropped.
spec_flexround_demoasserts relationships between the reported numbers,not per-backend pixel counts, so it means the same thing on AppKit and
GTK4. Wired into ci.sh phase 5k6. Driver specs cannot run in the local
sandbox, which blocks the bind, so CI is what exercises it; the spec itself
compiles clean against the driver library.
old numbers.
Closes #97
Closes #101
🤖 Generated with Claude Code