Skip to content

Commit d6a0368

Browse files
committed
Revert "fix: handle context menu on mouse release"
This reverts commit fd0b64e.
1 parent fd0b64e commit d6a0368

9 files changed

Lines changed: 55 additions & 222 deletions

File tree

‎crates/db_view/src/db_tree_view.rs‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,11 +2744,9 @@ impl DbTreeView {
27442744
let view_for_click = view.clone();
27452745
let view_for_double_click = view.clone();
27462746
let view_for_context = view.clone();
2747-
let view_for_context_up = view.clone();
27482747
let node_id_for_click = node_id.clone();
27492748
let node_id_for_double_click = node_id.clone();
27502749
let node_id_for_context = node_id.clone();
2751-
let node_id_for_context_up = node_id.clone();
27522750
let view_for_filter = view.clone();
27532751
let node_id_for_filter = node_id.clone();
27542752

@@ -2802,12 +2800,6 @@ impl DbTreeView {
28022800
cx.notify();
28032801
});
28042802
})
2805-
.on_mouse_up(MouseButton::Right, move |_event, _window, cx| {
2806-
view_for_context_up.update(cx, |this, cx| {
2807-
this.set_context_menu_target(&node_id_for_context_up, ix);
2808-
cx.notify();
2809-
});
2810-
})
28112803
// 内容
28122804
.child(
28132805
h_flex()

‎crates/mongodb_view/src/mongo_tree_view.rs‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,9 +1252,7 @@ impl MongoTreeView {
12521252
let view_for_double_click = cx.entity().clone();
12531253
let node_id_for_double_click = node_id.clone();
12541254
let view_for_context = cx.entity().clone();
1255-
let view_for_context_up = cx.entity().clone();
12561255
let node_id_for_context = node_id.clone();
1257-
let node_id_for_context_up = node_id.clone();
12581256
let view_for_arrow = cx.entity().clone();
12591257
let node_id_for_arrow = node_id.clone();
12601258

@@ -1286,12 +1284,6 @@ impl MongoTreeView {
12861284
cx.notify();
12871285
});
12881286
})
1289-
.on_mouse_up(MouseButton::Right, move |_event, _window, cx| {
1290-
view_for_context_up.update(cx, |view, cx| {
1291-
view.set_context_menu_target(&node_id_for_context_up);
1292-
cx.notify();
1293-
});
1294-
})
12951287
.child(div().w(indent))
12961288
.child(
12971289
div()

‎crates/one_ui/src/edit_table/state.rs‎

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,10 +1030,6 @@ where
10301030
_: &mut Window,
10311031
_: &mut Context<Self>,
10321032
) {
1033-
self.set_row_context_menu_target(row_ix);
1034-
}
1035-
1036-
fn set_row_context_menu_target(&mut self, row_ix: usize) {
10371033
self.right_clicked_row = Some(row_ix);
10381034
}
10391035

@@ -2826,12 +2822,6 @@ where
28262822
this.on_row_right_click(e, row_ix, window, cx);
28272823
}),
28282824
)
2829-
.on_mouse_up(
2830-
MouseButton::Right,
2831-
cx.listener(move |this, _, _, _| {
2832-
this.set_row_context_menu_target(row_ix);
2833-
}),
2834-
)
28352825
} else {
28362826
self.delegate
28372827
.render_tr(row_ix, window, cx)

‎crates/redis_view/src/redis_tree_view.rs‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,10 +1975,8 @@ impl RedisTreeView {
19751975
let view = cx.entity().clone();
19761976
let view_for_db_switch = cx.entity().clone();
19771977
let view_for_context = cx.entity().clone();
1978-
let view_for_context_up = cx.entity().clone();
19791978
let view_for_dbl = cx.entity().clone();
19801979
let node_id_for_context = node_id.clone();
1981-
let node_id_for_context_up = node_id.clone();
19821980
let node_id_for_dbl = node_id.clone();
19831981
let connection_id_for_load_more = node_connection_id.clone();
19841982

@@ -2044,12 +2042,6 @@ impl RedisTreeView {
20442042
cx.notify();
20452043
});
20462044
})
2047-
.on_mouse_up(MouseButton::Right, move |_event, _window, cx| {
2048-
view_for_context_up.update(cx, |view, cx| {
2049-
view.set_context_menu_target(&node_id_for_context_up);
2050-
cx.notify();
2051-
});
2052-
})
20532045
// 展开/折叠箭头
20542046
.child(
20552047
div()

‎crates/ui/src/input/popovers/context_menu.rs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use gpui::{
2-
Anchor, App, AppContext as _, Context, DismissEvent, Entity, IntoElement, ParentElement as _,
3-
Pixels, Point, Render, Styled, Subscription, Window, anchored, deferred, div,
4-
prelude::FluentBuilder as _, px,
2+
Anchor, App, AppContext as _, Context, DismissEvent, Entity, IntoElement, MouseDownEvent,
3+
ParentElement as _, Pixels, Point, Render, Styled, Subscription, Window, anchored, deferred,
4+
div, prelude::FluentBuilder as _, px,
55
};
66
use rust_i18n::t;
77

@@ -98,7 +98,7 @@ impl InputState {
9898

9999
pub(crate) fn handle_right_click_menu(
100100
&mut self,
101-
position: Point<Pixels>,
101+
event: &MouseDownEvent,
102102
offset: usize,
103103
window: &mut Window,
104104
cx: &mut Context<Self>,
@@ -130,7 +130,7 @@ impl InputState {
130130

131131
let action_context = self.focus_handle.clone();
132132
self.context_menu.update(cx, |this, cx| {
133-
this.mouse_position = position;
133+
this.mouse_position = event.position;
134134
this.menu.update(cx, |menu, cx| {
135135
let new_menu = if let Some(builder) = &self.context_menu_builder {
136136
builder(PopupMenu::new(cx), window, cx)

‎crates/ui/src/input/state.rs‎

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,7 @@ impl InputState {
15771577
// Show Mouse context menu
15781578
if event.button == MouseButton::Right {
15791579
if self.enable_context_menu || self.context_menu_builder.is_some() {
1580-
self.handle_right_click_menu(event.position, offset, window, cx);
1580+
self.handle_right_click_menu(event, offset, window, cx);
15811581
}
15821582
return;
15831583
}
@@ -1591,18 +1591,10 @@ impl InputState {
15911591

15921592
pub(super) fn on_mouse_up(
15931593
&mut self,
1594-
event: &MouseUpEvent,
1595-
window: &mut Window,
1596-
cx: &mut Context<Self>,
1594+
_: &MouseUpEvent,
1595+
_window: &mut Window,
1596+
_cx: &mut Context<Self>,
15971597
) {
1598-
if event.button == MouseButton::Right && self.context_menu_content.is_none() {
1599-
if self.enable_context_menu || self.context_menu_builder.is_some() {
1600-
let offset = self.index_for_mouse_position(event.position);
1601-
self.handle_right_click_menu(event.position, offset, window, cx);
1602-
}
1603-
return;
1604-
}
1605-
16061598
if self.selected_range.is_empty() {
16071599
self.selection_reversed = false;
16081600
}

‎crates/ui/src/menu/context_menu.rs‎

Lines changed: 46 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ use std::{cell::RefCell, rc::Rc};
33
use gpui::{
44
Anchor, AnyElement, App, Context, DismissEvent, Element, ElementId, Entity, Focusable,
55
GlobalElementId, Hitbox, HitboxBehavior, InspectorElementId, InteractiveElement, IntoElement,
6-
MouseButton, MouseDownEvent, MouseUpEvent, ParentElement, Pixels, Point, StyleRefinement,
7-
Styled, Subscription, Window, anchored, deferred, div, prelude::FluentBuilder, px,
6+
MouseButton, MouseDownEvent, ParentElement, Pixels, Point, StyleRefinement, Styled,
7+
Subscription, Window, anchored, deferred, div, prelude::FluentBuilder, px,
88
};
99

1010
use crate::menu::PopupMenu;
1111

12-
type PopupMenuBuilder = Rc<dyn Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu>;
13-
1412
/// A extension trait for adding a context menu to an element.
1513
pub trait ContextMenuExt: InteractiveElement + ParentElement + Styled {
1614
/// Add a context menu to the element.
@@ -42,7 +40,7 @@ impl<E: InteractiveElement + ParentElement + Styled> ContextMenuExt for E {}
4240
pub struct ContextMenu<E: ParentElement + Styled + Sized> {
4341
id: ElementId,
4442
element: Option<E>,
45-
menu: Option<PopupMenuBuilder>,
43+
menu: Option<Rc<dyn Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu>>,
4644
// This is not in use, just for style refinement forwarding.
4745
_ignore_style: StyleRefinement,
4846
anchor: Anchor,
@@ -121,57 +119,6 @@ struct ContextMenuSharedState {
121119
_subscription: Option<Subscription>,
122120
}
123121

124-
fn should_open_context_menu(state: &ContextMenuSharedState, position: Point<Pixels>) -> bool {
125-
!state.open || state.position != position
126-
}
127-
128-
fn mark_context_menu_open(state: &mut ContextMenuSharedState, position: Point<Pixels>) {
129-
state.menu_view = None;
130-
state._subscription = None;
131-
state.position = position;
132-
state.open = true;
133-
}
134-
135-
fn open_context_menu_at(
136-
shared_state: Rc<RefCell<ContextMenuSharedState>>,
137-
builder: Option<PopupMenuBuilder>,
138-
position: Point<Pixels>,
139-
window: &mut Window,
140-
cx: &mut App,
141-
) {
142-
{
143-
let mut state = shared_state.borrow_mut();
144-
if !should_open_context_menu(&state, position) {
145-
return;
146-
}
147-
mark_context_menu_open(&mut state, position);
148-
}
149-
150-
window.defer(cx, move |window, cx| {
151-
let menu = PopupMenu::build(window, cx, move |menu, window, cx| {
152-
let Some(build) = &builder else {
153-
return menu;
154-
};
155-
build(menu, window, cx)
156-
});
157-
158-
let _subscription = window.subscribe(&menu, cx, {
159-
let shared_state = shared_state.clone();
160-
move |_, _: &DismissEvent, window, _cx| {
161-
shared_state.borrow_mut().open = false;
162-
window.refresh();
163-
}
164-
});
165-
166-
{
167-
let mut state = shared_state.borrow_mut();
168-
state.menu_view = Some(menu.clone());
169-
state._subscription = Some(_subscription);
170-
window.refresh();
171-
}
172-
});
173-
}
174-
175122
pub struct ContextMenuState {
176123
element: Option<AnyElement>,
177124
shared_state: Rc<RefCell<ContextMenuSharedState>>,
@@ -323,86 +270,56 @@ impl<E: ParentElement + Styled + IntoElement + 'static> Element for ContextMenu<
323270
|_view, state: &mut ContextMenuState, window, _| {
324271
let shared_state = state.shared_state.clone();
325272

326-
let hitbox_for_down = hitbox.clone();
327-
let state_for_down = shared_state.clone();
328-
let builder_for_down = builder.clone();
329-
// Build the context menu from mouse down on platforms that emit it.
273+
let hitbox = hitbox.clone();
274+
// When right mouse click, to build content menu, and show it at the mouse position.
330275
window.on_mouse_event(move |event: &MouseDownEvent, phase, window, cx| {
331276
if phase.bubble()
332277
&& event.button == MouseButton::Right
333-
&& hitbox_for_down.is_hovered(window)
278+
&& hitbox.is_hovered(window)
334279
{
335-
open_context_menu_at(
336-
state_for_down.clone(),
337-
builder_for_down.clone(),
338-
event.position,
339-
window,
340-
cx,
341-
);
342-
}
343-
});
344-
345-
let hitbox_for_up = hitbox.clone();
346-
let state_for_up = shared_state.clone();
347-
let builder_for_up = builder.clone();
348-
// Some platforms, including the OHOS backend, surface context-menu
349-
// clicks on button release instead of button press.
350-
window.on_mouse_event(move |event: &MouseUpEvent, phase, window, cx| {
351-
if phase.bubble()
352-
&& event.button == MouseButton::Right
353-
&& hitbox_for_up.is_hovered(window)
354-
{
355-
open_context_menu_at(
356-
state_for_up.clone(),
357-
builder_for_up.clone(),
358-
event.position,
359-
window,
360-
cx,
361-
);
280+
{
281+
let mut shared_state = shared_state.borrow_mut();
282+
// Clear any existing menu view to allow immediate replacement
283+
// Set the new position and open the menu
284+
shared_state.menu_view = None;
285+
shared_state._subscription = None;
286+
shared_state.position = event.position;
287+
shared_state.open = true;
288+
}
289+
290+
// Use defer to build the menu in the next frame, avoiding race conditions
291+
window.defer(cx, {
292+
let shared_state = shared_state.clone();
293+
let builder = builder.clone();
294+
move |window, cx| {
295+
let menu = PopupMenu::build(window, cx, move |menu, window, cx| {
296+
let Some(build) = &builder else {
297+
return menu;
298+
};
299+
build(menu, window, cx)
300+
});
301+
302+
// Set up the subscription for dismiss handling
303+
let _subscription = window.subscribe(&menu, cx, {
304+
let shared_state = shared_state.clone();
305+
move |_, _: &DismissEvent, window, _cx| {
306+
shared_state.borrow_mut().open = false;
307+
window.refresh();
308+
}
309+
});
310+
311+
// Update the shared state with the built menu and subscription
312+
{
313+
let mut state = shared_state.borrow_mut();
314+
state.menu_view = Some(menu.clone());
315+
state._subscription = Some(_subscription);
316+
window.refresh();
317+
}
318+
}
319+
});
362320
}
363321
});
364322
},
365323
);
366324
}
367325
}
368-
369-
#[cfg(test)]
370-
mod tests {
371-
use super::*;
372-
use gpui::px;
373-
374-
fn test_state(position: Point<Pixels>, open: bool) -> ContextMenuSharedState {
375-
ContextMenuSharedState {
376-
menu_view: None,
377-
open,
378-
position,
379-
_subscription: None,
380-
}
381-
}
382-
383-
fn point(x: f32, y: f32) -> Point<Pixels> {
384-
Point { x: px(x), y: px(y) }
385-
}
386-
387-
#[test]
388-
fn context_menu_suppresses_same_click_release_after_press() {
389-
let position = point(10.0, 20.0);
390-
let mut state = test_state(position, false);
391-
392-
assert!(should_open_context_menu(&state, position));
393-
mark_context_menu_open(&mut state, position);
394-
395-
assert!(!should_open_context_menu(&state, position));
396-
}
397-
398-
#[test]
399-
fn context_menu_allows_release_only_or_new_position() {
400-
let position = point(10.0, 20.0);
401-
let new_position = point(20.0, 20.0);
402-
let open_state = test_state(position, true);
403-
let closed_state = test_state(position, false);
404-
405-
assert!(should_open_context_menu(&closed_state, position));
406-
assert!(should_open_context_menu(&open_state, new_position));
407-
}
408-
}

0 commit comments

Comments
 (0)