diff --git a/include/plot/plot/plot.hpp b/include/plot/plot/plot.hpp index 850a398..6bea531 100644 --- a/include/plot/plot/plot.hpp +++ b/include/plot/plot/plot.hpp @@ -479,6 +479,11 @@ class Plot { /// /// Ignored for a vertical cursor, whose snap is `SnapMode` -- see `set_cursor_snap()`. void set_cursor_h_snap(u32 id, HRulerSnap mode); + /// Recolours a cursor that already exists. A *readout* cursor -- one a host keeps as a + /// marker for something it computed, rather than an instrument the user placed -- has to + /// be told apart from its neighbours, and its colour is how it says which readout it + /// belongs to. An id that names no cursor is ignored, like every other setter here. + void set_cursor_color(u32 id, Color color); /// The measurement for `id`. Re-evaluated only when a cursor moved, when the /// measure was added, or when the series underneath it changed: a different diff --git a/src/plot/plot.cpp b/src/plot/plot.cpp index 46c72b2..2b79539 100644 --- a/src/plot/plot.cpp +++ b/src/plot/plot.cpp @@ -306,6 +306,11 @@ u32 Plot::add_annotation(const Annotation& annotation) { return static_cast(annotations_.size() - 1); } +void Plot::set_cursor_color(u32 id, Color color) { + if (id >= cursors_.size()) return; + cursors_[id].color = color; +} + void Plot::set_annotation(u32 id, const Annotation& annotation) { if (id >= annotations_.size()) return; annotations_[id] = annotation; diff --git a/tests/test_plot.cpp b/tests/test_plot.cpp index 5e441be..d35b118 100644 --- a/tests/test_plot.cpp +++ b/tests/test_plot.cpp @@ -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}; diff --git a/tests/test_render_smoke.cpp b/tests/test_render_smoke.cpp index f9ad2ba..f793f73 100644 --- a/tests/test_render_smoke.cpp +++ b/tests/test_render_smoke.cpp @@ -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(kW), static_cast(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);