mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-30 04:37:29 -06:00
Merge pull request #4313 from Hassan1305/fix-4283-wheel-animated-zoom
Fix #4283: a wheel notch zooms at once without Animated Zoom
This commit is contained in:
@@ -170,11 +170,12 @@ fn wheel_view(
|
||||
) -> (egui::PointerState, egui::Modifiers, bool, Option<Pos2>) {
|
||||
let line = ui.ctx().options(|o| o.input_options.line_scroll_speed);
|
||||
let wheel_zooms = app.session.prefs.zoom_with_mouse_wheel;
|
||||
let animate = animated_zoom(&app.session.prefs);
|
||||
let turn_id = egui::Id::unique("canvas-wheel-turn");
|
||||
let turn_before: WheelTurn = ui.data(|d| d.get_temp(turn_id)).unwrap_or_default();
|
||||
let mut turn = turn_before;
|
||||
let (pointer, m, space, (factor, scroll)) =
|
||||
ui.input(|i| (i.pointer.clone(), i.modifiers, i.key_down(egui::Key::Space), wheel(i, wheel_zooms, line, rect.height(), &mut turn)));
|
||||
ui.input(|i| (i.pointer.clone(), i.modifiers, i.key_down(egui::Key::Space), wheel(i, wheel_zooms, animate, line, rect.height(), &mut turn)));
|
||||
if turn != turn_before {
|
||||
ui.data_mut(|d| d.insert_temp(turn_id, turn));
|
||||
}
|
||||
|
||||
@@ -3929,6 +3929,60 @@ fn wheel_notches_zoom_in_a_glide() {
|
||||
assert_eq!(app.view().unwrap().zoom / before, done, "and it stops");
|
||||
}
|
||||
|
||||
/// #4283: with Performance › Animated Zoom off, or on without GPU Performance (which it needs), a
|
||||
/// wheel notch zooms the whole step on the frame it arrives, both the plain wheel with Zoom with
|
||||
/// Mouse Wheel and Alt-wheel without it.
|
||||
#[test]
|
||||
fn wheel_notches_zoom_at_once_without_animated_zoom() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.session.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
let run = |app: &mut VectorcraftApp| {
|
||||
let mut raw = egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(Pos2::ZERO, vec2(800.0, 600.0))), ..Default::default() };
|
||||
app.raw_input_hook(&ctx, &mut raw);
|
||||
let mut out = ctx.run_ui(raw, |ui| show(app, ui));
|
||||
out.textures_delta.clear();
|
||||
};
|
||||
run(&mut app);
|
||||
let at = app.canvas_rect.unwrap().center();
|
||||
for (animated, gpu, wheel_zooms, alt) in
|
||||
[(false, true, true, false), (false, true, false, true), (true, false, true, false), (true, false, false, true)]
|
||||
{
|
||||
app.session.execute("prefs.set", &json!({"key": "animatedZoom", "value": animated})).unwrap();
|
||||
app.session.execute("prefs.set", &json!({"key": "gpuPerformance", "value": gpu})).unwrap();
|
||||
app.session.execute("prefs.set", &json!({"key": "zoomWithMouseWheel", "value": wheel_zooms})).unwrap();
|
||||
// Any glide or spread scroll a case before left behind dies down first.
|
||||
for _ in 0..30 {
|
||||
run(&mut app);
|
||||
}
|
||||
let before = app.view().unwrap().zoom;
|
||||
crate::tests_synthetic::control(&mut app, &ctx, "ui.wheel", json!({"x": at.x, "y": at.y, "dy": 1, "alt": alt}));
|
||||
// One line notch's whole zoom.
|
||||
let expected = ctx.options(|o| f64::from(o.input_options.line_scroll_speed) * 0.01).exp();
|
||||
// The first frame the zoom moves (the event may land a frame later).
|
||||
let mut first = 1.0;
|
||||
for _ in 0..3 {
|
||||
run(&mut app);
|
||||
first = app.view().unwrap().zoom / before;
|
||||
if first != 1.0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
(first - expected).abs() < 1e-9,
|
||||
"the whole notch arrives at once (animated {animated}, gpu {gpu}, wheel zooms {wheel_zooms}, alt {alt}: expected {expected}, got {first})"
|
||||
);
|
||||
for _ in 0..30 {
|
||||
run(&mut app);
|
||||
}
|
||||
let done = app.view().unwrap().zoom / before;
|
||||
assert!(
|
||||
(done - first).abs() < 1e-9,
|
||||
"all of it on the first frame (animated {animated}, gpu {gpu}, wheel zooms {wheel_zooms}, alt {alt}: {first} then {done})"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// In each frame where a wheel scroll moves the view, the hover point (read by the rulers'
|
||||
/// pointer marks, the Info panel, the hover highlight and the tool cursor) is the document point
|
||||
/// under the pointer in the view the canvas draws in that frame.
|
||||
|
||||
@@ -64,7 +64,8 @@ pub(super) const HOLD_DELAY: f32 = 0.3;
|
||||
pub(super) const HOLD_ZOOM: f64 = std::f64::consts::LN_2;
|
||||
|
||||
/// Performance › Animated Zoom, which needs GPU Performance as in Illustrator: the Zoom tool zooms
|
||||
/// as it is dragged sideways or held, instead of zooming to the area dragged across.
|
||||
/// as it is dragged sideways or held, instead of zooming to the area dragged across, and a wheel
|
||||
/// notch's zoom glides in ([`wheel`]).
|
||||
pub(crate) fn animated_zoom(p: &vectorcraft_engine::Prefs) -> bool {
|
||||
p.animated_zoom && p.gpu_performance
|
||||
}
|
||||
@@ -336,11 +337,19 @@ struct ThumbDrag {
|
||||
/// a zoom factor (about the pointer) and a scroll (screen points the content moves). The wheel scrolls, Cmd- and Alt-wheel (Option
|
||||
/// on the Mac) zoom. With General › Zoom with Mouse Wheel (`wheel_zooms`) the wheel and Alt-wheel
|
||||
/// zoom, Shift-wheel scrolls up and down and Cmd/Ctrl-wheel sideways. `line` and `page`: points
|
||||
/// per wheel line and page. `turn`: kept by the caller across frames. A mouse wheel's notches zoom
|
||||
/// in a glide over a few frames, as scrolling does (#888); a trackpad's fine steps at once.
|
||||
pub(super) fn wheel(i: &egui::InputState, wheel_zooms: bool, line: f32, page: f32, turn: &mut WheelTurn) -> (f64, egui::Vec2) {
|
||||
/// per wheel line and page. `turn`: kept by the caller across frames. With Performance › Animated
|
||||
/// Zoom (`animate`) a mouse wheel's notches zoom in a glide over a few frames, as scrolling does
|
||||
/// (#888); off, each notch zooms on the frame it arrives (#4283). A trackpad's fine steps zoom at
|
||||
/// once either way.
|
||||
pub(super) fn wheel(i: &egui::InputState, wheel_zooms: bool, animate: bool, line: f32, page: f32, turn: &mut WheelTurn) -> (f64, egui::Vec2) {
|
||||
// Fingers on a touch screen pan the content with them (a trackpad sends scrolls instead).
|
||||
let pan = i.multi_touch().map_or(egui::Vec2::ZERO, |t| t.translation_delta);
|
||||
// A wheel event's motion in points.
|
||||
let points = |unit: &egui::MouseWheelUnit, delta: egui::Vec2| match unit {
|
||||
egui::MouseWheelUnit::Point => delta,
|
||||
egui::MouseWheelUnit::Line => delta * line,
|
||||
egui::MouseWheelUnit::Page => delta * page,
|
||||
};
|
||||
if !wheel_zooms {
|
||||
// egui makes Cmd-wheel (and a pinch) its zoom and the rest a scroll it spreads over a few
|
||||
// frames: the rest of an Alt-wheel turn zooms too, however soon Alt is let go.
|
||||
@@ -348,6 +357,17 @@ pub(super) fn wheel(i: &egui::InputState, wheel_zooms: bool, line: f32, page: f3
|
||||
turn.alt = m.alt && !m.command;
|
||||
}
|
||||
let (zoom, scroll) = (f64::from(i.zoom_delta()), i.smooth_scroll_delta);
|
||||
if turn.alt && !animate {
|
||||
// Without Animated Zoom, Alt-wheel zooms by the wheel events themselves, on the frame
|
||||
// they arrive; the rest of egui's spread scroll is dropped.
|
||||
let d: f32 = i
|
||||
.events
|
||||
.iter()
|
||||
.filter_map(|e| if let egui::Event::MouseWheel { unit, delta, .. } = e { Some(points(unit, *delta)) } else { None })
|
||||
.map(|d| d.x + d.y)
|
||||
.sum();
|
||||
return (zoom * (f64::from(d) * WHEEL_ZOOM).exp(), pan);
|
||||
}
|
||||
return if turn.alt && scroll != egui::Vec2::ZERO {
|
||||
(zoom * (f64::from(scroll.x + scroll.y) * WHEEL_ZOOM).exp(), pan)
|
||||
} else {
|
||||
@@ -360,16 +380,12 @@ pub(super) fn wheel(i: &egui::InputState, wheel_zooms: bool, line: f32, page: f3
|
||||
for e in &i.events {
|
||||
match e {
|
||||
egui::Event::MouseWheel { unit, delta, modifiers, .. } => {
|
||||
let d = match unit {
|
||||
egui::MouseWheelUnit::Point => *delta,
|
||||
egui::MouseWheelUnit::Line => *delta * line,
|
||||
egui::MouseWheelUnit::Page => *delta * page,
|
||||
};
|
||||
let d = points(unit, *delta);
|
||||
if modifiers.command {
|
||||
scroll.x += d.x + d.y;
|
||||
} else if modifiers.shift {
|
||||
scroll.y += d.x + d.y;
|
||||
} else if *unit == egui::MouseWheelUnit::Point {
|
||||
} else if *unit == egui::MouseWheelUnit::Point || !animate {
|
||||
zoom *= (f64::from(d.y) * WHEEL_ZOOM).exp();
|
||||
scroll.x += d.x;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user