diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 3e41aaceb6955653bfedfd5bb8464ff6b4b66353..12a79fa6695ddff8371fa1b648056f43bec0cb98 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -7672,59 +7672,85 @@ impl EditorElement { .max(0.01); move |event: &ScrollWheelEvent, phase, window, cx| { - let scroll_sensitivity = { - if event.modifiers.alt { - fast_scroll_sensitivity - } else { - base_scroll_sensitivity - } - }; - if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) { - delta = delta.coalesce(event.delta); - editor.update(cx, |editor, cx| { - let position_map: &PositionMap = &position_map; - - let line_height = position_map.line_height; - let glyph_width = position_map.em_layout_width; - let (delta, axis) = match delta { - gpui::ScrollDelta::Pixels(mut pixels) => { - //Trackpad - let axis = position_map.snapshot.ongoing_scroll.filter(&mut pixels); - (pixels, axis) - } + if event.modifiers.secondary() { + let delta_y = match event.delta { + ScrollDelta::Pixels(pixels) => pixels.y.into(), + ScrollDelta::Lines(lines) => lines.y, + }; + + if delta_y > 0.0 { + window.dispatch_action( + Box::new(zed_actions::IncreaseBufferFontSize { persist: false }), + cx, + ); + } else if delta_y < 0.0 { + window.dispatch_action( + Box::new(zed_actions::DecreaseBufferFontSize { persist: false }), + cx, + ); + } - gpui::ScrollDelta::Lines(lines) => { - //Not trackpad - let pixels = point(lines.x * glyph_width, lines.y * line_height); - (pixels, None) + cx.stop_propagation(); + } else { + let scroll_sensitivity = { + if event.modifiers.alt { + fast_scroll_sensitivity + } else { + base_scroll_sensitivity } }; - let current_scroll_position = position_map.snapshot.scroll_position(); - let x = (current_scroll_position.x * ScrollPixelOffset::from(glyph_width) - - ScrollPixelOffset::from(delta.x * scroll_sensitivity)) - / ScrollPixelOffset::from(glyph_width); - let y = (current_scroll_position.y * ScrollPixelOffset::from(line_height) - - ScrollPixelOffset::from(delta.y * scroll_sensitivity)) - / ScrollPixelOffset::from(line_height); - let mut scroll_position = - point(x, y).clamp(&point(0., 0.), &position_map.scroll_max); - let forbid_vertical_scroll = editor.scroll_manager.forbid_vertical_scroll(); - if forbid_vertical_scroll { - scroll_position.y = current_scroll_position.y; - } + delta = delta.coalesce(event.delta); + editor.update(cx, |editor, cx| { + let position_map: &PositionMap = &position_map; + + let line_height = position_map.line_height; + let glyph_width = position_map.em_layout_width; + let (delta, axis) = match delta { + gpui::ScrollDelta::Pixels(mut pixels) => { + //Trackpad + let axis = + position_map.snapshot.ongoing_scroll.filter(&mut pixels); + (pixels, axis) + } - if scroll_position != current_scroll_position { - editor.scroll(scroll_position, axis, window, cx); - cx.stop_propagation(); - } else if y < 0. { - // Due to clamping, we may fail to detect cases of overscroll to the top; - // We want the scroll manager to get an update in such cases and detect the change of direction - // on the next frame. - cx.notify(); - } - }); + gpui::ScrollDelta::Lines(lines) => { + //Not trackpad + let pixels = + point(lines.x * glyph_width, lines.y * line_height); + (pixels, None) + } + }; + + let current_scroll_position = position_map.snapshot.scroll_position(); + let x = (current_scroll_position.x + * ScrollPixelOffset::from(glyph_width) + - ScrollPixelOffset::from(delta.x * scroll_sensitivity)) + / ScrollPixelOffset::from(glyph_width); + let y = (current_scroll_position.y + * ScrollPixelOffset::from(line_height) + - ScrollPixelOffset::from(delta.y * scroll_sensitivity)) + / ScrollPixelOffset::from(line_height); + let mut scroll_position = + point(x, y).clamp(&point(0., 0.), &position_map.scroll_max); + let forbid_vertical_scroll = + editor.scroll_manager.forbid_vertical_scroll(); + if forbid_vertical_scroll { + scroll_position.y = current_scroll_position.y; + } + + if scroll_position != current_scroll_position { + editor.scroll(scroll_position, axis, window, cx); + cx.stop_propagation(); + } else if y < 0. { + // Due to clamping, we may fail to detect cases of overscroll to the top; + // We want the scroll manager to get an update in such cases and detect the change of direction + // on the next frame. + cx.notify(); + } + }); + } } } }); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 6dbe602f082c436e9055bfc8949526f0bb8f37c9..3d4ada8a1b90020090eb74a8a6ea752fa7a44ab3 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -2406,8 +2406,8 @@ mod tests { DisplayPoint, Editor, MultiBufferOffset, SelectionEffects, display_map::DisplayRow, }; use gpui::{ - Action, AnyWindowHandle, App, AssetSource, BorrowAppContext, TestAppContext, UpdateGlobal, - VisualTestContext, WindowHandle, actions, + Action, AnyWindowHandle, App, AssetSource, BorrowAppContext, Modifiers, TestAppContext, + UpdateGlobal, VisualTestContext, WindowHandle, actions, point, px, }; use language::LanguageRegistry; use languages::{markdown_lang, rust_lang}; @@ -4089,6 +4089,99 @@ mod tests { buffer.assert_released(); } + #[gpui::test] + async fn test_editor_zoom_with_scroll_wheel(cx: &mut TestAppContext) { + let app_state = init_test(cx); + app_state + .fs + .as_fake() + .insert_tree(path!("/root"), json!({ "file.txt": "hello\nworld\n" })) + .await; + + let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await; + let window = + cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); + let workspace = window + .read_with(cx, |mw, _| mw.workspace().clone()) + .unwrap(); + let cx = &mut VisualTestContext::from_window(*window, cx); + + let mouse_position = point(px(250.), px(250.)); + + let event_modifiers = { + #[cfg(target_os = "macos")] + { + Modifiers { + platform: true, + ..Modifiers::default() + } + } + + #[cfg(not(target_os = "macos"))] + { + Modifiers { + control: true, + ..Modifiers::default() + } + } + }; + + workspace + .update_in(cx, |workspace, window, cx| { + workspace.open_abs_path( + PathBuf::from(path!("/root/file.txt")), + OpenOptions::default(), + window, + cx, + ) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + + cx.update(|window, cx| { + window.draw(cx).clear(); + }); + + let initial_font_size = + cx.update(|_, cx| ThemeSettings::get_global(cx).buffer_font_size(cx).as_f32()); + + cx.simulate_event(gpui::ScrollWheelEvent { + position: mouse_position, + delta: gpui::ScrollDelta::Pixels(point(px(0.), px(1.))), + modifiers: event_modifiers, + ..Default::default() + }); + + let increased_font_size = + cx.update(|_, cx| ThemeSettings::get_global(cx).buffer_font_size(cx).as_f32()); + + assert!( + increased_font_size > initial_font_size, + "Editor buffer font-size should have increased from scroll-zoom" + ); + + cx.update(|window, cx| { + window.draw(cx).clear(); + }); + + cx.simulate_event(gpui::ScrollWheelEvent { + position: mouse_position, + delta: gpui::ScrollDelta::Pixels(point(px(0.), px(-1.))), + modifiers: event_modifiers, + ..Default::default() + }); + + let decreased_font_size = + cx.update(|_, cx| ThemeSettings::get_global(cx).buffer_font_size(cx).as_f32()); + + assert!( + decreased_font_size < increased_font_size, + "Editor buffer font-size should have decreased from scroll-zoom" + ); + } + #[gpui::test] async fn test_navigation(cx: &mut TestAppContext) { let app_state = init_test(cx);