feat(render): logical style metrics with a UI scale, so chrome has a consistent physical size

This commit is contained in:
Martino Ferrari committed 2026-09-28 12:17:53 +02:00
1 parent 1f03631e98
commit 7500fc90d2
21 files changed
+708 -82

No files matched your search

+72
View File
@@ -358,3 +358,75 @@ PLOT_TEST(key_f_auto_fits_traces) {
PLOT_CHECK(p.x_axis(ax).auto_scale); // a fit re-arms auto scale
PLOT_CHECK(p.y_axis(ay).auto_scale);
}
// --- tolerances are logical, coordinates are device pixels -------------------
/// The grab radius is a distance the user aims with, so it must be the same
/// *physical* distance at any DPI: the controller compares device-pixel coordinates
/// against `logical * Plot::ui_scale()`. The press positions below are the same
/// logical distance (0.9 and 1.1 of the 5 px radius) from the cursor at both scales,
/// so the same press grabs -- and the same press just outside does not.
PLOT_TEST(grab_radius_scales_with_dpi) {
for (const f32 scale : {1.0f, 2.0f}) {
plot::Plot p;
p.set_ui_scale(scale);
p.set_viewport({0, 0, 800.0f * scale, 400.0f * scale});
const u32 ax = p.add_x_axis({"t", {0.0, 100.0}, false, plot::AxisPlace::Bottom, false});
const u32 cid = p.add_cursor(50.0, plot::Color::hex(0xFF0000));
plot::input::Controller c(p);
c.set_viewport({0, 0, 800.0f * scale, 400.0f * scale});
PLOT_CHECK_NEAR(p.ui_scale(), scale, 1e-6);
const f32 sx = screen_x_of(p, ax, 50.0);
const f32 inside = 0.9f * 5.0f * scale; // logical: within the grab radius
const f32 outside = 1.1f * 5.0f * scale; // logical: just past it
c.on_pointer({sx + inside, 200.0f * scale, 0, 0, plot::input::Button::Left, 0, false, false,
false});
PLOT_CHECK(c.hovered_cursor() == cid);
c.on_pointer({sx + outside, 200.0f * scale, 0, 0, plot::input::Button::Left, 0, false, false,
false});
PLOT_CHECK(c.hovered_cursor() == plot::kInvalid);
// ...and a ctrl-drag at that same logical distance opens a cursor move, which is
// the gesture the radius actually gates.
c.on_pointer({sx + inside, 200.0f * scale, 0, 0, plot::input::Button::Left, kCtrl, true, true,
false});
PLOT_CHECK(c.drag_mode() == plot::input::DragMode::MoveCursor);
}
}
/// The box-zoom click threshold is a hand movement too: a selection the user
/// perceives as a few pixels is a click at any DPI, so both dimensions are compared
/// against `logical * Plot::ui_scale()`.
PLOT_TEST(box_zoom_click_threshold_scales_with_dpi) {
for (const f32 scale : {1.0f, 2.0f}) {
plot::Plot p;
p.set_ui_scale(scale);
p.set_viewport({0, 0, 800.0f * scale, 400.0f * scale});
const u32 ax = p.add_x_axis({"t", {0.0, 800.0}, true, plot::AxisPlace::Bottom, false});
plot::input::Controller c(p);
c.set_viewport({0, 0, 800.0f * scale, 400.0f * scale});
const plot::Range before = p.x_range(ax);
// 3 logical px on each side: a click, at both scales.
const f32 x0 = 100.0f * scale;
const f32 y0 = 50.0f * scale;
const f32 small = 3.0f * scale;
c.on_pointer({x0, y0, 0, 0, plot::input::Button::Left, kShift, true, true, false});
c.on_pointer({x0 + small, y0 + small, small, small, plot::input::Button::Left, kShift, true,
false, false});
c.on_pointer({x0 + small, y0 + small, 0, 0, plot::input::Button::Left, kShift, false, false,
true});
PLOT_CHECK_NEAR(p.x_range(ax).min, before.min, 1e-9);
PLOT_CHECK_NEAR(p.x_range(ax).max, before.max, 1e-9);
// 5 logical px on each side: a box, at both scales.
const f32 large = 5.0f * scale;
c.on_pointer({x0, y0, 0, 0, plot::input::Button::Left, kShift, true, true, false});
c.on_pointer({x0 + large, y0 + large, large, large, plot::input::Button::Left, kShift, true,
false, false});
c.on_pointer({x0 + large, y0 + large, 0, 0, plot::input::Button::Left, kShift, false, false,
true});
PLOT_CHECK(p.x_range(ax).min > before.min);
PLOT_CHECK(p.x_range(ax).max < before.max);
}
}