Rework Zoom controls

This commit is contained in:
2026-09-11 08:58:22 +02:00
parent d574680321
commit 900132deeb
5 changed files with 56 additions and 4 deletions
+1
View File
@@ -40,6 +40,7 @@ reshuffle.
| Middle- or right-drag | Pan |
| Drop files on the window | A file node each; a `.canvas` file opens instead |
| Wheel | Zoom around the pointer, anywhere on the canvas |
| Double-click the wheel button | Back to 100% |
**Markdown in text nodes**: headings, bold/italic/strikethrough, inline and
fenced code, quotes, bullet, numbered and task lists, rules, images and links.
+11 -3
View File
@@ -910,14 +910,21 @@ impl App {
}
if ui
.button(format!("{:.0}%", self.view.zoom() * 100.0))
.on_hover_text("Actual size (Ctrl+1)")
.clicked()
{
self.view.set_zoom(1.0);
}
if ui.button("+").on_hover_text("Zoom in (Ctrl++)").clicked() {
self.view.set_zoom(self.view.zoom() * 1.2);
}
if ui
.button("⛶")
.on_hover_text("Zoom to fit (Ctrl+0)")
.clicked()
{
self.view.zoom_to_fit(&self.doc.canvas);
}
if ui.button("+").on_hover_text("Zoom in (Ctrl++)").clicked() {
self.view.set_zoom(self.view.zoom() * 1.2);
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.toggle_value(&mut self.show_inspector, "Inspector");
@@ -1196,6 +1203,7 @@ const SHORTCUTS: &[(&str, &str)] = &[
("Arrow keys", "Nudge (hold Shift for 10 units)"),
("Double-click", "New note, or edit what is under the cursor"),
("Middle / right drag", "Pan the canvas"),
("Double-click wheel", "Back to 100%"),
("Wheel", "Zoom around the pointer"),
("Ctrl+0 / Ctrl+1", "Zoom to fit / actual size"),
];
+6 -1
View File
@@ -809,7 +809,8 @@ impl CanvasView {
// -- input ------------------------------------------------------------
/// Panning is a drag or a two-finger swipe; the wheel zooms, and so does
/// a swipe with the zoom modifier held.
/// a swipe with the zoom modifier held. Two clicks of the wheel button
/// go back to 1:1.
fn handle_pan_and_zoom(&mut self, ui: &egui::Ui, background: &egui::Response) {
if background.dragged_by(PointerButton::Middle)
|| background.dragged_by(PointerButton::Secondary)
@@ -826,6 +827,10 @@ impl CanvasView {
let Some(pointer) = ui.input(|i| i.pointer.latest_pos()) else {
return;
};
if ui.input(|i| i.pointer.button_double_clicked(PointerButton::Middle)) {
self.set_zoom(1.0);
return;
}
// Held down, the zoom modifier turns scrolling into zooming before it
// ever reaches here: egui reports it as a zoom and leaves no scroll
// behind. A pinch on a touchscreen arrives the same way.
+38
View File
@@ -563,6 +563,44 @@ fn the_wheel_zooms_over_a_node() {
assert!(moved < 1.0, "the canvas slid {moved} under the pointer");
}
/// Two clicks of the wheel button put the canvas back to 1:1, over a card
/// as readily as over bare canvas.
#[test]
fn a_double_click_of_the_wheel_button_goes_back_to_actual_size() {
let ctx = egui::Context::default();
let mut doc = Document::new();
doc.canvas = canvas_with_two_nodes();
let mut view = CanvasView::new();
// Zoomed in, with node "a" in the middle of the view.
view.to_global =
TSTransform::from_translation(vec2(475.0, 325.0)) * TSTransform::from_scaling(2.5);
let screen = Rect::from_min_size(Pos2::ZERO, vec2(1200.0, 900.0));
let at = pos2(600.0, 450.0);
let wheel = |pressed| egui::Event::PointerButton {
pos: at,
button: PointerButton::Middle,
pressed,
modifiers: egui::Modifiers::default(),
};
pass(
&ctx,
&mut view,
&mut doc,
screen,
vec![egui::Event::PointerMoved(at)],
);
pass(
&ctx,
&mut view,
&mut doc,
screen,
vec![wheel(true), wheel(false), wheel(true), wheel(false)],
);
assert_eq!(view.zoom(), 1.0, "the wheel button did not reset the zoom");
}
/// A two-finger swipe on a touchpad slides the canvas about, sideways as
/// readily as up and down, rather than zooming the way the wheel does.
#[test]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB