Uh oh!
There was an error while loading. Please reload this page.
Backgrounds: a panel behind a section, and behind each thing it draws - #20
Merged
ZombieHDGaming merged 3 commits intoAug 26, 2026
Merged
Conversation
A background is a fill, a shape and an edge: a colour, a linear or radial gradient, or an image fitted by cover, contain, stretch or tile; four corner radii; an optional border; a per-side outset and an opacity. It sits in one of eight slots on a section -- the section itself, its title, its subtitle, each logo, each list entry, every other entry, the bridge and a divider's artwork -- held as the slots a section has been given rather than as all eight always, so a section with no panels costs nothing to copy and writes nothing into the scene collection. That is also what lets an alternate entry panel be told apart from one set to draw nothing, which is how a striped list leaves every other row bare. A panel never takes part in layout. It is painted behind a box that has already been decided and its outset reaches outside that box the way a text shadow does, so switching one on never moves a section or changes the roll's duration; sectionBleed grows to count it, which keeps a band from being cut at a tile seam. The room inside a panel is the padding a section already had. Slots bind to named BackgroundPresets, a second collection beside the text styles on the document and in the machine-wide library, with their own linking, forking and rename trail -- separate because a panel and a typeface are not one decision, and because a shared namespace would make a background called "Card" collide with a style of the same name. A sticky block's stickyBackdrop, stickyBackdropColor and stickyBackdropPadding are gone: a block now uses its section slot like everything else, painted into the block's own picture. GradientSpec moves to model/Gradient.hpp so a panel can map a sweep over itself through the very code that maps one over a run of glyphs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUfbS9hZrjGeRN3NNg369X
A BackgroundEditor holds everything one panel carries, and the section editor puts up one folding group per slot -- built from the slot table, so a slot added to the model turns up here with nothing to write. Which groups are on screen follows backgroundSlotsFor(), which is the model's own answer rather than a second one assembled out of the predicates the visibility pass had already gathered. Each group is checkable, and the checkbox is what says the slot carries a panel at all -- a different question from what the panel is filled with. For an alternate entry the two really do differ: a list that alternates onto a panel filled with nothing is how every other row is left bare, where a list with no alternate draws the same panel behind every row. All eight read the same way rather than seven plus a footnote. The corner radii and the outset are each offered as one figure with a switch for four, because a panel with all four corners alike is what nearly every design wants and a row of four spin boxes to say so is four times the question. The style library manager grows a picker saying which of the library's two collections its lists are showing. One pair of lists rather than two, because publish, link, copy, rename and delete mean exactly the same thing for either kind. An import brings both collections in whichever way the picker is set: a file is imported whole. The sticky block's three backdrop rows are gone from the editor with the fields behind them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUfbS9hZrjGeRN3NNg369X
The suite pins down the rule the whole feature turns on -- a panel in any slot, at any size, changes no height and moves no section -- and then the things that rule costs: the outset reaching past the box, a band crossing a tile seam being drawn into both tiles rather than cut at it, and a Spacer's panel bleeding at all, which is why the bleed is taken over every type rather than only the ones that set text. Also the corner path and its scaling, the border staying inside the panel's bounds, an image clipped to the shape rather than the box around it, the four fits, striping by an alternate entry slot, preset binding and its fallback, and both collections in the library with a rename trail each. The fit checks use a solid image of their own rather than the harness's test logo: that one is a ring, so its ink reaches only the middle of each edge and its centre is transparent, which makes "cover fills the panel" an approximation rather than a measurement. A `backgrounds` scene shows the three shapes a panel is actually reached for -- a bordered card behind a heading, a band reaching past its section out to the edges of the frame, and a striped list. ARCHITECTURE.md gains sections on the panels and their presets, and two limitations: an outset is bounded by the roll's own extent, and a panel's image is a still. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUfbS9hZrjGeRN3NNg369X
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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.
A panel is a rectangle drawn behind something: a flat colour, a linear or radial gradient, or an image fitted by cover, contain, stretch or tile; four corner radii; an optional border; a per-side outset and an opacity.
There is a
backgroundsscene in the test harness to look at it with —./build/tests/closing-time-tests --artifacts out/writesbackgrounds.png, showing the three shapes a panel is actually reached for: a bordered card behind a heading, a band reaching past its section out to the edges of the frame, and a striped list.The rule the whole thing turns on
A panel never takes part in layout. It is painted behind a box the layout has already decided, and its outset reaches outside that box exactly the way a text shadow does. Switching a panel on — at any size, on any slot — cannot move a section, grow the roll or change how long it runs, so a roll can be given cards and bands after it has been timed.
sectionBleedcounts the outset, so a band crossing a tile seam is drawn into both tiles instead of being cut at it.The room inside a panel is the padding a section already has. The outset is for the other case — a band that has to reach past the section's box, out to the edges of the frame — and is per side because reaching past one edge is a different want from reaching past all four.
Eight slots, not eight fields
SectionTitleSubtitleLogoEntryEntryAltBridgeDividerA slot rather than a named field apiece: eight
BackgroundPanelmembers would be eight copies of the same save/load, eight branches in the editor and eight places for a new panel setting to be forgotten.backgroundSlotsForsays which of them a type has anything to sit behind, derived from the existing predicates rather than tabulated beside them.A section holds the slots it has been given rather than all eight always. A section with no panels costs nothing to copy onto the undo stack and writes nothing into the scene collection — which is every section in every roll written before this existed. It is also what makes striping work: a list with no alternate draws
Entrybehind every row, and a list that has one draws it behind the odd rows, so an alternate left onNoneis how every other row is left bare.Two mappings are not the obvious one. In a bridged row the two text slots are the row's two columns, which is how the two styles already map. And a plain list is offered no title slot: its line and its entry are one rectangle, and two names for the same place would be two settings drawing over each other.
Performance
A panel goes under something whose rectangle is only known once it has been measured, and measuring text twice is the most expensive thing this renderer could casually start doing.
SectionPanels::wantsis asked first: a slot with nothing in it — every slot until somebody sets one — costs one comparison and the content is laid out exactly once, as it always was. Only a slot that will really paint pays for the extra measure.Presets and the library
A slot binds to a named
BackgroundPreseton the document exactly the way a section binds to aStylePreset, with the same non-destructive fallback in both directions. They are a second collection beside the text styles — on the document and in the machine-wide library — because a panel and a typeface are not one decision made twice, and because a shared namespace would make a background calledCardcollide with a style of the same name. The library therefore keeps two rename trails; their mechanics are written once as free functions over a trail and used by both.refreshLinkedPresetsbrings both collections up to date in one call, so a caller cannot follow its styles and leave its panels behind.Removed
Section::stickyBackdrop,stickyBackdropColorandstickyBackdropPaddingare gone. That trio was this feature in miniature for one section type — a flat colour and a padding, with no corners, no gradient, no image and no preset behind it. A block now uses itsSectionslot like everything else, painted into the block's own picture (it leaves a hole in the strip, so it cannot use the pre-switch paint site the other types do). No migration is written: the feature was confirmed unused.GradientSpecmoves tomodel/Gradient.hppso a panel can map a sweep over itself through the very code that maps one over a run of glyphs —textFillBrushis now a thin wrapper over the sharedgradientBrush.Designer
One folding group per slot, built from the slot table, showing only the slots the section's type has a use for. Each group is checkable, and the checkbox is what says the slot carries a panel at all — a different question from what it is filled with, and one that genuinely matters for the alternate entry. The corner radii and the outset are each offered as one figure with a switch for four, because a panel with all four corners alike is what nearly every design wants.
The style library manager gains a picker saying which of the two collections its lists are showing; publish, link, copy, rename and delete mean the same thing for either kind, so it is one pair of lists rather than two.
Verification
Backgroundssuite covers the never-reflow rule across all eight slots, the outset, a band crossing a tile seam, the corner path and its scaling, the border staying inside the panel's bounds, an image clipped to the shape rather than the box around it, the four fits, striping, preset binding and its fallback, and both library collections with a rename trail each.-Wall -Wextra -Werror;clang-format-19andgersemiare clean.Known limitations, documented