Fix context menu in tab bar

This commit is contained in:
Antonio Scandurra 2023-12-22 10:23:27 +01:00
parent 3d5b903f78
commit 3de72f8366
10 changed files with 100 additions and 30 deletions

View file

@ -993,6 +993,7 @@ impl CollabPanel {
}; };
context_menu = context_menu.entry( context_menu = context_menu.entry(
expand_action_name, expand_action_name,
None,
cx.handler_for(&this, move |this, cx| { cx.handler_for(&this, move |this, cx| {
this.toggle_channel_collapsed(channel_id, cx) this.toggle_channel_collapsed(channel_id, cx)
}), }),
@ -1002,18 +1003,21 @@ impl CollabPanel {
context_menu = context_menu context_menu = context_menu
.entry( .entry(
"Open Notes", "Open Notes",
None,
cx.handler_for(&this, move |this, cx| { cx.handler_for(&this, move |this, cx| {
this.open_channel_notes(channel_id, cx) this.open_channel_notes(channel_id, cx)
}), }),
) )
.entry( .entry(
"Open Chat", "Open Chat",
None,
cx.handler_for(&this, move |this, cx| { cx.handler_for(&this, move |this, cx| {
this.join_channel_chat(channel_id, cx) this.join_channel_chat(channel_id, cx)
}), }),
) )
.entry( .entry(
"Copy Channel Link", "Copy Channel Link",
None,
cx.handler_for(&this, move |this, cx| { cx.handler_for(&this, move |this, cx| {
this.copy_channel_link(channel_id, cx) this.copy_channel_link(channel_id, cx)
}), }),
@ -1024,14 +1028,17 @@ impl CollabPanel {
.separator() .separator()
.entry( .entry(
"New Subchannel", "New Subchannel",
None,
cx.handler_for(&this, move |this, cx| this.new_subchannel(channel_id, cx)), cx.handler_for(&this, move |this, cx| this.new_subchannel(channel_id, cx)),
) )
.entry( .entry(
"Rename", "Rename",
None,
cx.handler_for(&this, move |this, cx| this.rename_channel(channel_id, cx)), cx.handler_for(&this, move |this, cx| this.rename_channel(channel_id, cx)),
) )
.entry( .entry(
"Move this channel", "Move this channel",
None,
cx.handler_for(&this, move |this, cx| { cx.handler_for(&this, move |this, cx| {
this.start_move_channel(channel_id, cx) this.start_move_channel(channel_id, cx)
}), }),
@ -1040,6 +1047,7 @@ impl CollabPanel {
if let Some(channel_name) = clipboard_channel_name { if let Some(channel_name) = clipboard_channel_name {
context_menu = context_menu.separator().entry( context_menu = context_menu.separator().entry(
format!("Move '#{}' here", channel_name), format!("Move '#{}' here", channel_name),
None,
cx.handler_for(&this, move |this, cx| { cx.handler_for(&this, move |this, cx| {
this.move_channel_on_clipboard(channel_id, cx) this.move_channel_on_clipboard(channel_id, cx)
}), }),
@ -1050,14 +1058,17 @@ impl CollabPanel {
.separator() .separator()
.entry( .entry(
"Invite Members", "Invite Members",
None,
cx.handler_for(&this, move |this, cx| this.invite_members(channel_id, cx)), cx.handler_for(&this, move |this, cx| this.invite_members(channel_id, cx)),
) )
.entry( .entry(
"Manage Members", "Manage Members",
None,
cx.handler_for(&this, move |this, cx| this.manage_members(channel_id, cx)), cx.handler_for(&this, move |this, cx| this.manage_members(channel_id, cx)),
) )
.entry( .entry(
"Delete", "Delete",
None,
cx.handler_for(&this, move |this, cx| this.remove_channel(channel_id, cx)), cx.handler_for(&this, move |this, cx| this.remove_channel(channel_id, cx)),
); );
} }

View file

@ -532,7 +532,7 @@ impl ChannelModalDelegate {
let user_id = user.id; let user_id = user.id;
let picker = cx.view().clone(); let picker = cx.view().clone();
let context_menu = ContextMenu::build(cx, |mut menu, _cx| { let context_menu = ContextMenu::build(cx, |mut menu, _cx| {
menu = menu.entry("Remove Member", { menu = menu.entry("Remove Member", None, {
let picker = picker.clone(); let picker = picker.clone();
move |cx| { move |cx| {
picker.update(cx, |picker, cx| { picker.update(cx, |picker, cx| {
@ -544,7 +544,7 @@ impl ChannelModalDelegate {
let picker = picker.clone(); let picker = picker.clone();
match role { match role {
ChannelRole::Admin => { ChannelRole::Admin => {
menu = menu.entry("Revoke Admin", move |cx| { menu = menu.entry("Revoke Admin", None, move |cx| {
picker.update(cx, |picker, cx| { picker.update(cx, |picker, cx| {
picker picker
.delegate .delegate
@ -553,7 +553,7 @@ impl ChannelModalDelegate {
}); });
} }
ChannelRole::Member => { ChannelRole::Member => {
menu = menu.entry("Make Admin", move |cx| { menu = menu.entry("Make Admin", None, move |cx| {
picker.update(cx, |picker, cx| { picker.update(cx, |picker, cx| {
picker picker
.delegate .delegate

View file

@ -133,8 +133,11 @@ impl CopilotButton {
pub fn build_copilot_start_menu(&mut self, cx: &mut ViewContext<Self>) -> View<ContextMenu> { pub fn build_copilot_start_menu(&mut self, cx: &mut ViewContext<Self>) -> View<ContextMenu> {
let fs = self.fs.clone(); let fs = self.fs.clone();
ContextMenu::build(cx, |menu, cx| { ContextMenu::build(cx, |menu, cx| {
menu.entry("Sign In", initiate_sign_in) menu.entry("Sign In", None, initiate_sign_in).entry(
.entry("Disable Copilot", move |cx| hide_copilot(fs.clone(), cx)) "Disable Copilot",
None,
move |cx| hide_copilot(fs.clone(), cx),
)
}) })
} }
@ -154,6 +157,7 @@ impl CopilotButton {
if language_enabled { "Hide" } else { "Show" }, if language_enabled { "Hide" } else { "Show" },
language.name() language.name()
), ),
None,
move |cx| toggle_copilot_for_language(language.clone(), fs.clone(), cx), move |cx| toggle_copilot_for_language(language.clone(), fs.clone(), cx),
); );
} }
@ -169,6 +173,7 @@ impl CopilotButton {
"{} Suggestions for This Path", "{} Suggestions for This Path",
if path_enabled { "Hide" } else { "Show" } if path_enabled { "Hide" } else { "Show" }
), ),
None,
move |cx| { move |cx| {
if let Some(workspace) = cx.window_handle().downcast::<Workspace>() { if let Some(workspace) = cx.window_handle().downcast::<Workspace>() {
if let Ok(workspace) = workspace.root_view(cx) { if let Ok(workspace) = workspace.root_view(cx) {
@ -194,6 +199,7 @@ impl CopilotButton {
} else { } else {
"Show Suggestions for All Files" "Show Suggestions for All Files"
}, },
None,
move |cx| toggle_copilot_globally(fs.clone(), cx), move |cx| toggle_copilot_globally(fs.clone(), cx),
) )
.separator() .separator()

View file

@ -763,6 +763,7 @@ impl Render for LspLogToolbarItemView {
)) ))
.entry( .entry(
SERVER_LOGS, SERVER_LOGS,
None,
cx.handler_for(&log_view, move |view, cx| { cx.handler_for(&log_view, move |view, cx| {
view.show_logs_for_server(row.server_id, cx); view.show_logs_for_server(row.server_id, cx);
}), }),

View file

@ -459,6 +459,7 @@ impl SyntaxTreeToolbarItemView {
layer.language.name(), layer.language.name(),
format_node_range(layer.node()) format_node_range(layer.node())
), ),
None,
cx.handler_for(&view, move |view, cx| { cx.handler_for(&view, move |view, cx| {
view.select_layer(layer_ix, cx); view.select_layer(layer_ix, cx);
}), }),

View file

@ -400,6 +400,7 @@ impl ProjectPanel {
if is_root { if is_root {
menu = menu.entry( menu = menu.entry(
"Remove from Project", "Remove from Project",
None,
cx.handler_for(&this, move |this, cx| { cx.handler_for(&this, move |this, cx| {
this.project.update(cx, |project, cx| { this.project.update(cx, |project, cx| {
project.remove_worktree(worktree_id, cx) project.remove_worktree(worktree_id, cx)

View file

@ -76,13 +76,14 @@ impl ContextMenu {
pub fn entry( pub fn entry(
mut self, mut self,
label: impl Into<SharedString>, label: impl Into<SharedString>,
action: Option<Box<dyn Action>>,
handler: impl Fn(&mut WindowContext) + 'static, handler: impl Fn(&mut WindowContext) + 'static,
) -> Self { ) -> Self {
self.items.push(ContextMenuItem::Entry { self.items.push(ContextMenuItem::Entry {
label: label.into(), label: label.into(),
handler: Rc::new(handler), handler: Rc::new(handler),
icon: None, icon: None,
action: None, action,
}); });
self self
} }
@ -282,7 +283,10 @@ impl Render for ContextMenu {
ListItem::new(ix) ListItem::new(ix)
.inset(true) .inset(true)
.selected(Some(ix) == self.selected_index) .selected(Some(ix) == self.selected_index)
.on_click(move |_, cx| handler(cx)) .on_click(cx.listener(move |_, _, cx| {
handler(cx);
cx.emit(DismissEvent);
}))
.child( .child(
h_stack() h_stack()
.w_full() .w_full()
@ -303,7 +307,10 @@ impl Render for ContextMenu {
ListItem::new(ix) ListItem::new(ix)
.inset(true) .inset(true)
.selected(Some(ix) == self.selected_index) .selected(Some(ix) == self.selected_index)
.on_click(move |_, cx| handler(cx)) .on_click(cx.listener(move |_, _, cx| {
handler(cx);
cx.emit(DismissEvent);
}))
.child(entry_render(cx)) .child(entry_render(cx))
.into_any_element() .into_any_element()
} }

View file

@ -1,4 +1,4 @@
use gpui::{actions, Action, AnchorCorner, Div, Render, View}; use gpui::{actions, AnchorCorner, Div, Render, View};
use story::Story; use story::Story;
use crate::prelude::*; use crate::prelude::*;
@ -10,12 +10,9 @@ fn build_menu(cx: &mut WindowContext, header: impl Into<SharedString>) -> View<C
ContextMenu::build(cx, |menu, _| { ContextMenu::build(cx, |menu, _| {
menu.header(header) menu.header(header)
.separator() .separator()
.entry("Print current time", |cx| { .action("Print current time", Box::new(PrintCurrentDate))
println!("dispatching PrintCurrentTime action"); .entry("Print best food", Some(Box::new(PrintBestFood)), |cx| {
cx.dispatch_action(PrintCurrentDate.boxed_clone()) cx.dispatch_action(Box::new(PrintBestFood))
})
.entry("Print best foot", |cx| {
cx.dispatch_action(PrintBestFood.boxed_clone())
}) })
}) })
} }

View file

@ -625,7 +625,7 @@ impl Render for PanelButtons {
&& panel.position_is_valid(position, cx) && panel.position_is_valid(position, cx)
{ {
let panel = panel.clone(); let panel = panel.clone();
menu = menu.entry(position.to_label(), move |cx| { menu = menu.entry(position.to_label(), None, move |cx| {
panel.set_position(position, cx); panel.set_position(position, cx);
}) })
} }

View file

@ -990,7 +990,7 @@ impl Pane {
&mut self, &mut self,
cx: &mut ViewContext<Pane>, cx: &mut ViewContext<Pane>,
mut save_intent: SaveIntent, mut save_intent: SaveIntent,
should_close: impl 'static + Fn(EntityId) -> bool, should_close: impl Fn(EntityId) -> bool,
) -> Task<Result<()>> { ) -> Task<Result<()>> {
// Find the items to close. // Find the items to close.
let mut items_to_close = Vec::new(); let mut items_to_close = Vec::new();
@ -1571,28 +1571,74 @@ impl Pane {
} }
}; };
let pane = cx.view().clone();
right_click_menu(ix).trigger(tab).menu(move |cx| { right_click_menu(ix).trigger(tab).menu(move |cx| {
ContextMenu::build(cx, |menu, _| { let pane = pane.clone();
ContextMenu::build(cx, move |menu, cx| {
let menu = menu let menu = menu
.action("Close", CloseActiveItem { save_intent: None }.boxed_clone()) .entry(
.action("Close Others", CloseInactiveItems.boxed_clone()) "Close",
Some(Box::new(CloseActiveItem { save_intent: None })),
cx.handler_for(&pane, move |pane, cx| {
pane.close_item_by_id(item_id, SaveIntent::Close, cx)
.detach_and_log_err(cx);
}),
)
.entry(
"Close Others",
Some(Box::new(CloseInactiveItems)),
cx.handler_for(&pane, move |pane, cx| {
pane.close_items(cx, SaveIntent::Close, |id| id != item_id)
.detach_and_log_err(cx);
}),
)
.separator() .separator()
.action("Close Left", CloseItemsToTheLeft.boxed_clone()) .entry(
.action("Close Right", CloseItemsToTheRight.boxed_clone()) "Close Left",
Some(Box::new(CloseItemsToTheLeft)),
cx.handler_for(&pane, move |pane, cx| {
pane.close_items_to_the_left_by_id(item_id, cx)
.detach_and_log_err(cx);
}),
)
.entry(
"Close Right",
Some(Box::new(CloseItemsToTheRight)),
cx.handler_for(&pane, move |pane, cx| {
pane.close_items_to_the_right_by_id(item_id, cx)
.detach_and_log_err(cx);
}),
)
.separator() .separator()
.action("Close Clean", CloseCleanItems.boxed_clone()) .entry(
.action( "Close Clean",
Some(Box::new(CloseCleanItems)),
cx.handler_for(&pane, move |pane, cx| {
pane.close_clean_items(&CloseCleanItems, cx)
.map(|task| task.detach_and_log_err(cx));
}),
)
.entry(
"Close All", "Close All",
CloseAllItems { save_intent: None }.boxed_clone(), Some(Box::new(CloseAllItems { save_intent: None })),
cx.handler_for(&pane, |pane, cx| {
pane.close_all_items(&CloseAllItems { save_intent: None }, cx)
.map(|task| task.detach_and_log_err(cx));
}),
); );
if let Some(entry) = single_entry_to_resolve { if let Some(entry) = single_entry_to_resolve {
menu.separator().action( let entry_id = entry.to_proto();
menu.separator().entry(
"Reveal In Project Panel", "Reveal In Project Panel",
RevealInProjectPanel { Some(Box::new(RevealInProjectPanel { entry_id })),
entry_id: entry.to_proto(), cx.handler_for(&pane, move |pane, cx| {
} pane.project.update(cx, |_, cx| {
.boxed_clone(), cx.emit(project::Event::RevealInProjectPanel(
ProjectEntryId::from_proto(entry_id),
))
});
}),
) )
} else { } else {
menu menu