diff --git a/crates/agent_ui/src/sidebar.rs b/crates/agent_ui/src/sidebar.rs index 2f1b3fb0719731b6cbdc7e26a2209be6b6c80ee9..24ca6a0e9641c7b9fe0b8c4196ecf84a6fc58a67 100644 --- a/crates/agent_ui/src/sidebar.rs +++ b/crates/agent_ui/src/sidebar.rs @@ -33,7 +33,7 @@ use workspace::{ dock::{DockPosition, Panel, PanelEvent, PanelIconButton}, multi_workspace_enabled, }; -use zed_actions::assistant::ToggleThreadsSidebar; +use zed_actions::assistant::{ToggleAgentDrawer, ToggleThreadsSidebar}; use zed_actions::editor::{MoveDown, MoveUp}; actions!( @@ -2034,6 +2034,14 @@ impl Panel for Sidebar { } } + fn secondary_button(&self, _window: &Window, _cx: &App) -> Option { + Some(PanelIconButton { + icon: IconName::Ai, + tooltip: "Agent Drawer", + action: Box::new(ToggleAgentDrawer), + }) + } + fn activation_priority(&self) -> u32 { 4 } diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 9f8960e498362a064d5268c931b563013ba7237d..91cc15def50c0c30ef663492ee4342bf449b5380 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -41,6 +41,9 @@ pub trait Panel: Focusable + EventEmitter + Render + Sized { fn size(&self, window: &Window, cx: &App) -> Pixels; fn set_size(&mut self, size: Option, window: &mut Window, cx: &mut Context); fn icon_button(&self, window: &Window, cx: &App) -> PanelIconButton; + fn secondary_button(&self, _window: &Window, _cx: &App) -> Option { + None + } fn is_zoomed(&self, _window: &Window, _cx: &App) -> bool { false } @@ -76,6 +79,7 @@ pub trait PanelHandle: Send + Sync { fn size(&self, window: &Window, cx: &App) -> Pixels; fn set_size(&self, size: Option, window: &mut Window, cx: &mut App); fn icon_button(&self, window: &Window, cx: &App) -> PanelIconButton; + fn secondary_button(&self, window: &Window, cx: &App) -> Option; fn panel_focus_handle(&self, cx: &App) -> FocusHandle; fn to_any(&self) -> AnyView; fn activation_priority(&self, cx: &App) -> u32; @@ -157,6 +161,10 @@ where self.read(cx).icon_button(window, cx) } + fn secondary_button(&self, window: &Window, cx: &App) -> Option { + self.read(cx).secondary_button(window, cx) + } + fn to_any(&self) -> AnyView { self.clone().into() } @@ -907,6 +915,7 @@ impl Render for PanelButtons { tooltip: icon_tooltip, action: toggle_action, } = entry.panel.icon_button(window, cx); + let secondary_button = entry.panel.secondary_button(window, cx); let name = entry.panel.persistent_name(); let panel = entry.panel.clone(); @@ -953,10 +962,10 @@ impl Render for PanelButtons { }) .anchor(menu_anchor) .attach(menu_attach) - .trigger(move |is_active, _window, _cx| { + .trigger(move |is_active, _window, cx| { // Include active state in element ID to invalidate the cached // tooltip when panel state changes (e.g., via keyboard shortcut) - IconButton::new((name, is_active_button as u64), icon) + let button = IconButton::new((name, is_active_button as u64), icon) .icon_size(IconSize::Small) .toggle_state(is_active_button) .on_click({ @@ -970,7 +979,48 @@ impl Render for PanelButtons { this.tooltip(move |_window, cx| { Tooltip::for_action(tooltip.clone(), &*action, cx) }) - }) + }); + + match secondary_button { + Some(secondary_button) => { + let action = secondary_button.action.boxed_clone(); + let secondary_button = + IconButton::new("secondary-button", secondary_button.icon) + .icon_size(IconSize::Small) + .toggle_state(false) // todo! show active when drawer is open + .on_click({ + let action = action.boxed_clone(); + move |_, window, cx| { + window.dispatch_action(action.boxed_clone(), cx) + } + }) + .when(!is_active, |this| { + this.tooltip(move |_window, cx| { + Tooltip::for_action( + secondary_button.tooltip, + &*action, + cx, + ) + }) + }); + + h_flex() + .min_w_0() + .rounded_sm() + .gap_px() + .border_1() + .border_color(cx.theme().colors().border) + .when( + matches!(dock_position, DockPosition::Right), + |this| this.flex_row_reverse(), + ) + .child(button) + .child(div().h_4().w_px().bg(cx.theme().colors().border)) + .child(secondary_button) + .into_any_element() + } + None => button.into_any_element(), + } }), ) })