test(input): pin the region snap's once-on-release rule and the live-follow data anchoring
This commit is contained in:
1 parent
354e79eea2
commit
5e610bc138
1 file changed
+49
@@ -1155,3 +1155,52 @@ PLOT_TEST(region_holds_in_data_space_under_live_follow) {
|
|||||||
PLOT_CHECK_NEAR(f.graph.region(rid).x0, x0 + delta, 1e-12);
|
PLOT_CHECK_NEAR(f.graph.region(rid).x0, x0 + delta, 1e-12);
|
||||||
PLOT_CHECK_NEAR(f.graph.region(rid).x1, x1 + delta, 1e-12);
|
PLOT_CHECK_NEAR(f.graph.region(rid).x1, x1 + delta, 1e-12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `RegionSnap::NearestSample` is applied **once**, on release -- not on every motion. A
|
||||||
|
/// body dragged a fraction of a sample would otherwise snap both ends back onto the
|
||||||
|
/// samples they started on, and the region would never move at all while the pointer did;
|
||||||
|
/// a region that never snapped would instead end its drag between two samples, which is
|
||||||
|
/// what the snap exists to prevent. Both halves are observable, and one drag shows both.
|
||||||
|
PLOT_TEST(region_snap_is_applied_once_on_release) {
|
||||||
|
constexpr u32 kSamples = 120u;
|
||||||
|
std::vector<f32> samples(kSamples);
|
||||||
|
for (u32 i = 0; i < kSamples; ++i) samples[i] = static_cast<f32>(i);
|
||||||
|
plot::data::ArraySeries s(std::move(samples), 0.0, 1.0); // the sample grid is the integers
|
||||||
|
|
||||||
|
Fixture f;
|
||||||
|
f.ay = f.plot.add_y_axis({"v", {0.0, 120.0}, false, plot::AxisPlace::Left, false});
|
||||||
|
f.plot.add_trace({&s, plot::Color::hex(0x40C0FF), 1.5f, f.ax, f.ay});
|
||||||
|
|
||||||
|
plot::Region snapping; // the default: NearestSample
|
||||||
|
snapping.x0 = 10.4;
|
||||||
|
snapping.x1 = 20.6;
|
||||||
|
const u32 rid = f.plot.add_region(snapping);
|
||||||
|
// On the way in, both bounds land on the grid the traces define.
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(rid).x0, 10.0, 1e-9);
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(rid).x1, 21.0, 1e-9);
|
||||||
|
// The contrast: a Free region keeps what it was given. It is placed clear of the snapped
|
||||||
|
// one, because two bodies under the pointer resolve to the region on top -- the later
|
||||||
|
// one -- and this case is about the drag of *this* region.
|
||||||
|
plot::Region kept = snapping;
|
||||||
|
kept.x0 = 40.4;
|
||||||
|
kept.x1 = 50.6;
|
||||||
|
kept.snap = plot::RegionSnap::Free;
|
||||||
|
const u32 free_id = f.plot.add_region(kept);
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(free_id).x0, 40.4, 1e-12);
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(free_id).x1, 50.6, 1e-12);
|
||||||
|
|
||||||
|
// Drag the snapped region's body by six tenths of a sample.
|
||||||
|
const f32 mid = 0.5f * (bound_x(f.plot, rid, true) + bound_x(f.plot, rid, false));
|
||||||
|
const f32 to = column_of(f.plot, f.ax, data_at(f.plot, f.ax, mid) + 0.6);
|
||||||
|
press(f.controller, mid);
|
||||||
|
PLOT_CHECK(f.controller.drag_mode() == plot::input::DragMode::MoveRegion);
|
||||||
|
move_to(f.controller, to);
|
||||||
|
// Mid-drag the bounds are exactly where the pointer put them: no snapping yet.
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(rid).x0, 10.6, 1e-3);
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(rid).x1, 21.6, 1e-3);
|
||||||
|
release(f.controller, to);
|
||||||
|
// On release they are pulled onto the grid, once, and both ends moved.
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(rid).x0, 11.0, 1e-9);
|
||||||
|
PLOT_CHECK_NEAR(f.plot.region(rid).x1, 22.0, 1e-9);
|
||||||
|
PLOT_CHECK(f.plot.region(rid).x1 > f.plot.region(rid).x0); // the interval survived both ends moving
|
||||||
|
}
|
||||||
Reference in new issue
Block a user