diff --git a/src/forms/options.rs b/src/forms/options.rs index 562aa65..b90abce 100644 --- a/src/forms/options.rs +++ b/src/forms/options.rs @@ -321,6 +321,7 @@ impl Popup<'_> { }) .max_w(window.viewport_size().width - theme.window_margin() * 2.0) .max_h(theme.list_max_height()) + .occlude() .overflow_y_scroll() .when_some(self.scroll, |list, handle| list.track_scroll(handle)) .p_1() diff --git a/src/forms/tests/mod.rs b/src/forms/tests/mod.rs index 1899257..6777dd5 100644 --- a/src/forms/tests/mod.rs +++ b/src/forms/tests/mod.rs @@ -2,6 +2,7 @@ mod choices; mod colors; mod dates; mod other; +mod popup; mod stale; mod structure; mod tags; diff --git a/src/forms/tests/popup.rs b/src/forms/tests/popup.rs new file mode 100644 index 0000000..98b53f9 --- /dev/null +++ b/src/forms/tests/popup.rs @@ -0,0 +1,50 @@ +use gpui::{ + Context, IntoElement, KeyUpEvent, Keystroke, Modifiers, ParentElement, Render, ScrollDelta, + ScrollHandle, ScrollWheelEvent, Styled, TestAppContext, TouchPhase, Window, div, point, + prelude::*, px, +}; + +use super::setup; +use crate::forms::{Choice, Select}; + +/// A long select at the top of a page that scrolls. +struct Page(ScrollHandle); + +impl Render for Page { + fn render(&mut self, _: &mut Window, _: &mut Context) -> impl IntoElement { + let choices = (0..40).map(|ix| Choice::new(format!("{ix}"), format!("Choice {ix}"))); + div() + .id("page") + .size_full() + .overflow_y_scroll() + .track_scroll(&self.0) + .child(div().w(px(200.0)).child(Select::new("long", choices))) + .child(div().h(px(2000.0))) + } +} + +#[gpui::test] +fn a_wheel_over_an_open_list_leaves_the_page(cx: &mut TestAppContext) { + setup(cx); + let page = ScrollHandle::new(); + let (_, cx) = cx.add_window_view({ + let page = page.clone(); + |_, _| Page(page) + }); + cx.run_until_parked(); + cx.update(|window, cx| window.focus_next(cx)); + cx.simulate_keystrokes("enter"); + cx.simulate_event(KeyUpEvent { + keystroke: Keystroke::parse("enter").unwrap(), + }); + cx.run_until_parked(); + let list = cx.debug_bounds("option-list").expect("the list opens"); + cx.simulate_event(ScrollWheelEvent { + position: list.center(), + delta: ScrollDelta::Pixels(point(px(0.0), px(-120.0))), + modifiers: Modifiers::none(), + touch_phase: TouchPhase::Moved, + }); + cx.run_until_parked(); + assert_eq!(page.offset().y, px(0.0), "the page stayed"); +} diff --git a/tasks/github.md b/tasks/github.md index 899f093..f6562ef 100644 --- a/tasks/github.md +++ b/tasks/github.md @@ -18,7 +18,7 @@ - [x] G10 CI: `cargo fmt` on the files the last commits left unformatted - [x] G11 Issue #7: a caret is a whole number of device pixels wide at a device pixel, so it never shows thin then thick; tested - [x] G12 Issue #7: an IME asks for its candidate box past the laid-out text; the box clamps to the last layout, as `bounds_for` does; tested -- [ ] G13 Issue #12: a floating option list occludes, so the wheel scrolls the list and not the page under it; tested +- [x] G13 Issue #12: a floating option list occludes, so the wheel scrolls the list and not the page under it; tested - [ ] G14 Issue #7: BlockEditor scrolls in its own `ScrollArea` with its scrollbar and keeps the caret in view as blocks are added; tested - [ ] G15 Issue #7: BlockEditor turns into Markdown and back; tested - [ ] G16 Issue #7: a selection across blocks: drag or Shift-press selects, copy, cut, delete and typing act on it, undo restores; tested