fix: a fit undoes an x zoom instead of redefining the time window

The previous commit took "fit x sets the window properly" to mean a fit should
frame the data and propagate that as the new time scale. It should not: a fit is
a plot interaction, and the window is also the trigger's event span and how the
samples are stored, so a fit that framed the data could re-plan the rings and
drop the history on a menu click. What a fit means here is the undo of a zoom --
a 2 s window zoomed into reads 2 s again.

`fit_x()` therefore reads `window_s_` and never writes it. Live it takes the
window-control path with the window already set, which re-arms the follow and
parks the newest span at the live edge. Pinned -- a held event, a filling capture
or a paused view -- it restores the pin's full range, which is the snapshot's own
span and may be narrower than the requested window, and it writes the per-row
member axes as well as the link group: `hold_pinned_window()` prefers a member
that differs from `pinned_stated_`, so writing the group alone is reverted to the
zoomed range one frame later. `apply_window_scale()` is folded back into
`apply_time_window()`, which the window control is again the only caller of.

The probe now zooms in before fitting, since otherwise there is nothing to undo,
and reports `pinned=`. `window` and `event_span` must be unchanged on every line.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-10-05 16:26:37 +02:00
1 parent 9888fd9977
commit 3d7e214295
7 files changed
+193 -150

No files matched your search

+20 -14
View File
@@ -983,9 +983,9 @@ that changes nothing still says why. Each plot's y axis has a right-click menu
with auto scale, a fixed range, **Fit X axis**, **Fit all**, and one
**Remove '<signal>' from plot N** entry per occupied trace slot (a plot with nothing on
it says so instead). The two fits are the same pair the overflow menu and the `f` key
offer, split by what they touch: **Fit X axis** frames the window on the data the ring
holds and leaves every y scale exactly as the user set it, **Fit all** does that and
auto-scales the y axes too.
offer, split by what they touch: **Fit X axis** puts the x view back on the whole time
window and leaves every y scale exactly as the user set it, **Fit all** does that and
auto-scales the y axes too. Neither changes the time window itself — see below.
**The plot does not twitch.** Two independent causes were fixed, both of which
showed up as the x axis moving a few pixels every frame — including while paused,
@@ -1276,18 +1276,24 @@ logged with both rates and the new anti-alias corner. A window change that leave
limitations below); only the shared clock is decimated.
**Fit to data** (overflow menu, the `f` key, or **Fit all** in a plot's right-click menu)
auto-scales every row's y axis and re-frames the x window on the data the ring holds,
propagated to every row. **Fit X axis** is the same re-framing without the y scaling, for
the common case where the window should be the data's but the levels were placed by hand.
The status line acknowledges either (`x fitted to the buffered data (1.25 s)`).
auto-scales every row's y axis to the data it holds and puts the x view back on the whole time
window, propagated to every row. **Fit X axis** is that x half alone, for the common case where
a zoom should be undone but the levels were placed by hand. The status line acknowledges either
(`x back to the 2 s window`).
Either fit **states a new time window**, and states the whole of it: the span it framed goes
through the same door a typed window does, so the trigger's event span, the buffer partition and
the window control all land on the fitted value and the control reads it back. A **zoom or a pan
never does** — a gesture moves the view inside the window and leaves the window alone, which is
what keeps a wheel from silently re-planning the buffer and dropping the history. The one thing a
fit does *not* borrow from the typed path is the live re-follow: fitting a held event or a paused
view keeps it pinned rather than throwing it back onto the stream.
**Nothing you do on the plot changes the time window** — only the window control does. A fit is
the *undo of a zoom*: a 2 s window zoomed into reads 2 s again. That matters because the window
is not just the axis. It is also the trigger's event span, how the samples are stored (a window
long enough to move the decimation re-plans the rings and **drops the history**), the control's
readout and what the session file records — so a wheel notch or a Fit that redefined it would
quietly throw the buffer away. A zoom and a pan are view-only by construction; the fits read the
window and never write it.
Which 2 s depends on the state, and the fit restores the whole of whatever the view is allowed to
show: live, the newest window at the live edge; and for a held event or a paused view, the pin's
full range — the snapshot's own span, which is legitimately *narrower* than the requested window
when the ring had not filled it. A fit of a frozen view keeps it frozen rather than throwing it
back onto the stream.
**Shared x axis.** The rows are the rows of **one `plot::Figure`**, drawn by one
`plot::gtk4::PlotArea` in figure mode, and they all join a single x link group.