plot host: split rows share y, rulers per row
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
135310ceca
commit
5f0bc75c27
5 files changed
+174
-24
No files matched your search
+111
-3
@@ -3974,6 +3974,18 @@ void split_probe_assign(App& a, int p, std::size_t c) {
|
||||
a.rows->assign(p, 0, ch.name, ch.name, signal_color_index(a.model->signals(), ch.signal));
|
||||
}
|
||||
|
||||
/// What the shared-y steps carry from the step that measures to the step that prints.
|
||||
struct SharedYProbe {
|
||||
int y_shared = 0;
|
||||
int y_gutter = 0;
|
||||
int ruler_mirror = 0;
|
||||
std::string ranges;
|
||||
std::string axes_w;
|
||||
RowSet::CursorMode was_mode = RowSet::CursorMode::Mix;
|
||||
bool was_on = false;
|
||||
};
|
||||
SharedYProbe g_shared_y;
|
||||
|
||||
void split_probe_clear_all(App& a) {
|
||||
for (int r = 0; r < RowSet::kMaxRows; ++r) {
|
||||
for (int s = 0; s < RowSet::kSlotsPerRow; ++s) a.rows->assign(r, s, "", "", 0);
|
||||
@@ -4393,9 +4405,10 @@ gboolean split_probe_step(gpointer user) {
|
||||
}
|
||||
case 18: {
|
||||
split_probe_report(*a, "after-assign");
|
||||
// The cursors pane's ruler labels (`rebuild_cursors_pane()`, ruler modes): a plot of a split row is
|
||||
// "plot <label>", a plot of an unsplit row keeps "row <index>". Both arrangements are read off the
|
||||
// pane's own label widgets, the all-split one first and a mixed one second.
|
||||
// The cursors pane's ruler labels (`rebuild_cursors_pane()`, ruler modes): one line per figure row,
|
||||
// since a split row's cells share their y axis and their rulers. A split row is "row <figure row,
|
||||
// from 1>" (one line, not one per cell); an unsplit row keeps "row <index>". Both arrangements are
|
||||
// read off the pane's own label widgets, the all-split one first and a mixed one second.
|
||||
const RowSet::CursorMode was_mode = rs.cursor_mode();
|
||||
rs.set_cursor_mode(RowSet::CursorMode::Both);
|
||||
const auto ruler_labels = [&]() {
|
||||
@@ -4415,6 +4428,101 @@ gboolean split_probe_step(gpointer user) {
|
||||
mixed_labels.c_str());
|
||||
rs.set_cursor_mode(was_mode);
|
||||
rebuild_cursors_pane(*a);
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
// --- Steps 19..21: a split row shares one y axis ---
|
||||
case 19: {
|
||||
// One figure row of two cells with a different trace in each (sine, ramp), rulers on. The next
|
||||
// step sets a range on cell A against a frame that was laid out with this arrangement.
|
||||
g_shared_y.was_mode = rs.cursor_mode();
|
||||
g_shared_y.was_on = rs.cursors_visible();
|
||||
rs.set_cells_per_row({2});
|
||||
split_probe_clear_all(*a);
|
||||
if (a->model->channel_count() >= 3) {
|
||||
split_probe_assign(*a, 0, 0);
|
||||
split_probe_assign(*a, 1, 2);
|
||||
}
|
||||
rs.set_cursor_mode(RowSet::CursorMode::Both);
|
||||
rs.set_cursors_visible(true);
|
||||
rs.reset_cursors();
|
||||
split_probe_restructured(*a);
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 20: {
|
||||
// A range set on cell A; the frame between this step and the next is the row's next layout.
|
||||
rs.set_y_range(0, -3.0, 7.0);
|
||||
split_probe_restructured(*a);
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 21: {
|
||||
const RowSet::Row& ra = rs.row(0);
|
||||
const RowSet::Row& rb = rs.row(1);
|
||||
if (ra.plot == nullptr || rb.plot == nullptr) {
|
||||
std::fprintf(stderr, "[split-probe] shared-y no plots\n");
|
||||
break;
|
||||
}
|
||||
// 1. The range set on A is B's.
|
||||
const plot::Range a_rng = ra.plot->y_range(ra.axis_y);
|
||||
const plot::Range b_rng = rb.plot->y_range(rb.axis_y);
|
||||
const int y_shared = (std::fabs(b_rng.min + 3.0) < 1e-9 && std::fabs(b_rng.max - 7.0) < 1e-9 &&
|
||||
std::fabs(a_rng.min + 3.0) < 1e-9 && std::fabs(a_rng.max - 7.0) < 1e-9)
|
||||
? 1 : 0;
|
||||
// 2. Only the first cell has a gutter, and the two plots are the same width.
|
||||
const plot::PlotLayout& la = ra.plot->layout();
|
||||
const plot::PlotLayout& lb = rb.plot->layout();
|
||||
const int y_gutter = (la.y_axis_width > 0.0f && lb.y_axis_width == 0.0f && lb.y_label_area.w == 0.0f &&
|
||||
std::fabs(la.axes.w - lb.axes.w) <= 1.0f)
|
||||
? 1 : 0;
|
||||
const std::string ranges_before =
|
||||
"A=" + std::to_string(a_rng.min) + ".." + std::to_string(a_rng.max) +
|
||||
" B=" + std::to_string(b_rng.min) + ".." + std::to_string(b_rng.max);
|
||||
const std::string axes_w = std::to_string(la.axes.w) + "," + std::to_string(lb.axes.w);
|
||||
// 4. A ruler written on A's plot and read back by sync_cursors() is B's too.
|
||||
ra.plot->set_cursor_y(ra.ruler, 1.25, plot::CursorPlacement::Free);
|
||||
ra.plot->set_cursor_y(ra.ruler_b, 4.5, plot::CursorPlacement::Free);
|
||||
rs.sync_cursors(0);
|
||||
const int ruler_mirror = (rs.ruler_y(0) == 1.25 && rs.ruler_y(1) == 1.25 && rs.ruler_b_y(0) == 4.5 &&
|
||||
rs.ruler_b_y(1) == 4.5 && rb.plot->cursor(rb.ruler).y == 1.25 &&
|
||||
rb.plot->cursor(rb.ruler_b).y == 4.5)
|
||||
? 1 : 0;
|
||||
g_shared_y.y_shared = y_shared;
|
||||
g_shared_y.y_gutter = y_gutter;
|
||||
g_shared_y.ruler_mirror = ruler_mirror;
|
||||
g_shared_y.ranges = ranges_before;
|
||||
g_shared_y.axes_w = axes_w;
|
||||
// 3. Fit all: the next frame's layout fits the union of both cells' traces.
|
||||
rs.fit_all();
|
||||
split_probe_restructured(*a);
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 22: {
|
||||
const RowSet::Row& ra = rs.row(0);
|
||||
const RowSet::Row& rb = rs.row(1);
|
||||
if (ra.plot == nullptr || rb.plot == nullptr) break;
|
||||
const plot::Range a_rng = ra.plot->y_range(ra.axis_y);
|
||||
const plot::Range b_rng = rb.plot->y_range(rb.axis_y);
|
||||
plot::Range da{};
|
||||
plot::Range db{};
|
||||
const bool have_a = ra.plot->y_data_bounds(ra.axis_y, da);
|
||||
const bool have_b = rb.plot->y_data_bounds(rb.axis_y, db);
|
||||
const double lo = have_a && have_b ? std::min(da.min, db.min) : 0.0;
|
||||
const double hi = have_a && have_b ? std::max(da.max, db.max) : 0.0;
|
||||
const int y_fit = (have_a && have_b && a_rng.min == b_rng.min && a_rng.max == b_rng.max &&
|
||||
a_rng.min <= lo && a_rng.max >= hi && a_rng.max - a_rng.min < 10.0)
|
||||
? 1 : 0;
|
||||
std::fprintf(stderr,
|
||||
"[split-probe] shared-y y_shared=%d y_gutter=%d y_fit=%d ruler_mirror=%d "
|
||||
"ranges=[%s | fit A=%.9g..%.9g B=%.9g..%.9g data=%.4g..%.4g] axes_w=[%s] auto=%d\n",
|
||||
g_shared_y.y_shared, g_shared_y.y_gutter, y_fit, g_shared_y.ruler_mirror,
|
||||
g_shared_y.ranges.c_str(), a_rng.min, a_rng.max, b_rng.min, b_rng.max, lo, hi,
|
||||
g_shared_y.axes_w.c_str(), rs.figure().row_y_auto(0) ? 1 : 0);
|
||||
rs.set_cursor_mode(g_shared_y.was_mode);
|
||||
rs.set_cursors_visible(g_shared_y.was_on);
|
||||
rebuild_cursors_pane(*a);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in new issue
Block a user