fix(plot,render,glfw): a hue-neutral crosshair, an em-dash placeholder, one layout per figure event, and a usable readout switch

This commit is contained in:
Martino Ferrari committed 2026-09-28 19:38:30 +02:00
1 parent 10d5129fbf
commit a14f333dbe
10 files changed
+175 -70

No files matched your search

+44 -8
View File
@@ -4575,18 +4575,54 @@ PLOT_TEST(horizontal_ruler_stays_inside_the_axes_at_the_edges) {
namespace {
/// The crosshair's own colour (0xB8E8FF) at real coverage: a pale cyan, green clearly above red
/// and blue above green, which no other element of the frames this case draws produces. The two
/// traces here are magenta and green -- deliberately *not* blue, which is the one other colour
/// that would satisfy "blue above green and green above red" (0x40C0FF does). The axis text
/// (0xC8D0DC) is grey enough to fail the green-over-red term, the chrome and the grid are darker
/// still, and the same hue at lower coverage still passes, so a partially covered stroke counts
/// as ink rather than the test needing a fully covered pixel to exist.
/// The crosshair's own ink: **bright and hue-neutral**, which is the property the default colour
/// has on purpose (see `Style::crosshair`) so that it can never be read as a trace of any hue.
/// This predicate is therefore about brightness and chroma rather than about a hue, and it needs no
/// "not this trace's colour" exception: every other element of these frames is either dark (the
/// background, the grid), saturated (the magenta, green and orange traces) or dimmer than the
/// crosshair (the axis text 0xC8D0DC, whose red channel is 200 against the crosshair's 230).
bool crosshair_pixel(const plot::u8 px[4]) {
return px[1] > px[0] + 25 && px[2] > px[1] + 12 && px[2] > 120;
const int lo = std::min(px[0], std::min(px[1], px[2]));
const int hi = std::max(px[0], std::max(px[1], px[2]));
return px[0] > 215 && hi - lo <= 24;
}
} // namespace
/// The crosshair's colour has to be tellable from a trace, and telling colours apart by hue is the
/// one thing a reader cannot be asked to do at a glance: the library's own default trace colour is a
/// saturated cyan, so a saturated cyan crosshair would differ from it in lightness alone. The
/// default is therefore near-white -- a colour no saturated trace of any hue can be -- and still
/// plainly not the cursor accent. Both halves are asserted, so a future recolouring that makes it
/// confusable with a trace or with a handle fails here rather than in a screenshot.
PLOT_TEST(crosshair_colour_cannot_be_mistaken_for_a_trace) {
const plot::render::Style style;
const plot::Trace default_trace;
// `Color` stores normalised channels; the comparisons below are in 0..255, like the hex literals
// the colours are written with.
const auto chan = [](plot::f32 c) { return static_cast<int>(c * 255.0f + 0.5f); };
const int lo = std::min({chan(style.crosshair.r), chan(style.crosshair.g), chan(style.crosshair.b)});
const int hi = std::max({chan(style.crosshair.r), chan(style.crosshair.g), chan(style.crosshair.b)});
// Hue-neutral: its channels are within a few levels of each other, so it is a grey/white and not
// a hue at all. A saturated colour -- the default trace's cyan included -- is 150+ levels apart.
PLOT_CHECK(hi - lo <= 24);
PLOT_CHECK(lo > 200); // bright chrome, not a mid-tone that a dimmed trace could reach
// `Color` is a plain channel struct with no comparison of its own, so the two "not this colour"
// assertions spell the channels out.
const auto same = [](plot::Color a, plot::Color b) {
return a.r == b.r && a.g == b.g && a.b == b.b;
};
PLOT_CHECK(!same(style.crosshair, default_trace.color));
PLOT_CHECK(!same(style.crosshair, style.cursor));
// ... and a saturated trace of any hue is out of reach for it by construction: the *most*
// chromatic colour the crosshair could be confused with has to be within the chroma bound above,
// and every trace colour in this library's demos is far outside it.
const plot::Color demo_traces[3] = {plot::Color::hex(0x40C0FF), plot::Color::hex(0xFFB020),
plot::Color::hex(0x35D0A8)};
for (const plot::Color trace : demo_traces) {
PLOT_CHECK(!same(style.crosshair, trace));
}
}
namespace {
/// A third colour predicate for the lateral case below: the orange 0xFFB020 of a trace of its