Commit Graph
7 Commits
Author SHA1 Message Date
Martino Ferrari a493737ca1 ui: one channel list, and the math pane is gone
`rebuild_signal_list()` is handed `model.signals()`, and `append_math_signals_locked()` already
appends one synthetic entry per math channel -- "they go through the ordinary signal path on
purpose: a derived channel is a channel" -- so **every math channel was already a row of the
signal list**, with its tick, chip, name, unit and menu. The math pane listed the same channels a
second time, so this is mostly a deletion: `build_math_panel()`, `rebuild_math_pane()`,
`src/ui/math-panel.ui` and its resource entry, `App::math_list`, and the `math panel:` dump line.

What the one list gains:

- a non-selectable `MATH` divider before the first math row, carrying the `+` that creates a
  channel -- appended even when there are no math channels at all, because a `+` conditional on
  one existing could never create the first one;
- a math row's own menu: *Edit graph…*, *Default colour*, *Delete*. No Information and no
  Calibrate (calibration is applied at ingest, and a derived channel has no stream to describe),
  and no rename, because the node editor owns a channel's name and unit -- a second place to
  change them would be a second answer to the same question. An item dismisses the row's popover
  before opening or destroying anything from it;
- `App::math` mirrored from a math row's tick: `enable_locked()` mirrors it into the model, but
  `App::math` is the copy the session file is written from. The mirror sits *before* the
  `apply_math_channels()` in the `!on` path, which would otherwise push a stale `enabled = true`
  straight back into the model;
- a tick visible in a file view too: a derived channel is computed, and a file view has no
  acquisition to start, which is the other tick's question.

`rebuild_signal_list()` also publishes the list's own shape -- `rows`, `signals`, `math` -- and
the dump prints `divider=1` when `rows == signals + 1 + math`: the reading for a list that lost
its `+`.

Verified: `make test-ui` 14 files (was 15); `signals panel: labels=2 list=1 rows=9 signals=4
math=4 divider=1`; `[math-probe] 3 math channels`, every other line unchanged; no `math panel:`
line, and zero `Gtk-CRITICAL`.
2026-10-14 12:56:31 +02:00
Martino FerrariandClaude Opus 4.6 619b5e356c fix: five review findings on the tabbed-sidebar commit
Finding 2 — four builder ids had no null check. `side_stack`,
`side_switcher`, `measure_page` and `signals_page` were resolved at
lines 4709-4712, well past the skeleton null-guard. A typo in the `.ui`
would have been a silent segfault.  The four resolutions are moved to
the guard block and added to its condition, in the same form the guard
already uses.

Finding 3 — the 'editable focused: m refused' leg of keys_probe was
deleted instead of ported.  It is restored, adapted for the new
behaviour: 'm' now selects the Measure tab instead of toggling a pane,
so the refusal is observed as the side_tab name being unchanged across
the synthesised key, not as a toggle that did not flip.  The dump line
keeps its existing name and `refused=` field so probe-readings.md:601
still describes it.

Finding 4 — `exit_probe_step3` assigned `sidebar_shown` to both
`dbg_side_visible` and `dbg_side_column_after_hide`, and the panels:
dump line read the wrong one (dbg_side_visible) for its `(visible=)`
field.  Two readings that cannot disagree diagnose nothing.  Resolved
by making `panels:` read `dbg_side_column_after_hide` and removing the
redundant `dbg_side_visible` field.

Finding 5 — the three-line rationale comment above `reload_file_view`
in `apply_math_channels` was removed by the commit under review.
Nothing it said became untrue.  Restored verbatim from e10a92f.

Finding 6 — three comments the change made false:
- `on_activate`: 'the sidebar's scroller' replaced with 'the sidebar's
  tab switcher and two-page stack', matching the actual ui file.
- `update_side_visibility`: 'Hiding the scroller instead left an empty
  column where the panels should be' removed; the design it described
  no longer exists.
- `header-bar.ui`: 'two of them are toggles' updated to 'one of them
  is a toggle'; after signal_toggle's deletion the overflow menu holds
  one toggle (layout).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-10-14 11:45:00 +02:00
Martino FerrariandClaude Sonnet 4.6 44d2fd35dc ui: the sidebar is two tabs, and a toggle disables its pane
Replace the sidebar's five-panel scrolling column with an AdwViewStack
carrying two pages — Measure (cursors + measurements) and Signals
(trigger + math + channel list) — with an AdwViewSwitcher above it. The
trigger and cursors toggles change from "reveal/hide my pane" to
"enable/disable my feature, leaving the pane insensitive", following the
disable-not-hide principle. The keys probe loses a duplicate registration
that was toggling the sidebar back on before the exit probe captured its
state; the exit-probe captures now read adw_overlay_split_view_get_show_
sidebar() instead of gtk_widget_get_visible(), which AdwOverlaySplitView
never changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-14 11:11:21 +02:00
Martino Ferrari 5c2c221777 ui: the node editor offers the de-noise node and persists its window
The form gains a `median samples` row, shown only for `DeNoise`; the corner row widens to
anything that reads `fc` (`math_op_uses_fc()`) while `q` stays band-pass-only, and the wiring
row keeps its place at the end so the form's order is unchanged for every existing op.

The session format gains a thirteenth field, `med_n`, after `y`. A twelve-field node -- a file
written before this node existed -- still loads, with `med_n` left at the struct's default,
which is what such a file meant; the reader's `return number(...) && ...` chain had to become a
guarded sequence so the thirteenth field could be read conditionally.

The math probe enables the channel it builds its graphs from, the same self-sufficiency rule
the noise and measurement probes already follow: `enable_all_probe` ends by switching one
signal off, and with `sine` gone the graphs landed on `square`, changing a documented line for
reasons unrelated to the math.

Readings: `[math-probe] 2 math channels on 'sine' and 'noise'`, `pane add: 'math3' sources
'sine'`, `graph edit: stored_slots 31000 -> 32000`, `dialog build: nodes=2, output after add=1`
and the rest of the suite unchanged; no `Gtk-CRITICAL`.
2026-10-13 15:50:58 +02:00
Martino Ferrari b090cc2a21 fix: math in a file view -- the buffer was emptied, and the derived ring filled twice
Two defects, both reached by adding a math channel to an open waveform or a replayed
event, and both measured before and after.

**A file view has no producer, so a structural change left it empty.** `set_math_channels()`
rebuilds the channels *and* the buffer, and a rebuild drops the history: right for a stream,
whose producer refills it from the next packet, and wrong for a file, which has nothing to
refill it with. The `--open` dump read `0 samples vs 0 time slots` for *every* channel,
the file's own `sine`/`square`/`ramp`/`noise` included, though the load had reported 402 --
that is what "adding a math node breaks the plotter" was. `reload_file_view()` re-reads the
file after such a change, which is also what computes the derived channels over it: the
load's own pushes run the math once the set is in place, so `--open` with a session that
defines graphs works for the first time.

**The file path pushed into the derived rings, and so did the engine.** `push_loaded_slot()`
did not honour the rule `ChannelInfo::math` states for the packet path ("the ingest must skip
it"), so each loaded slot put a value in a derived ring and `push_math_sample()` then put the
computed one: two samples per slot, a trace at double rate -- the derived channels read
`804 samples vs 402 time slots`. Skipping them there is the whole fix.

Readings now, all equal, which is the assertion this file's own invariant makes:

    --open the file:  math x2  402 samples vs 402 time slots, y=[-1.9021, 0.0063]  (2x the sine)
                      math lp  402 vs 402, mean=-0.4900 (a real filter output, not zero)
    live:             math x2  25100 vs 25100
    replayed event:   math x2  4000 vs 4000

I first tried filtering the file's *derived columns* out by name, since an export writes
every plotted channel. It removed the double count and zeroed `math lp`, because the column
it dropped was the source a session graph reads -- so it is reverted: those columns are
legitimate data, and the fix belongs in the push, not the loader.
2026-10-12 19:49:39 +02:00
Martino Ferrari 90a17eb186 ui: the math panel's frame is a .ui file
The first half of this plan row. src/ui/math-panel.ui holds the panel: the box and its
margins, the heading row with the title and the add button, and the list the channel rows
go in. The rows stay in code -- each is a channel with its name, unit, expression, colour
and its own edit and remove buttons -- so the file holds the frame, as in the measurements
and signals panels beside it.

Read back by a dump line that also reads the file's own text:
`math panel: head=2 buttons=1 list=1 title='Math channels'`, where buttons=0 is a lost
`+` and title='-' a lost label. `[math-probe]` still drives the add and opens the editor,
so the rows landing in the file's list is read as well as the frame.

The other half is the node editor's chrome, which is where least of that file is template:
the canvas is a GtkDrawingArea that is drawn rather than declared, and the gestures, the
parameter fields and the palette are code. That is its own change.
2026-10-12 15:53:35 +02:00
Martino Ferrari 8f54841c2c working on todo.md features 2026-10-10 22:52:12 +02:00