From 634b699281a3ab66a690fa93cead04e78d94aa9c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 9 May 2023 15:05:29 +0200 Subject: [PATCH] Allow customization of `Pane` tab bar buttons --- crates/terminal_view/src/terminal_panel.rs | 72 +++++++----- crates/workspace/src/pane.rs | 128 +++++++++++---------- 2 files changed, 114 insertions(+), 86 deletions(-) diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 5b1a7d20df..90072ea652 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -21,6 +21,7 @@ pub struct TerminalPanel { impl TerminalPanel { pub fn new(workspace: &Workspace, cx: &mut ViewContext) -> Self { + let this = cx.weak_handle(); let pane = cx.add_view(|cx| { let window_id = cx.window_id(); let mut pane = Pane::new( @@ -36,6 +37,23 @@ impl TerminalPanel { item.handle.act_as::(cx).is_some() }) }); + pane.set_render_tab_bar_buttons(cx, move |_, cx| { + let this = this.clone(); + Pane::render_tab_bar_button( + 0, + "icons/plus_12.svg", + cx, + move |_, cx| { + let this = this.clone(); + cx.window_context().defer(move |cx| { + if let Some(this) = this.upgrade(cx) { + this.update(cx, |this, cx| this.add_terminal(cx)); + } + }) + }, + None, + ) + }); pane }); let subscriptions = vec![ @@ -61,6 +79,33 @@ impl TerminalPanel { _ => {} } } + + fn add_terminal(&mut self, cx: &mut ViewContext) { + if let Some(workspace) = self.workspace.upgrade(cx) { + let working_directory_strategy = cx + .global::() + .terminal_overrides + .working_directory + .clone() + .unwrap_or(WorkingDirectory::CurrentProjectDirectory); + let working_directory = + crate::get_working_directory(workspace.read(cx), cx, working_directory_strategy); + let window_id = cx.window_id(); + if let Some(terminal) = self.project.update(cx, |project, cx| { + project + .create_terminal(working_directory, window_id, cx) + .log_err() + }) { + workspace.update(cx, |workspace, cx| { + let terminal = + Box::new(cx.add_view(|cx| { + TerminalView::new(terminal, workspace.database_id(), cx) + })); + Pane::add_item(workspace, &self.pane, terminal, true, true, None, cx); + }); + } + } + } } impl Entity for TerminalPanel { @@ -78,32 +123,7 @@ impl View for TerminalPanel { fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { if self.pane.read(cx).items_len() == 0 { - if let Some(workspace) = self.workspace.upgrade(cx) { - let working_directory_strategy = cx - .global::() - .terminal_overrides - .working_directory - .clone() - .unwrap_or(WorkingDirectory::CurrentProjectDirectory); - let working_directory = crate::get_working_directory( - workspace.read(cx), - cx, - working_directory_strategy, - ); - let window_id = cx.window_id(); - if let Some(terminal) = self.project.update(cx, |project, cx| { - project - .create_terminal(working_directory, window_id, cx) - .log_err() - }) { - workspace.update(cx, |workspace, cx| { - let terminal = Box::new(cx.add_view(|cx| { - TerminalView::new(terminal, workspace.database_id(), cx) - })); - Pane::add_item(workspace, &self.pane, terminal, true, true, None, cx); - }); - } - } + self.add_terminal(cx) } } } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index fd617e1685..0523f082ea 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -150,6 +150,7 @@ pub struct Pane { has_focus: bool, can_drop: Rc, &WindowContext) -> bool>, can_split: bool, + render_tab_bar_buttons: Rc) -> AnyElement>, } pub struct ItemNavHistory { @@ -257,6 +258,27 @@ impl Pane { has_focus: false, can_drop: Rc::new(|_, _| true), can_split: true, + render_tab_bar_buttons: Rc::new(|pane, cx| { + Flex::row() + // New menu + .with_child(Self::render_tab_bar_button( + 0, + "icons/plus_12.svg", + cx, + |pane, cx| pane.deploy_new_menu(cx), + pane.tab_bar_context_menu + .handle_if_kind(TabBarContextMenuKind::New), + )) + .with_child(Self::render_tab_bar_button( + 2, + "icons/split_12.svg", + cx, + |pane, cx| pane.deploy_split_menu(cx), + pane.tab_bar_context_menu + .handle_if_kind(TabBarContextMenuKind::Split), + )) + .into_any() + }), } } @@ -289,6 +311,14 @@ impl Pane { cx.notify(); } + pub fn set_render_tab_bar_buttons(&mut self, cx: &mut ViewContext, render: F) + where + F: 'static + Fn(&mut Pane, &mut ViewContext) -> AnyElement, + { + self.render_tab_bar_buttons = Rc::new(render); + cx.notify(); + } + pub fn nav_history_for_item(&self, item: &ViewHandle) -> ItemNavHistory { ItemNavHistory { history: self.nav_history.clone(), @@ -1475,33 +1505,37 @@ impl Pane { .into_any() } - fn render_tab_bar_buttons( - &mut self, - theme: &Theme, - cx: &mut ViewContext, - ) -> AnyElement { - Flex::row() - // New menu - .with_child(render_tab_bar_button( - 0, - "icons/plus_12.svg", - cx, - |pane, cx| pane.deploy_new_menu(cx), - self.tab_bar_context_menu - .handle_if_kind(TabBarContextMenuKind::New), - )) - .with_child(render_tab_bar_button( - 2, - "icons/split_12.svg", - cx, - |pane, cx| pane.deploy_split_menu(cx), - self.tab_bar_context_menu - .handle_if_kind(TabBarContextMenuKind::Split), - )) - .contained() - .with_style(theme.workspace.tab_bar.pane_button_container) + pub fn render_tab_bar_button)>( + index: usize, + icon: &'static str, + cx: &mut ViewContext, + on_click: F, + context_menu: Option>, + ) -> AnyElement { + enum TabBarButton {} + + 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) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, pane, cx| on_click(pane, cx)), + ) + .with_children( + context_menu.map(|menu| ChildView::new(&menu, cx).aligned().bottom().right()), + ) .flex(1., false) - .into_any() + .into_any_named("tab bar button") } fn render_blank_pane(&self, theme: &Theme, _cx: &mut ViewContext) -> AnyElement { @@ -1554,7 +1588,14 @@ impl View for Pane { .with_child(self.render_tabs(cx).flex(1., true).into_any_named("tabs")); if self.is_active { - tab_row.add_child(self.render_tab_bar_buttons(&theme, cx)) + let render_tab_bar_buttons = self.render_tab_bar_buttons.clone(); + tab_row.add_child( + (render_tab_bar_buttons)(self, cx) + .contained() + .with_style(theme.workspace.tab_bar.pane_button_container) + .flex(1., false) + .into_any(), + ) } stack.add_child(tab_row); @@ -1676,39 +1717,6 @@ impl View for Pane { } } -fn render_tab_bar_button)>( - index: usize, - icon: &'static str, - cx: &mut ViewContext, - on_click: F, - context_menu: Option>, -) -> AnyElement { - enum TabBarButton {} - - 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) - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, pane, cx| on_click(pane, cx)), - ) - .with_children( - context_menu.map(|menu| ChildView::new(&menu, cx).aligned().bottom().right()), - ) - .flex(1., false) - .into_any_named("tab bar button") -} - impl ItemNavHistory { pub fn push(&self, data: Option, cx: &mut WindowContext) { self.history.borrow_mut().push(data, self.item.clone(), cx);