feat: an open box zoom draws the frame the release will apply
The controller has always tracked its selection; nothing drew it, so a Ctrl or Shift drag framed a range with no feedback until the release. The preview is the area the release will change, not what the pointer swept: Ctrl frames the x range only, so a band across the plot is what it will zoom, where the sliver a straight horizontal drag sweeps is only the gesture. The plot carries the rect a host hands it -- it learns nothing about pointers -- and the renderer draws a low-alpha fill under a light border over everything else inside the axes.
This commit is contained in:
1 parent
1fc97d818f
commit
be1f31a04f
14 files changed
+276
-1
No files matched your search
@@ -7461,3 +7461,61 @@ PLOT_TEST(a_repaired_invalid_span_is_fainter_than_a_missing_one) {
|
||||
missing_ink, m_lo, m_hi, repaired_ink, r_lo, r_hi);
|
||||
ctx.destroy();
|
||||
}
|
||||
|
||||
PLOT_TEST(the_box_zoom_frame_lands_exactly_where_it_says) {
|
||||
// The frame a host sets has to reach the framebuffer and cover exactly the rect it names. Both halves
|
||||
// are read back rather than trusted, and the two renders are compared: what is under the frame is a
|
||||
// trace, the grid and the axis chrome, so the assertions are differential -- a predicate guessing
|
||||
// those colours would be testing the guess.
|
||||
plottest::HeadlessContext ctx(kW, kH);
|
||||
plot::Status st;
|
||||
PLOT_CHECK(ctx.create(&st));
|
||||
PLOT_CHECK(plot::gl::load(nullptr));
|
||||
plot::Renderer r;
|
||||
PLOT_CHECK(r.init(&st));
|
||||
|
||||
plot::data::ArraySeries s(sine_samples(), 0.0, 1.0);
|
||||
plot::Plot p;
|
||||
p.set_viewport({0, 0, static_cast<plot::f32>(kW), static_cast<plot::f32>(kH)});
|
||||
const plot::u32 ax = p.add_x_axis({"t", s.x_bounds(), true, plot::AxisPlace::Bottom, false});
|
||||
const plot::u32 ay = p.add_y_axis({"v", {-1.0, 1.0}, true, plot::AxisPlace::Left, false});
|
||||
p.add_trace({&s, plot::Color::hex(0x40C0FF), 1.5f, ax, ay});
|
||||
|
||||
// The *floor* of a pixel rather than its luminance: the fill is the axis furniture's light neutral at
|
||||
// a low alpha, so over a saturated trace it can lower a channel while it raises the floor, and the
|
||||
// floor is what says "something light was laid over this".
|
||||
const auto floor_of = [&](plot::u32 x, plot::u32 y) {
|
||||
plot::u8 px[4] = {};
|
||||
PLOT_CHECK(ctx.read_pixel(x, ctx.height - 1u - y, px));
|
||||
return static_cast<int>(std::min(px[0], std::min(px[1], px[2])));
|
||||
};
|
||||
// The renderer does not clear -- that is the host's -- and a second draw over the first would double
|
||||
// every trace and change every pixel for reasons that have nothing to do with the frame.
|
||||
const auto draw = [&](bool framed) {
|
||||
if (framed) p.set_selection_rect({200.0f, 100.0f, 200.0f, 120.0f});
|
||||
plot::gl::glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
plot::gl::glClear(plot::gl::GL_COLOR_BUFFER_BIT);
|
||||
r.begin_frame(kW, kH, {0, 0, static_cast<plot::f32>(kW), static_cast<plot::f32>(kH)});
|
||||
r.draw(p);
|
||||
r.end_frame();
|
||||
};
|
||||
|
||||
draw(false);
|
||||
const int border_before = floor_of(200, 160); // the frame's left border, mid-height
|
||||
const int inside_before = floor_of(300, 160); // the middle of the framed area
|
||||
const int outside_before = floor_of(500, 160); // to the right of it
|
||||
draw(true);
|
||||
const int border_after = floor_of(200, 160);
|
||||
const int inside_after = floor_of(300, 160);
|
||||
const int outside_after = floor_of(500, 160);
|
||||
|
||||
// A frame, not a wash: the border is nearly opaque, the fill is not.
|
||||
PLOT_CHECK(border_after > inside_after);
|
||||
PLOT_CHECK(border_after > border_before + 60);
|
||||
// A fill, not a panel: it lightens what it covers and leaves it readable.
|
||||
PLOT_CHECK(inside_after > inside_before + 10);
|
||||
// Exactly the rect, and not a pixel beyond it: this is the assertion that the frame matches the area
|
||||
// the gesture is choosing rather than merely being somewhere on screen.
|
||||
PLOT_CHECK(outside_after == outside_before);
|
||||
p.clear_selection_rect();
|
||||
}
|
||||
Reference in new issue
Block a user