From caa6a7523813877617c73f23e70f6e819ad30879 Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Fri, 3 Mar 2023 15:04:35 -0800 Subject: [PATCH] Show a pop up menu for terminals Co-Authored-By: Joseph T. Lyons <19867440+JosephTLyons@users.noreply.github.com> Co-Authored-By: Antonio Scandurra --- crates/project/src/terminals.rs | 4 + crates/workspace/src/pane.rs | 2 +- crates/workspace/src/terminal_button.rs | 159 +++++++++++++++--------- crates/workspace/src/workspace.rs | 8 +- 4 files changed, 111 insertions(+), 62 deletions(-) diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index b01546ff5c..f7b4105dd2 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -58,6 +58,10 @@ impl Project { terminal } } + + pub fn local_terminal_handles(&self) -> &Vec> { + &self.terminals.local_handles + } } // TODO: Add a few tests for adding and removing terminal tabs diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 98fcac664c..f9ba6ef5b4 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -166,8 +166,8 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx)); cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx)); cx.add_action(Pane::deploy_split_menu); - cx.add_action(Pane::deploy_new_menu); cx.add_action(Pane::deploy_dock_menu); + cx.add_action(Pane::deploy_new_menu); cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| { Pane::reopen_closed_item(workspace, cx).detach(); }); diff --git a/crates/workspace/src/terminal_button.rs b/crates/workspace/src/terminal_button.rs index 118df7cab1..6573809359 100644 --- a/crates/workspace/src/terminal_button.rs +++ b/crates/workspace/src/terminal_button.rs @@ -1,26 +1,26 @@ +use context_menu::{ContextMenu, ContextMenuItem}; use gpui::{ - elements::{Empty, MouseEventHandler, Svg}, - CursorStyle, Element, ElementBox, Entity, MouseButton, RenderContext, View, ViewContext, - ViewHandle, WeakViewHandle, + actions, elements::*, geometry::vector::vec2f, CursorStyle, Element, ElementBox, Entity, + MouseButton, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle, }; use settings::Settings; -use crate::{dock::FocusDock, item::ItemHandle, StatusItemView, Workspace}; +use crate::{dock::FocusDock, item::ItemHandle, NewTerminal, StatusItemView, Workspace}; + +// #[derive(Clone, PartialEq)] +// pub struct DeployTerminalMenu { +// position: Vector2F, +// } + +actions!(terminal, [DeployTerminalMenu]); + +pub fn init(cx: &mut MutableAppContext) { + cx.add_action(TerminalButton::deploy_terminal_menu); +} pub struct TerminalButton { workspace: WeakViewHandle, -} - -// TODO: Rename this to `DeployTerminalButton` -impl TerminalButton { - pub fn new(workspace: ViewHandle, cx: &mut ViewContext) -> Self { - // When terminal moves, redraw so that the icon and toggle status matches. - cx.subscribe(&workspace, |_, _, _, cx| cx.notify()).detach(); - - Self { - workspace: workspace.downgrade(), - } - } + popup_menu: ViewHandle, } impl Entity for TerminalButton { @@ -34,52 +34,93 @@ impl View for TerminalButton { fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox { let workspace = self.workspace.upgrade(cx); - - if workspace.is_none() { - return Empty::new().boxed(); - } - - // let workspace = workspace.unwrap(); + let project = match workspace { + Some(workspace) => workspace.read(cx).project().read(cx), + None => return Empty::new().boxed(), + }; + let has_terminals = !project.local_terminal_handles().is_empty(); + let terminal_count = project.local_terminal_handles().iter().count(); let theme = cx.global::().theme.clone(); - MouseEventHandler::::new(0, cx, { - let theme = theme.clone(); - move |state, _| { - let style = theme - .workspace - .status_bar - .sidebar_buttons - .item - .style_for(state, true); + Stack::new() + .with_child( + MouseEventHandler::::new(0, cx, { + let theme = theme.clone(); + move |state, _| { + let style = theme + .workspace + .status_bar + .sidebar_buttons + .item + .style_for(state, true); - Svg::new("icons/terminal_12.svg") - .with_color(style.icon_color) - .constrained() - .with_width(style.icon_size) - .with_height(style.icon_size) - .contained() - .with_style(style.container) - .boxed() - } - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_up(MouseButton::Left, move |_, _| { - // TODO: Do we need this stuff? - // let dock_pane = workspace.read(cx.app).dock_pane(); - // let drop_index = dock_pane.read(cx.app).items_len() + 1; - // handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx); - }) - .on_click(MouseButton::Left, |_, cx| { - cx.dispatch_action(FocusDock); - }) - .with_tooltip::( - 0, - "Show Terminal".into(), - Some(Box::new(FocusDock)), - theme.tooltip.clone(), - cx, - ) - .boxed() + Svg::new("icons/terminal_12.svg") + .with_color(style.icon_color) + .constrained() + .with_width(style.icon_size) + .with_height(style.icon_size) + .contained() + .with_style(style.container) + .boxed() + } + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_up(MouseButton::Left, move |_, _| { + // TODO: Do we need this stuff? + // let dock_pane = workspace.read(cx.app).dock_pane(); + // let drop_index = dock_pane.read(cx.app).items_len() + 1; + // handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx); + }) + .on_click(MouseButton::Left, move |_, cx| { + if has_terminals { + cx.dispatch_action(DeployTerminalMenu); + println!("Yes, has_terminals {}", terminal_count); + } else { + cx.dispatch_action(FocusDock); + }; + }) + .with_tooltip::( + 0, + "Show Terminal".into(), + Some(Box::new(FocusDock)), + theme.tooltip.clone(), + cx, + ) + .boxed(), + ) + .with_child(ChildView::new(&self.popup_menu, cx).boxed()) + .boxed() + } +} + +// TODO: Rename this to `DeployTerminalButton` +impl TerminalButton { + pub fn new(workspace: ViewHandle, cx: &mut ViewContext) -> Self { + // When terminal moves, redraw so that the icon and toggle status matches. + cx.subscribe(&workspace, |_, _, _, cx| cx.notify()).detach(); + Self { + workspace: workspace.downgrade(), + popup_menu: cx.add_view(|cx| { + let mut menu = ContextMenu::new(cx); + menu.set_position_mode(OverlayPositionMode::Local); + menu + }), + } + } + + pub fn deploy_terminal_menu( + &mut self, + _action: &DeployTerminalMenu, + cx: &mut ViewContext, + ) { + self.popup_menu.update(cx, |menu, cx| { + menu.show( + vec2f(0., 0.), + AnchorCorner::TopLeft, + vec![ContextMenuItem::item("New Terminal", NewTerminal)], + cx, + ); + }); } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index b9d80e7150..db15839ad0 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -83,7 +83,7 @@ use status_bar::StatusBar; pub use status_bar::StatusItemView; use theme::{Theme, ThemeRegistry}; pub use toolbar::{ToolbarItemLocation, ToolbarItemView}; -use util::ResultExt; +use util::{ResultExt, StaffMode}; lazy_static! { static ref ZED_WINDOW_SIZE: Option = env::var("ZED_WINDOW_SIZE") @@ -185,6 +185,7 @@ impl_actions!(workspace, [ActivatePane]); pub fn init(app_state: Arc, cx: &mut MutableAppContext) { pane::init(cx); dock::init(cx); + terminal_button::init(cx); notifications::init(cx); cx.add_global_action(open); @@ -595,7 +596,10 @@ impl Workspace { status_bar.add_left_item(left_sidebar_buttons, cx); status_bar.add_right_item(right_sidebar_buttons, cx); status_bar.add_right_item(toggle_dock, cx); - status_bar.add_right_item(toggle_terminal, cx); + // TOOD: Remove this when things are done + if **cx.default_global::() { + status_bar.add_right_item(toggle_terminal, cx); + } status_bar });