diff --git a/src/menus/hosts.rs b/src/menus/hosts.rs index 4534f5c..0fd16d0 100644 --- a/src/menus/hosts.rs +++ b/src/menus/hosts.rs @@ -2,8 +2,8 @@ use std::rc::Rc; use gpui::{ AnyElement, App, ClickEvent, Div, ElementId, Entity, InteractiveElement, IntoElement, - MouseButton, ParentElement, Pixels, Point, RenderOnce, SharedString, Stateful, Styled, Window, - div, prelude::*, + MouseButton, ParentElement, Pixels, Point, RenderOnce, SharedString, Stateful, StyleRefinement, + Styled, Window, div, prelude::*, }; use smallvec::SmallVec; @@ -221,13 +221,14 @@ impl RenderOnce for SplitButton { } } -/// Its children, and a menu that opens at the pointer on a right click. +/// Its children, and a menu that opens at the pointer on a right click. Styles size the host, so a list inside can fill it. #[derive(IntoElement)] pub struct ContextMenu { id: ElementId, menu: Menu, request: Option)>>, children: SmallVec<[AnyElement; 2]>, + base: Div, } impl ContextMenu { @@ -237,6 +238,7 @@ impl ContextMenu { menu, request: None, children: SmallVec::new(), + base: div(), } } @@ -253,6 +255,12 @@ impl ParentElement for ContextMenu { } } +impl Styled for ContextMenu { + fn style(&mut self) -> &mut StyleRefinement { + self.base.style() + } +} + impl RenderOnce for ContextMenu { fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { let state = state(&self.id, window, cx); @@ -265,7 +273,7 @@ impl RenderOnce for ContextMenu { } } let (open, shut, menu) = (state.clone(), state.clone(), self.menu.clone()); - div() + self.base .id(self.id.clone()) .relative() .when(self.request.is_none(), |host| { diff --git a/src/menus/tests/more.rs b/src/menus/tests/more.rs index b01b8e4..8fbc129 100644 --- a/src/menus/tests/more.rs +++ b/src/menus/tests/more.rs @@ -246,3 +246,36 @@ fn pie_confirm_keys_stay_inside_and_ignore_modifiers(cx: &mut TestAppContext) { assert_eq!(view.read_with(cx, |wheel, _| wheel.ran.clone()), ["copy"]); assert_eq!(view.read_with(cx, |wheel, _| wheel.enters_above), 0); } + +/// A sized context menu over a child that fills it. +struct Filled { + seen: std::rc::Rc>, +} + +impl Render for Filled { + fn render(&mut self, _: &mut Window, _: &mut Context) -> impl IntoElement { + let seen = self.seen.clone(); + let fill = gpui::canvas( + move |bounds, _, _| seen.set(f32::from(bounds.size.height)), + |_, _, _, _| {}, + ) + .size_full(); + div().h(px(200.)).w(px(100.)).child( + crate::menus::ContextMenu::new("filled", crate::menus::Menu::new()) + .size_full() + .child(fill), + ) + } +} + +#[gpui::test] +fn a_sized_context_menu_lets_its_child_fill_it(cx: &mut TestAppContext) { + cx.update(Theme::init); + let seen = std::rc::Rc::new(std::cell::Cell::new(0.0)); + let (_, cx) = cx.add_window_view({ + let seen = seen.clone(); + move |_, _| Filled { seen } + }); + settle(cx); + assert_eq!(seen.get(), 200.0); +}