Dock menu

Conrad Irwin created

Change summary

crates/terminal_view2/src/terminal_view.rs | 13 +++----
crates/ui2/src/components/context_menu.rs  |  5 +++
crates/workspace2/src/dock.rs              | 39 ++++++++++++++++++++---
3 files changed, 44 insertions(+), 13 deletions(-)

Detailed changes

crates/terminal_view2/src/terminal_view.rs 🔗

@@ -32,7 +32,7 @@ use workspace::{
     notifications::NotifyResultExt,
     register_deserializable_item,
     searchable::{SearchEvent, SearchOptions, SearchableItem},
-    ui::{ContextMenu, Label},
+    ui::{ContextMenu, Label, ListEntry},
     CloseActiveItem, NewCenterTerminal, Pane, ToolbarItemLocation, Workspace, WorkspaceId,
 };
 
@@ -85,7 +85,7 @@ pub struct TerminalView {
     has_new_content: bool,
     //Currently using iTerm bell, show bell emoji in tab until input is received
     has_bell: bool,
-    context_menu: Option<View<ContextMenu>>,
+    context_menu: Option<View<ContextMenu<Self>>>,
     blink_state: bool,
     blinking_on: bool,
     blinking_paused: bool,
@@ -300,11 +300,10 @@ impl TerminalView {
         position: gpui::Point<Pixels>,
         cx: &mut ViewContext<Self>,
     ) {
-        self.context_menu = Some(cx.build_view(|cx| {
-            ContextMenu::new(cx)
-                .entry(Label::new("Clear"), Box::new(Clear))
-                .entry(
-                    Label::new("Close"),
+        self.context_menu = Some(ContextMenu::build(cx, |menu, _| {
+            menu.action(ListEntry::new(Label::new("Clear")), Box::new(Clear))
+                .action(
+                    ListEntry::new(Label::new("Close")),
                     Box::new(CloseActiveItem { save_intent: None }),
                 )
         }));

crates/ui2/src/components/context_menu.rs 🔗

@@ -69,6 +69,11 @@ impl<V: Render> ContextMenu<V> {
         self
     }
 
+    pub fn action(self, view: ListEntry<Self>, action: Box<dyn Action>) -> Self {
+        // todo: add the keybindings to the list entry
+        self.entry(view, move |_, cx| cx.dispatch_action(action.boxed_clone()))
+    }
+
     pub fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
         // todo!()
         cx.emit(Dismiss);

crates/workspace2/src/dock.rs 🔗

@@ -8,7 +8,9 @@ use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use std::sync::Arc;
 use theme2::ActiveTheme;
-use ui::{h_stack, menu_handle, ContextMenu, IconButton, InteractionState, Tooltip};
+use ui::{
+    h_stack, menu_handle, ContextMenu, IconButton, InteractionState, Label, ListEntry, Tooltip,
+};
 
 pub enum PanelEvent {
     ChangePosition,
@@ -672,6 +674,7 @@ impl Render for PanelButtons {
         let dock = self.dock.read(cx);
         let active_index = dock.active_panel_index;
         let is_open = dock.is_open;
+        let dock_position = dock.position;
 
         let (menu_anchor, menu_attach) = match dock.position {
             DockPosition::Left => (AnchorCorner::BottomLeft, AnchorCorner::TopLeft),
@@ -684,9 +687,10 @@ impl Render for PanelButtons {
             .panel_entries
             .iter()
             .enumerate()
-            .filter_map(|(i, panel)| {
-                let icon = panel.panel.icon(cx)?;
-                let name = panel.panel.persistent_name();
+            .filter_map(|(i, entry)| {
+                let icon = entry.panel.icon(cx)?;
+                let name = entry.panel.persistent_name();
+                let panel = entry.panel.clone();
 
                 let mut button: IconButton<Self> = if i == active_index && is_open {
                     let action = dock.toggle_action();
@@ -697,7 +701,7 @@ impl Render for PanelButtons {
                         .action(action.boxed_clone())
                         .tooltip(move |_, cx| Tooltip::for_action(tooltip.clone(), &*action, cx))
                 } else {
-                    let action = panel.panel.toggle_action(cx);
+                    let action = entry.panel.toggle_action(cx);
 
                     IconButton::new(name, icon)
                         .action(action.boxed_clone())
@@ -708,7 +712,30 @@ impl Render for PanelButtons {
                     menu_handle()
                         .id(name)
                         .menu(move |_, cx| {
-                            cx.build_view(|cx| ContextMenu::new(cx).header("SECTION"))
+                            const POSITIONS: [DockPosition; 3] = [
+                                DockPosition::Left,
+                                DockPosition::Right,
+                                DockPosition::Bottom,
+                            ];
+                            ContextMenu::build(cx, |mut menu, cx| {
+                                for position in POSITIONS {
+                                    if position != dock_position
+                                        && panel.position_is_valid(position, cx)
+                                    {
+                                        let panel = panel.clone();
+                                        menu = menu.entry(
+                                            ListEntry::new(Label::new(format!(
+                                                "Dock {}",
+                                                position.to_label()
+                                            ))),
+                                            move |_, cx| {
+                                                panel.set_position(position, cx);
+                                            },
+                                        )
+                                    }
+                                }
+                                menu
+                            })
                         })
                         .anchor(menu_anchor)
                         .attach(menu_attach)