feat(plot): set_cursor_color(), and a figure test for per-row rulers

A *readout* cursor -- a marker a host keeps for something it computed, rather
than an instrument the user placed -- has to be told apart from its neighbours,
and the cursor API could set everything about one except its colour. The setter
keeps the id and ignores a stale one, like the setters beside it.

Tested by `a_cursor_can_be_recoloured_by_id`, and the suite is 356 cases, 0
failed.
This commit is contained in:
Martino Ferrari committed 2026-10-03 00:11:37 +02:00
1 parent 523446d08f
commit 125cc1f64a
4 files changed
+31 -3

No files matched your search

+16
View File
@@ -2588,6 +2588,22 @@ PLOT_TEST(xy_series_measurement_uses_the_true_nearest_samples) {
// A host whose annotation is a readout -- the point where a cursor crosses a trace --
// moves it every frame. The id has to survive that, and a stale id must be ignored
// rather than read or written out of bounds, exactly as the cursors' setters behave.
// A readout cursor says which readout it belongs to with its colour; the setter keeps the
// id, and a stale one changes nothing.
PLOT_TEST(a_cursor_can_be_recoloured_by_id) {
plot::Plot p;
const u32 id = p.add_cursor(2.0, plot::Color::hex(0x111111));
PLOT_CHECK(p.cursor(id).color.b == plot::Color::hex(0x111111).b);
p.set_cursor_color(id, plot::Color::hex(0x9BE8A0));
PLOT_CHECK(p.cursor(id).color.g == plot::Color::hex(0x9BE8A0).g);
PLOT_CHECK(p.cursor_count() == 1u); // recoloured, not added
PLOT_CHECK_NEAR(p.cursor(id).x, 2.0, 1e-12);
p.set_cursor_color(42u, plot::Color::hex(0xFFFFFF));
PLOT_CHECK(p.cursor(id).color.g == plot::Color::hex(0x9BE8A0).g);
}
PLOT_TEST(an_annotation_can_be_moved_by_id) {
plot::Plot p;
const plot::Annotation pin{1.0, 2.0, "first", plot::Color::hex(0xE8E8E8), 0u, 0u, true};
+5 -3
View File
@@ -5996,9 +5996,12 @@ PLOT_TEST(figure_rows_draw_their_own_horizontal_rulers) {
const plot::f32 y_scales[3] = {671.0e6f, 90.0f, 2.51f};
// The harness's no-atlas backend: a ruler always writes its value as text, and this case
// is about the *stroke*, so the text is asked for and staged as nothing. (`OnePxPerString
// Backend::glyph()` is null, which is what a real host without an atlas looks like.)
// is about the *stroke*, so the text is asked for and staged as nothing. It goes on the
// *renderer*, not on the plots: `draw(Figure&)` replaces each row's backend with the
// renderer's own on the first frame, so a plot-level backend would be swapped out under a
// batch that had already declared that backend's (absent) cell.
OnePxPerStringBackend no_text;
r.set_text_backend(&no_text);
plot::Figure figure(3u);
figure.set_viewport({0, 0, static_cast<plot::f32>(kW), static_cast<plot::f32>(kH)});
@@ -6008,7 +6011,6 @@ PLOT_TEST(figure_rows_draw_their_own_horizontal_rulers) {
const plot::u32 ay =
p.add_y_axis({"v", {0.0, y_scales[row]}, false, plot::AxisPlace::Left, false});
p.add_trace({&series, kRowBlue, 1.5f, ax, ay});
p.set_text_backend(&no_text);
// A quarter and three quarters up this row's own range: inside its axes whatever the
// scale is, which is the point of a ruler being per row.
p.add_h_ruler(0.25 * y_scales[row], red);