Zoom the page with Ctrl+scroll and pinch (#139) (#179)

The canvas ignored egui's zoom delta, so Ctrl/Cmd+wheel and trackpad pinch
did nothing over the document. Apply it through view.zoom, starting from the
shown scale so fit modes (Page Width etc.) zoom from where they are.

Co-authored-by: Simon Geljic <simon.geljic2@det.nsw.edu.au>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Si
2026-10-10 06:17:33 -04:00
committed by GitHub
co-authored by Simon Geljic Claude Opus 5.5
parent bd123c3808
commit 97aad95d4d
2 changed files with 49 additions and 0 deletions
+7
View File
@@ -168,6 +168,13 @@ pub fn show(app: &mut WordApp, ui: &mut Ui) {
(None, None, full)
};
app.canvas.canvas_rect = Some(area);
// Ctrl/⌘ + wheel (and trackpad pinch) zooms the document, like Word. egui reports both as a
// zoom factor and doesn't scroll for them. Start from the shown scale so fit modes zoom too.
let zoom_delta = ui.input(|i| i.zoom_delta());
if (zoom_delta - 1.0).abs() > 1e-3 && ui.rect_contains_pointer(area) {
let pct = (app.canvas.scale / PX_PER_PT * zoom_delta * 100.0).clamp(10.0, 500.0);
let _ = app.run("view.zoom", json!({"value": pct}));
}
let geo = geometry(app, &layout, area.size() - vec2(14.0, 0.0));
app.canvas.scale = geo.scale;
let caret = layout.caret_on(&app.session.sel.focus, app.session.page_hint);
+42
View File
@@ -612,6 +612,48 @@ mod tests {
WordApp::new(Session::new(wordcraft_doc::Document::new()), Services::default())
}
/// Issue #139: Ctrl+wheel over the page didn't zoom.
#[test]
fn ctrl_wheel_over_canvas_zooms() {
let ctx = egui::Context::default();
let mut a = app();
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1280.0, 800.0));
let mut t = 0.0;
let mut frame = |a: &mut WordApp, events: Vec<egui::Event>| {
t += 1.0 / 60.0;
let input = egui::RawInput { events, time: Some(t), screen_rect: Some(screen), ..Default::default() };
ctx.run_ui(input, |ui| {
a.logic(ui.ctx());
a.ui(ui);
})
.drop_without_applying_deltas();
};
// The first frames install fonts; the canvas appears after them.
for _ in 0..3 {
frame(&mut a, Vec::new());
}
let over_page = a.canvas.canvas_rect.unwrap().center();
frame(&mut a, vec![egui::Event::PointerMoved(over_page)]);
let before = a.canvas.scale;
let wheel = |y: f32| egui::Event::MouseWheel {
unit: egui::MouseWheelUnit::Line,
delta: egui::vec2(0.0, y),
phase: egui::TouchPhase::Move,
modifiers: egui::Modifiers::COMMAND,
};
frame(&mut a, vec![wheel(1.0)]);
for _ in 0..30 {
frame(&mut a, Vec::new());
}
assert!(a.canvas.scale > before * 1.05, "Ctrl+wheel up zooms in: {before} -> {}", a.canvas.scale);
let zoomed = a.canvas.scale;
frame(&mut a, vec![wheel(-1.0)]);
for _ in 0..30 {
frame(&mut a, Vec::new());
}
assert!(a.canvas.scale < zoomed, "Ctrl+wheel down zooms out");
}
#[test]
fn user_name_survives_restart() {
let mut first = app();