Start getting pane focus code ported

Julia created

Change summary

crates/breadcrumbs2/src/breadcrumbs.rs | 43 +++++++--------
crates/workspace2/src/pane.rs          | 76 ++++++++++++++++++++++++++-
crates/workspace2/src/toolbar.rs       |  1 
3 files changed, 93 insertions(+), 27 deletions(-)

Detailed changes

crates/breadcrumbs2/src/breadcrumbs.rs 🔗

@@ -1,6 +1,6 @@
 use gpui::{
-    div, Div, Element, EventEmitter, InteractiveElement, IntoElement, ParentElement, Render,
-    Stateful, StatefulInteractiveElement, StyledText, Subscription, ViewContext, WeakView,
+    Div, Element, EventEmitter, InteractiveElement, IntoElement, ParentElement, Render, Stateful,
+    StatefulInteractiveElement, Styled, StyledText, Subscription, ViewContext, WeakView,
 };
 use itertools::Itertools;
 use theme::ActiveTheme;
@@ -18,7 +18,7 @@ pub struct Breadcrumbs {
     pane_focused: bool,
     active_item: Option<Box<dyn ItemHandle>>,
     subscription: Option<Subscription>,
-    workspace: WeakView<Workspace>,
+    _workspace: WeakView<Workspace>,
 }
 
 impl Breadcrumbs {
@@ -27,7 +27,7 @@ impl Breadcrumbs {
             pane_focused: false,
             active_item: Default::default(),
             subscription: Default::default(),
-            workspace: workspace.weak_handle(),
+            _workspace: workspace.weak_handle(),
         }
     }
 }
@@ -39,45 +39,44 @@ impl Render for Breadcrumbs {
     type Element = Stateful<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        let id = "breadcrumbs";
-        let default_style = cx.text_style();
+        let div = h_stack().id("breadcrumbs").bg(gpui::red());
 
         let active_item = match &self.active_item {
             Some(active_item) => active_item,
-            None => return div().id(id),
+            None => return div,
         };
         let not_editor = active_item.downcast::<editor::Editor>().is_none();
 
         let breadcrumbs = match active_item.breadcrumbs(cx.theme(), cx) {
             Some(breadcrumbs) => breadcrumbs,
-            None => return div().id(id),
+            None => return div,
         }
         .into_iter()
         .map(|breadcrumb| {
             StyledText::new(breadcrumb.text)
-                .with_highlights(&default_style, breadcrumb.highlights.unwrap_or_default())
+                .with_highlights(&cx.text_style(), breadcrumb.highlights.unwrap_or_default())
                 .into_any()
         });
 
-        let crumbs = h_stack().children(Itertools::intersperse_with(breadcrumbs, || {
+        let crumbs = div.children(Itertools::intersperse_with(breadcrumbs, || {
             Label::new(" › ").into_any_element()
         }));
 
         if not_editor || !self.pane_focused {
-            return crumbs.id(id);
+            return crumbs;
         }
 
-        let this = cx.view().downgrade();
-        crumbs.id(id).on_click(move |_, cx| {
-            this.update(cx, |this, cx| {
-                if let Some(workspace) = this.workspace.upgrade() {
-                    workspace.update(cx, |_workspace, _cx| {
-                        todo!("outline::toggle");
-                        // outline::toggle(workspace, &Default::default(), cx)
-                    })
-                }
-            })
-            .ok();
+        // let this = cx.view().downgrade();
+        crumbs.on_click(move |_, _cx| {
+            todo!("outline::toggle");
+            // this.update(cx, |this, cx| {
+            //     if let Some(workspace) = this.workspace.upgrade() {
+            //         workspace.update(cx, |_workspace, _cx| {
+            //             outline::toggle(workspace, &Default::default(), cx)
+            //         })
+            //     }
+            // })
+            // .ok();
         })
     }
 }

crates/workspace2/src/pane.rs 🔗

@@ -7,9 +7,9 @@ use crate::{
 use anyhow::Result;
 use collections::{HashMap, HashSet, VecDeque};
 use gpui::{
-    actions, prelude::*, Action, AppContext, AsyncWindowContext, Div, EntityId, EventEmitter,
-    FocusHandle, Focusable, FocusableView, Model, Pixels, Point, PromptLevel, Render, Task, View,
-    ViewContext, VisualContext, WeakView, WindowContext,
+    actions, prelude::*, Action, AnyWeakView, AppContext, AsyncWindowContext, Div, EntityId,
+    EventEmitter, FocusHandle, Focusable, FocusableView, Model, Pixels, Point, PromptLevel, Render,
+    Task, View, ViewContext, VisualContext, WeakView, WindowContext,
 };
 use parking_lot::Mutex;
 use project2::{Project, ProjectEntryId, ProjectPath};
@@ -143,13 +143,18 @@ impl fmt::Debug for Event {
     }
 }
 
+struct FocusedView {
+    view: AnyWeakView,
+    focus_handle: FocusHandle,
+}
+
 pub struct Pane {
     focus_handle: FocusHandle,
     items: Vec<Box<dyn ItemHandle>>,
     activation_history: Vec<EntityId>,
     zoomed: bool,
     active_item_index: usize,
-    //     last_focused_view_by_item: HashMap<usize, AnyWeakViewHandle>,
+    last_focused_view_by_item: HashMap<EntityId, FocusHandle>,
     autoscroll: bool,
     nav_history: NavHistory,
     toolbar: View<Toolbar>,
@@ -306,7 +311,7 @@ impl Pane {
             activation_history: Vec::new(),
             zoomed: false,
             active_item_index: 0,
-            // last_focused_view_by_item: Default::default(),
+            last_focused_view_by_item: Default::default(),
             autoscroll: false,
             nav_history: NavHistory(Arc::new(Mutex::new(NavHistoryState {
                 mode: NavigationMode::Normal,
@@ -395,6 +400,53 @@ impl Pane {
         self.focus_handle.contains_focused(cx)
     }
 
+    fn focus_in(&mut self, cx: &mut ViewContext<Self>) {
+        println!("focus_in");
+
+        if !self.has_focus(cx) {
+            cx.emit(Event::Focus);
+            cx.notify();
+        }
+
+        self.toolbar.update(cx, |toolbar, cx| {
+            toolbar.focus_changed(true, cx);
+        });
+
+        if let Some(active_item) = self.active_item() {
+            if self.focus_handle.is_focused(cx) {
+                // Pane was focused directly. We need to either focus a view inside the active item,
+                // or focus the active item itself
+                if let Some(weak_last_focused_view) =
+                    self.last_focused_view_by_item.get(&active_item.item_id())
+                {
+                    weak_last_focused_view.focus(cx);
+                    // if let Some(last_focused_view) = weak_last_focused_view.upgrade() {
+                    //     last_focused_view.cx.focus(&last_focused_view);
+                    //     return;
+                    // } else {
+                    //     self.last_focused_view_by_item.remove(&active_item.id());
+                    // }
+                }
+
+                active_item.focus_handle(cx).focus(cx);
+            // todo!() Do this once we have tab bar context menu
+            // } else if !self.tab_bar_context_menu.handle.is_focused() {
+            } else if let Some(focused) = cx.focused() {
+                self.last_focused_view_by_item
+                    .insert(active_item.item_id(), focused);
+            }
+        }
+    }
+
+    fn focus_out(&mut self, cx: &mut ViewContext<Self>) {
+        println!("focus_out");
+
+        self.toolbar.update(cx, |toolbar, cx| {
+            toolbar.focus_changed(false, cx);
+        });
+        cx.notify();
+    }
+
     pub fn active_item_index(&self) -> usize {
         self.active_item_index
     }
@@ -1936,9 +1988,23 @@ impl Render for Pane {
     type Element = Focusable<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        let this = cx.view().downgrade();
+
         v_stack()
             .key_context("Pane")
             .track_focus(&self.focus_handle)
+            .on_focus_in({
+                let this = this.clone();
+                move |event, cx| {
+                    this.update(cx, |this, cx| this.focus_in(cx)).ok();
+                }
+            })
+            .on_focus_out({
+                let this = this.clone();
+                move |event, cx| {
+                    this.update(cx, |this, cx| this.focus_out(cx)).ok();
+                }
+            })
             .on_action(cx.listener(|pane: &mut Pane, _: &SplitLeft, cx| {
                 pane.split(SplitDirection::Left, cx)
             }))

crates/workspace2/src/toolbar.rs 🔗

@@ -289,6 +289,7 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
     }
 
     fn focus_changed(&mut self, pane_focused: bool, cx: &mut WindowContext) {
+        println!("focus changed, pane_focused: {pane_focused}");
         self.update(cx, |this, cx| {
             this.pane_focus_update(pane_focused, cx);
             cx.notify();