Menus · ContextMenu: styles size its host, so a list inside can fill it

This commit is contained in:
ZacharyZhang-NY committed 2026-10-06 09:17:56 -04:00
1 parent 617a8d68de
commit 2ce336895c
2 files changed
+45 -4

No files matched your search

+12 -4
View File
@@ -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<Option<(u64, Point<Pixels>)>>,
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| {
+33
View File
@@ -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<std::cell::Cell<f32>>,
}
impl Render for Filled {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> 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);
}