diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index b0d7b78708..f4a5ad026a 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -82,19 +82,13 @@ pub struct GoForward { } #[derive(Clone, PartialEq)] -pub struct DeploySplitMenu { - position: Vector2F, -} +pub struct DeploySplitMenu; #[derive(Clone, PartialEq)] -pub struct DeployDockMenu { - position: Vector2F, -} +pub struct DeployDockMenu; #[derive(Clone, PartialEq)] -pub struct DeployNewMenu { - position: Vector2F, -} +pub struct DeployNewMenu; impl_actions!(pane, [GoBack, GoForward, ActivateItem]); impl_internal_actions!( @@ -215,7 +209,7 @@ pub struct Pane { autoscroll: bool, nav_history: Rc>, toolbar: ViewHandle, - tab_bar_context_menu: ViewHandle, + tab_bar_context_menu: TabBarContextMenu, docked: Option, _background_actions: BackgroundActions, _workspace_id: usize, @@ -274,6 +268,27 @@ enum ItemType { All, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum TabBarContextMenuKind { + New, + Split, + Dock, +} + +struct TabBarContextMenu { + kind: TabBarContextMenuKind, + handle: ViewHandle, +} + +impl TabBarContextMenu { + fn handle_if_kind(&self, kind: TabBarContextMenuKind) -> Option> { + if self.kind == kind { + return Some(self.handle.clone()); + } + None + } +} + impl Pane { pub fn new( workspace_id: usize, @@ -283,6 +298,10 @@ impl Pane { ) -> Self { let handle = cx.weak_handle(); let context_menu = cx.add_view(ContextMenu::new); + context_menu.update(cx, |menu, _| { + menu.set_position_mode(OverlayPositionMode::Local) + }); + Self { items: Vec::new(), activation_history: Vec::new(), @@ -299,7 +318,10 @@ impl Pane { pane: handle.clone(), })), toolbar: cx.add_view(|_| Toolbar::new(handle)), - tab_bar_context_menu: context_menu, + tab_bar_context_menu: TabBarContextMenu { + kind: TabBarContextMenuKind::New, + handle: context_menu, + }, docked, _background_actions: background_actions, _workspace_id: workspace_id, @@ -1076,10 +1098,10 @@ impl Pane { cx.emit(Event::Split(direction)); } - fn deploy_split_menu(&mut self, action: &DeploySplitMenu, cx: &mut ViewContext) { - self.tab_bar_context_menu.update(cx, |menu, cx| { + fn deploy_split_menu(&mut self, _: &DeploySplitMenu, cx: &mut ViewContext) { + self.tab_bar_context_menu.handle.update(cx, |menu, cx| { menu.show( - action.position, + Default::default(), AnchorCorner::TopRight, vec![ ContextMenuItem::item("Split Right", SplitRight), @@ -1090,12 +1112,14 @@ impl Pane { cx, ); }); + + self.tab_bar_context_menu.kind = TabBarContextMenuKind::Split; } - fn deploy_dock_menu(&mut self, action: &DeployDockMenu, cx: &mut ViewContext) { - self.tab_bar_context_menu.update(cx, |menu, cx| { + fn deploy_dock_menu(&mut self, _: &DeployDockMenu, cx: &mut ViewContext) { + self.tab_bar_context_menu.handle.update(cx, |menu, cx| { menu.show( - action.position, + Default::default(), AnchorCorner::TopRight, vec![ ContextMenuItem::item("Anchor Dock Right", AnchorDockRight), @@ -1105,12 +1129,14 @@ impl Pane { cx, ); }); + + self.tab_bar_context_menu.kind = TabBarContextMenuKind::Dock; } - fn deploy_new_menu(&mut self, action: &DeployNewMenu, cx: &mut ViewContext) { - self.tab_bar_context_menu.update(cx, |menu, cx| { + fn deploy_new_menu(&mut self, _: &DeployNewMenu, cx: &mut ViewContext) { + self.tab_bar_context_menu.handle.update(cx, |menu, cx| { menu.show( - action.position, + Default::default(), AnchorCorner::TopRight, vec![ ContextMenuItem::item("New File", NewFile), @@ -1120,6 +1146,8 @@ impl Pane { cx, ); }); + + self.tab_bar_context_menu.kind = TabBarContextMenuKind::New; } pub fn toolbar(&self) -> &ViewHandle { @@ -1398,28 +1426,45 @@ impl Pane { ) -> ElementBox { Flex::row() // New menu - .with_child(tab_bar_button(0, "icons/plus_12.svg", cx, |position| { - DeployNewMenu { position } - })) + .with_child(render_tab_bar_button( + 0, + "icons/plus_12.svg", + cx, + DeployNewMenu, + self.tab_bar_context_menu + .handle_if_kind(TabBarContextMenuKind::New), + )) .with_child( self.docked .map(|anchor| { // Add the dock menu button if this pane is a dock let dock_icon = icon_for_dock_anchor(anchor); - tab_bar_button(1, dock_icon, cx, |position| DeployDockMenu { position }) + render_tab_bar_button( + 1, + dock_icon, + cx, + DeployDockMenu, + self.tab_bar_context_menu + .handle_if_kind(TabBarContextMenuKind::Dock), + ) }) .unwrap_or_else(|| { // Add the split menu if this pane is not a dock - tab_bar_button(2, "icons/split_12.svg", cx, |position| DeploySplitMenu { - position, - }) + render_tab_bar_button( + 2, + "icons/split_12.svg", + cx, + DeploySplitMenu, + self.tab_bar_context_menu + .handle_if_kind(TabBarContextMenuKind::Split), + ) }), ) // Add the close dock button if this pane is a dock .with_children( self.docked - .map(|_| tab_bar_button(3, "icons/x_mark_8.svg", cx, |_| HideDock)), + .map(|_| render_tab_bar_button(3, "icons/x_mark_8.svg", cx, HideDock, None)), ) .contained() .with_style(theme.workspace.tab_bar.pane_button_container) @@ -1554,7 +1599,6 @@ impl View for Pane { }) .boxed(), ) - .with_child(ChildView::new(&self.tab_bar_context_menu, cx).boxed()) .named("pane") } @@ -1575,7 +1619,7 @@ impl View for Pane { } cx.focus(active_item); - } else if focused != self.tab_bar_context_menu { + } else if focused != self.tab_bar_context_menu.handle { self.last_focused_view_by_item .insert(active_item.id(), focused.downgrade()); } @@ -1591,34 +1635,41 @@ impl View for Pane { } } -fn tab_bar_button( +fn render_tab_bar_button( index: usize, icon: &'static str, cx: &mut RenderContext, - action_builder: impl 'static + Fn(Vector2F) -> A, + action: A, + context_menu: Option>, ) -> ElementBox { enum TabBarButton {} - MouseEventHandler::::new(index, cx, |mouse_state, cx| { - let theme = &cx.global::().theme.workspace.tab_bar; - let style = theme.pane_button.style_for(mouse_state, false); - Svg::new(icon) - .with_color(style.color) - .constrained() - .with_width(style.icon_width) - .aligned() - .constrained() - .with_width(style.button_width) - .with_height(style.button_width) - // .aligned() - .boxed() - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |e, cx| { - cx.dispatch_action(action_builder(e.region.lower_right())); - }) - .flex(1., false) - .boxed() + Stack::new() + .with_child( + MouseEventHandler::::new(index, cx, |mouse_state, cx| { + let theme = &cx.global::().theme.workspace.tab_bar; + let style = theme.pane_button.style_for(mouse_state, false); + Svg::new(icon) + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .boxed() + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, cx| { + cx.dispatch_action(action.clone()); + }) + .boxed(), + ) + .with_children( + context_menu.map(|menu| ChildView::new(menu, cx).aligned().bottom().right().boxed()), + ) + .flex(1., false) + .boxed() } impl ItemNavHistory {