@@ -2,11 +2,13 @@ use crate::face_pile::FacePile;
use call::{ActiveCall, ParticipantLocation, Room};
use client::{proto::PeerId, Client, ParticipantIndex, User, UserStore};
use gpui::{
- actions, canvas, div, point, px, rems, AppContext, Div, Element, Hsla, InteractiveElement,
- IntoElement, Model, ParentElement, Path, Render, Stateful, StatefulInteractiveElement, Styled,
- Subscription, ViewContext, VisualContext, WeakView, WindowBounds,
+ actions, canvas, div, overlay, point, px, rems, AppContext, DismissEvent, Div, Element,
+ FocusableView, Hsla, InteractiveElement, IntoElement, Model, Overlay, ParentElement, Path,
+ Render, Stateful, StatefulInteractiveElement, Styled, Subscription, ViewContext, VisualContext,
+ WeakView, WindowBounds,
};
use project::{Project, RepositoryEntry};
+use recent_projects::RecentProjects;
use std::sync::Arc;
use theme::{ActiveTheme, PlayerColors};
use ui::{
@@ -14,7 +16,7 @@ use ui::{
IconButton, IconElement, KeyBinding, Tooltip,
};
use util::ResultExt;
-use workspace::{notifications::NotifyResultExt, Workspace};
+use workspace::{notifications::NotifyResultExt, Workspace, WORKSPACE_DB};
const MAX_PROJECT_NAME_LENGTH: usize = 40;
const MAX_BRANCH_NAME_LENGTH: usize = 40;
@@ -49,7 +51,7 @@ pub struct CollabTitlebarItem {
client: Arc<Client>,
workspace: WeakView<Workspace>,
//branch_popover: Option<ViewHandle<BranchList>>,
- //project_popover: Option<ViewHandle<recent_projects::RecentProjects>>,
+ project_popover: Option<recent_projects::RecentProjects>,
//user_menu: ViewHandle<ContextMenu>,
_subscriptions: Vec<Subscription>,
}
@@ -328,7 +330,7 @@ impl CollabTitlebarItem {
// menu
// }),
// branch_popover: None,
- // project_popover: None,
+ project_popover: None,
_subscriptions: subscriptions,
}
}
@@ -366,11 +368,27 @@ impl CollabTitlebarItem {
let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH);
- div().border().border_color(gpui::red()).child(
- Button::new("project_name_trigger", name)
- .style(ButtonStyle::Subtle)
- .tooltip(move |cx| Tooltip::text("Recent Projects", cx)),
- )
+ div()
+ .border()
+ .border_color(gpui::red())
+ .child(
+ Button::new("project_name_trigger", name)
+ .style(ButtonStyle::Subtle)
+ .tooltip(move |cx| Tooltip::text("Recent Projects", cx))
+ .on_click(cx.listener(|this, _, cx| {
+ this.toggle_project_menu(&ToggleProjectMenu, cx);
+ })),
+ )
+ .children(self.project_popover.as_ref().map(|popover| {
+ overlay().child(
+ div()
+ .min_w_56()
+ .on_mouse_down_out(cx.listener_for(&popover.picker, |picker, _, cx| {
+ picker.cancel(&Default::default(), cx)
+ }))
+ .child(popover.picker.clone()),
+ )
+ }))
}
pub fn render_project_branch(&self, cx: &mut ViewContext<Self>) -> Option<impl Element> {
@@ -611,43 +629,40 @@ impl CollabTitlebarItem {
// cx.notify();
// }
- // pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext<Self>) {
- // let workspace = self.workspace.clone();
- // if self.project_popover.take().is_none() {
- // cx.spawn(|this, mut cx| async move {
- // let workspaces = WORKSPACE_DB
- // .recent_workspaces_on_disk()
- // .await
- // .unwrap_or_default()
- // .into_iter()
- // .map(|(_, location)| location)
- // .collect();
-
- // let workspace = workspace.clone();
- // this.update(&mut cx, move |this, cx| {
- // let view = cx.add_view(|cx| build_recent_projects(workspace, workspaces, cx));
-
- // cx.subscribe(&view, |this, _, event, cx| {
- // match event {
- // PickerEvent::Dismiss => {
- // this.project_popover = None;
- // }
- // }
-
- // cx.notify();
- // })
- // .detach();
- // cx.focus(&view);
- // this.branch_popover.take();
- // this.project_popover = Some(view);
- // cx.notify();
- // })
- // .log_err();
- // })
- // .detach();
- // }
- // cx.notify();
- // }
+ pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext<Self>) {
+ let workspace = self.workspace.clone();
+ if self.project_popover.take().is_none() {
+ cx.spawn(|this, mut cx| async move {
+ let workspaces = WORKSPACE_DB
+ .recent_workspaces_on_disk()
+ .await
+ .unwrap_or_default()
+ .into_iter()
+ .map(|(_, location)| location)
+ .collect();
+
+ let workspace = workspace.clone();
+ this.update(&mut cx, move |this, cx| {
+ let view = RecentProjects::open_popover(workspace, workspaces, cx);
+
+ cx.subscribe(&view.picker, |this, _, _: &DismissEvent, cx| {
+ this.project_popover = None;
+ cx.notify();
+ })
+ .detach();
+ let focus_handle = view.focus_handle(cx);
+ cx.focus(&focus_handle);
+ // todo!()
+ //this.branch_popover.take();
+ this.project_popover = Some(view);
+ cx.notify();
+ })
+ .log_err();
+ })
+ .detach();
+ }
+ cx.notify();
+ }
// fn render_user_menu_button(
// &self,
@@ -1,8 +1,8 @@
use editor::Editor;
use gpui::{
- div, prelude::*, rems, uniform_list, AnyElement, AppContext, Div, FocusHandle, FocusableView,
- MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle, View, ViewContext,
- WindowContext,
+ div, prelude::*, rems, uniform_list, AnyElement, AppContext, DismissEvent, Div, EventEmitter,
+ FocusHandle, FocusableView, MouseButton, MouseDownEvent, Render, Task, UniformListScrollHandle,
+ View, ViewContext, WindowContext,
};
use std::{cmp, sync::Arc};
use ui::{prelude::*, v_stack, Color, Divider, Label};
@@ -113,8 +113,9 @@ impl<D: PickerDelegate> Picker<D> {
cx.notify();
}
- fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
+ pub fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
self.delegate.dismissed(cx);
+ cx.emit(DismissEvent);
}
fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
@@ -146,9 +147,15 @@ impl<D: PickerDelegate> Picker<D> {
event: &editor::EditorEvent,
cx: &mut ViewContext<Self>,
) {
- if let editor::EditorEvent::BufferEdited = event {
- let query = self.editor.read(cx).text(cx);
- self.update_matches(query, cx);
+ match event {
+ editor::EditorEvent::BufferEdited => {
+ let query = self.editor.read(cx).text(cx);
+ self.update_matches(query, cx);
+ }
+ editor::EditorEvent::Blurred => {
+ self.cancel(&menu::Cancel, cx);
+ }
+ _ => {}
}
}
@@ -189,6 +196,8 @@ impl<D: PickerDelegate> Picker<D> {
}
}
+impl<D: PickerDelegate> EventEmitter<DismissEvent> for Picker<D> {}
+
impl<D: PickerDelegate> Render for Picker<D> {
type Element = Div;
@@ -23,14 +23,15 @@ pub fn init(cx: &mut AppContext) {
cx.observe_new_views(RecentProjects::register).detach();
}
+#[derive(Clone)]
pub struct RecentProjects {
- picker: View<Picker<RecentProjectsDelegate>>,
+ pub picker: View<Picker<RecentProjectsDelegate>>,
}
impl ModalView for RecentProjects {}
impl RecentProjects {
- fn new(delegate: RecentProjectsDelegate, cx: &mut ViewContext<Self>) -> Self {
+ fn new(delegate: RecentProjectsDelegate, cx: &mut WindowContext<'_>) -> Self {
Self {
picker: cx.build_view(|cx| Picker::new(delegate, cx)),
}
@@ -86,6 +87,16 @@ impl RecentProjects {
Ok(())
}))
}
+ pub fn open_popover(
+ workspace: WeakView<Workspace>,
+ workspaces: Vec<WorkspaceLocation>,
+ cx: &mut WindowContext<'_>,
+ ) -> Self {
+ Self::new(
+ RecentProjectsDelegate::new(workspace, workspaces, false),
+ cx,
+ )
+ }
}
impl EventEmitter<DismissEvent> for RecentProjects {}
@@ -127,7 +138,7 @@ impl RecentProjectsDelegate {
}
}
}
-
+impl EventEmitter<DismissEvent> for RecentProjectsDelegate {}
impl PickerDelegate for RecentProjectsDelegate {
type ListItem = ListItem;
@@ -202,11 +213,11 @@ impl PickerDelegate for RecentProjectsDelegate {
.open_workspace_for_paths(workspace_location.paths().as_ref().clone(), cx)
})
.detach_and_log_err(cx);
- self.dismissed(cx);
+ cx.emit(DismissEvent);
}
}
- fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
+ fn dismissed(&mut self, _: &mut ViewContext<Picker<Self>>) {}
fn render_match(
&self,