From 931b0d108cdb6b77b6f8122835603f512dedc033 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Wed, 4 Nov 2026 07:26:30 +0100 Subject: [PATCH] layout editor: in-between split buttons sit above the divider handle; doc nits --- docs/claude/invariants-plot-and-layout.md | 2 +- docs/claude/invariants-time-axis-and-window.md | 2 +- docs/claude/verification.md | 2 +- src/ui.cpp | 5 ++++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/claude/invariants-plot-and-layout.md b/docs/claude/invariants-plot-and-layout.md index ae4dd27..903e658 100644 --- a/docs/claude/invariants-plot-and-layout.md +++ b/docs/claude/invariants-plot-and-layout.md @@ -126,7 +126,7 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear - **One y per figure row.** The cells of a figure row share one y range (the plotter's `Figure::set_share_row_y(true)`, which `rebuild_all()` sets before the cells are populated): one y axis (auto or fixed), one pair of horizontal rulers, one fit. A wheel or axis drag in any cell moves - the row, an x gesture on any bottom-row cell moves the shared window. The host therefore acts on the + the row, an x gesture on any cell that carries an x strip moves the shared window. The host therefore acts on the **figure row** of a plot it is given (`set_y_auto`, `set_y_range`, `fit_all`, the Auto/Fixed dialog, `row_unit`, which joins the units of every cell and reads "" if they differ). The rulers are stored on the row's first plot index, copied to the other cells by `sync_cursors()` / `insert_cell()` / diff --git a/docs/claude/invariants-time-axis-and-window.md b/docs/claude/invariants-time-axis-and-window.md index e1e26e4..de1e362 100644 --- a/docs/claude/invariants-time-axis-and-window.md +++ b/docs/claude/invariants-time-axis-and-window.md @@ -74,7 +74,7 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear slightly around when user zoom/pan" was. Three things follow. The **text is the host's**, because the caption has to name the anchor precisely enough that label + caption is the exact absolute time and `format_time()` would round it to three figures (`"t0 = %.6g s"`); only a plot - whose x strip draws labels** (`plot::x_strip_has_labels(x_strip_mode())`: the bottom row, and any row above it whose + whose x strip draws labels (`plot::x_strip_has_labels(x_strip_mode())`: the bottom row, and any row above it whose columns differ from the row below's) carries one, every other plot being set to `""`; and the renderer measures it rather than `Plot::layout()` — it reserves no space and nothing can be picked on it, so there is no rect to read back, and a caption explaining the x labels must not be able to move the layout diff --git a/docs/claude/verification.md b/docs/claude/verification.md index d72b145..6314ba5 100644 --- a/docs/claude/verification.md +++ b/docs/claude/verification.md @@ -206,7 +206,7 @@ precedent, not an exception. emitting `::clicked`, never `gtk_widget_activate()`, which holds a `GtkButton` for its 250 ms `ACTIVATE_TIMEOUT` and then emits into a button the rebuild has already destroyed. - `UDPSCOPE_PROBE_SPLIT_MS` — drive the horizontal plot split, 28 steps 250 ms apart (so a run needs - `UDPSCOPE_PROBE_SPLIT_MS=1500 UDPSCOPE_EXIT_AFTER_MS=10500` at least; it enables and assigns the + `UDPSCOPE_PROBE_SPLIT_MS=1500 UDPSCOPE_EXIT_AFTER_MS=12000` at least; it enables and assigns the signals itself, so `UDPSCOPE_ENABLE_ALL_MS` is not needed). Each step restructures the cells, re-points the area at the new figure and lets the *next* step read a frame that was actually laid out with them, which is why every report line describes the previous step's change. It splits and diff --git a/src/ui.cpp b/src/ui.cpp index 690a2f9..c36a031 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -666,7 +666,10 @@ void sync_layout_editor(App& app) { gtk_widget_set_margin_start( b, static_cast(std::clamp(cx, 0.0, std::max(0.0, static_cast(gtk_widget_get_width(app.area_widget)) - kLayoutButtonPx)) + 0.5)); - gtk_widget_set_margin_top(b, static_cast(std::clamp(row_cy - half, 0.0, height - kLayoutButtonPx) + 0.5)); + // An in-between `+` sits above the divider's resize handle (centred on the same point), or the + // handle, added later, would cover it and "split here" there could not be clicked. + const double top = pos > 0 && pos < n ? row_cy - half - kLayoutButtonPx - 2.0 : row_cy - half; + gtk_widget_set_margin_top(b, static_cast(std::clamp(top, 0.0, height - kLayoutButtonPx) + 0.5)); } else if (resize) { // Row resize handle: placed on the boundary between figure rows. const int idx = row_key(b);