feat(plot): horizontal rulers alongside the vertical cursors

This commit is contained in:
Martino Ferrari committed 2026-09-28 17:18:43 +02:00
1 parent 2d819c4228
commit 63f9655ae1
11 files changed
+514 -29

No files matched your search

+23 -2
View File
@@ -502,6 +502,21 @@ void Controller::move_cursor(const PointerEvent& e) {
if (drag_cursor_ == kInvalid) return;
const u32 id = static_cast<u32>(drag_cursor_);
const Cursor& cursor = plot_->cursor(id);
// A grabbed cursor mutates the coordinate its own orientation owns and nothing else, and
// each half names the one setter for it -- so a ruler dragged along y can never disturb a
// marker's x, and the dead coordinate of either is untouched by construction.
if (cursor.orientation == CursorOrientation::Horizontal) {
// Clamped to the ruler's own y axis: a pointer that has left the axes has no data under
// it, and the coordinate it extrapolates to is past the end of the axis the ruler reads
// values off -- a position where the ruler would either vanish (the renderer skips a row
// outside `axes`) or, worse, have to be dragged back by a zoom nobody asked for. Clamping
// keeps it readable at the edge it was dragged to instead. `set_cursor_y()` itself stays
// verbatim, so a *caller* that means to park a ruler off range still can.
const Axis& axis = plot_->y_axis(cursor.axis_y);
const f64 y = plot_->y_transform(cursor.axis_y).to_data_y(static_cast<f64>(e.y));
plot_->set_cursor_y(id, std::clamp(y, axis.range.min, axis.range.max));
return;
}
plot_->set_cursor_x(id, plot_->x_transform(cursor.axis_x).to_data_x(static_cast<f64>(e.x)));
}
@@ -590,8 +605,14 @@ u64 Controller::cursor_at(f32 px, f32 py) const {
for (u32 i = 0; i < plot_->cursor_count(); ++i) {
const Cursor& cursor = plot_->cursor(i);
if (!cursor.visible) continue;
const f32 sx = static_cast<f32>(plot_->x_transform(cursor.axis_x).to_screen_x(cursor.x));
const f32 d = std::fabs(sx - px);
// One hit test for both orientations, because a cursor *is* one line across the axes:
// what the pointer has to be near is that line's own coordinate -- the column of a
// vertical marker, the row of a horizontal ruler -- measured with the same radius
// either way, which is what keeps hover and grab agreeing about a ruler exactly as
// they do about a marker. A point within reach of one of each resolves to the nearer,
// so neither orientation widens the other's target.
const bool horizontal = cursor.orientation == CursorOrientation::Horizontal;
const f32 d = std::fabs(plot_->cursor_screen_coordinate(i) - (horizontal ? py : px));
if (d > radius) continue;
if (best == kInvalid || d < best_d) {
best = i;