@@ -539,7 +539,11 @@ python3 tools/ansi_frame_to_image.py frame.ansi frame.html # or .svg
539539 wording, and this is the one that happens many times an hour), ` prefix-panel ` (the ⌃B which-key
540540 panel — the state ` prefix ` becomes a few hundred milliseconds later, if no key has arrived),
541541 ` focus ` /` focus-moved ` (a split * and* a second command line — the one geometry showing a focused pane
542- beside an unfocused one and an armed bar above an idle one, before and after a real ⌃→), plus the
542+ beside an unfocused one and an armed bar above an idle one, before and after a real ⌃→),
543+ ` tabs ` (** two tabs in the pane that does * not* hold the focus** — the one geometry that can show a
544+ strip saying which tab is in front, since every other view has at most one tab in an unfocused pane.
545+ It opens a third window for itself alone, and re-activates the main window before splitting, because
546+ opening brings a window to the front and a split carries the tabs that are not), plus the
543547 default workspace
544548 (no ` --view ` ). Any settings screen also takes a ` -edit ` suffix, which opens it and drives real
545549 keys in so the frame shows a field mid-edit. State toggles: ` collapsed ` , ` prefix ` , ` timestamps ` ,
@@ -854,10 +858,25 @@ markup (`[bold #rrggbb on #rrggbb]…[/]`, `[[`/`]]` escaping, `[link=url]…[/]
854858 ` TabTitles ` claimed the opposite for as long as it existed, and the claim had two costs: the unread
855859 count went out untinted, and a window title was never escaped — a window called ` [Chat] ` , or a web view
856860 titled from the page it loaded, had that eaten as a tag by the parser * and* by the hit test. Titles are
857- ` MarkupText.Escape ` d now. The tint covers the name and the count only; the ` ▌ ` stays outside it, because
858- focus and activity are independent facts and a marker that changed colour on an incoming line would be
859- reporting the wrong one. ** The two cues are different channels on purpose** — focus is said entirely in
860- * backgrounds* from the theme's chrome family, activity in a * foreground* no plane is painted in.
861+ ` MarkupText.Escape ` d now. The tint and the selection ** bold** cover the name and the count only; the ` ▌ `
862+ stays outside them, because focus, selection and activity are independent facts and a marker that
863+ changed colour on an incoming line would be reporting the wrong one. ** The cues are different channels
864+ on purpose** — focus in * background luminance* , activity in a * foreground* no plane is painted in,
865+ selection in * weight* and in a within-strip step. A selected tab can be unread, so the two are one tag
866+ (` [bold #rrggbb] ` ) rather than two nested ones.
867+ - ** A tab chip says which tab you are viewing, relative to its own strip — and pane focus is not a term in
868+ it.** The selected chip is painted ` PaneSurfaceTone ` exactly, the plane its own page is painted on, and
869+ its siblings are ` WorkspacePalette.Recessed ` one step below it (` BackdropScale ` , the backdrop's own
870+ step). Focus arrives already folded into that plane — tinted for the character, lifted for focus — so
871+ one ratio inside every strip reads whether or not the pane holds the keyboard, and hue is untouched.
872+ Deriving the selected chip * from* focus is what made this unreadable: ` PaintTabChips ` computed an
873+ unfocused pane's selected chip and its siblings from the same expression, background ** and** ink, so
874+ every chip in a background pane was byte-identical to the pane's surface and the ` ▌ ` was no help
875+ because ` TabTitles ` only emits it on the focused pane. ` TabSelectionTests ` , and the ` tabs ` view is the
876+ frame — no other view has two tabs in an unfocused pane, which is why nothing caught it.
877+ ** Not fixed here** : the ` │ ` between chips and the ` ─ ` filling the rest of the strip are hardcoded
878+ ` Color.Grey ` in ` TabControl.Rendering.cs ` , unthemeable in all three header styles. That is an upstream
879+ change.
861880- ** One unread count, one spelling: ` UnreadBadge ` .** The sidebar and the tab strip are two views of
862881 ` WorkspaceWindow.Unread ` , and they had two formatters — the rail capped at ` 99+ ` , the tab printed the
863882 raw integer, so a busy channel read ` 99+ ` in one place and ` (4127) ` in the other. Cap, field width and
@@ -889,7 +908,7 @@ markup (`[bold #rrggbb on #rrggbb]…[/]`, `[[`/`]]` escaping, `[link=url]…[/]
889908 is derived from the pane rectangle (` PaneOutputRects ` ), so a border, gutter or marker column that only
890909 the focused pane has would re-announce a different terminal size to every connected server on every
891910 focus change and reflow the game's own output. The cues are the pane's own plane
892- (` WorkspacePalette.Focus ` ), the active tab's chip colour ( ` TabControl.Active*BackgroundColor ` ) , and a
911+ (` WorkspacePalette.Focus ` ), the tab chips it carries that plane into , and a
893912 ` ▌ ` in the tab * title* — all zero-cost. ` FocusIndicationTests.MovingFocusDoesNotMoveAnyPaneRectangle `
894913 is the test that stops this being "improved" into a border. Colours live in ` WorkspacePalette ` , whose
895914 constants are all derived from a ` ScreenPalette ` pair so the workspace and the settings screens share
0 commit comments