Add `Modal::has_focus` and introduce a `ModalHandle` trait object

Antonio Scandurra created

Change summary

crates/go_to_line/src/go_to_line.rs | 11 +++++++++++
crates/picker/src/picker.rs         | 11 +++++++++++
crates/workspace/src/workspace.rs   | 16 ++++++++++++++++
3 files changed, 38 insertions(+)

Detailed changes

crates/go_to_line/src/go_to_line.rs 🔗

@@ -24,6 +24,7 @@ pub struct GoToLine {
     prev_scroll_position: Option<Vector2F>,
     cursor_point: Point,
     max_point: Point,
+    has_focus: bool,
 }
 
 pub enum Event {
@@ -57,6 +58,7 @@ impl GoToLine {
             prev_scroll_position: scroll_position,
             cursor_point,
             max_point,
+            has_focus: false,
         }
     }
 
@@ -178,11 +180,20 @@ impl View for GoToLine {
     }
 
     fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
+        self.has_focus = true;
         cx.focus(&self.line_editor);
     }
+
+    fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {
+        self.has_focus = false;
+    }
 }
 
 impl Modal for GoToLine {
+    fn has_focus(&self) -> bool {
+        self.has_focus
+    }
+
     fn dismiss_on_event(event: &Self::Event) -> bool {
         matches!(event, Event::Dismissed)
     }

crates/picker/src/picker.rs 🔗

@@ -25,6 +25,7 @@ pub struct Picker<D: PickerDelegate> {
     theme: Arc<Mutex<Box<dyn Fn(&theme::Theme) -> theme::Picker>>>,
     confirmed: bool,
     pending_update_matches: Task<Option<()>>,
+    has_focus: bool,
 }
 
 pub trait PickerDelegate: Sized + 'static {
@@ -140,13 +141,22 @@ impl<D: PickerDelegate> View for Picker<D> {
     }
 
     fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
+        self.has_focus = true;
         if cx.is_self_focused() {
             cx.focus(&self.query_editor);
         }
     }
+
+    fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {
+        self.has_focus = false;
+    }
 }
 
 impl<D: PickerDelegate> Modal for Picker<D> {
+    fn has_focus(&self) -> bool {
+        self.has_focus
+    }
+
     fn dismiss_on_event(event: &Self::Event) -> bool {
         matches!(event, PickerEvent::Dismiss)
     }
@@ -191,6 +201,7 @@ impl<D: PickerDelegate> Picker<D> {
             theme,
             confirmed: false,
             pending_update_matches: Task::ready(None),
+            has_focus: false,
         };
         this.update_matches(String::new(), cx);
         this

crates/workspace/src/workspace.rs 🔗

@@ -97,9 +97,25 @@ lazy_static! {
 }
 
 pub trait Modal: View {
+    fn has_focus(&self) -> bool;
     fn dismiss_on_event(event: &Self::Event) -> bool;
 }
 
+trait ModalHandle {
+    fn as_any(&self) -> &AnyViewHandle;
+    fn has_focus(&self, cx: &WindowContext) -> bool;
+}
+
+impl<T: Modal> ModalHandle for ViewHandle<T> {
+    fn as_any(&self) -> &AnyViewHandle {
+        self
+    }
+
+    fn has_focus(&self, cx: &WindowContext) -> bool {
+        self.read(cx).has_focus()
+    }
+}
+
 #[derive(Clone, PartialEq)]
 pub struct RemoveWorktreeFromProject(pub WorktreeId);