test(plot): pin the crosshair's lookup, readout, placement, sync and clip
This commit is contained in:
1 parent
fd0c471430
commit
8e27e22ebe
6 files changed
+798
-17
No files matched your search
@@ -1640,3 +1640,88 @@ PLOT_TEST(a_figures_live_edge_hint_is_published_only_while_the_group_follows) {
|
||||
PLOT_CHECK(solo.x_follow(0u) == plot::XFollow::Live);
|
||||
PLOT_CHECK(!solo.x_live_owner(0u, edge));
|
||||
}
|
||||
|
||||
// ------------------------------------------------- the crosshair (spec §15)
|
||||
|
||||
/// Spec §15, the wiring: a pointer over the data area places the crosshair at the data
|
||||
/// coordinates under it, and a pointer that leaves the axes clears it. A press neither clears it
|
||||
/// nor moves it away from the pointer -- it follows the pointer, and a pointer still over the
|
||||
/// axes is still pointing at what it grabbed -- while a wheel, which moves the data without
|
||||
/// moving the pointer, re-anchors it to the same pointer position rather than leaving it on the
|
||||
/// value it was placed at.
|
||||
PLOT_TEST(crosshair_tracks_motion_and_clears_on_leave) {
|
||||
Fixture fx;
|
||||
fx.plot.add_y_axis({"v", {0.0, 100.0}, false, plot::AxisPlace::Left, false});
|
||||
fx.plot.layout();
|
||||
|
||||
const plot::Rect axes = fx.plot.layout().axes;
|
||||
const f32 cx = axes.x + 0.37f * axes.w;
|
||||
const f32 cy = axes.y + 0.61f * axes.h;
|
||||
|
||||
// No pointer has been seen, so there is no crosshair: it is a hover, and a hover needs a
|
||||
// pointer.
|
||||
PLOT_CHECK(!fx.plot.crosshair().active);
|
||||
|
||||
// A motion inside the data area places it at the coordinates under the pointer, through the
|
||||
// same transforms every gesture uses -- so the line, the value and the pointer cannot drift.
|
||||
fx.controller.on_pointer({cx, cy, 0.0f, 0.0f, plot::input::Button::Left, 0u, false,
|
||||
/*down=*/false, false});
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
PLOT_CHECK_NEAR(fx.plot.crosshair().x, fx.plot.x_transform(0u).to_data_x(cx), 1e-9);
|
||||
PLOT_CHECK_NEAR(fx.plot.crosshair().y, fx.plot.y_transform(0u).to_data_y(cy), 1e-9);
|
||||
// Both lines: a pointer over the axes knows its x and its y.
|
||||
PLOT_CHECK(fx.plot.crosshair().vertical);
|
||||
PLOT_CHECK(fx.plot.crosshair().horizontal);
|
||||
|
||||
// Moving re-anchors it, and a press keeps it: the pointer did not leave the axes.
|
||||
const f32 moved_x = axes.x + 0.52f * axes.w;
|
||||
fx.controller.on_pointer({moved_x, cy, moved_x - cx, 0.0f, plot::input::Button::Left, 0u, true,
|
||||
true, false});
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
PLOT_CHECK_NEAR(fx.plot.crosshair().x, fx.plot.x_transform(0u).to_data_x(moved_x), 1e-9);
|
||||
fx.controller.on_pointer({moved_x, cy, 0.0f, 0.0f, plot::input::Button::Left, 0u, false, false,
|
||||
true});
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
|
||||
// A pointer that leaves the data area clears it -- into the y label strip, where no data is
|
||||
// under the pointer at all.
|
||||
fx.controller.on_pointer({axes.x - 4.0f, cy, -4.0f, 0.0f, plot::input::Button::Left, 0u, false,
|
||||
false, false});
|
||||
PLOT_CHECK(fx.plot.layout().y_label_area.contains(axes.x - 4.0f, cy)); // the premise
|
||||
PLOT_CHECK(!fx.plot.crosshair().active);
|
||||
// ... and back inside re-places it, with the coordinate of the new position.
|
||||
fx.controller.on_pointer({cx, cy, 0.0f, 0.0f, plot::input::Button::Left, 0u, false, false,
|
||||
false});
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
PLOT_CHECK_NEAR(fx.plot.crosshair().x, fx.plot.x_transform(0u).to_data_x(cx), 1e-9);
|
||||
|
||||
// A wheel moved the data under a stationary pointer, so the crosshair is re-anchored: the
|
||||
// value it reports is the one under the pointer *now*, not the one it was placed at.
|
||||
const f64 before = fx.plot.crosshair().x;
|
||||
fx.controller.on_wheel({cx, cy, 0.0f, 1.0f, 0u});
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
PLOT_CHECK_NEAR(fx.plot.crosshair().x, fx.plot.x_transform(0u).to_data_x(cx), 1e-9);
|
||||
PLOT_CHECK(fx.plot.crosshair().x != before);
|
||||
// The same for an axis zoom from the keyboard: the ranges move, the pointer does not.
|
||||
const f64 after_wheel = fx.plot.crosshair().x;
|
||||
fx.controller.on_key({plot::input::kKeyZoomOut, 0u, true});
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
PLOT_CHECK_NEAR(fx.plot.crosshair().x, fx.plot.x_transform(0u).to_data_x(cx), 1e-9);
|
||||
PLOT_CHECK(fx.plot.crosshair().x != after_wheel);
|
||||
|
||||
// A resize moves the axes under a stationary pointer, so the crosshair is re-placed against
|
||||
// the new rect -- and a resize that leaves the pointer outside the new axes clears it, the
|
||||
// same rule as a pointer that left.
|
||||
const f32 far_x = axes.right() - 2.0f;
|
||||
fx.controller.on_pointer({far_x, cy, far_x - cx, 0.0f, plot::input::Button::Left, 0u, false,
|
||||
false, false});
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
fx.controller.set_viewport({0.0f, 0.0f, 800.0f, 120.0f}); // the pointer is now below it
|
||||
PLOT_CHECK(!fx.plot.layout().axes.contains(far_x, cy)); // the premise: the pointer is out
|
||||
PLOT_CHECK(!fx.plot.crosshair().active);
|
||||
// Restoring the rect puts the pointer back over the data, and the crosshair with it.
|
||||
fx.controller.set_viewport({0.0f, 0.0f, 800.0f, 400.0f});
|
||||
PLOT_CHECK(fx.plot.layout().axes.contains(far_x, cy));
|
||||
PLOT_CHECK(fx.plot.crosshair().active);
|
||||
PLOT_CHECK_NEAR(fx.plot.crosshair().x, fx.plot.x_transform(0u).to_data_x(far_x), 1e-9);
|
||||
}
|
||||
Reference in new issue
Block a user