diff --git a/README.md b/README.md index d412394..6ec2bd6 100644 --- a/README.md +++ b/README.md @@ -2394,8 +2394,8 @@ now — they are listed so they are not mistaken for anything else: section was short of room, and finding one meant scrolling past the others. The built sidebar is a **Measure** tab (the cursors readout and the measurements) and a **Signals** tab (the trigger and the channels), **each a pill with its own glyph and no text** — the - cursors and the ruler for Measure, a sine crossing its trigger level and the channel list for - Signals (the same picture the toolbar's trigger button carries), drawn as a + cursors and the ruler for Measure, a signal rising above its trigger level and the channel list + for Signals (the same picture the toolbar's trigger button carries), drawn as a 32x16 pair so both motifs are legible at a glance — with the words kept as each pill's tooltip and accessible name. The design spec had the switcher showing *titles* and neither page an `icon-name`; `narrow` alone does not do it (libadwaita still draws a label beside the icon, diff --git a/docs/claude/invariants-gtk-and-chrome.md b/docs/claude/invariants-gtk-and-chrome.md index 06bd216..5235505 100644 --- a/docs/claude/invariants-gtk-and-chrome.md +++ b/docs/claude/invariants-gtk-and-chrome.md @@ -61,74 +61,24 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear an icon with a live user is not an orphan, whatever the toggle that introduced it did -- and it is the Preferences window's icon, not the tab's. - The two **tabs** got glyphs of their own, and each is a *pair* rather than one of the icons above: - `udpscope-tab-measure-symbolic` is the cursors and the ruler they read against, and - `udpscope-tab-signals-symbolic` is the trigger's edge above the channel list it acts on. They are not - reuses because a glyph the toolbar already carries means two things the moment a tab shows it too. Both - are **32x16** composites: the Measure pill is two cursors *standing on* the scale they read against — the - one band with alternating marks, each marker centred on one of them, which is one instrument rather - than two icons in a box — and the Signals pill a sine with a dashed level through it beside the - channel list. That picture is shared on - purpose: the trigger's *own* toolbar icon (`udpscope-trigger-symbolic`) is the same sine and the same - level, one period of one-pixel stairs, so the pill and the button that turns the trigger on are - recognisably about the same thing. The trigger glyph used to be a rising edge, and one edge names only - one of the four shape triggers the panel offers — a wave crossing a level names the trigger's job. - Wider than tall on purpose — a 16px square cell carries - one motif, and squeezing a pair into it is what turns both into a smear — and the pill has the width for - it, in a 300px column whose switcher has two pills in it. **GDK paints an icon into a square box whatever - the document's aspect** (measured: `gtk_icon_theme_lookup_icon()` at 32 reports `32x32`, and librsvg - fits it to `32x16`), so the pair is letterboxed, not stretched — and the pill's image is given - `pixel_size` 32 in `name_side_tabs()`, which draws the artwork at exactly the size it is written, so its - 2px bars stay crisp. A fractional scale is what blurs them, which is why nothing here is drawn at 24 or - 48. The bars in the Signals list are all one length, because unequal ones read as a bar chart and a chart - is not a list; their ink fractions (23% and 33%) sit inside the range the icons above set, which is the - check that a composite has not turned into a blot. Beside them in - `src/icons/scalable/apps/` are the two - **application** icons, `org.udpscope.app.svg` (128px colour artwork) and - `org.udpscope.app-symbolic.svg` (16px). The `apps` context is where an icon theme keeps an - application's own icon and is where the **in-process** window icon resolves from; it is also - the layout that `cmake/install_desktop_entry.cmake` mirrors when it copies the same two files - into `$XDG_DATA_HOME/icons/hicolor/scalable/apps` and `.../symbolic/apps` — those installed - copies are what makes `Icon=org.udpscope.app` in the desktop entry resolve (a desktop shell - cannot read a GResource compiled into the binary). - All nine are bundled by `src/icons/udpscope.gresource.xml` (CMake runs - `glib-compile-resources`) and reached through **one** - `gtk_icon_theme_add_resource_path()` in `run_ui()`, right after `adw_init()` — not at the top - of `build_toolbar()`, where it used to be: there are two consumers now (the window's own icon, - set before the toolbar is built, and the toolbar's buttons) and `run_ui()` is the one place - ahead of both. `adw_init()` calls `gtk_init()`, which is what makes - `gdk_display_get_default()` valid there. - A resource rather than files beside the binary because udpscope is run straight out of the - build tree and has no install step. Five authoring rules, each of which fails quietly: - * **GTK's symbolic recolour only reaches `fill` on `path`, `rect` and `circle`.** It wraps the - SVG in a stylesheet for those selectors, so a `stroke`, a `line` or a `polyline` keeps the - colour written in the file and stays dark on a dark theme. **In a symbolic icon everything is - therefore a filled `path`** — including anything that wants to look stroked, which is drawn as - a closed band (two offset curves joined) instead. The rule is scoped to symbolic icons on - purpose: `org.udpscope.app.svg` is 128px colour artwork that is never recoloured, so it strokes - its sine freely, which is the sane way to draw a smooth one. Do not "fix" one to match the - other. - * **Whole-pixel coordinates**, because these are drawn at 16 px far more often than not: the - first draft placed features on half-pixels and the whole icon was a grey smear at 1x. - * `fill-rule="evenodd"` is how the ruler's body is a hole *and* its ticks still fill -- a tick - inside the hole is three crossings deep, which is odd. Nonzero would fill the hole back in. - * Overlapping subpaths under the default nonzero rule must be **wound the same way** or they - cancel instead of uniting. All of them run clockwise. - * **A malformed SVG is a build error, and that is the only place it can be caught.** Every - `` in `src/icons/udpscope.gresource.xml` carries `preprocess="xml-stripblanks"`, which - makes `glib-compile-resources` pipe it through `xmllint` — so `--` inside an XML comment, which - is illegal and which librsvg refuses the whole file for, fails the build with a file, a line - and a caret under the offending character (`…app-symbolic.svg:5: parser error : Double hyphen - within comment`). It has to be here because **no runtime check can see it**: librsvg refuses - the file but the icon *name* still resolves, so `gtk_icon_theme_has_icon()` returns true and - the icon draws nothing. `gtk_icon_theme_lookup_icon()` cannot tell either (see the `app icons:` line under - Verification), `GMarkup` accepts the double hyphen because it is a lenient subset parser, and - `gdk_pixbuf` goes through glycin here, which sandboxes a subprocess per load and refuses this - project's own icons outright. The cost is that the `xmllint` binary is a build dependency; it - ships with libxml2, which GTK already requires. - `gtk_icon_theme_has_icon()` is checked for every toolbar button and reported by the dump (see - `toolbar icons:` in [probe-readings.md](probe-readings.md)): a resource path that was never added does not raise an - error, it draws `image-missing`. + The two **tabs** got glyphs of their own, and each is a *pair* rather than one of the icons above. + `udpscope-tab-measure-symbolic` is two cursors beside the ruler they read against — each a cap over two + bold dashes, beside a ruler of two bands with three marks between them and **no end caps** (a closed + frame reads as a rectangle, and costs a fifth of the ink on two lines that say nothing) — and + `udpscope-tab-signals-symbolic` is a signal rising above its level, beside two bold channel rows. They + are not reuses, because a glyph the toolbar already carries means two things the moment a tab shows it + too; instead the *trigger's* own icon (`udpscope-trigger-symbolic`) was redrawn to the Signals pill's + picture, so the pill and the button that turns the trigger on are recognisably about the same thing. + Both are **32x16** composites drawn **bold** — one thick band, two thick dashes, few features — because + at this size a thin wave or a 1px tick reads as *texture* rather than as a shape, which is what "not + clear" looks like. Wider than tall on purpose: a 16px square cell carries one motif, not a pair. And + **GDK paints an icon into a square box whatever the document's aspect** (measured: + `gtk_icon_theme_lookup_icon()` at 32 reports `32x32`, and librsvg fits it to `32x16`), so the pair is + letterboxed rather than stretched — and the pill's image is given `pixel_size` 32 in `name_side_tabs()`, + which draws the artwork at the size it is written, so its bars stay crisp. Every glyph here is + **inset two pixels**, because art flush with the cell edge is what a button's padding or a crop takes a + pixel off, and a fractional scale is what would blur it, which is why nothing is drawn at 24 or 48. The + two tab glyphs measure 29% and 30% ink, inside the range the icons above them set. - **A shortcut table row's `accel` is GTK accelerator syntax, and a pointer gesture has none.** `src/shortcuts.cpp`'s strings are handed to `AdwShortcutsItem`, which parses them with `gtk_accelerator_parse()` — so they are `"space"`, `"e"`, `"slash"`, diff --git a/docs/claude/verification.md b/docs/claude/verification.md index 2f96e79..c212fba 100644 --- a/docs/claude/verification.md +++ b/docs/claude/verification.md @@ -16,7 +16,7 @@ xvfb-run -a env UDPSCOPE_EXIT_AFTER_MS=8000 UDPSCOPE_ENABLE_ALL_MS=1000 \ Two baselines every run is read against. A clean build emits **four** warnings and no more: two `-Wmissing-field-initializers` on `MathNode::source` and `-Woverlength-strings` on **both** generated GResource `.c` files — the help pages' (**514660** bytes) and the icons', whose blob is -**12624** against C99's 4095-byte string-literal limit with the seven action icons and the two app icons +**11774** against C99's 4095-byte string-literal limit with the seven action icons and the two app icons that remain (a note about a generated file, which GCC itself supports) -- re-measured when the tab work changed the set (that icon left, the two tab glyphs arrived, and this file's help page was rewritten), which did not move the count; re-measure by touching each `*.gresource.xml` diff --git a/src/icons/scalable/actions/udpscope-tab-measure-symbolic.svg b/src/icons/scalable/actions/udpscope-tab-measure-symbolic.svg index f95881a..c59cc50 100644 --- a/src/icons/scalable/actions/udpscope-tab-measure-symbolic.svg +++ b/src/icons/scalable/actions/udpscope-tab-measure-symbolic.svg @@ -1,26 +1,21 @@ - + - + diff --git a/src/icons/scalable/actions/udpscope-tab-signals-symbolic.svg b/src/icons/scalable/actions/udpscope-tab-signals-symbolic.svg index a052491..dae8748 100644 --- a/src/icons/scalable/actions/udpscope-tab-signals-symbolic.svg +++ b/src/icons/scalable/actions/udpscope-tab-signals-symbolic.svg @@ -1,32 +1,27 @@ - + - + diff --git a/src/icons/scalable/actions/udpscope-trigger-symbolic.svg b/src/icons/scalable/actions/udpscope-trigger-symbolic.svg index 777e512..6d7baed 100644 --- a/src/icons/scalable/actions/udpscope-trigger-symbolic.svg +++ b/src/icons/scalable/actions/udpscope-trigger-symbolic.svg @@ -1,26 +1,22 @@ - + - +