diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 0e65eb4687..e1656b02ce 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -518,3 +518,11 @@ impl Element for () { ) { } } + +impl Render for () { + type Element = Self; + + fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { + () + } +} diff --git a/crates/recent_projects2/src/recent_projects.rs b/crates/recent_projects2/src/recent_projects.rs index db9f6208cd..64c1c934bc 100644 --- a/crates/recent_projects2/src/recent_projects.rs +++ b/crates/recent_projects2/src/recent_projects.rs @@ -29,7 +29,11 @@ pub struct RecentProjectsMenu { impl ModalView for RecentProjectsMenu {} impl RecentProjectsMenu { - fn new(delegate: RecentProjectsDelegate, rem_width: f32, cx: &mut ViewContext) -> Self { + pub fn new( + delegate: RecentProjectsDelegate, + rem_width: f32, + cx: &mut ViewContext, + ) -> Self { let picker = cx.build_view(|cx| Picker::new(delegate, cx)); let _subscription = cx.subscribe(&picker, |_, _, _, cx| cx.emit(DismissEvent)); // We do not want to block the UI on a potentially lenghty call to DB, so we're gonna swap diff --git a/crates/workspace2_ui/examples/titlebar.rs b/crates/workspace2_ui/examples/titlebar.rs index 7f29e59690..9d388572e0 100644 --- a/crates/workspace2_ui/examples/titlebar.rs +++ b/crates/workspace2_ui/examples/titlebar.rs @@ -1,11 +1,14 @@ use assets::Assets; use clap::Parser; -use gpui::{px, App, Bounds, Render, Size, VisualContext, WindowBounds, WindowOptions}; +use gpui::{ + px, App, Bounds, IntoElement, Render, Size, VisualContext, WindowBounds, WindowOptions, +}; use log::LevelFilter; use settings::Settings; use simplelog::SimpleLogger; use std::sync::Arc; use theme::{LoadThemes, ThemeRegistry, ThemeSettings}; +use workspace2_ui::{Branches, PeerId, ProjectHost, Titlebar}; #[derive(Parser)] struct Args { @@ -54,9 +57,30 @@ fn main() { struct TitlebarExample; impl Render for TitlebarExample { - type Element = (); + type Element = ::Element; fn render(&mut self, cx: &mut ui::prelude::ViewContext) -> Self::Element { - todo!() + let delegate = cx.build_view(|_| ()); + + Titlebar { + delegate: delegate.clone(), + full_screen: false, + project_host: Some(ProjectHost { + delegate: delegate.clone(), + id: PeerId(1), + login: "nathansobo".into(), + peer_index: todo!(), + }), + recent_projects: RecentProjects { + delegate: delegate.clone(), + current_project: "zed", + recent_projects: (), + }, + branch: Some(Branches { + current: "main".into(), + }), + collaborators: vec![], + } + .into_element() } } diff --git a/crates/workspace2_ui/src/titlebar.rs b/crates/workspace2_ui/src/titlebar.rs index daf7c1f386..5134de95eb 100644 --- a/crates/workspace2_ui/src/titlebar.rs +++ b/crates/workspace2_ui/src/titlebar.rs @@ -1,48 +1,69 @@ use gpui::{ - div, img, prelude::*, px, rems, AnyElement, DismissEvent, Div, EventEmitter, FocusHandle, - FocusableView, SharedString, Stateful, View, ViewContext, WindowContext, + div, img, prelude::*, px, rems, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView, + SharedString, Stateful, View, ViewContext, WindowContext, }; use theme::ActiveFabricTheme; -use ui::{Button, ButtonCommon, ButtonStyle, Clickable, Color, LabelSize, PopoverMenu, Tooltip}; +use ui::{ + popover_menu, Button, ButtonCommon, ButtonStyle, Clickable, Color, LabelSize, PopoverMenu, + Tooltip, +}; -pub struct PeerId(u32); +#[derive(Clone, Copy, Debug)] +pub struct PeerId(pub u32); + +#[derive(Clone, Copy, Debug)] +pub struct ProjectId(u64); pub trait TitlebarDelegate: 'static + Sized { fn toggle_following(&mut self, peer_index: PeerId, cx: &mut ViewContext); } impl TitlebarDelegate for () { - fn toggle_following(&mut self, peer: PeerId, cx: &mut ViewContext) { - log::info!("deploy host menu"); + fn toggle_following(&mut self, peer: PeerId, _cx: &mut ViewContext) { + log::info!("toggle following {:?}", peer); } } #[derive(IntoElement)] pub struct Titlebar { - delegate: Option>, - full_screen: bool, - project_host: Option>, - recent_projects: RecentProjects, - branch: Option, - collaborators: Vec, + pub delegate: View, + pub full_screen: bool, + pub project_host: Option>, + pub recent_projects: Projects, + pub branch: Option, + pub collaborators: Vec, } #[derive(IntoElement)] -struct ProjectHost { - delegate: Option>, - id: PeerId, - login: SharedString, - peer_index: u32, +pub struct ProjectHost { + pub delegate: View, + pub id: PeerId, + pub login: SharedString, + pub peer_index: u32, } #[derive(IntoElement)] -struct RecentProjects { +pub struct Projects { + pub delegate: View, + pub current: SharedString, + pub recent: Vec, +} + +#[derive(Clone)] +pub struct Project { + pub name: SharedString, + pub id: ProjectId, +} + +pub struct ProjectsMenu { delegate: View, - current_project: SharedString, - recent_projects: Vec, + focus: FocusHandle, + recent_projects: Vec, } -struct Branches {} +pub struct Branches { + pub current: SharedString, +} #[derive(IntoElement, Default)] pub struct FacePile { @@ -203,28 +224,22 @@ impl RenderOnce for ProjectHost { type Rendered = Button; fn render(self, _: &mut WindowContext) -> Self::Rendered { + let delegate = self.delegate; Button::new("project-host", self.login) .color(Color::Player(self.peer_index)) .style(ButtonStyle::Subtle) .label_size(LabelSize::Small) .tooltip(move |cx| Tooltip::text("Toggle following", cx)) - .when_some(self.delegate, |div, delegate| { - div.on_click(move |_, cx| { - let host_id = self.id; - delegate.update(cx, |this, cx| this.toggle_following(host_id, cx)) - }) + .on_click(move |_, cx| { + let host_id = self.id; + delegate.update(cx, |this, cx| this.toggle_following(host_id, cx)) }) } } -struct RecentProjectsMenu { - delegate: Option, - focus: FocusHandle, -} +impl EventEmitter for ProjectsMenu {} -impl EventEmitter for RecentProjectsMenu {} - -impl Render for RecentProjectsMenu { +impl Render for ProjectsMenu { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { @@ -232,18 +247,37 @@ impl Render for RecentProjectsMenu { } } -impl FocusableView for RecentProjectsMenu { +impl FocusableView for ProjectsMenu { fn focus_handle(&self, cx: &gpui::AppContext) -> gpui::FocusHandle { self.focus.clone() } } -impl RenderOnce for RecentProjects { - type Rendered = RecentProjectsMenu; +impl RenderOnce for Projects { + type Rendered = PopoverMenu>; - fn render(self, cx: &mut WindowContext) -> Self::Rendered { - todo!() - // PopoverMenu::new("recent-projects").trigger() + fn render(self, _cx: &mut WindowContext) -> Self::Rendered { + let delegate = self.delegate; + let recent_projects = self.recent; + + popover_menu("recent-projects") + .trigger( + Button::new("trigger", self.current) + .style(ButtonStyle::Subtle) + .label_size(LabelSize::Small) + .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), + ) + .menu(move |cx| { + if recent_projects.is_empty() { + None + } else { + Some(cx.build_view(|cx| ProjectsMenu { + delegate: delegate.clone(), + focus: cx.focus_handle(), + recent_projects: recent_projects.clone(), + })) + } + }) } }