Repository navigation
History window: cap a row's badges, count the rest in words, hint the whole line - #151
Merged
Merged
Conversation
The History window painted a badge for every slot an operation touched, but the layout only made room for three. The card's first sighting touches all 99, so 96 badges ran over the action, the detail and the audio column (#143). The hit test walked the same unbounded list, and a click anywhere on that row silently filtered to a slot. Which badges a row wears is now one answer, history::badges::shown, read by both the painting and the hit test: up to three slots, then a "+N" chip in the last position counting the rest, and none at all for a snapshot, whose sentence already says "99 slots". The chip is a number, not a filter; the counted slots still answer the slot filter, and a restore out of a snapshot still goes by the filtered slot. A click in a row is now a mouse-free action, clickAt, so the tests can press the chip and see nothing happen.
A detail that did not fit was cut at its end with an ellipsis, which is exactly the part that matters: a normalize that says "already peaking at the -1 dBTP ceiling (measured -19.2 LUFS), nothing to..." lost the "nothing to do" (#143). elideMiddle fits a sentence into a width by replacing as little of its middle as has to go with one ellipsis, the tail never shorter than the head. It is pure: the width of a string comes from a function the painting site provides, so the fit is tested through a stand-in face, and every candidate is measured, so what comes back has been seen to fit — or is the ellipsis alone when not even that does.
With the detail cut to the row's width, the rest of a sentence could be read nowhere: the window had no hints at all (#143). Each row now answers getTooltipForRow with its whole line — when, action, detail, state, audio — joined by a dash, the parts that are empty left out. A juce::TooltipWindow shows tips only for components sharing its own peer, so the main window's never reached a view living in its own desktop window. HistoryWindowHost, the frame the view lives in, owns one now, with the main window's delay so the two feel alike.
…red slot in sight The snapshot row wore no badges, but nothing said its slots in words either: rows::forCard words the row as "Card first seen" and "<N> takes, <bytes>", and the window's test had typed "99 slots" into the detail by hand (#143, review). Now a row counted in words paints "<N> slots" across the badge strip in the chip's quiet ink, and its hint carries the same words. The test feeds a snapshot row worded by rows::forCard from a 99-slot entry, so the words are proven to be the window's own. Filtering to a slot behind the chip left the row with no violet badge, so nothing said why it was listed. The filtered slot now takes the last badge position in place of the row's slot there — the chip keeps its count, one slot out of hiding as one went in — and the hit test reads the same answer. The hint also says what the row paints and the strip only counts: "slots 3, 7, 12, 40, 99" for a row with a chip, and "pinned" for a pinned row. badgeStripText reads the strip in words — the badges' numbers, the chip, or the words — from the same list the painting draws.
… in the strip from playing show() took any row: slot 0, slot 100, a slot twice, slots out of order. The badge for such a slot then threw from inside JUCE's mouse dispatch when clicked, far from the mistake (#143, review). The store hands slots ascending, each once, and the pedal has 1..99 of them; a row that says otherwise is now refused by its op before the window changes. A double-click returned early only where badgeAt answered, so a double-click on the chip, or on the "99 slots" words, played the row. The guard is now the whole badge strip — badge, chip or words, the first click has answered — and a double-click past it still plays. doubleClickAt is the mouse-free version, like clickAt, so the tests can press it.
elideMiddle cut by character, so a cut could land between a letter and its combining accent, inside a family joined by zero-width joiners, or between the two letters of a flag: valid UTF-8 that renders wrong, and take names from macOS often come decomposed (#143, review). Each side of the cut now pulls back to the cluster it would have cut into — the head's end down, the tail's start up — over the clusters UAX #29 has for what names and sentences carry: combining marks, variation selectors, skin-tone modifiers, the joiner and what follows it, and regional-indicator pairs. The fit is still measured, candidate by candidate. "One ellipsis" means one put in: a sentence carrying its own keeps it, and the comment now says so.
The History window's frame had its own 600 next to the main window's 600 (#143, review). kHintDelayMs lives in HintDelay.h now, and both windows read it.
This was referenced Oct 4, 2026
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.
Closes #143.
The first-sighting row painted a badge for every one of its 99 slots over its own words, and the hit test answered everywhere on it, so a click anywhere silently filtered the window to a slot.
app/HistoryBadges.h) decides which badges a row wears; painting and the hit test both read it, so they cannot drift apart. A snapshot row wears none and says "99 slots" in the badge strip instead; a multi-slot operation shows the first badges and a "+N" chip that is not a filter target. A slot filter keeps the filtered slot in sight even when it would sit behind the chip.TooltipWindowit needs, since the main window's cannot reach a view in another window.app/MiddleEllipsis.h), so "nothing to do" survives; the cut never splits a grapheme cluster.show()refuses a row whose slots are not the pedal's (outside 1..99, duplicates, unsorted); a double-click inside the badge strip never plays.app/HintDelay.h).Tests:
history_badges_tests(53),middle_ellipsis_tests(2183),history_window_tests(303, the snapshot row built throughrows::forCard). Non-GUI ctest 58/58; the six GUI harnesses 6/6 locally; a headless--history-windowrender on a fixture card shows the snapshot row as "99 slots · Card first seen · 0 takes, 0 bytes".