mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
ui: Use popover menus for tab bar in panes (#16497)
Closes #ISSUE Release Notes: - N/A
This commit is contained in:
parent
72b5cda356
commit
182b7af299
@ -3,10 +3,9 @@ use editor::Editor;
|
|||||||
use extension::ExtensionStore;
|
use extension::ExtensionStore;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, deferred, percentage, Animation, AnimationExt as _, AppContext, CursorStyle,
|
actions, percentage, Animation, AnimationExt as _, AppContext, CursorStyle, EventEmitter,
|
||||||
DismissEvent, EventEmitter, InteractiveElement as _, Model, ParentElement as _, Render,
|
InteractiveElement as _, Model, ParentElement as _, Render, SharedString,
|
||||||
SharedString, StatefulInteractiveElement, Styled, Transformation, View, ViewContext,
|
StatefulInteractiveElement, Styled, Transformation, View, ViewContext, VisualContext as _,
|
||||||
VisualContext as _,
|
|
||||||
};
|
};
|
||||||
use language::{
|
use language::{
|
||||||
LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId, LanguageServerName,
|
LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId, LanguageServerName,
|
||||||
@ -14,7 +13,7 @@ use language::{
|
|||||||
use project::{LanguageServerProgress, Project};
|
use project::{LanguageServerProgress, Project};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration};
|
use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration};
|
||||||
use ui::{prelude::*, ContextMenu};
|
use ui::{prelude::*, ButtonLike, ContextMenu, PopoverMenu, PopoverMenuHandle};
|
||||||
use workspace::{item::ItemHandle, StatusItemView, Workspace};
|
use workspace::{item::ItemHandle, StatusItemView, Workspace};
|
||||||
|
|
||||||
actions!(activity_indicator, [ShowErrorMessage]);
|
actions!(activity_indicator, [ShowErrorMessage]);
|
||||||
@ -27,7 +26,7 @@ pub struct ActivityIndicator {
|
|||||||
statuses: Vec<LspStatus>,
|
statuses: Vec<LspStatus>,
|
||||||
project: Model<Project>,
|
project: Model<Project>,
|
||||||
auto_updater: Option<Model<AutoUpdater>>,
|
auto_updater: Option<Model<AutoUpdater>>,
|
||||||
context_menu: Option<View<ContextMenu>>,
|
context_menu_handle: PopoverMenuHandle<ContextMenu>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LspStatus {
|
struct LspStatus {
|
||||||
@ -79,7 +78,7 @@ impl ActivityIndicator {
|
|||||||
statuses: Default::default(),
|
statuses: Default::default(),
|
||||||
project: project.clone(),
|
project: project.clone(),
|
||||||
auto_updater,
|
auto_updater,
|
||||||
context_menu: None,
|
context_menu_handle: Default::default(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -368,72 +367,7 @@ impl ActivityIndicator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_language_server_work_context_menu(&mut self, cx: &mut ViewContext<Self>) {
|
fn toggle_language_server_work_context_menu(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
if self.context_menu.take().is_some() {
|
self.context_menu_handle.toggle(cx);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.build_lsp_work_context_menu(cx);
|
|
||||||
cx.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_lsp_work_context_menu(&mut self, cx: &mut ViewContext<Self>) {
|
|
||||||
let mut has_work = false;
|
|
||||||
let this = cx.view().downgrade();
|
|
||||||
let context_menu = ContextMenu::build(cx, |mut menu, cx| {
|
|
||||||
for work in self.pending_language_server_work(cx) {
|
|
||||||
has_work = true;
|
|
||||||
|
|
||||||
let this = this.clone();
|
|
||||||
let title = SharedString::from(
|
|
||||||
work.progress
|
|
||||||
.title
|
|
||||||
.as_deref()
|
|
||||||
.unwrap_or(work.progress_token)
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
if work.progress.is_cancellable {
|
|
||||||
let language_server_id = work.language_server_id;
|
|
||||||
let token = work.progress_token.to_string();
|
|
||||||
menu = menu.custom_entry(
|
|
||||||
move |_| {
|
|
||||||
h_flex()
|
|
||||||
.w_full()
|
|
||||||
.justify_between()
|
|
||||||
.child(Label::new(title.clone()))
|
|
||||||
.child(Icon::new(IconName::XCircle))
|
|
||||||
.into_any_element()
|
|
||||||
},
|
|
||||||
move |cx| {
|
|
||||||
this.update(cx, |this, cx| {
|
|
||||||
this.project.update(cx, |project, cx| {
|
|
||||||
project.cancel_language_server_work(
|
|
||||||
language_server_id,
|
|
||||||
Some(token.clone()),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
this.context_menu.take();
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
menu = menu.label(title.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu
|
|
||||||
});
|
|
||||||
|
|
||||||
if has_work {
|
|
||||||
cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| {
|
|
||||||
this.context_menu.take();
|
|
||||||
cx.notify();
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
cx.focus_view(&context_menu);
|
|
||||||
self.context_menu = Some(context_menu);
|
|
||||||
cx.notify();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,19 +389,72 @@ impl Render for ActivityIndicator {
|
|||||||
on_click(this, cx);
|
on_click(this, cx);
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
let this = cx.view().downgrade();
|
||||||
result
|
result.gap_2().child(
|
||||||
.gap_2()
|
PopoverMenu::new("activity-indicator-popover")
|
||||||
.children(content.icon)
|
.trigger(
|
||||||
.child(Label::new(SharedString::from(content.message)).size(LabelSize::Small))
|
ButtonLike::new("activity-indicator-trigger").child(
|
||||||
.children(self.context_menu.as_ref().map(|menu| {
|
h_flex()
|
||||||
deferred(
|
.gap_2()
|
||||||
anchored()
|
.children(content.icon)
|
||||||
.anchor(gpui::AnchorCorner::BottomLeft)
|
.child(Label::new(content.message).size(LabelSize::Small)),
|
||||||
.child(menu.clone()),
|
),
|
||||||
)
|
)
|
||||||
.with_priority(1)
|
.anchor(gpui::AnchorCorner::BottomLeft)
|
||||||
}))
|
.menu(move |cx| {
|
||||||
|
let strong_this = this.upgrade()?;
|
||||||
|
ContextMenu::build(cx, |mut menu, cx| {
|
||||||
|
for work in strong_this.read(cx).pending_language_server_work(cx) {
|
||||||
|
let this = this.clone();
|
||||||
|
let mut title = work
|
||||||
|
.progress
|
||||||
|
.title
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or(work.progress_token)
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
if work.progress.is_cancellable {
|
||||||
|
let language_server_id = work.language_server_id;
|
||||||
|
let token = work.progress_token.to_string();
|
||||||
|
let title = SharedString::from(title);
|
||||||
|
menu = menu.custom_entry(
|
||||||
|
move |_| {
|
||||||
|
h_flex()
|
||||||
|
.w_full()
|
||||||
|
.justify_between()
|
||||||
|
.child(Label::new(title.clone()))
|
||||||
|
.child(Icon::new(IconName::XCircle))
|
||||||
|
.into_any_element()
|
||||||
|
},
|
||||||
|
move |cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.project.update(cx, |project, cx| {
|
||||||
|
project.cancel_language_server_work(
|
||||||
|
language_server_id,
|
||||||
|
Some(token.clone()),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
this.context_menu_handle.hide(cx);
|
||||||
|
cx.notify();
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if let Some(progress_message) = work.progress.message.as_ref() {
|
||||||
|
title.push_str(": ");
|
||||||
|
title.push_str(progress_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu = menu.label(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu
|
||||||
|
})
|
||||||
|
.into()
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@ use fs::Fs;
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
canvas, div, img, percentage, point, pulsating_between, size, Action, Animation, AnimationExt,
|
canvas, div, img, percentage, point, pulsating_between, size, Action, Animation, AnimationExt,
|
||||||
AnyElement, AnyView, AppContext, AsyncWindowContext, ClipboardEntry, ClipboardItem,
|
AnyElement, AnyView, AppContext, AsyncWindowContext, ClipboardEntry, ClipboardItem,
|
||||||
Context as _, DismissEvent, Empty, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
|
Context as _, Empty, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, FontWeight,
|
||||||
FontWeight, InteractiveElement, IntoElement, Model, ParentElement, Pixels, ReadGlobal, Render,
|
InteractiveElement, IntoElement, Model, ParentElement, Pixels, ReadGlobal, Render, RenderImage,
|
||||||
RenderImage, SharedString, Size, StatefulInteractiveElement, Styled, Subscription, Task,
|
SharedString, Size, StatefulInteractiveElement, Styled, Subscription, Task, Transformation,
|
||||||
Transformation, UpdateGlobal, View, VisualContext, WeakView, WindowContext,
|
UpdateGlobal, View, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use indexed_docs::IndexedDocsStore;
|
use indexed_docs::IndexedDocsStore;
|
||||||
use language::{
|
use language::{
|
||||||
@ -349,6 +349,7 @@ impl AssistantPanel {
|
|||||||
model_summary_editor.clone(),
|
model_summary_editor.clone(),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let pane = cx.new_view(|cx| {
|
let pane = cx.new_view(|cx| {
|
||||||
let mut pane = Pane::new(
|
let mut pane = Pane::new(
|
||||||
workspace.weak_handle(),
|
workspace.weak_handle(),
|
||||||
@ -385,6 +386,7 @@ impl AssistantPanel {
|
|||||||
pane.active_item()
|
pane.active_item()
|
||||||
.map_or(false, |item| item.downcast::<ContextHistory>().is_some()),
|
.map_or(false, |item| item.downcast::<ContextHistory>().is_some()),
|
||||||
);
|
);
|
||||||
|
let _pane = cx.view().clone();
|
||||||
let right_children = h_flex()
|
let right_children = h_flex()
|
||||||
.gap(Spacing::Small.rems(cx))
|
.gap(Spacing::Small.rems(cx))
|
||||||
.child(
|
.child(
|
||||||
@ -395,32 +397,27 @@ impl AssistantPanel {
|
|||||||
.tooltip(|cx| Tooltip::for_action("New Context", &NewFile, cx)),
|
.tooltip(|cx| Tooltip::for_action("New Context", &NewFile, cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
IconButton::new("menu", IconName::Menu)
|
PopoverMenu::new("assistant-panel-popover-menu")
|
||||||
.icon_size(IconSize::Small)
|
.trigger(
|
||||||
.on_click(cx.listener(|pane, _, cx| {
|
IconButton::new("menu", IconName::Menu).icon_size(IconSize::Small),
|
||||||
let zoom_label = if pane.is_zoomed() {
|
)
|
||||||
|
.menu(move |cx| {
|
||||||
|
let zoom_label = if _pane.read(cx).is_zoomed() {
|
||||||
"Zoom Out"
|
"Zoom Out"
|
||||||
} else {
|
} else {
|
||||||
"Zoom In"
|
"Zoom In"
|
||||||
};
|
};
|
||||||
let menu = ContextMenu::build(cx, |menu, cx| {
|
let focus_handle = _pane.focus_handle(cx);
|
||||||
menu.context(pane.focus_handle(cx))
|
Some(ContextMenu::build(cx, move |menu, _| {
|
||||||
|
menu.context(focus_handle.clone())
|
||||||
.action("New Context", Box::new(NewFile))
|
.action("New Context", Box::new(NewFile))
|
||||||
.action("History", Box::new(DeployHistory))
|
.action("History", Box::new(DeployHistory))
|
||||||
.action("Prompt Library", Box::new(DeployPromptLibrary))
|
.action("Prompt Library", Box::new(DeployPromptLibrary))
|
||||||
.action("Configure", Box::new(ShowConfiguration))
|
.action("Configure", Box::new(ShowConfiguration))
|
||||||
.action(zoom_label, Box::new(ToggleZoom))
|
.action(zoom_label, Box::new(ToggleZoom))
|
||||||
});
|
}))
|
||||||
cx.subscribe(&menu, |pane, _, _: &DismissEvent, _| {
|
}),
|
||||||
pane.new_item_menu = None;
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
pane.new_item_menu = Some(menu);
|
|
||||||
})),
|
|
||||||
)
|
)
|
||||||
.when_some(pane.new_item_menu.as_ref(), |el, new_item_menu| {
|
|
||||||
el.child(Pane::render_menu_overlay(new_item_menu))
|
|
||||||
})
|
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
@ -8,13 +8,14 @@ use editor::actions::{
|
|||||||
use editor::{Editor, EditorSettings};
|
use editor::{Editor, EditorSettings};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, deferred, Action, AnchorCorner, ClickEvent, DismissEvent, ElementId, EventEmitter,
|
Action, AnchorCorner, ClickEvent, ElementId, EventEmitter, InteractiveElement, ParentElement,
|
||||||
InteractiveElement, ParentElement, Render, Styled, Subscription, View, ViewContext, WeakView,
|
Render, Styled, Subscription, View, ViewContext, WeakView,
|
||||||
};
|
};
|
||||||
use search::{buffer_search, BufferSearchBar};
|
use search::{buffer_search, BufferSearchBar};
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use ui::{
|
use ui::{
|
||||||
prelude::*, ButtonStyle, ContextMenu, IconButton, IconButtonShape, IconName, IconSize, Tooltip,
|
prelude::*, ButtonStyle, ContextMenu, IconButton, IconButtonShape, IconName, IconSize,
|
||||||
|
PopoverMenu, PopoverMenuHandle, Tooltip,
|
||||||
};
|
};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
|
item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
|
||||||
@ -27,10 +28,9 @@ pub struct QuickActionBar {
|
|||||||
_inlay_hints_enabled_subscription: Option<Subscription>,
|
_inlay_hints_enabled_subscription: Option<Subscription>,
|
||||||
active_item: Option<Box<dyn ItemHandle>>,
|
active_item: Option<Box<dyn ItemHandle>>,
|
||||||
buffer_search_bar: View<BufferSearchBar>,
|
buffer_search_bar: View<BufferSearchBar>,
|
||||||
repl_menu: Option<View<ContextMenu>>,
|
|
||||||
show: bool,
|
show: bool,
|
||||||
toggle_selections_menu: Option<View<ContextMenu>>,
|
toggle_selections_handle: PopoverMenuHandle<ContextMenu>,
|
||||||
toggle_settings_menu: Option<View<ContextMenu>>,
|
toggle_settings_handle: PopoverMenuHandle<ContextMenu>,
|
||||||
workspace: WeakView<Workspace>,
|
workspace: WeakView<Workspace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,10 +44,9 @@ impl QuickActionBar {
|
|||||||
_inlay_hints_enabled_subscription: None,
|
_inlay_hints_enabled_subscription: None,
|
||||||
active_item: None,
|
active_item: None,
|
||||||
buffer_search_bar,
|
buffer_search_bar,
|
||||||
repl_menu: None,
|
|
||||||
show: true,
|
show: true,
|
||||||
toggle_selections_menu: None,
|
toggle_selections_handle: Default::default(),
|
||||||
toggle_settings_menu: None,
|
toggle_settings_handle: Default::default(),
|
||||||
workspace: workspace.weak_handle(),
|
workspace: workspace.weak_handle(),
|
||||||
};
|
};
|
||||||
this.apply_settings(cx);
|
this.apply_settings(cx);
|
||||||
@ -79,17 +78,6 @@ impl QuickActionBar {
|
|||||||
ToolbarItemLocation::Hidden
|
ToolbarItemLocation::Hidden
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_menu_overlay(menu: &View<ContextMenu>) -> Div {
|
|
||||||
div().absolute().bottom_0().right_0().size_0().child(
|
|
||||||
deferred(
|
|
||||||
anchored()
|
|
||||||
.anchor(AnchorCorner::TopRight)
|
|
||||||
.child(menu.clone()),
|
|
||||||
)
|
|
||||||
.with_priority(1),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for QuickActionBar {
|
impl Render for QuickActionBar {
|
||||||
@ -158,150 +146,155 @@ impl Render for QuickActionBar {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let editor_selections_dropdown = selection_menu_enabled.then(|| {
|
let editor_selections_dropdown = selection_menu_enabled.then(|| {
|
||||||
IconButton::new("toggle_editor_selections_icon", IconName::TextCursor)
|
let focus = editor.focus_handle(cx);
|
||||||
.shape(IconButtonShape::Square)
|
PopoverMenu::new("editor-selections-dropdown")
|
||||||
.icon_size(IconSize::Small)
|
.trigger(
|
||||||
.style(ButtonStyle::Subtle)
|
IconButton::new("toggle_editor_selections_icon", IconName::TextCursor)
|
||||||
.selected(self.toggle_selections_menu.is_some())
|
.shape(IconButtonShape::Square)
|
||||||
.on_click({
|
.icon_size(IconSize::Small)
|
||||||
let focus = editor.focus_handle(cx);
|
.style(ButtonStyle::Subtle)
|
||||||
cx.listener(move |quick_action_bar, _, cx| {
|
.selected(self.toggle_selections_handle.is_deployed())
|
||||||
let focus = focus.clone();
|
.when(!self.toggle_selections_handle.is_deployed(), |this| {
|
||||||
let menu = ContextMenu::build(cx, move |menu, _| {
|
this.tooltip(|cx| Tooltip::text("Selection Controls", cx))
|
||||||
menu.context(focus.clone())
|
}),
|
||||||
.action("Select All", Box::new(SelectAll))
|
)
|
||||||
.action(
|
.with_handle(self.toggle_selections_handle.clone())
|
||||||
"Select Next Occurrence",
|
.anchor(AnchorCorner::TopRight)
|
||||||
Box::new(SelectNext {
|
.menu(move |cx| {
|
||||||
replace_newest: false,
|
let focus = focus.clone();
|
||||||
}),
|
let menu = ContextMenu::build(cx, move |menu, _| {
|
||||||
)
|
menu.context(focus.clone())
|
||||||
.action("Expand Selection", Box::new(SelectLargerSyntaxNode))
|
.action("Select All", Box::new(SelectAll))
|
||||||
.action("Shrink Selection", Box::new(SelectSmallerSyntaxNode))
|
.action(
|
||||||
.action("Add Cursor Above", Box::new(AddSelectionAbove))
|
"Select Next Occurrence",
|
||||||
.action("Add Cursor Below", Box::new(AddSelectionBelow))
|
Box::new(SelectNext {
|
||||||
.separator()
|
replace_newest: false,
|
||||||
.action("Go to Symbol", Box::new(ToggleOutline))
|
}),
|
||||||
.action("Go to Line/Column", Box::new(ToggleGoToLine))
|
)
|
||||||
.separator()
|
.action("Expand Selection", Box::new(SelectLargerSyntaxNode))
|
||||||
.action("Next Problem", Box::new(GoToDiagnostic))
|
.action("Shrink Selection", Box::new(SelectSmallerSyntaxNode))
|
||||||
.action("Previous Problem", Box::new(GoToPrevDiagnostic))
|
.action("Add Cursor Above", Box::new(AddSelectionAbove))
|
||||||
.separator()
|
.action("Add Cursor Below", Box::new(AddSelectionBelow))
|
||||||
.action("Next Hunk", Box::new(GoToHunk))
|
.separator()
|
||||||
.action("Previous Hunk", Box::new(GoToPrevHunk))
|
.action("Go to Symbol", Box::new(ToggleOutline))
|
||||||
.separator()
|
.action("Go to Line/Column", Box::new(ToggleGoToLine))
|
||||||
.action("Move Line Up", Box::new(MoveLineUp))
|
.separator()
|
||||||
.action("Move Line Down", Box::new(MoveLineDown))
|
.action("Next Problem", Box::new(GoToDiagnostic))
|
||||||
.action("Duplicate Selection", Box::new(DuplicateLineDown))
|
.action("Previous Problem", Box::new(GoToPrevDiagnostic))
|
||||||
});
|
.separator()
|
||||||
cx.subscribe(&menu, |quick_action_bar, _, _: &DismissEvent, _cx| {
|
.action("Next Hunk", Box::new(GoToHunk))
|
||||||
quick_action_bar.toggle_selections_menu = None;
|
.action("Previous Hunk", Box::new(GoToPrevHunk))
|
||||||
})
|
.separator()
|
||||||
.detach();
|
.action("Move Line Up", Box::new(MoveLineUp))
|
||||||
quick_action_bar.toggle_selections_menu = Some(menu);
|
.action("Move Line Down", Box::new(MoveLineDown))
|
||||||
})
|
.action("Duplicate Selection", Box::new(DuplicateLineDown))
|
||||||
})
|
});
|
||||||
.when(self.toggle_selections_menu.is_none(), |this| {
|
Some(menu)
|
||||||
this.tooltip(|cx| Tooltip::text("Selection Controls", cx))
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let editor_settings_dropdown =
|
let editor = editor.downgrade();
|
||||||
IconButton::new("toggle_editor_settings_icon", IconName::Sliders)
|
let editor_settings_dropdown = PopoverMenu::new("editor-settings")
|
||||||
.shape(IconButtonShape::Square)
|
.trigger(
|
||||||
.icon_size(IconSize::Small)
|
IconButton::new("toggle_editor_settings_icon", IconName::Sliders)
|
||||||
.style(ButtonStyle::Subtle)
|
.shape(IconButtonShape::Square)
|
||||||
.selected(self.toggle_settings_menu.is_some())
|
.icon_size(IconSize::Small)
|
||||||
.on_click({
|
.style(ButtonStyle::Subtle)
|
||||||
let editor = editor.clone();
|
.selected(self.toggle_settings_handle.is_deployed())
|
||||||
cx.listener(move |quick_action_bar, _, cx| {
|
.when(!self.toggle_settings_handle.is_deployed(), |this| {
|
||||||
let menu = ContextMenu::build(cx, |mut menu, _| {
|
this.tooltip(|cx| Tooltip::text("Editor Controls", cx))
|
||||||
if supports_inlay_hints {
|
}),
|
||||||
menu = menu.toggleable_entry(
|
)
|
||||||
"Inlay Hints",
|
.anchor(AnchorCorner::TopRight)
|
||||||
inlay_hints_enabled,
|
.with_handle(self.toggle_settings_handle.clone())
|
||||||
IconPosition::Start,
|
.menu(move |cx| {
|
||||||
Some(editor::actions::ToggleInlayHints.boxed_clone()),
|
let menu = ContextMenu::build(cx, |mut menu, _| {
|
||||||
{
|
if supports_inlay_hints {
|
||||||
let editor = editor.clone();
|
menu = menu.toggleable_entry(
|
||||||
move |cx| {
|
"Inlay Hints",
|
||||||
editor.update(cx, |editor, cx| {
|
inlay_hints_enabled,
|
||||||
editor.toggle_inlay_hints(
|
IconPosition::Start,
|
||||||
&editor::actions::ToggleInlayHints,
|
Some(editor::actions::ToggleInlayHints.boxed_clone()),
|
||||||
cx,
|
{
|
||||||
);
|
let editor = editor.clone();
|
||||||
});
|
move |cx| {
|
||||||
}
|
editor
|
||||||
},
|
.update(cx, |editor, cx| {
|
||||||
);
|
editor.toggle_inlay_hints(
|
||||||
}
|
&editor::actions::ToggleInlayHints,
|
||||||
|
|
||||||
menu = menu.toggleable_entry(
|
|
||||||
"Inline Git Blame",
|
|
||||||
git_blame_inline_enabled,
|
|
||||||
IconPosition::Start,
|
|
||||||
Some(editor::actions::ToggleGitBlameInline.boxed_clone()),
|
|
||||||
{
|
|
||||||
let editor = editor.clone();
|
|
||||||
move |cx| {
|
|
||||||
editor.update(cx, |editor, cx| {
|
|
||||||
editor.toggle_git_blame_inline(
|
|
||||||
&editor::actions::ToggleGitBlameInline,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
menu = menu.toggleable_entry(
|
|
||||||
"Selection Menu",
|
|
||||||
selection_menu_enabled,
|
|
||||||
IconPosition::Start,
|
|
||||||
Some(editor::actions::ToggleSelectionMenu.boxed_clone()),
|
|
||||||
{
|
|
||||||
let editor = editor.clone();
|
|
||||||
move |cx| {
|
|
||||||
editor.update(cx, |editor, cx| {
|
|
||||||
editor.toggle_selection_menu(
|
|
||||||
&editor::actions::ToggleSelectionMenu,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
menu = menu.toggleable_entry(
|
|
||||||
"Auto Signature Help",
|
|
||||||
auto_signature_help_enabled,
|
|
||||||
IconPosition::Start,
|
|
||||||
Some(editor::actions::ToggleAutoSignatureHelp.boxed_clone()),
|
|
||||||
{
|
|
||||||
let editor = editor.clone();
|
|
||||||
move |cx| {
|
|
||||||
editor.update(cx, |editor, cx| {
|
|
||||||
editor.toggle_auto_signature_help_menu(
|
|
||||||
&editor::actions::ToggleAutoSignatureHelp,
|
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
});
|
})
|
||||||
}
|
.ok();
|
||||||
},
|
}
|
||||||
);
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
menu
|
menu = menu.toggleable_entry(
|
||||||
});
|
"Inline Git Blame",
|
||||||
cx.subscribe(&menu, |quick_action_bar, _, _: &DismissEvent, _cx| {
|
git_blame_inline_enabled,
|
||||||
quick_action_bar.toggle_settings_menu = None;
|
IconPosition::Start,
|
||||||
})
|
Some(editor::actions::ToggleGitBlameInline.boxed_clone()),
|
||||||
.detach();
|
{
|
||||||
quick_action_bar.toggle_settings_menu = Some(menu);
|
let editor = editor.clone();
|
||||||
})
|
move |cx| {
|
||||||
})
|
editor
|
||||||
.when(self.toggle_settings_menu.is_none(), |this| {
|
.update(cx, |editor, cx| {
|
||||||
this.tooltip(|cx| Tooltip::text("Editor Controls", cx))
|
editor.toggle_git_blame_inline(
|
||||||
|
&editor::actions::ToggleGitBlameInline,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
menu = menu.toggleable_entry(
|
||||||
|
"Selection Menu",
|
||||||
|
selection_menu_enabled,
|
||||||
|
IconPosition::Start,
|
||||||
|
Some(editor::actions::ToggleSelectionMenu.boxed_clone()),
|
||||||
|
{
|
||||||
|
let editor = editor.clone();
|
||||||
|
move |cx| {
|
||||||
|
editor
|
||||||
|
.update(cx, |editor, cx| {
|
||||||
|
editor.toggle_selection_menu(
|
||||||
|
&editor::actions::ToggleSelectionMenu,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
menu = menu.toggleable_entry(
|
||||||
|
"Auto Signature Help",
|
||||||
|
auto_signature_help_enabled,
|
||||||
|
IconPosition::Start,
|
||||||
|
Some(editor::actions::ToggleAutoSignatureHelp.boxed_clone()),
|
||||||
|
{
|
||||||
|
let editor = editor.clone();
|
||||||
|
move |cx| {
|
||||||
|
editor
|
||||||
|
.update(cx, |editor, cx| {
|
||||||
|
editor.toggle_auto_signature_help_menu(
|
||||||
|
&editor::actions::ToggleAutoSignatureHelp,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
menu
|
||||||
});
|
});
|
||||||
|
Some(menu)
|
||||||
|
});
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id("quick action bar")
|
.id("quick action bar")
|
||||||
@ -316,21 +309,6 @@ impl Render for QuickActionBar {
|
|||||||
)
|
)
|
||||||
.children(editor_selections_dropdown)
|
.children(editor_selections_dropdown)
|
||||||
.child(editor_settings_dropdown)
|
.child(editor_settings_dropdown)
|
||||||
.when_some(self.repl_menu.as_ref(), |el, repl_menu| {
|
|
||||||
el.child(Self::render_menu_overlay(repl_menu))
|
|
||||||
})
|
|
||||||
.when_some(
|
|
||||||
self.toggle_settings_menu.as_ref(),
|
|
||||||
|el, toggle_settings_menu| {
|
|
||||||
el.child(Self::render_menu_overlay(toggle_settings_menu))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.when_some(
|
|
||||||
self.toggle_selections_menu.as_ref(),
|
|
||||||
|el, toggle_selections_menu| {
|
|
||||||
el.child(Self::render_menu_overlay(toggle_selections_menu))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use collections::{HashMap, HashSet};
|
|||||||
use db::kvp::KEY_VALUE_STORE;
|
use db::kvp::KEY_VALUE_STORE;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, Action, AnyView, AppContext, AsyncWindowContext, DismissEvent, Entity, EventEmitter,
|
actions, Action, AnchorCorner, AnyView, AppContext, AsyncWindowContext, Entity, EventEmitter,
|
||||||
ExternalPaths, FocusHandle, FocusableView, IntoElement, Model, ParentElement, Pixels, Render,
|
ExternalPaths, FocusHandle, FocusableView, IntoElement, Model, ParentElement, Pixels, Render,
|
||||||
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
|
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
@ -20,7 +20,7 @@ use terminal::{
|
|||||||
Terminal,
|
Terminal,
|
||||||
};
|
};
|
||||||
use ui::{
|
use ui::{
|
||||||
h_flex, ButtonCommon, Clickable, ContextMenu, FluentBuilder, IconButton, IconSize, Selectable,
|
h_flex, ButtonCommon, Clickable, ContextMenu, IconButton, IconSize, PopoverMenu, Selectable,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
};
|
};
|
||||||
use util::{ResultExt, TryFutureExt};
|
use util::{ResultExt, TryFutureExt};
|
||||||
@ -173,47 +173,42 @@ impl TerminalPanel {
|
|||||||
let additional_buttons = self.additional_tab_bar_buttons.clone();
|
let additional_buttons = self.additional_tab_bar_buttons.clone();
|
||||||
self.pane.update(cx, |pane, cx| {
|
self.pane.update(cx, |pane, cx| {
|
||||||
pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
|
pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
|
||||||
if !pane.has_focus(cx) {
|
if !pane.has_focus(cx) && !pane.context_menu_focused(cx) {
|
||||||
return (None, None);
|
return (None, None);
|
||||||
}
|
}
|
||||||
|
let focus_handle = pane.focus_handle(cx);
|
||||||
let right_children = h_flex()
|
let right_children = h_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.children(additional_buttons.clone())
|
.children(additional_buttons.clone())
|
||||||
.child(
|
.child(
|
||||||
IconButton::new("plus", IconName::Plus)
|
PopoverMenu::new("terminal-tab-bar-popover-menu")
|
||||||
.icon_size(IconSize::Small)
|
.trigger(
|
||||||
.on_click(cx.listener(|pane, _, cx| {
|
IconButton::new("plus", IconName::Plus)
|
||||||
let focus_handle = pane.focus_handle(cx);
|
.icon_size(IconSize::Small)
|
||||||
|
.tooltip(|cx| Tooltip::text("New...", cx)),
|
||||||
|
)
|
||||||
|
.anchor(AnchorCorner::TopRight)
|
||||||
|
.with_handle(pane.new_item_context_menu_handle.clone())
|
||||||
|
.menu(move |cx| {
|
||||||
|
let focus_handle = focus_handle.clone();
|
||||||
let menu = ContextMenu::build(cx, |menu, _| {
|
let menu = ContextMenu::build(cx, |menu, _| {
|
||||||
menu.action(
|
menu.context(focus_handle.clone())
|
||||||
"New Terminal",
|
.action(
|
||||||
workspace::NewTerminal.boxed_clone(),
|
"New Terminal",
|
||||||
)
|
workspace::NewTerminal.boxed_clone(),
|
||||||
.entry(
|
)
|
||||||
"Spawn task",
|
// We want the focus to go back to terminal panel once task modal is dismissed,
|
||||||
Some(tasks_ui::Spawn::modal().boxed_clone()),
|
// hence we focus that first. Otherwise, we'd end up without a focused element, as
|
||||||
move |cx| {
|
// context menu will be gone the moment we spawn the modal.
|
||||||
// We want the focus to go back to terminal panel once task modal is dismissed,
|
.action(
|
||||||
// hence we focus that first. Otherwise, we'd end up without a focused element, as
|
"Spawn task",
|
||||||
// context menu will be gone the moment we spawn the modal.
|
tasks_ui::Spawn::modal().boxed_clone(),
|
||||||
cx.focus(&focus_handle);
|
)
|
||||||
cx.dispatch_action(
|
|
||||||
tasks_ui::Spawn::modal().boxed_clone(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
cx.subscribe(&menu, |pane, _, _: &DismissEvent, _| {
|
|
||||||
pane.new_item_menu = None;
|
Some(menu)
|
||||||
})
|
}),
|
||||||
.detach();
|
|
||||||
pane.new_item_menu = Some(menu);
|
|
||||||
}))
|
|
||||||
.tooltip(|cx| Tooltip::text("New...", cx)),
|
|
||||||
)
|
)
|
||||||
.when_some(pane.new_item_menu.as_ref(), |el, new_item_menu| {
|
|
||||||
el.child(Pane::render_menu_overlay(new_item_menu))
|
|
||||||
})
|
|
||||||
.child({
|
.child({
|
||||||
let zoomed = pane.is_zoomed();
|
let zoomed = pane.is_zoomed();
|
||||||
IconButton::new("toggle_zoom", IconName::Maximize)
|
IconButton::new("toggle_zoom", IconName::Maximize)
|
||||||
|
@ -56,6 +56,23 @@ impl<M: ManagedView> PopoverMenuHandle<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_deployed(&self) -> bool {
|
||||||
|
self.0
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |state| state.menu.borrow().as_ref().is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_focused(&self, cx: &mut WindowContext) -> bool {
|
||||||
|
self.0.borrow().as_ref().map_or(false, |state| {
|
||||||
|
state
|
||||||
|
.menu
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |view| view.focus_handle(cx).is_focused(cx))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PopoverMenu<M: ManagedView> {
|
pub struct PopoverMenu<M: ManagedView> {
|
||||||
@ -340,9 +357,12 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
|
|||||||
// want a click on the toggle to re-open it.
|
// want a click on the toggle to re-open it.
|
||||||
cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
|
cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && child_hitbox.is_hovered(cx) {
|
if phase == DispatchPhase::Bubble && child_hitbox.is_hovered(cx) {
|
||||||
menu_handle.borrow_mut().take();
|
if let Some(menu) = menu_handle.borrow().as_ref() {
|
||||||
|
menu.update(cx, |_, cx| {
|
||||||
|
cx.emit(DismissEvent);
|
||||||
|
});
|
||||||
|
}
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
cx.refresh();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@ use collections::{BTreeSet, HashMap, HashSet, VecDeque};
|
|||||||
use futures::{stream::FuturesUnordered, StreamExt};
|
use futures::{stream::FuturesUnordered, StreamExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, deferred, impl_actions, prelude::*, Action, AnchorCorner, AnyElement,
|
actions, anchored, deferred, impl_actions, prelude::*, Action, AnchorCorner, AnyElement,
|
||||||
AppContext, AsyncWindowContext, ClickEvent, ClipboardItem, DismissEvent, Div, DragMoveEvent,
|
AppContext, AsyncWindowContext, ClickEvent, ClipboardItem, Div, DragMoveEvent, EntityId,
|
||||||
EntityId, EventEmitter, ExternalPaths, FocusHandle, FocusOutEvent, FocusableView, KeyContext,
|
EventEmitter, ExternalPaths, FocusHandle, FocusOutEvent, FocusableView, KeyContext, Model,
|
||||||
Model, MouseButton, MouseDownEvent, NavigationDirection, Pixels, Point, PromptLevel, Render,
|
MouseButton, MouseDownEvent, NavigationDirection, Pixels, Point, PromptLevel, Render,
|
||||||
ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakFocusHandle, WeakView,
|
ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakFocusHandle, WeakView,
|
||||||
WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
@ -43,7 +43,7 @@ use theme::ThemeSettings;
|
|||||||
|
|
||||||
use ui::{
|
use ui::{
|
||||||
prelude::*, right_click_menu, ButtonSize, Color, IconButton, IconButtonShape, IconName,
|
prelude::*, right_click_menu, ButtonSize, Color, IconButton, IconButtonShape, IconName,
|
||||||
IconSize, Indicator, Label, Tab, TabBar, TabPosition, Tooltip,
|
IconSize, Indicator, Label, PopoverMenu, PopoverMenuHandle, Tab, TabBar, TabPosition, Tooltip,
|
||||||
};
|
};
|
||||||
use ui::{v_flex, ContextMenu};
|
use ui::{v_flex, ContextMenu};
|
||||||
use util::{debug_panic, maybe, truncate_and_remove_front, ResultExt};
|
use util::{debug_panic, maybe, truncate_and_remove_front, ResultExt};
|
||||||
@ -250,8 +250,6 @@ pub struct Pane {
|
|||||||
last_focus_handle_by_item: HashMap<EntityId, WeakFocusHandle>,
|
last_focus_handle_by_item: HashMap<EntityId, WeakFocusHandle>,
|
||||||
nav_history: NavHistory,
|
nav_history: NavHistory,
|
||||||
toolbar: View<Toolbar>,
|
toolbar: View<Toolbar>,
|
||||||
pub new_item_menu: Option<View<ContextMenu>>,
|
|
||||||
split_item_menu: Option<View<ContextMenu>>,
|
|
||||||
pub(crate) workspace: WeakView<Workspace>,
|
pub(crate) workspace: WeakView<Workspace>,
|
||||||
project: Model<Project>,
|
project: Model<Project>,
|
||||||
drag_split_direction: Option<SplitDirection>,
|
drag_split_direction: Option<SplitDirection>,
|
||||||
@ -269,6 +267,8 @@ pub struct Pane {
|
|||||||
display_nav_history_buttons: Option<bool>,
|
display_nav_history_buttons: Option<bool>,
|
||||||
double_click_dispatch_action: Box<dyn Action>,
|
double_click_dispatch_action: Box<dyn Action>,
|
||||||
save_modals_spawned: HashSet<EntityId>,
|
save_modals_spawned: HashSet<EntityId>,
|
||||||
|
pub new_item_context_menu_handle: PopoverMenuHandle<ContextMenu>,
|
||||||
|
split_item_context_menu_handle: PopoverMenuHandle<ContextMenu>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ActivationHistoryEntry {
|
pub struct ActivationHistoryEntry {
|
||||||
@ -369,8 +369,6 @@ impl Pane {
|
|||||||
next_timestamp,
|
next_timestamp,
|
||||||
}))),
|
}))),
|
||||||
toolbar: cx.new_view(|_| Toolbar::new()),
|
toolbar: cx.new_view(|_| Toolbar::new()),
|
||||||
new_item_menu: None,
|
|
||||||
split_item_menu: None,
|
|
||||||
tab_bar_scroll_handle: ScrollHandle::new(),
|
tab_bar_scroll_handle: ScrollHandle::new(),
|
||||||
drag_split_direction: None,
|
drag_split_direction: None,
|
||||||
workspace,
|
workspace,
|
||||||
@ -380,7 +378,7 @@ impl Pane {
|
|||||||
can_split: true,
|
can_split: true,
|
||||||
should_display_tab_bar: Rc::new(|cx| TabBarSettings::get_global(cx).show),
|
should_display_tab_bar: Rc::new(|cx| TabBarSettings::get_global(cx).show),
|
||||||
render_tab_bar_buttons: Rc::new(move |pane, cx| {
|
render_tab_bar_buttons: Rc::new(move |pane, cx| {
|
||||||
if !pane.has_focus(cx) {
|
if !pane.has_focus(cx) && !pane.context_menu_focused(cx) {
|
||||||
return (None, None);
|
return (None, None);
|
||||||
}
|
}
|
||||||
// Ideally we would return a vec of elements here to pass directly to the [TabBar]'s
|
// Ideally we would return a vec of elements here to pass directly to the [TabBar]'s
|
||||||
@ -389,10 +387,16 @@ impl Pane {
|
|||||||
// Instead we need to replicate the spacing from the [TabBar]'s `end_slot` here.
|
// Instead we need to replicate the spacing from the [TabBar]'s `end_slot` here.
|
||||||
.gap(Spacing::Small.rems(cx))
|
.gap(Spacing::Small.rems(cx))
|
||||||
.child(
|
.child(
|
||||||
IconButton::new("plus", IconName::Plus)
|
PopoverMenu::new("pane-tab-bar-popover-menu")
|
||||||
.icon_size(IconSize::Small)
|
.trigger(
|
||||||
.on_click(cx.listener(|pane, _, cx| {
|
IconButton::new("plus", IconName::Plus)
|
||||||
let menu = ContextMenu::build(cx, |menu, _| {
|
.icon_size(IconSize::Small)
|
||||||
|
.tooltip(|cx| Tooltip::text("New...", cx)),
|
||||||
|
)
|
||||||
|
.anchor(AnchorCorner::TopRight)
|
||||||
|
.with_handle(pane.new_item_context_menu_handle.clone())
|
||||||
|
.menu(move |cx| {
|
||||||
|
Some(ContextMenu::build(cx, |menu, _| {
|
||||||
menu.action("New File", NewFile.boxed_clone())
|
menu.action("New File", NewFile.boxed_clone())
|
||||||
.action(
|
.action(
|
||||||
"Open File",
|
"Open File",
|
||||||
@ -412,37 +416,27 @@ impl Pane {
|
|||||||
)
|
)
|
||||||
.separator()
|
.separator()
|
||||||
.action("New Terminal", NewTerminal.boxed_clone())
|
.action("New Terminal", NewTerminal.boxed_clone())
|
||||||
});
|
}))
|
||||||
cx.subscribe(&menu, |pane, _, _: &DismissEvent, cx| {
|
}),
|
||||||
pane.focus(cx);
|
|
||||||
pane.new_item_menu = None;
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
pane.new_item_menu = Some(menu);
|
|
||||||
}))
|
|
||||||
.tooltip(|cx| Tooltip::text("New...", cx)),
|
|
||||||
)
|
)
|
||||||
.when_some(pane.new_item_menu.as_ref(), |el, new_item_menu| {
|
|
||||||
el.child(Self::render_menu_overlay(new_item_menu))
|
|
||||||
})
|
|
||||||
.child(
|
.child(
|
||||||
IconButton::new("split", IconName::Split)
|
PopoverMenu::new("pane-tab-bar-split")
|
||||||
.icon_size(IconSize::Small)
|
.trigger(
|
||||||
.on_click(cx.listener(|pane, _, cx| {
|
IconButton::new("split", IconName::Split)
|
||||||
let menu = ContextMenu::build(cx, |menu, _| {
|
.icon_size(IconSize::Small)
|
||||||
|
.tooltip(|cx| Tooltip::text("Split Pane", cx)),
|
||||||
|
)
|
||||||
|
.anchor(AnchorCorner::TopRight)
|
||||||
|
.with_handle(pane.split_item_context_menu_handle.clone())
|
||||||
|
.menu(move |cx| {
|
||||||
|
ContextMenu::build(cx, |menu, _| {
|
||||||
menu.action("Split Right", SplitRight.boxed_clone())
|
menu.action("Split Right", SplitRight.boxed_clone())
|
||||||
.action("Split Left", SplitLeft.boxed_clone())
|
.action("Split Left", SplitLeft.boxed_clone())
|
||||||
.action("Split Up", SplitUp.boxed_clone())
|
.action("Split Up", SplitUp.boxed_clone())
|
||||||
.action("Split Down", SplitDown.boxed_clone())
|
.action("Split Down", SplitDown.boxed_clone())
|
||||||
});
|
|
||||||
cx.subscribe(&menu, |pane, _, _: &DismissEvent, cx| {
|
|
||||||
pane.focus(cx);
|
|
||||||
pane.split_item_menu = None;
|
|
||||||
})
|
})
|
||||||
.detach();
|
.into()
|
||||||
pane.split_item_menu = Some(menu);
|
}),
|
||||||
}))
|
|
||||||
.tooltip(|cx| Tooltip::text("Split Pane", cx)),
|
|
||||||
)
|
)
|
||||||
.child({
|
.child({
|
||||||
let zoomed = pane.is_zoomed();
|
let zoomed = pane.is_zoomed();
|
||||||
@ -461,9 +455,6 @@ impl Pane {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.when_some(pane.split_item_menu.as_ref(), |el, split_item_menu| {
|
|
||||||
el.child(Self::render_menu_overlay(split_item_menu))
|
|
||||||
})
|
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
.into();
|
.into();
|
||||||
(None, right_children)
|
(None, right_children)
|
||||||
@ -474,6 +465,8 @@ impl Pane {
|
|||||||
_subscriptions: subscriptions,
|
_subscriptions: subscriptions,
|
||||||
double_click_dispatch_action,
|
double_click_dispatch_action,
|
||||||
save_modals_spawned: HashSet::default(),
|
save_modals_spawned: HashSet::default(),
|
||||||
|
split_item_context_menu_handle: Default::default(),
|
||||||
|
new_item_context_menu_handle: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,11 +550,9 @@ impl Pane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn context_menu_focused(&self, cx: &mut ViewContext<Self>) -> bool {
|
pub fn context_menu_focused(&self, cx: &mut ViewContext<Self>) -> bool {
|
||||||
self.new_item_menu
|
self.new_item_context_menu_handle.is_focused(cx)
|
||||||
.as_ref()
|
|| self.split_item_context_menu_handle.is_focused(cx)
|
||||||
.or(self.split_item_menu.as_ref())
|
|
||||||
.map_or(false, |menu| menu.focus_handle(cx).is_focused(cx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_out(&mut self, _event: FocusOutEvent, cx: &mut ViewContext<Self>) {
|
fn focus_out(&mut self, _event: FocusOutEvent, cx: &mut ViewContext<Self>) {
|
||||||
|
Loading…
Reference in New Issue
Block a user