fix(panel): align the chart with the blocks under it #23

Merged
yuris merged 1 commit from fix/align-right-column into main 2026-09-05 20:04:27 +00:00
Owner

No, I liked the chart's width. It's not an overhang when that's the target
width for the search bar and the list.

Right, and the first version of this PR had it backwards — it narrowed the chart
to 287 to meet the blocks below. Reversed: the chart is untouched and everything
else reaches it.

The measurement that started it

block right edge
scope total x = 1211
a row's duration x = 1211
chart's last bar x = 1230

The cause was that the derivation only ran one way. The chart's width was the
column's, and every block under it was that minus the scroll's own insets:

RIGHT_W  = BAR_W * DAYS + BAR_GAP * (DAYS - 1)              -- 305, the chart
LIST_W   = RIGHT_W - 2 * VIEWPORT_INSET - SCROLLBAR_GUTTER  -- 283
CHROME_W = LIST_W + VIEWPORT_INSET                          -- 287

The fix

CONTENT_W is still the chart's own width. The other blocks reach it, and the
18 px comes off the panel instead of off them:

CONTENT_W = BAR_W * DAYS + BAR_GAP * (DAYS - 1)             -- 305, unchanged
LIST_W    = CONTENT_W - VIEWPORT_INSET                      -- 301
CHROME_W  = CONTENT_W                                       -- 305
RIGHT_W   = CONTENT_W + VIEWPORT_INSET + SCROLLBAR_GUTTER   -- 323

plugin.toml's width goes 578 → 596. The scrollbar now gets a strip of its own
beside the content rather than a bite out of it. BAR_W is back to a plain 19 —
the chart is the width chosen for a reason here, so it is the input, not the
output.

A row stays one viewport inset narrower than the chrome because it starts that
far in, which is what puts the two right edges on the same pixel. A row cannot be
CONTENT_W exactly at any panel width: ScrollView::m_viewportPaddingH is
unreachable from the plugin whitelist, so the 4 px is not optional — widening the
panel is what makes the row's right edge land on the chart's anyway.

The gutter is still reserved unconditionally, for the reason already in the file:
m_scrollbarShown flips at the exact row count where the list starts scrolling
(scroll_view.cpp:429), and a row sized to live content would jump 14 px there.

Verified on screen

aligned

A 1 px guide dropped at the content edge lands on the search field's right edge,
the chart's last column, and the scope total — all three on the same pixel, with
the bars visibly unchanged. Measured before the change, those were 1211 / 1211 /
1230.

Suite

17 states, 2358 field comparisons / ok; lint 0 errors, 0 warnings.

Pinned: each block's right edge against the others, the caption's elide budget
against them, the bars summing to the row they are pinned inside (the row's
own width cannot say it — a node does not clip its children, so a BAR_W that
does not come to CONTENT_W leaves the row declaring one width and painting
another), and the columns adding up to 596 - 28. That last one ties
plugin.toml's width to the constants for the first time — flagged on #21 as
out of reach, and deriving RIGHT_W is what brought it in reach.

11 mutations, no survivors. Notably B8 — narrowing the rows by the gutter again
— is the exact old behaviour, and it now fails.

> No, I liked the chart's width. It's not an overhang when that's the target > width for the search bar and the list. Right, and the first version of this PR had it backwards — it narrowed the chart to 287 to meet the blocks below. Reversed: the chart is untouched and everything else reaches it. ## The measurement that started it | block | right edge | |---|---| | scope total | x = 1211 | | a row's duration | x = 1211 | | chart's last bar | **x = 1230** | The cause was that the derivation only ran one way. The chart's width *was* the column's, and every block under it was that **minus** the scroll's own insets: ``` RIGHT_W = BAR_W * DAYS + BAR_GAP * (DAYS - 1) -- 305, the chart LIST_W = RIGHT_W - 2 * VIEWPORT_INSET - SCROLLBAR_GUTTER -- 283 CHROME_W = LIST_W + VIEWPORT_INSET -- 287 ``` ## The fix `CONTENT_W` is still the chart's own width. The other blocks reach it, and the 18 px comes off the **panel** instead of off them: ``` CONTENT_W = BAR_W * DAYS + BAR_GAP * (DAYS - 1) -- 305, unchanged LIST_W = CONTENT_W - VIEWPORT_INSET -- 301 CHROME_W = CONTENT_W -- 305 RIGHT_W = CONTENT_W + VIEWPORT_INSET + SCROLLBAR_GUTTER -- 323 ``` `plugin.toml`'s `width` goes 578 → 596. The scrollbar now gets a strip of its own beside the content rather than a bite out of it. `BAR_W` is back to a plain 19 — the chart is the width chosen for a reason here, so it is the input, not the output. A row stays one viewport inset narrower than the chrome because it *starts* that far in, which is what puts the two right edges on the same pixel. A row cannot be `CONTENT_W` exactly at any panel width: `ScrollView::m_viewportPaddingH` is unreachable from the plugin whitelist, so the 4 px is not optional — widening the panel is what makes the row's right edge land on the chart's anyway. The gutter is still reserved unconditionally, for the reason already in the file: `m_scrollbarShown` flips at the exact row count where the list starts scrolling (`scroll_view.cpp:429`), and a row sized to live content would jump 14 px there. ## Verified on screen ![aligned](guide) A 1 px guide dropped at the content edge lands on the search field's right edge, the chart's last column, and the scope total — all three on the same pixel, with the bars visibly unchanged. Measured before the change, those were 1211 / 1211 / 1230. ## Suite `17 states, 2358 field comparisons` / `ok`; lint `0 errors, 0 warnings`. Pinned: each block's right edge against the others, the caption's elide budget against them, **the bars summing to the row they are pinned inside** (the row's own `width` cannot say it — a node does not clip its children, so a `BAR_W` that does not come to `CONTENT_W` leaves the row declaring one width and painting another), and the columns adding up to `596 - 28`. That last one ties `plugin.toml`'s `width` to the constants for the first time — flagged on #21 as out of reach, and deriving `RIGHT_W` is what brought it in reach. 11 mutations, no survivors. Notably `B8` — narrowing the rows by the gutter again — is the exact old behaviour, and it now fails.
The right column ran its geometry backwards. BAR_W was fixed at 19, the
chart's width fell out of it, and the search row, scope row and history
rows were that minus the scroll's own insets -- so the chart came out 18
px wider than every block under it and overhung them to the right by
exactly the viewport inset plus the scrollbar strip. Measured on screen:
the scope total and the row durations both end at x=1211, the chart's
last bar at x=1230.

The chart is the block with no reason to be the widest, so it follows
now. CONTENT_W is the one number, and the chart row, the caption's elide
budget, both chrome rows and the history rows all land their right edge
on it; BAR_W is whatever is left over divided by DAYS, which is 17.71 at
the shipped numbers -- a fraction is fine, props reach the reconciler as
doubles and are scaled rather than rounded. RIGHT_W is now derived as
the content plus the strip only the scrollbar uses, so the column and
the panel's manifest width are unchanged.

The suite gains the four claims that make this hold: every block's right
edge on one pixel, the caption eliding at that edge rather than into the
scrollbar's strip, the bars summing to the row they are pinned inside --
which the row's own width prop cannot say, since a node does not clip
its children -- and the columns adding up to plugin.toml's 578 less the
shell's 28 a side, which nothing tied together before.
yuris force-pushed fix/align-right-column from f2c6b3994d to 08fb8b6d18 2026-09-05 20:00:10 +00:00 Compare
yuris merged commit e2263f0ce3 into main 2026-09-05 20:04:27 +00:00
yuris deleted branch fix/align-right-column 2026-09-05 20:04:27 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/noctalia-timew!23
No description provided.