Menus · ContextMenu manual: opens on the owner's numbered request at a point, not on a right click, for rows that come after the press
This commit is contained in:
1 parent
f6f8b20624
commit
2c62b4f7b9
2 files changed
+56
-7
No files matched your search
+24
-6
@@ -2,8 +2,8 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, App, ClickEvent, Div, ElementId, Entity, InteractiveElement, IntoElement,
|
AnyElement, App, ClickEvent, Div, ElementId, Entity, InteractiveElement, IntoElement,
|
||||||
MouseButton, ParentElement, RenderOnce, SharedString, Stateful, Styled, Window, div,
|
MouseButton, ParentElement, Pixels, Point, RenderOnce, SharedString, Stateful, Styled, Window,
|
||||||
prelude::*,
|
div, prelude::*,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
@@ -226,6 +226,7 @@ impl RenderOnce for SplitButton {
|
|||||||
pub struct ContextMenu {
|
pub struct ContextMenu {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
menu: Menu,
|
menu: Menu,
|
||||||
|
request: Option<Option<(u64, Point<Pixels>)>>,
|
||||||
children: SmallVec<[AnyElement; 2]>,
|
children: SmallVec<[AnyElement; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,9 +235,16 @@ impl ContextMenu {
|
|||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
menu,
|
menu,
|
||||||
|
request: None,
|
||||||
children: SmallVec::new(),
|
children: SmallVec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens on the owner's numbered request, not on a right click: for rows that come after the press.
|
||||||
|
pub fn manual(mut self, request: Option<(u64, Point<Pixels>)>) -> Self {
|
||||||
|
self.request = Some(request);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParentElement for ContextMenu {
|
impl ParentElement for ContextMenu {
|
||||||
@@ -248,14 +256,24 @@ impl ParentElement for ContextMenu {
|
|||||||
impl RenderOnce for ContextMenu {
|
impl RenderOnce for ContextMenu {
|
||||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let state = state(&self.id, window, cx);
|
let state = state(&self.id, window, cx);
|
||||||
|
if let Some(Some((number, at))) = self.request {
|
||||||
|
let asked = window.use_keyed_state((self.id.clone(), "asked"), cx, |_, _| None);
|
||||||
|
if *asked.read(cx) != Some(number) {
|
||||||
|
asked.update(cx, |asked, _| *asked = Some(number));
|
||||||
|
log::info!("context menu {:?}: asked at {at:?}", self.id);
|
||||||
|
Open::show(&state, &self.menu, Spot::At(at), false, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
let (open, shut, menu) = (state.clone(), state.clone(), self.menu.clone());
|
let (open, shut, menu) = (state.clone(), state.clone(), self.menu.clone());
|
||||||
div()
|
div()
|
||||||
.id(self.id.clone())
|
.id(self.id.clone())
|
||||||
.relative()
|
.relative()
|
||||||
.on_mouse_down(MouseButton::Right, move |event, window, cx| {
|
.when(self.request.is_none(), |host| {
|
||||||
window.prevent_default();
|
host.on_mouse_down(MouseButton::Right, move |event, window, cx| {
|
||||||
log::info!("context menu: at {:?}", event.position);
|
window.prevent_default();
|
||||||
Open::show(&open, &menu, Spot::At(event.position), false, cx);
|
log::info!("context menu: at {:?}", event.position);
|
||||||
|
Open::show(&open, &menu, Spot::At(event.position), false, cx);
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.on_mouse_down(MouseButton::Left, move |_, window, cx| {
|
.on_mouse_down(MouseButton::Left, move |_, window, cx| {
|
||||||
if shut.read(cx).is_open() {
|
if shut.read(cx).is_open() {
|
||||||
|
|||||||
+32
-1
@@ -18,6 +18,7 @@ struct Desk {
|
|||||||
view_rows: bool,
|
view_rows: bool,
|
||||||
enters_above: usize,
|
enters_above: usize,
|
||||||
shift: bool,
|
shift: bool,
|
||||||
|
asked: Option<(u64, gpui::Point<gpui::Pixels>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Desk {
|
impl Desk {
|
||||||
@@ -83,7 +84,15 @@ impl Render for Desk {
|
|||||||
ContextMenu::new("area", menu.clone())
|
ContextMenu::new("area", menu.clone())
|
||||||
.child(div().w(px(200.0)).h(px(120.0))),
|
.child(div().w(px(200.0)).h(px(120.0))),
|
||||||
)
|
)
|
||||||
.child(SearchableMenu::new("find", "Find", menu)),
|
.child(SearchableMenu::new("find", "Find", menu.clone()))
|
||||||
|
.child(
|
||||||
|
ContextMenu::new("late", menu).manual(self.asked).child(
|
||||||
|
div()
|
||||||
|
.debug_selector(|| "late".into())
|
||||||
|
.w(px(200.0))
|
||||||
|
.h(px(40.0)),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,6 +126,7 @@ fn desk(cx: &mut TestAppContext) -> (gpui::Entity<Desk>, &mut VisualTestContext)
|
|||||||
view_rows: true,
|
view_rows: true,
|
||||||
enters_above: 0,
|
enters_above: 0,
|
||||||
shift: false,
|
shift: false,
|
||||||
|
asked: None,
|
||||||
});
|
});
|
||||||
settle(cx);
|
settle(cx);
|
||||||
(view, cx)
|
(view, cx)
|
||||||
@@ -209,6 +219,27 @@ fn a_right_click_opens_the_context_menu_where_it_lands(cx: &mut TestAppContext)
|
|||||||
assert_eq!(ran(&view, cx), ["cut"]);
|
assert_eq!(ran(&view, cx), ["cut"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_manual_context_menu_opens_only_from_its_owner(cx: &mut TestAppContext) {
|
||||||
|
let (view, cx) = desk(cx);
|
||||||
|
let at = cx.debug_bounds("late").expect("the host").center();
|
||||||
|
cx.simulate_mouse_move(at, None, Modifiers::none());
|
||||||
|
cx.simulate_mouse_down(at, MouseButton::Right, Modifiers::none());
|
||||||
|
cx.simulate_mouse_up(at, MouseButton::Right, Modifiers::none());
|
||||||
|
settle(cx);
|
||||||
|
press("down", cx);
|
||||||
|
press("enter", cx);
|
||||||
|
assert!(ran(&view, cx).is_empty(), "a right click opens nothing");
|
||||||
|
view.update(cx, |desk, cx| {
|
||||||
|
desk.asked = Some((1, point(px(60.0), px(80.0))));
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
settle(cx);
|
||||||
|
press("down", cx);
|
||||||
|
press("enter", cx);
|
||||||
|
assert_eq!(ran(&view, cx), ["cut"]);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn the_trigger_toggles_and_a_press_outside_closes(cx: &mut TestAppContext) {
|
fn the_trigger_toggles_and_a_press_outside_closes(cx: &mut TestAppContext) {
|
||||||
let (view, cx) = desk(cx);
|
let (view, cx) = desk(cx);
|
||||||
|
|||||||
Reference in new issue
Block a user