feat(input): Ctrl restricts keyboard zoom to x, Alt to y
CI / debug (tests + all adapters) (push) Canceled after 0s
CI / coverage (floor + measured table) (push) Canceled after 0s
CI / asan (AddressSanitizer) (push) Canceled after 0s

This commit is contained in:
Martino Ferrari committed 2026-10-04 12:03:01 +02:00
1 parent 0ee6e10c81
commit 26a7c82a80
2 files changed
+31

No files matched your search

+10
View File
@@ -323,18 +323,28 @@ void Controller::on_key(const KeyEvent& e) {
if (zooms) { if (zooms) {
const f64 notches = e.key == kKeyZoomIn ? kKeyZoomNotches : -kKeyZoomNotches; const f64 notches = e.key == kKeyZoomIn ? kKeyZoomNotches : -kKeyZoomNotches;
const f64 factor = zoom_factor(notches); const f64 factor = zoom_factor(notches);
// Ctrl restricts the zoom to x, Alt to y; bare +/- zooms both. (Shift cannot be
// used: '+' is shift+'=' on common layouts, so key_from() folds them together and
// a bare zoom-in already arrives with Mod::Shift set.) Ctrl+Alt zooms neither,
// which is harmless and needs no special case.
const bool only_x = has_mod(e.mods, Mod::Ctrl);
const bool only_y = has_mod(e.mods, Mod::Alt);
if (!only_y) {
for (u32 i = 0; i < plot_->x_axis_count(); ++i) { for (u32 i = 0; i < plot_->x_axis_count(); ++i) {
const Axis& a = plot_->x_axis(i); const Axis& a = plot_->x_axis(i);
const f64 lo = to_space(a.range.min, a.log); const f64 lo = to_space(a.range.min, a.log);
const f64 hi = to_space(a.range.max, a.log); const f64 hi = to_space(a.range.max, a.log);
zoom_x_axis(i, from_space(0.5 * (lo + hi), a.log), factor); zoom_x_axis(i, from_space(0.5 * (lo + hi), a.log), factor);
} }
}
if (!only_x) {
for (u32 i = 0; i < plot_->y_axis_count(); ++i) { for (u32 i = 0; i < plot_->y_axis_count(); ++i) {
const Axis& a = plot_->y_axis(i); const Axis& a = plot_->y_axis(i);
const f64 lo = to_space(a.range.min, a.log); const f64 lo = to_space(a.range.min, a.log);
const f64 hi = to_space(a.range.max, a.log); const f64 hi = to_space(a.range.max, a.log);
zoom_y_axis(i, from_space(0.5 * (lo + hi), a.log), factor); zoom_y_axis(i, from_space(0.5 * (lo + hi), a.log), factor);
} }
}
} else if (fits) { } else if (fits) {
plot_->auto_fit_x(); plot_->auto_fit_x();
for (u32 i = 0; i < plot_->y_axis_count(); ++i) plot_->auto_fit_y(i); for (u32 i = 0; i < plot_->y_axis_count(); ++i) plot_->auto_fit_y(i);
+21
View File
@@ -263,6 +263,27 @@ PLOT_TEST(key_minus_zooms_out) {
PLOT_CHECK(f.plot.x_range(f.ax).span() > 100.0); PLOT_CHECK(f.plot.x_range(f.ax).span() > 100.0);
} }
PLOT_TEST(ctrl_plus_zooms_only_x) {
Fixture f;
f.ay = f.plot.add_y_axis({"v", {-1.0, 1.0}, false, plot::AxisPlace::Left, false});
const f64 x_before = f.plot.x_range(f.ax).span();
const f64 y_before = f.plot.y_range(f.ay).span();
f.controller.on_key({plot::input::kKeyZoomIn, kCtrl, true});
PLOT_CHECK(f.plot.x_range(f.ax).span() < x_before);
PLOT_CHECK_NEAR(f.plot.y_range(f.ay).span(), y_before, 1e-12);
}
PLOT_TEST(alt_plus_zooms_only_y) {
Fixture f;
f.ay = f.plot.add_y_axis({"v", {-1.0, 1.0}, false, plot::AxisPlace::Left, false});
constexpr plot::u32 kAlt = static_cast<plot::u32>(plot::input::Mod::Alt);
const f64 x_before = f.plot.x_range(f.ax).span();
const f64 y_before = f.plot.y_range(f.ay).span();
f.controller.on_key({plot::input::kKeyZoomIn, kAlt, true});
PLOT_CHECK_NEAR(f.plot.x_range(f.ax).span(), x_before, 1e-12);
PLOT_CHECK(f.plot.y_range(f.ay).span() < y_before);
}
/// A host can hand the controller a coordinate that is not a number: ImGui reports /// A host can hand the controller a coordinate that is not a number: ImGui reports
/// (-FLT_MAX, -FLT_MAX) for "no mouse position", and any host can produce a NaN out /// (-FLT_MAX, -FLT_MAX) for "no mouse position", and any host can produce a NaN out
/// of a degenerate mapping of its own. The pan arithmetic runs through the axis /// of a degenerate mapping of its own. The pan arithmetic runs through the axis