Feature/source plugins #1
@@ -0,0 +1,80 @@
|
||||
# Split rows share one y axis -- design
|
||||
|
||||
Amends `2026-11-03-horizontal-split-design.md`. Where the two disagree, this one governs.
|
||||
|
||||
## Goal
|
||||
|
||||
The cells of a split row share one y range and draw one y axis, the way the rows of the figure share
|
||||
one x window and draw one x axis. A split row reads as one wide plot with dividers.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **Always shared, no option.** All cells of a figure row have one y range. An unsplit row is
|
||||
unaffected.
|
||||
2. **One y axis per row.** Only the leftmost cell has a y gutter and y labels. The other cells have
|
||||
none, as only the bottom row carries x labels.
|
||||
3. **Rulers are per row.** The two horizontal rulers (cursor pair) belong to the figure row and are
|
||||
drawn at the same y in every cell. A drag in any cell moves them.
|
||||
4. **Approach.** Extend the vendored plotter with a y link, symmetric to the x link. Rejected: syncing
|
||||
the ranges from the host every frame (the plotter's own per-plot autoscale and the controller's
|
||||
gestures would fight it, which is the problem the x link already solves).
|
||||
|
||||
## Plotter (`deps/plotter`)
|
||||
|
||||
- `Figure::set_share_row_y(bool)`, default off so existing figures and `tests/test_figure.cpp` are
|
||||
unchanged. When on, the cells of each figure row form an implicit y link group. The group is rebuilt
|
||||
with the cells.
|
||||
- A y link syncs like the x link: in `layout()` a new `sync_y_links()` adopts a member's changed
|
||||
`y_range` as the group range and pushes it to the other members. Wheel, pan, box zoom and axis drag
|
||||
go through `set_y_range`, so they need no controller change.
|
||||
- Auto scale: a member's own autoscale is suppressed (as `Axis::link_member` already blocks `Live`).
|
||||
The group owns the auto flag and fits to the union of its members' visible traces; cells with no
|
||||
trace are ignored; a log axis takes the union in axis space. `fit_all` and double-click fit the
|
||||
group, not one cell. A manual `set_y_range` on a member clears the group's auto flag.
|
||||
- `YStrip {Both, None}` and `Plot::set_y_strip_mode`, mirroring `XStrip`. `None` forces the y label
|
||||
width, title width and reserved floor to 0. `Figure::layout` sets `None` on every cell but the
|
||||
first of its row, structurally from the column index, never from content. `None` cells are skipped
|
||||
in the common-gutter maximum.
|
||||
- Cell widths: the row's y gutter is taken off the row width first, then the cells share the rest by
|
||||
the existing `floor + extra*w/total` rule. Equal weights therefore give equal plot areas; the first
|
||||
cell's rect is gutter plus its plot width, and the cell rects still tile the row exactly. The
|
||||
floors apply to plot widths.
|
||||
- A y axis-drag can only start in the leftmost cell (the others have no label area).
|
||||
- Documented in `docs/claude/build-and-run.md` with the other vendored changes.
|
||||
|
||||
## Host (`src/plot_host.*`, `src/ui*.cpp`)
|
||||
|
||||
- `set_y_auto`, `set_y_range`, `fit_all`, and the Auto/Fixed dialog act on the figure row of the plot
|
||||
they are given. The dialog reads the row's range.
|
||||
- Rulers: one pair per figure row, stored on the row's first plot index and placed in every cell by
|
||||
`place_cursors`; `sync_cursors` reads the dragged one back; `reset_cursors` and the measure level
|
||||
marks use the row's range. The cursors pane lists the pair once per figure row.
|
||||
- `row_unit` joins the units over all cells of the row, "" if mixed.
|
||||
- `sync_compare_axes` writes y once per figure row.
|
||||
- `rebuild_all` turns the sharing on for the new `Figure` before the cells are populated.
|
||||
- Readouts and measurements stay per trace and per plot index; only the axis is shared.
|
||||
- Session file: unchanged (y ranges were never persisted).
|
||||
|
||||
## Layout editor
|
||||
|
||||
Divider drag maps the pointer to weights through plot widths, not cell widths: for the first cell,
|
||||
subtract the row's gutter from the left rect before applying `frac = (want_left-64)/(pair-128)`. The
|
||||
96 px logical floor applies to the plot area. Nothing else changes.
|
||||
|
||||
## Verification
|
||||
|
||||
- `tests/test_figure.cpp`: with sharing on, a `{2}` row has equal y ranges after a `set_y_range` on
|
||||
either cell; a second cell has zero y gutter and the first the common maximum; widths tile exactly and
|
||||
equal weights give equal plot widths; group autoscale covers the union and ignores empty cells; sharing
|
||||
off reproduces today's layout; `{1}` rows unaffected.
|
||||
- Split probe gains: after a y gesture on one cell the other's range is identical; non-first cells have
|
||||
no y gutter; fit-all covers both cells' traces; both rulers line up across cells; a divider drag still
|
||||
tracks the pointer within 1 px.
|
||||
- Regression: layout, cursors, measurements, readouts, E-1608 probes read as before; re-baseline only
|
||||
what this feature explains. `gtk warnings: 0`, no `Gtk-CRITICAL`.
|
||||
|
||||
## Docs
|
||||
|
||||
`README.md`, `docs/USER-GUIDE.md`, `help/C/org.udpscope.app/` (layout page), `docs/claude/probe-readings.md`,
|
||||
`docs/claude/invariants-plot-and-layout.md` (the "one gutter, not per column" rule and the per-cell y
|
||||
rule), `docs/claude/build-and-run.md`, `ui_context_help.cpp`, `CLAUDE.md` if it mentions per-cell y.
|
||||
Reference in new issue
Block a user