v0.8.14: icons from the desktop's theme (Breeze), readable text, composer frame

The window drew its icons with unicode glyphs -- a clip emoji for attach, a
gear, a hamburger, a chevron, a multiplication sign for delete. Those render
in whichever font happens to cover them (colour emoji in a grey toolbar) and
are a box on a machine without that glyph. They now come from the icon theme,
the way every other desktop app gets them.

Icons
- app/src/ui/ThemeIcons.{h,cpp}: a QQuickImageProvider for
  image://csttheme/<name>?color=%23rrggbb -- QIcon::fromTheme() in the
  desktop's theme (whatever the platform theme set, else breeze-dark, breeze,
  hicolor), tinted with QPainter's SourceIn and rasterised at the requested
  size and the screen's device pixel ratio. Qt only builds its theme search
  paths from XDG once a theme name is set, so the provider fills them itself
  (GenericDataLocation/icons, ~/.icons and, on NixOS,
  /run/current-system/sw/share/icons, for a shell started outside the desktop
  session). An unknown name yields a null image, which QML reports as
  Image.Error.
- app/qml/ThemeIcon.qml: the one component that asks for an icon. Every use
  still names the old character as `glyph:`, so a host with no icon theme
  degrades to exactly what the window looked like before instead of going
  blank. installThemeIcons() is called by main() and by --uitest, so the test
  loads the same icons the app does.
- Replaced: nav (application-menu), settings (settings-configure), attach
  (mail-attachment), copy (edit-copy), session delete (edit-delete), new
  session (list-add), expand/collapse (arrow-right/arrow-down), jump to the end
  (go-down), the plan checklist (task-complete/box). A tool card also shows
  what kind of tool ran -- Theme.toolIcon(): pencil for patch/write, text page
  for read, folder for list/glob, magnifier for grep, braces for a shell,
  globe for web, list for a plan. Toolbar icons are 22 px (Breeze's toolbar
  size), card and row icons 14-16 px.

Colours (the "some text is unreadable" part)
- textFaint #6d757b -> #8d959c: ~3.4:1 -> ~5:1 on the card fill. It carries
  hints, provider URLs, session metadata and placeholders, so it is text, not
  decoration.
- A selected provider row and the open session row write on the accent fill;
  they now use accentText / accentTextDim / okOnAccent instead of faint grey
  and green on blue (named "accentText", not "onAccent": QML reads any `onFoo`
  property as a signal handler and refuses the assignment).
- The filled buttons (Send, Use this) take their ink from Theme.accentInk.

Composer
- The frame is one Theme.pad around its column on every side (anchors.fill,
  implicitHeight + 2*pad). With the top margin alone the last row -- the clip
  and Send -- hung over the lower border, which is what put the clip on the
  frame instead of inside it.

app/README.md gains an "Icons, colors" section (the provider, why the theme
search paths are filled by hand, the qtsvg requirement for rasterising Breeze,
the tool map, and the contrast rules).

Verified: --uitest 52/52, --selftest OK, and the 0.8.14 window relaunched in
the Plasma session (no QML warnings).

Version 0.8.14.

mode = coding
This commit is contained in:
WHC
2026-10-11 12:53:49 +08:00
parent 8694afca94
commit 3fd039cb51
19 changed files with 392 additions and 64 deletions
+35 -1
View File
@@ -200,6 +200,37 @@ list, and — with an 8×8 image put on the clipboard — `clipboardHasImage()`
for that (a row as JSON — an object would not survive
`QMetaObject::invokeMethod`).
## Icons, colors
- Icons come from the desktop's **icon theme** (Breeze on KDE), through
`image://csttheme/<name>?color=%23rrggbb` (`app/src/ui/ThemeIcons.{h,cpp}`).
Qt Quick has no icon provider of its own without Kirigami, so the window used
unicode glyphs before (a clip emoji, a gear, a hamburger): those render in
whichever font covers them — colour emoji in a grey toolbar — and are a box
on a machine without that glyph. `app/qml/ThemeIcon.qml` is the one place
that asks for an icon, and every use still names the old character as
`glyph:`: a host with no icon theme degrades to what it looked like before
rather than going blank.
- The provider fills Qt's theme search paths itself (XDG data dirs, `~/.icons`
and, on NixOS, `/run/current-system/sw/share/icons`): Qt only builds them
from XDG once a theme name is set. It then tries the theme the desktop chose,
else `breeze-dark` (this window is dark), `breeze`, `hicolor`. Rasterising
Breeze needs the Qt SVG image format plugin (`qt6.qtsvg` on Nix, part of a
desktop Qt install) — without it the icons fall back to the glyphs instead of
disappearing.
- `Theme.toolIcon(name)` maps a tool onto its icon: patch/write → pencil,
read → text page, list/glob → folder, grep → magnifier, shell → braces,
web → globe, plan → list, ask → question mark. Toolbar icons are 22 px
(Breeze's toolbar size), card and row icons 14–16 px.
- `textFaint` is readable grey, not decoration (~5:1 on the card fill): it
carries hints, secondary lines and provider URLs. Anything written *on* the
accent fill (a selected provider row, the open session) uses `accentText`,
`accentTextDim` and `okOnAccent` — green or faint grey on `accentDim` is
unreadable. The names are not `onAccent…`: QML reads every `onFoo` property
as a signal handler and refuses the assignment.
- The composer's frame is one `Theme.pad` around its column on **all** sides;
with the top margin alone the clip and Send hung over the lower border.
## Tools the app provides
A tool implemented in the front end is registered with `cst_tool_register()`
@@ -258,7 +289,10 @@ The build flag that keeps Unix helpers out of the picture is
- [x] session list in the sidebar: new / switch / delete, transcript replay
- [x] settings dialog: provider, model, key (`cst_ps_*`), token counters
- [x] attachments: picker, drop on the window, Ctrl+V image paste
- [x] icons from the desktop's icon theme (Breeze), with a glyph fallback
- [x] contrast pass: faint text and selected rows are readable
- [ ] a real turn driven through the window (needs a provider key)
- [ ] tool results that carry images (they are stored, not drawn yet)
- [ ] Kirigami (Breeze look), tray, global shortcuts
- [ ] Kirigami (the rest of the Breeze look: colors, controls), tray,
global shortcuts
- [ ] Android APK (engine in-process, JNI platform tools)