The strip becomes a panel, and the rest of the page verbs arrive - #9
Merged
Conversation
The strip held nine things and the library behind it holds about twenty-five.
A tenth button already reached two thirds of the way across, and most of what
is left cannot be a button at all: it has to be told which pages, or how many
to a sheet, or what to write, and a row of buttons has nowhere to say it.
So the verbs are grouped, and a group opens a panel BESIDE the page rather
than instead of it. Beside is the whole design decision. Every verb here
changes the document, and this workbench draws the document by writing it out
and reading it back — so typing a crop box and watching the page come back
cropped is what the control is for. A panel over the page would hide the one
thing worth looking at.
WHAT IS NOW REACHABLE
Pages which pages to keep or drop, turn them a quarter / a half / three
quarters, reverse the order, move the page on the screen, crop to a
box, insert a blank page, split into files of n pages
Sheet n pages to a sheet, fold into a booklet, add another file after this
one, lay another file over it
Marks write a watermark across every page, in words somebody chose
File strip what runs rather than shows
Two up, Watermark and Sanitize leave the strip for the group each belongs to.
Two up becomes a number, so it is also three up and sixteen up.
THREE THINGS THAT WERE DEAD AND ARE NOT ANY MORE
None of this could have worked without them, and none of them was visible
before there was a panel to notice it in.
A press arrived at a widget in SURFACE coordinates, and a container reads the
point it is given as local to itself before adding its own origin back on. On
a strip eight pixels from the top that is a near miss the sweep in the test
papered over. On a panel that starts forty-six pixels down it is a press on
the wrong row.
The view got no events at all: handleClick reached only the toolbar. The Fill
in panel, which is a panel of real widgets bound through observables, could
not be pressed in a browser — it was a picture of controls.
Char() returned false, always. Nothing could be typed anywhere, so 76.3% of
the fields in the form panel — the text ones — had no way in.
The scroll view underneath was the fourth: toolkit v0.250.0 did not forward a
press to what is inside one, so every control in a scrolling panel was dead to
the mouse. That is fixed upstream in v0.267.0, which is why this bumps the
toolkit to v0.272.0.
A gap that is not fixed: neither ScrollView nor FormField implements the
unexported focusableChildren, so the toolkit's own focus walk stops at the
scroll view and cannot find a box inside it. The workbench therefore hands a
keystroke straight to the box it knows was last pressed. It works and it is
honest, but Tab does not walk the panel.
WHAT WAS MEASURED
Eleven verbs over 400 real forms taken evenly from the eleven issuing bodies
in /Users/Shared/pdfforms — 400 of the 1 633 real documents, the 635 vendor
fixtures left out. 4 400 outputs: every one written by ops, read back by our
own reader, parsed by pdfinfo and drawn by pdftoppm with ink on the page.
4 311 of 4 311 applicable outputs passed all four
89 not applicable: one-page documents where deleting page one leaves a
document with none, which the panel refuses for that reason
Two apparent failures in the first run were the measurement's own and are
worth recording: pdftoppm pads the page number to the width of the page count,
so page-1.png is not always what it writes; and a blank page inserted at the
front is MEANT to come out blank, so the ink has to be looked for on page two.
Read the output, not the exit code.
In a real browser, with nothing eyeballed: the check now presses along the
strip from the right until the right-hand band of the canvas lights up, presses
down that panel until one of its verbs changes the band where the page is,
saves, and parses what came back to find (DRAFT) Tj in it. A panel that is
painted and gets no events looks exactly like one that works.
100% of statements, and every control in every group is reached by pressing it
where it was drawn rather than by calling its handler.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Two boxes in one panel and every letter typed into the second went into the first. A press on a box focuses it; nothing ever defocuses the one that had the caret before, so both are focused at once and the workbench hands the keystroke to whichever it finds first. The toolkit does have a rule for this — a click walks the container for its focusable descendants and focuses exactly the one it hit — but the walk needs each container to enumerate its focusable children, and neither ScrollView nor FormField does. Every control in this panel is inside both, so the walk finds nothing and defocuses nothing. So a press clears the caret from every box before it is routed, which leaves it in exactly the box the press landed in, and in none at all when it landed somewhere else. 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.
The strip held nine things. The library behind it holds about twenty-five, and
most of what is left cannot be a button at all: it has to be told which pages,
or how many to a sheet, or what to write, and a row of buttons has nowhere to
say it. A tenth button already reached two thirds of the way across.
The design decision, and why
The verbs are grouped, and a group opens a panel beside the page rather
than instead of it.
Beside is the whole of it. Every verb here changes the document, and this
workbench draws the document by writing it out and reading it back — so typing
a crop box and watching the page come back cropped is what the control is
for. A panel over the page (which is what
Fill indoes, correctly, becausea hundred fields need the room) would hide the one thing worth looking at. The
page is rescaled to what the panel leaves, so it shrinks rather than being
pushed off the edge.
The alternative considered and rejected was tabs or a segmented switcher: both
truncate their labels, and
PagesandSheetwould both be reduced to an S —the same reason the strip is buttons rather than a
Toolbar.What is now reachable
Strip: Open · Save · < · > · Rotate · Delete · Pages · Sheet · Marks · File ·
Fill in. What stays on it is what needs no telling.
Two up, Watermark and Sanitize leave the strip for the group each belongs to.
Two up becomes a number, so it is also three up and sixteen up.
Deliberately left out of this PR
number,bates,stamp,compress,flatten,encrypt,decrypt,permissions,info,text,images— a second PR, so that this one isabout the shape the panel takes and that one is about filling it.
fillisalready done and is not touched.
merge/overlayare here because they neednothing but a second file;
splitis here because it needs only a number.Three things that were dead, and one in the toolkit
None of this could work without them, and none was visible before there was a
panel to notice it in.
is given as local to itself and adds its own origin back on before
hit-testing. On a strip 8 px from the top that is a near miss the sweeping
test papered over; on a panel that starts 46 px down it is a press on the
wrong row.
handleClickreached only the toolbar.The
Fill inpanel, real widgets bound through observables, could not bepressed in a browser. It was a picture of controls.
Char()returnedfalse, always. Nothing could be typed anywhere, sothe 76.3% of form fields that are text had no way in.
ScrollViewdid not forward a press to its child in toolkit v0.250.0,so every control in a scrolling panel was dead to the mouse. Fixed upstream
in v0.267.0; this bumps the toolkit to v0.272.0 for it.
A gap that is not fixed, named rather than worked around
Neither
ScrollViewnorFormFieldimplements the toolkit's unexportedfocusableChildren, so its own focus walk stops at the scroll view and cannotfind a box inside one. The workbench therefore hands a keystroke straight to
the box it knows was last pressed — which works, and is honest, but Tab does
not walk the panel. That belongs upstream, not here.
What was measured
Eleven verbs over 400 real forms, taken evenly from the eleven issuing
bodies in
/Users/Shared/pdfforms— 400 of the 1 633 real documents, the635 vendor fixtures excluded. 4 400 outputs, each written by
ops, readback by our own reader, parsed by
pdfinfoand drawn bypdftoppmwith ink counted on the page:
Two apparent failures in the first run were the measurement's own, and are
worth recording:
pdftoppmpads the page number to the width of the pagecount, so
page-1.pngis not always what it writes; and a blank page insertedat the front is meant to come out blank, so the ink has to be looked for on
page two. Read the output, not the exit code.
In a real browser
The check now presses along the strip from the right until the right-hand band
of the canvas lights up, presses down that panel until one of its verbs changes
the band where the page is, saves, and parses what came back to find
(DRAFT) Tjin it:A panel that is painted and gets no events looks exactly like one that works,
so the pixels are read either side of every press — and the wait before each
look is deliberate:
webcanvasrepaints on an animation frame, not on thepress.
Checks
100% of statements. Every control in every group is reached by pressing it
where it was drawn, not by calling its handler.
go vetandgofmtclean onnine targets,
-raceclean, and the window was rendered and looked at at eachstep — which is how the panel was found drawing nothing at all the first time
(a
ScrollViewkeeps its child's own width and height, and nobody had giventhe column one).