fix(input): clamp a dragged ruler on an ordered y range and share the orientation test

This commit is contained in:
Martino Ferrari committed 2026-09-28 17:58:42 +02:00
1 parent 93ad774281
commit a153b73ead
5 files changed
+62 -14

No files matched your search

+31
View File
@@ -874,6 +874,37 @@ PLOT_TEST(horizontal_ruler_is_grabbed_and_dragged_along_y) {
PLOT_CHECK(f.plot.cursor(ruler).y > 40.0);
}
/// An inverted (descending) y range is ordinary -- depth, row index, descending time -- because
/// `set_y_range()` stores the range verbatim and only the transform widens it. The drag's clamp
/// must therefore order the bounds: `std::clamp` requires `min <= max`, so a raw
/// `clamp(y, range.min, range.max)` collapses the ruler onto one end on such an axis (and is
/// undefined behaviour besides). The ruler has to follow the pointer here, and stay inside the
/// range.
PLOT_TEST(horizontal_ruler_follows_the_pointer_on_an_inverted_y_range) {
Fixture f;
// Descending: the layout maps `range.min` (100) to the axes' bottom and `range.max` (0) to its
// top, so a pointer further down is a *larger* y.
f.ay = f.plot.add_y_axis({"v", {100.0, 0.0}, false, plot::AxisPlace::Left, false});
const u32 ruler = f.plot.add_h_ruler(50.0, plot::Color::hex(0x35D0A8));
f.plot.layout();
const f32 column = screen_x_of(f.plot, f.ax, 50.0);
const f32 row = row_of(f.plot, f.ay, 50.0);
hover(f.controller, column, row);
PLOT_CHECK(f.controller.hovered_cursor() == ruler);
press(f.controller, column, row);
PLOT_CHECK(f.controller.grabbed_cursor() == ruler);
const f32 moved = row + 60.0f;
move_to(f.controller, column, moved);
// Exactly the data under the pointer, not a collapsed bound, and inside the range.
PLOT_CHECK_NEAR(f.plot.cursor(ruler).y, data_at_row(f.plot, f.ay, moved), 1e-9);
PLOT_CHECK(f.plot.cursor(ruler).y > 50.0);
PLOT_CHECK(f.plot.cursor(ruler).y < 100.0);
release(f.controller, column, moved);
PLOT_CHECK(f.plot.cursor(ruler).y > 50.0);
}
/// Nearest-first resolution *across* orientations: a pointer within reach of both a marker and a
/// ruler takes the nearer of the two, so neither widens the other's target -- which is what lets
/// one hit test serve two instruments. Each press below is 1 px from its winner and 4 px from the