summaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/plans')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md123
1 files changed, 98 insertions, 25 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
index 21e7a91..8b3858b 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
@@ -53,7 +53,7 @@ taking that too literally.
| 2 | No way to see full message details (From/To/Cc/Subject) | information | M | **done** |
| 3 | Too few clickable affordances, shortcuts are the only route | discoverability | M | **done** |
| 4 | Message-pane font size does not survive restart | persistence | S | **done** |
-| 5 | Thread list is cramped, poor readability | presentation | S | open |
+| 5 | Thread list is cramped, poor readability | presentation | S | **done** |
| 6 | Opened message stays unread | behavior | S | **done** |
| 7 | HTML view should be default for HTML messages | behavior | XS | **done** (already worked) |
| 8 | No buttons or menu entries for archive, undo, etc | discoverability | M | **done** |
@@ -446,20 +446,36 @@ to copy.
Two concrete sub-items, from using the list rather than looking at it:
- **"All items look unread (bold), maybe use regular for read items?"**
- **Done 2026-08-07, and the guess written here was wrong on both branches.**
-
- Bold was indeed already conditional, and the user's list was not mostly
- unread, and bold was not leaking. The actual cause: **bold renders
- identically to regular on the user's system.** Confirmed by eye against a
- bare `QTableView` holding a plain `QStandardItemModel` with no qtmaildir code
- involved, so the fault is in Qt or fontconfig, below this application, and
- nothing in the model could ever have reached it. Bold was unread's ONLY cue.
-
- The fix inverts the emphasis instead: unread rows keep the palette's text
- colour and READ rows are dimmed toward the background, via
- `ThreadListModel::readColour()`. The cue rides on `Qt::ForegroundRole`, costs
- no column, and suits the real ratio, which was 99 unread against 4220 read.
- Bold is kept, since it works on other systems, but nothing depends on it.
+ **Resolved 2026-08-07. The cause was a misconfigured desktop font, not code.**
+
+ The user's Qt font was set to **Bold in qt6ct**, so every row rendered bold
+ and nothing could stand out. Bold in the model was working correctly the
+ whole time. Correcting the qt6ct setting fixed the original complaint on its
+ own.
+
+ **Read this before trusting any measurement in this file.** Three wrong
+ conclusions were reached before that came out, and the reasoning behind each
+ is worth keeping, because the same mistakes are easy to repeat.
+
+ 1. Dismissed from thread counts (99 unread against 4220 read), which
+ explained why two screenshots looked alike but said nothing about whether
+ bold rendered.
+ 2. Dismissed again by a probe counting lit pixels. Antialiasing makes a bold
+ and a regular glyph light a similar number, so the metric read "identical"
+ regardless of the truth. **Text width is the honest measure**: with the
+ font misconfigured both weights measured 277px, and once corrected they
+ measured 277px against 306px.
+ 3. Concluded that Qt or fontconfig was broken, from a bare `QTableView` with
+ a plain `QStandardItemModel` painting two rows identically. That test was
+ correct and its conclusion was wrong: the baseline font was already bold,
+ so `setBold(true)` genuinely changed nothing.
+
+ **The dimming was kept anyway**, and stands on its own merits rather than on
+ that mistaken diagnosis. `ThreadListModel::readColour()` dims READ rows
+ toward the background while unread keeps the palette's text colour. With 99
+ unread among 4220 read, dimming the bulk carries the list better than
+ emphasising the few, and it is a second cue that survives a font setting like
+ the one that caused this. Bold still applies on top.
**A caution for anyone adding another `ForegroundRole` cue.** Qt resolves
that role into the palette and then prefers it over `HighlightedText`, so a
@@ -469,21 +485,78 @@ Two concrete sub-items, from using the list rather than looking at it:
delegate is installed view-wide rather than on the subject column alone so
every column gets the same handling.
- **How this was nearly missed twice.** It was first dismissed from thread
- counts, which explained why two screenshots looked alike but said nothing
- about rendering. It was then dismissed again by a probe that counted lit
- pixels: antialiasing makes a bold and a regular glyph light a similar number,
- so the metric read "identical" regardless. Text WIDTH distinguishes them
- (277px against 288px for the same string) and a strict pixel diff does; an
- ink count does not. The tests that now guard this strip the font from the
- model's answer entirely and require the two states to still differ, which is
- the assertion that was missing all along.
+ **One test had to be rewritten when the font was corrected.**
+ `aSelectedReadThreadIsNotDimmedIntoTheHighlight` originally compared a
+ selected read row against a selected unread one and required them to paint
+ identically. That only held because every row was bold; with bold working,
+ the unread row differs legitimately. It now asserts the resolved palette
+ rather than pixels, which is the property the fix actually changes.
- **A star column for flagged threads**, mirroring the paperclip column that
already exists for attachments. `ThreadSummary` carries the tags and
`flagged` is an ordinary notmuch tag, so this needs no new worker query, the
same way item 15's paperclip did not. Keep it narrow: an icon column, no
- text.
+ text. **Done 2026-08-07**, as `FlagColumn` beside `AttachmentColumn`, using
+ the same glyph-with-ASCII-fallback pattern (`flagGlyph()`).
+
+### Built 2026-08-07, and what the layout cost
+
+The row is roughly doubled in height, with the tags shown as chips beneath the
+subject, alternating row colours, and the star column above.
+
+**The tag strip is painted by the VIEW, not by a delegate**, which is why
+`ThreadListView` exists at all. A delegate is handed one cell's rectangle and
+cannot paint outside its column, so a strip drawn from the subject column's
+delegate stops at that column's edge, losing the last tags of a well-tagged
+thread, and starts at that column's left edge, which puts it under the subject
+rather than under the row. The user asked for it under the whole row:
+
+```
+[ date ][ from ][ subject ...................... ]
+ [ pill ][ pill ][ pill ]
+```
+
+**Which tags appear.** Everything except `inbox`, `unread`, `flagged`,
+`attachment` and the account tag, since the row already shows those as
+structure, dimming, the star, the paperclip and the chip. Sorted, because
+notmuch's order is not guaranteed stable and a row whose chips reordered
+between repaints would flicker.
+
+**Six defects were introduced and fixed while building this**, every one of
+them a consequence of the same thing: a `QTableView` paints PER CELL, and a
+row-wide strip is not a cell. Worth listing, because each is easy to
+reintroduce.
+
+1. `SubjectDelegate` was installed view-wide to spread the selection fix
+ across every column. It reads `AccountLabelRole`, which belongs to the row,
+ so every column drew the account chip. Split into `RowStyleDelegate` (the
+ selection fix, every column) and `SubjectDelegate` (chip, subject column
+ only), with a `Q_ASSERT` guarding the latter.
+2. Row height was returned from `sizeHint`, which does nothing: a table takes
+ ONE height per row, so a hint from a single column applies only if the view
+ happens to ask that column. Set on the vertical header instead.
+3. The strip used `viewportMargins().left()`, which is 0, so it painted from
+ the viewport edge across the marker columns. It compiled because the method
+ is protected and the call was inside the subclass.
+4. The text band and the strip were measured with one font, so the pills rode
+ up over the date and sender.
+5. Alternating colours and the selection are painted per cell, so the strip's
+ band showed the bare viewport background as a stripe across every other
+ row. The view now fills that band itself, and must honour three cases: the
+ model's own `BackgroundRole` first (a deleted thread's fill would otherwise
+ be cut in half), then the selection, then the alternating colour.
+6. That fill spanned the full width, and the marker glyphs are centred in the
+ full row height, so its top edge cut the paperclip and star at their
+ midpoint. The band starts at the date column now.
+
+**A note on verifying any of this.** Several rendering probes written during
+this work returned results that were confidently wrong: counting "lit" pixels
+cannot tell bold from regular, since antialiasing lights a similar number
+either way, and `viewport()->render()` returned a blank image more than once.
+Text width distinguishes weights; a strict pixel diff distinguishes renders;
+an ink count distinguishes nothing. Two versions of the strip's own test passed
+under mutation before one was written that matched the exact chip colours the
+model supplies.
## 6. Opened message stays unread