Rework context menu's custom element API to handle clicks properly
This commit is contained in:
parent
19d1568140
commit
331af82cb1
2 changed files with 97 additions and 87 deletions
|
@ -3,9 +3,8 @@ use editor::{Editor, EditorElement, EditorEvent, MoveToEnd};
|
||||||
use futures::{channel::mpsc, StreamExt};
|
use futures::{channel::mpsc, StreamExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, AnchorCorner, AnyElement, AppContext, Context, Div, EventEmitter, FocusHandle,
|
actions, div, AnchorCorner, AnyElement, AppContext, Context, Div, EventEmitter, FocusHandle,
|
||||||
FocusableView, InteractiveElement, IntoElement, Model, ModelContext, MouseButton,
|
FocusableView, IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription,
|
||||||
ParentElement, Render, Styled, Subscription, View, ViewContext, VisualContext, WeakModel,
|
View, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||||
WindowContext,
|
|
||||||
};
|
};
|
||||||
use language::{LanguageServerId, LanguageServerName};
|
use language::{LanguageServerId, LanguageServerName};
|
||||||
use lsp::IoKind;
|
use lsp::IoKind;
|
||||||
|
@ -776,47 +775,48 @@ impl Render for LspLogToolbarItemView {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu = menu.custom_entry({
|
menu = menu.custom_entry(
|
||||||
let log_view = log_view.clone();
|
{
|
||||||
let log_toolbar_view = log_toolbar_view.clone();
|
let log_toolbar_view = log_toolbar_view.clone();
|
||||||
move |cx| {
|
move |cx| {
|
||||||
h_stack()
|
h_stack()
|
||||||
.w_full()
|
.w_full()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.child(Label::new(RPC_MESSAGES))
|
.child(Label::new(RPC_MESSAGES))
|
||||||
.child(
|
.child(
|
||||||
Checkbox::new(
|
div().z_index(120).child(
|
||||||
ix,
|
Checkbox::new(
|
||||||
if row.rpc_trace_enabled {
|
ix,
|
||||||
Selection::Selected
|
if row.rpc_trace_enabled {
|
||||||
} else {
|
Selection::Selected
|
||||||
Selection::Unselected
|
} else {
|
||||||
},
|
Selection::Unselected
|
||||||
)
|
},
|
||||||
.on_click(
|
)
|
||||||
cx.listener_for(
|
.on_click(cx.listener_for(
|
||||||
&log_toolbar_view,
|
&log_toolbar_view,
|
||||||
move |view, selection, cx| {
|
move |view, selection, cx| {
|
||||||
let enabled =
|
let enabled = matches!(
|
||||||
matches!(selection, Selection::Selected);
|
selection,
|
||||||
view.toggle_logging_for_server(
|
Selection::Selected
|
||||||
row.server_id,
|
);
|
||||||
enabled,
|
view.toggle_logging_for_server(
|
||||||
cx,
|
row.server_id,
|
||||||
);
|
enabled,
|
||||||
},
|
cx,
|
||||||
|
);
|
||||||
|
cx.stop_propagation();
|
||||||
|
},
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
)
|
.into_any_element()
|
||||||
.on_mouse_down(
|
}
|
||||||
MouseButton::Left,
|
},
|
||||||
cx.listener_for(&log_view, move |view, _, cx| {
|
cx.handler_for(&log_view, move |view, cx| {
|
||||||
view.show_rpc_trace_for_server(row.server_id, cx);
|
view.show_rpc_trace_for_server(row.server_id, cx);
|
||||||
}),
|
}),
|
||||||
)
|
);
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if server_selected && row.rpc_trace_selected {
|
if server_selected && row.rpc_trace_selected {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
Some(ix * 3 + 2),
|
Some(ix * 3 + 2),
|
||||||
|
|
|
@ -20,6 +20,7 @@ enum ContextMenuItem {
|
||||||
},
|
},
|
||||||
CustomEntry {
|
CustomEntry {
|
||||||
entry_render: Box<dyn Fn(&mut WindowContext) -> AnyElement>,
|
entry_render: Box<dyn Fn(&mut WindowContext) -> AnyElement>,
|
||||||
|
handler: Rc<dyn Fn(&mut WindowContext)>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,9 +90,11 @@ impl ContextMenu {
|
||||||
pub fn custom_entry(
|
pub fn custom_entry(
|
||||||
mut self,
|
mut self,
|
||||||
entry_render: impl Fn(&mut WindowContext) -> AnyElement + 'static,
|
entry_render: impl Fn(&mut WindowContext) -> AnyElement + 'static,
|
||||||
|
handler: impl Fn(&mut WindowContext) + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.items.push(ContextMenuItem::CustomEntry {
|
self.items.push(ContextMenuItem::CustomEntry {
|
||||||
entry_render: Box::new(entry_render),
|
entry_render: Box::new(entry_render),
|
||||||
|
handler: Rc::new(handler),
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -117,10 +120,12 @@ impl ContextMenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
|
pub fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(ContextMenuItem::Entry { handler, .. }) =
|
match self.selected_index.and_then(|ix| self.items.get(ix)) {
|
||||||
self.selected_index.and_then(|ix| self.items.get(ix))
|
Some(
|
||||||
{
|
ContextMenuItem::Entry { handler, .. }
|
||||||
(handler)(cx)
|
| ContextMenuItem::CustomEntry { handler, .. },
|
||||||
|
) => (handler)(cx),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.emit(DismissEvent);
|
cx.emit(DismissEvent);
|
||||||
|
@ -251,51 +256,56 @@ impl Render for ContextMenu {
|
||||||
})
|
})
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.child(List::new().children(self.items.iter_mut().enumerate().map(
|
.child(List::new().children(self.items.iter_mut().enumerate().map(
|
||||||
|(ix, item)| {
|
|(ix, item)| match item {
|
||||||
match item {
|
ContextMenuItem::Separator => ListSeparator.into_any_element(),
|
||||||
ContextMenuItem::Separator => ListSeparator.into_any_element(),
|
ContextMenuItem::Header(header) => {
|
||||||
ContextMenuItem::Header(header) => {
|
ListSubHeader::new(header.clone()).into_any_element()
|
||||||
ListSubHeader::new(header.clone()).into_any_element()
|
}
|
||||||
}
|
ContextMenuItem::Entry {
|
||||||
ContextMenuItem::Entry {
|
label,
|
||||||
label,
|
handler,
|
||||||
handler,
|
icon,
|
||||||
icon,
|
action,
|
||||||
action,
|
} => {
|
||||||
} => {
|
let handler = handler.clone();
|
||||||
let handler = handler.clone();
|
|
||||||
|
|
||||||
let label_element = if let Some(icon) = icon {
|
let label_element = if let Some(icon) = icon {
|
||||||
h_stack()
|
h_stack()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.child(Label::new(label.clone()))
|
.child(Label::new(label.clone()))
|
||||||
.child(IconElement::new(*icon))
|
.child(IconElement::new(*icon))
|
||||||
.into_any_element()
|
|
||||||
} else {
|
|
||||||
Label::new(label.clone()).into_any_element()
|
|
||||||
};
|
|
||||||
|
|
||||||
ListItem::new(ix)
|
|
||||||
.inset(true)
|
|
||||||
.selected(Some(ix) == self.selected_index)
|
|
||||||
.on_click(move |_, cx| handler(cx))
|
|
||||||
.child(
|
|
||||||
h_stack()
|
|
||||||
.w_full()
|
|
||||||
.justify_between()
|
|
||||||
.child(label_element)
|
|
||||||
.children(action.as_ref().and_then(|action| {
|
|
||||||
KeyBinding::for_action(&**action, cx)
|
|
||||||
.map(|binding| div().ml_1().child(binding))
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
} else {
|
||||||
ContextMenuItem::CustomEntry { entry_render } => ListItem::new(ix)
|
Label::new(label.clone()).into_any_element()
|
||||||
|
};
|
||||||
|
|
||||||
|
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))
|
||||||
|
.child(
|
||||||
|
h_stack()
|
||||||
|
.w_full()
|
||||||
|
.justify_between()
|
||||||
|
.child(label_element)
|
||||||
|
.children(action.as_ref().and_then(|action| {
|
||||||
|
KeyBinding::for_action(&**action, cx)
|
||||||
|
.map(|binding| div().ml_1().child(binding))
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
ContextMenuItem::CustomEntry {
|
||||||
|
entry_render,
|
||||||
|
handler,
|
||||||
|
} => {
|
||||||
|
let handler = handler.clone();
|
||||||
|
ListItem::new(ix)
|
||||||
|
.inset(true)
|
||||||
|
.selected(Some(ix) == self.selected_index)
|
||||||
|
.on_click(move |_, cx| handler(cx))
|
||||||
.child(entry_render(cx))
|
.child(entry_render(cx))
|
||||||
.into_any_element(),
|
.into_any_element()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
))),
|
))),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue