diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-11 20:24:05 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-11 20:24:05 +0200 |
| commit | 1faf94eb35e8270a659f215d260db73bcaa3f8d7 (patch) | |
| tree | 6305f6532cf1abc000eb261ce85c3ce12bc0a8d3 /docs | |
| parent | 64d3138ba923071069da6c9bc458a25a9cc7d27f (diff) | |
| download | qtmaildir-1faf94eb35e8270a659f215d260db73bcaa3f8d7.tar.gz qtmaildir-1faf94eb35e8270a659f215d260db73bcaa3f8d7.zip | |
feat(panes): draw the pane marks from shipped SVGs, not font glyphs
Items 70 and 69, the second folded into the first as item 70's own size note
predicted it should be.
The panes drew their state marks as font glyphs: U+1F4CE for an attachment and
U+2605 for a flagged thread, each with a fallback for a font that cannot render
it. Both fell back to "*", so on such a font a flagged thread and one carrying
an attachment were indistinguishable, which is a defect the fallback introduced
rather than prevented. What a mark looks like was also the desktop's decision
rather than this application's, and the panes are exactly where it should not
be: the user asked for the toolbar and menus to keep following their icon theme
while the panes stop.
Six marks now ship in assets/icons/marks/: flagged, attachment, passed, replied
and the two expander triangles. QIcon::fromTheme still resolves every toolbar
and menu icon and was not touched.
Licensing chose the shapes. The look came from a GPL3 icon theme, and this
project is GPLv2-only, which are incompatible: GPLv2's "no further
restrictions" clause bars shipping GPL3 assets in a v2-only work. The six were
drawn fresh in the same idiom instead, with no path data copied. The idiom is
generic: solid single-path silhouettes at 16x16 with no strokes.
They are compiled in as string literals rather than loaded from a .qrc.
src/CMakeLists.txt already records why resources belong to the executable: a
qrc in the static library registers itself from a global initialiser the linker
drops. The tests link the library, so a resource-based mark would be missing
exactly where it needs asserting. assets/icons/marks/ stays the editable
source.
One asset serves both palettes. Every payload paints with fill="currentColor",
which QSvgRenderer renders black rather than resolving, so Marks::pixmap
composites the wanted colour with CompositionMode_SourceIn. A mark then takes
the card's own pen colour and follows selection and the read/unread dimming
without a second variant to keep in step.
CardLayout reserves a rect per mark and CardDelegate paints into it. The marks
were glyphs inside the subject STRING, so their width came free from the text
metrics; as icons the geometry has to know they are there or the subject runs
underneath them. The expander pill had the same trap, its triangle being a
glyph in expanderLabel(), and now reserves that width explicitly.
Item 69's part: passed and replied were words in the tag strip and are marks
beside the subject now. The message pane's header carries the flagged and
attachment marks next to the subject, per the user's decision that the right
pane needs those two and only outside the message area.
A duplicate that no test caught is worth recording. Every geometry assertion
passed while a card showed passed as BOTH an arrow and a green tag chip: the
chip filter had no reason to know a mark had appeared. It was found by
rendering real cards to an image and looking at them. isDrawnAsAMark() is now
one list consulted by both PillTagsRole and MessageOwnTagsRole, since two
copies drifting apart is how a tag ends up drawn twice on one row and not at
all on another.
Fourteen tests: nine in test_marks, four in test_cardlayout, one in
test_threadlistmodel. Mutation-checked at four points, each failing a test: the
subject ignoring the marks, the flag not indenting the subject, the pill
forgetting the triangle's width, and the recolour composite removed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | 55 |
1 files changed, 53 insertions, 2 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 2663b44..0a1f4dc 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 @@ -125,8 +125,8 @@ taking that too literally. | 66 | Selecting a thread root leaves the message pane blank until a reply has been selected | defect | S | open; needs a reproduction before a fix | | 67 | The placeholder pane counts unread, flagged and inbox, but not sent or drafts | information | XS | **done** 2026-08-11, shipped in 0.15.0 | | 68 | A forwarded subject gets no `passed` tag | workflow | S | open; no subject rule exists, measured 2026-08-11. Decision needed: display mark (XS) or write the flag (S, syncs out) | -| 69 | `passed` and `replied` read as words where every other state is a glyph | presentation | S | open; depends on 68 for what `passed` means | -| 70 | Pane icons are a private set where the main window uses the system theme | presentation | M | open | +| 69 | `passed` and `replied` read as words where every other state is a glyph | presentation | S | **done** 2026-08-11, inside item 70 | +| 70 | Pane icons are a private set where the main window uses the system theme | presentation | M | **done** 2026-08-11; six shipped SVGs | | 71 | A toolbar action does not sync, so the edit sits until the next cron run | workflow | S | **done** 2026-08-11; 2s default, `auto_sync_delay_ms` | | 72 | No khard/khal integration | workflow | ? | open, unspecified; the user places it after send, so v2 at the earliest | | 73 | This backlog is past four thousand lines | maintenance | S | open | @@ -4423,6 +4423,57 @@ covers actions only and will not catch a collision between pane marks. **Size: M**, and it overlaps 69, which should probably be done inside it rather than before it. +**Done 2026-08-11, with item 69 folded in as the Size note predicted.** Six +marks ship with the application in `assets/icons/marks/`: flagged, attachment, +passed, replied and the two expander triangles. The toolbar and menus still +resolve through `QIcon::fromTheme` and were not touched, which is the split the +user stated. + +**Licensing decided the shapes.** The user pointed at the Material-Black-Plum-Suru +theme as the look they wanted. That set is GPL3 (`index.theme` names Sam Hewitt +and the licence) and this project is GPLv2-ONLY (`src/main.cpp:6`, no "or +later"), which are incompatible: GPLv2's "no further restrictions" clause bars +shipping GPL3 assets in a v2-only work. The user chose to have the six drawn +fresh in the same idiom rather than relicense, so no Suru path data was copied. +The idiom itself is generic: solid single-path silhouettes at 16x16, no strokes. + +**Not a .qrc.** `src/CMakeLists.txt` already records that a qrc compiled into the +static library registers itself from a global initialiser the linker drops, so +resources belong to the executable. The tests link the LIBRARY, so a +resource-based mark would be absent exactly where it needs asserting. The +payloads are compiled in as string literals in `src/marks.cpp`, generated from +the assets, which stay the editable originals. + +**One asset per mark, not one per theme.** Every payload paints with +`fill="currentColor"`, which `QSvgRenderer` does not resolve: it renders black. +`Marks::pixmap` composites the wanted colour with `CompositionMode_SourceIn`, +so a mark takes the card's own pen colour and follows selection and the +read/unread dimming for free. Cached by (mark, size, colour, ratio), since a +delegate repaints these per row per frame. + +**`CardLayout` reserves the rects; `CardDelegate` paints them.** The marks were +glyphs inside the subject STRING, so their width came free from the text +metrics; as icons the geometry has to know they exist or the subject runs +underneath them. That is why `Input` grew four bools. The same trap bit the +expander pill, whose triangle was a glyph in `expanderLabel()` and now needs its +width reserved explicitly. + +**What the tests could not catch, and the render did.** Every geometry +assertion passed while a card showed `passed` as BOTH an arrow and a green tag +chip: the chip filter had no reason to know a mark had appeared. Found by +rendering real cards to a PNG and looking at it. `isDrawnAsAMark()` is now one +list consulted by both `PillTagsRole` and `MessageOwnTagsRole`, since two copies +drifting is how a tag ends up drawn twice on one row and not at all on another. + +Nine tests in `test_marks` and four in `test_cardlayout`, plus one in +`test_threadlistmodel` for the de-duplication. Mutation-checked at four points: +the subject ignoring the marks, the flag not indenting the subject, the pill +forgetting the triangle's width, and the recolour composite removed. Each failed +a test. The old `flagGlyph()`/`attachmentGlyph()` and their `*` fallback are +deleted; that fallback was a latent defect of its own, since both collapsed to +the same character and made a flagged thread indistinguishable from one with an +attachment. + ## 71. A toolbar action does not sync, so the edit sits until the next cron run **Observed (user, from the notes):** "clicking one action in the toolbar should be |
