From 92d2048aa4315713b46c7c731b51430e5989393f Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 00:28:05 -0500 Subject: [PATCH 01/13] WIP --- crates/collab_ui2/src/collab_titlebar_item.rs | 26 +++++++++++-- crates/ui2/src/components.rs | 2 + crates/ui2/src/components/popover_menu.rs | 39 +++++++++++++++++++ crates/workspace2/src/workspace2.rs | 2 + 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 crates/ui2/src/components/popover_menu.rs diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index d76242afa32e766ce5b885870e0fd20006ff6517..fc743585f53027fa8abf1670e9f0eafebe61b17b 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -37,7 +37,10 @@ use gpui::{ }; use project::Project; use theme::ActiveTheme; -use ui::{h_stack, prelude::*, Avatar, Button, ButtonStyle2, IconButton, KeyBinding, Tooltip}; +use ui::{ + h_stack, prelude::*, v_stack, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, + IconElement, KeyBinding, List, ListItem, PopoverMenu, Tooltip, +}; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -288,10 +291,25 @@ impl Render for CollabTitlebarItem { ), ) }) - .map(|this| { + .child(h_stack().px_1p5().map(|this| { if let Some(user) = current_user { this.when_some(user.avatar.clone(), |this, avatar| { - this.child(ui::Avatar::data(avatar)) + this.child( + PopoverMenu::new( + ButtonLike::new("user-menu") + .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( + IconElement::new(Icon::ChevronDown).color(Color::Muted), + )) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) + .into_any_element(), + ) + .children(vec![ + ListItem::new("foo"), + ListItem::new("bar"), + ListItem::new("baz"), + ]), + ) }) } else { this.child(Button::new("sign_in", "Sign in").on_click(move |_, cx| { @@ -305,7 +323,7 @@ impl Render for CollabTitlebarItem { .detach(); })) } - }) + })) } } diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index be95fc1fab6cc66edaef96f1a74622a01457e0f1..28dc8f3f06a65f9e091ca49146e320c741c162f6 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -9,6 +9,7 @@ mod keybinding; mod label; mod list; mod popover; +mod popover_menu; mod stack; mod tooltip; @@ -26,6 +27,7 @@ pub use keybinding::*; pub use label::*; pub use list::*; pub use popover::*; +pub use popover_menu::*; pub use stack::*; pub use tooltip::*; diff --git a/crates/ui2/src/components/popover_menu.rs b/crates/ui2/src/components/popover_menu.rs new file mode 100644 index 0000000000000000000000000000000000000000..a0431c57b326fa4be2c3adcdd421cc52bd7269ac --- /dev/null +++ b/crates/ui2/src/components/popover_menu.rs @@ -0,0 +1,39 @@ +use gpui::{ + div, overlay, AnyElement, Div, Element, ElementId, IntoElement, ParentElement, RenderOnce, + Styled, WindowContext, +}; +use smallvec::SmallVec; + +use crate::{prelude::*, ElevationIndex, List, Popover}; + +#[derive(IntoElement)] +pub struct PopoverMenu { + trigger: AnyElement, + children: SmallVec<[AnyElement; 2]>, +} + +impl RenderOnce for PopoverMenu { + type Rendered = Div; + + fn render(self, cx: &mut WindowContext) -> Self::Rendered { + div() + .relative() + .child(self.trigger) + .child(overlay().child(Popover::new().children(self.children))) + } +} + +impl PopoverMenu { + pub fn new(trigger: AnyElement) -> Self { + Self { + trigger, + children: SmallVec::new(), + } + } +} + +impl ParentElement for PopoverMenu { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + &mut self.children + } +} diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 23907f8dae882f0780e5a8ad351a96f74129c363..2f7d95c34437f9b571ebea9aeb9939c49d5d4e8c 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -3711,6 +3711,8 @@ impl Render for Workspace { .items_start() .text_color(cx.theme().colors().text) .bg(cx.theme().colors().background) + .border() + .border_color(cx.theme().colors().border) .children(self.titlebar_item.clone()) .child( div() From 82b3efa16c83c1555cf7217084a39ca38933512b Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 09:12:39 -0500 Subject: [PATCH 02/13] Update collab button styles --- crates/collab_ui2/src/collab_titlebar_item.rs | 126 ++++++++++-------- crates/ui2/src/components/popover_menu.rs | 11 +- 2 files changed, 75 insertions(+), 62 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index fc743585f53027fa8abf1670e9f0eafebe61b17b..c8076376f0c21bace8d978fdee3fecbf4af6c76a 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -239,54 +239,74 @@ impl Render for CollabTitlebarItem { .when(is_in_room, |this| { this.child( h_stack() + .gap_1() .child( h_stack() - .child(Button::new( - "toggle_sharing", - if is_shared { "Unshare" } else { "Share" }, - )) - .child(IconButton::new("leave-call", ui::Icon::Exit).on_click({ - let workspace = workspace.clone(); - move |_, cx| { - workspace - .update(cx, |this, cx| { - this.call_state().hang_up(cx).detach(); - }) - .log_err(); - } - })), + .gap_1() + .child( + Button::new( + "toggle_sharing", + if is_shared { "Unshare" } else { "Share" }, + ) + .style(ButtonStyle2::Subtle), + ) + .child( + IconButton::new("leave-call", ui::Icon::Exit) + .style(ButtonStyle2::Subtle) + .on_click({ + let workspace = workspace.clone(); + move |_, cx| { + workspace + .update(cx, |this, cx| { + this.call_state().hang_up(cx).detach(); + }) + .log_err(); + } + }), + ), ) .child( h_stack() - .child(IconButton::new("mute-microphone", mic_icon).on_click({ - let workspace = workspace.clone(); - move |_, cx| { - workspace - .update(cx, |this, cx| { - this.call_state().toggle_mute(cx); - }) - .log_err(); - } - })) - .child(IconButton::new("mute-sound", speakers_icon).on_click({ - let workspace = workspace.clone(); - move |_, cx| { - workspace - .update(cx, |this, cx| { - this.call_state().toggle_deafen(cx); - }) - .log_err(); - } - })) - .child(IconButton::new("screen-share", ui::Icon::Screen).on_click( - move |_, cx| { - workspace - .update(cx, |this, cx| { - this.call_state().toggle_screen_share(cx); - }) - .log_err(); - }, - )) + .gap_1() + .child( + IconButton::new("mute-microphone", mic_icon) + .style(ButtonStyle2::Subtle) + .on_click({ + let workspace = workspace.clone(); + move |_, cx| { + workspace + .update(cx, |this, cx| { + this.call_state().toggle_mute(cx); + }) + .log_err(); + } + }), + ) + .child( + IconButton::new("mute-sound", speakers_icon) + .style(ButtonStyle2::Subtle) + .on_click({ + let workspace = workspace.clone(); + move |_, cx| { + workspace + .update(cx, |this, cx| { + this.call_state().toggle_deafen(cx); + }) + .log_err(); + } + }), + ) + .child( + IconButton::new("screen-share", ui::Icon::Screen) + .style(ButtonStyle2::Subtle) + .on_click(move |_, cx| { + workspace + .update(cx, |this, cx| { + this.call_state().toggle_screen_share(cx); + }) + .log_err(); + }), + ) .pl_2(), ), ) @@ -295,20 +315,14 @@ impl Render for CollabTitlebarItem { if let Some(user) = current_user { this.when_some(user.avatar.clone(), |this, avatar| { this.child( - PopoverMenu::new( - ButtonLike::new("user-menu") - .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( + ButtonLike::new("user-menu") + .child( + h_stack().gap_0p5().child(Avatar::data(avatar)).child( IconElement::new(Icon::ChevronDown).color(Color::Muted), - )) - .style(ButtonStyle2::Subtle) - .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) - .into_any_element(), - ) - .children(vec![ - ListItem::new("foo"), - ListItem::new("bar"), - ListItem::new("baz"), - ]), + ), + ) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), ) }) } else { diff --git a/crates/ui2/src/components/popover_menu.rs b/crates/ui2/src/components/popover_menu.rs index a0431c57b326fa4be2c3adcdd421cc52bd7269ac..17354e6ec6b1f527aa46bd2035fc2cf13246ae52 100644 --- a/crates/ui2/src/components/popover_menu.rs +++ b/crates/ui2/src/components/popover_menu.rs @@ -1,10 +1,9 @@ -use gpui::{ - div, overlay, AnyElement, Div, Element, ElementId, IntoElement, ParentElement, RenderOnce, - Styled, WindowContext, -}; +use gpui::{div, overlay, AnyElement, Div, ParentElement, RenderOnce, Styled, WindowContext}; use smallvec::SmallVec; -use crate::{prelude::*, ElevationIndex, List, Popover}; +use crate::{prelude::*, Popover}; + +// 🚧 Under Construction #[derive(IntoElement)] pub struct PopoverMenu { @@ -15,7 +14,7 @@ pub struct PopoverMenu { impl RenderOnce for PopoverMenu { type Rendered = Div; - fn render(self, cx: &mut WindowContext) -> Self::Rendered { + fn render(self, _cx: &mut WindowContext) -> Self::Rendered { div() .relative() .child(self.trigger) From daf6201debd7dfee0a8dfea1d98e02c3871189f5 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 09:35:37 -0500 Subject: [PATCH 03/13] Start plugging selected states into collab ui --- crates/collab_ui2/src/collab_titlebar_item.rs | 56 ++++++++++++------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index c8076376f0c21bace8d978fdee3fecbf4af6c76a..c93d5687a50165684b670c3ddc84248c409bd980 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -103,17 +103,18 @@ impl Render for CollabTitlebarItem { .update(cx, |this, cx| this.call_state().remote_participants(cx)) .log_err() .flatten(); - let mic_icon = if self + let is_muted = self .workspace .update(cx, |this, cx| this.call_state().is_muted(cx)) .log_err() .flatten() - .unwrap_or_default() - { - ui::Icon::MicMute - } else { - ui::Icon::Mic - }; + .unwrap_or_default(); + let is_deafened = self + .workspace + .update(cx, |this, cx| this.call_state().is_deafened(cx)) + .log_err() + .flatten() + .unwrap_or_default(); let speakers_icon = if self .workspace .update(cx, |this, cx| this.call_state().is_deafened(cx)) @@ -269,22 +270,39 @@ impl Render for CollabTitlebarItem { h_stack() .gap_1() .child( - IconButton::new("mute-microphone", mic_icon) - .style(ButtonStyle2::Subtle) - .on_click({ - let workspace = workspace.clone(); - move |_, cx| { - workspace - .update(cx, |this, cx| { - this.call_state().toggle_mute(cx); - }) - .log_err(); - } - }), + IconButton::new( + "mute-microphone", + if is_muted.clone() { + ui::Icon::MicMute + } else { + ui::Icon::Mic + }, + ) + .style(ButtonStyle2::Subtle) + .selected(is_muted.clone()) + .on_click({ + let workspace = workspace.clone(); + move |_, cx| { + workspace + .update(cx, |this, cx| { + this.call_state().toggle_mute(cx); + }) + .log_err(); + } + }), ) .child( IconButton::new("mute-sound", speakers_icon) .style(ButtonStyle2::Subtle) + .selected(is_deafened.clone()) + .tooltip(move |cx| { + Tooltip::with_meta( + "Deafen Audio", + None, + "Mic will be muted", + cx, + ) + }) .on_click({ let workspace = workspace.clone(); move |_, cx| { From e20309f560dec87c74a1ca9856b622d6a020c1ea Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 09:44:33 -0500 Subject: [PATCH 04/13] Update collab_titlebar_item.rs [no ci] --- crates/collab_ui2/src/collab_titlebar_item.rs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index c93d5687a50165684b670c3ddc84248c409bd980..52381926d93b5d4a2e1e2a53e34afeb0084921e7 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -151,18 +151,20 @@ impl Render for CollabTitlebarItem { h_stack() .gap_1() // TODO - Add player menu - .child( - div() - .border() - .border_color(gpui::red()) - .id("project_owner_indicator") - .child( - Button::new("player", "player") - .style(ButtonStyle2::Subtle) - .color(Some(Color::Player(0))), - ) - .tooltip(move |cx| Tooltip::text("Toggle following", cx)), - ) + .when(is_in_room, |this| { + this.child( + div() + .border() + .border_color(gpui::red()) + .id("project_owner_indicator") + .child( + Button::new("project_owner", "project_owner") + .style(ButtonStyle2::Subtle) + .color(Some(Color::Player(0))), + ) + .tooltip(move |cx| Tooltip::text("Toggle following", cx)), + ) + }) // TODO - Add project menu .child( div() From 8d4652a4dbe224c0ab8050a3e0e2ea3435eb8427 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 12:41:17 -0500 Subject: [PATCH 05/13] Scaffold out `render_project_owner` Co-Authored-By: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> --- crates/collab_ui2/src/collab_titlebar_item.rs | 85 +++++++++++++++---- 1 file changed, 68 insertions(+), 17 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index 52381926d93b5d4a2e1e2a53e34afeb0084921e7..ec7677cae79710cf3ad09edb28c4d5031504b69a 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -38,8 +38,8 @@ use gpui::{ use project::Project; use theme::ActiveTheme; use ui::{ - h_stack, prelude::*, v_stack, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, - IconElement, KeyBinding, List, ListItem, PopoverMenu, Tooltip, + h_stack, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, IconElement, + KeyBinding, Tooltip, }; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -150,21 +150,24 @@ impl Render for CollabTitlebarItem { .child( h_stack() .gap_1() - // TODO - Add player menu .when(is_in_room, |this| { - this.child( - div() - .border() - .border_color(gpui::red()) - .id("project_owner_indicator") - .child( - Button::new("project_owner", "project_owner") - .style(ButtonStyle2::Subtle) - .color(Some(Color::Player(0))), - ) - .tooltip(move |cx| Tooltip::text("Toggle following", cx)), - ) + this.children(self.render_project_owner(cx)) }) + // TODO - Add player menu + // .when(is_in_room, |this| { + // this.child( + // div() + // .border() + // .border_color(gpui::red()) + // .id("project_owner_indicator") + // .child( + // Button::new("project_owner", "project_owner") + // .style(ButtonStyle2::Subtle) + // .color(Some(Color::Player(0))), + // ) + // .tooltip(move |cx| Tooltip::text("Toggle following", cx)), + // ) + // }) // TODO - Add project menu .child( div() @@ -274,14 +277,14 @@ impl Render for CollabTitlebarItem { .child( IconButton::new( "mute-microphone", - if is_muted.clone() { + if is_muted { ui::Icon::MicMute } else { ui::Icon::Mic }, ) .style(ButtonStyle2::Subtle) - .selected(is_muted.clone()) + .selected(is_muted) .on_click({ let workspace = workspace.clone(); move |_, cx| { @@ -476,6 +479,54 @@ impl CollabTitlebarItem { } } + // resolve if you are in a room -> render_project_owner + // render_project_owner -> resolve if you are in a room -> Option + + pub fn render_project_owner(&self, cx: &mut ViewContext) -> Option { + // TODO: We can't finish implementing this until project sharing works + // - [ ] Show the project owner when the project is remote (maybe done) + // - [x] Show the project owner when the project is local + // - [ ] Show the project owner with a lock icon when the project is local and unshared + + let remote_id = self.project.read(cx).remote_id(); + let is_local = remote_id.is_none(); + let is_shared = self.project.read(cx).is_shared(); + let (user_name, participant_index) = { + if let Some(host) = self.project.read(cx).host() { + debug_assert!(!is_local); + let (Some(host_user), Some(participant_index)) = ( + self.user_store.read(cx).get_cached_user(host.user_id), + self.user_store + .read(cx) + .participant_indices() + .get(&host.user_id), + ) else { + return None; + }; + (host_user.github_login.clone(), participant_index.0) + } else { + debug_assert!(is_local); + let name = self + .user_store + .read(cx) + .current_user() + .map(|user| user.github_login.clone())?; + (name, 0) + } + }; + Some( + Button::new( + "project_owner_trigger", + format!("{user_name} ({})", !is_shared), + ) + .color(Color::Player(participant_index)) + .style(ButtonStyle2::Subtle) + .into_element(), + ) + + // add lock if you are in a locked project + } + // fn collect_title_root_names( // &self, // theme: Arc, From 679851e3496ecdcb172264efa76324d474dd0ed6 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 12:51:55 -0500 Subject: [PATCH 06/13] Add `render_project_name` and `render_project_branch` Co-Authored-By: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> --- crates/collab_ui2/src/collab_titlebar_item.rs | 152 +++++++++++------- 1 file changed, 96 insertions(+), 56 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index ec7677cae79710cf3ad09edb28c4d5031504b69a..38cdb73f85544ed9ec610b1df6fc1f0790043a95 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -35,7 +35,7 @@ use gpui::{ ParentElement, Render, RenderOnce, Stateful, StatefulInteractiveElement, Styled, Subscription, ViewContext, VisualContext, WeakView, WindowBounds, }; -use project::Project; +use project::{Project, RepositoryEntry}; use theme::ActiveTheme; use ui::{ h_stack, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, IconElement, @@ -46,8 +46,8 @@ use workspace::{notifications::NotifyResultExt, Workspace}; use crate::face_pile::FacePile; -// const MAX_PROJECT_NAME_LENGTH: usize = 40; -// const MAX_BRANCH_NAME_LENGTH: usize = 40; +const MAX_PROJECT_NAME_LENGTH: usize = 40; +const MAX_BRANCH_NAME_LENGTH: usize = 40; // actions!( // collab, @@ -153,58 +153,60 @@ impl Render for CollabTitlebarItem { .when(is_in_room, |this| { this.children(self.render_project_owner(cx)) }) - // TODO - Add player menu - // .when(is_in_room, |this| { - // this.child( - // div() - // .border() - // .border_color(gpui::red()) - // .id("project_owner_indicator") - // .child( - // Button::new("project_owner", "project_owner") - // .style(ButtonStyle2::Subtle) - // .color(Some(Color::Player(0))), - // ) - // .tooltip(move |cx| Tooltip::text("Toggle following", cx)), - // ) - // }) - // TODO - Add project menu - .child( - div() - .border() - .border_color(gpui::red()) - .id("titlebar_project_menu_button") - .child( - Button::new("project_name", "project_name") - .style(ButtonStyle2::Subtle), - ) - .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), - ) - // TODO - Add git menu - .child( - div() - .border() - .border_color(gpui::red()) - .id("titlebar_git_menu_button") - .child( - Button::new("branch_name", "branch_name") - .style(ButtonStyle2::Subtle) - .color(Some(Color::Muted)), - ) - .tooltip(move |cx| { - cx.build_view(|_| { - Tooltip::new("Recent Branches") - .key_binding(KeyBinding::new(gpui::KeyBinding::new( - "cmd-b", - // todo!() Replace with real action. - gpui::NoAction, - None, - ))) - .meta("Only local branches shown") - }) - .into() - }), - ), + .child(self.render_project_name(cx)) + .children(self.render_project_branch(cx)), + // TODO - Add player menu + // .when(is_in_room, |this| { + // this.child( + // div() + // .border() + // .border_color(gpui::red()) + // .id("project_owner_indicator") + // .child( + // Button::new("project_owner", "project_owner") + // .style(ButtonStyle2::Subtle) + // .color(Some(Color::Player(0))), + // ) + // .tooltip(move |cx| Tooltip::text("Toggle following", cx)), + // ) + // }) + // TODO - Add project menu + // .child( + // div() + // .border() + // .border_color(gpui::red()) + // .id("titlebar_project_menu_button") + // .child( + // Button::new("project_name", "project_name") + // .style(ButtonStyle2::Subtle), + // ) + // .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), + // ) + // TODO - Add git menu + // .child( + // div() + // .border() + // .border_color(gpui::red()) + // .id("titlebar_git_menu_button") + // .child( + // Button::new("branch_name", "branch_name") + // .style(ButtonStyle2::Subtle) + // .color(Some(Color::Muted)), + // ) + // .tooltip(move |cx| { + // cx.build_view(|_| { + // Tooltip::new("Recent Branches") + // .key_binding(KeyBinding::new(gpui::KeyBinding::new( + // "cmd-b", + // // todo!() Replace with real action. + // gpui::NoAction, + // None, + // ))) + // .meta("Only local branches shown") + // }) + // .into() + // }), + // ), ) .when_some( users.zip(current_user.clone()), @@ -523,8 +525,46 @@ impl CollabTitlebarItem { .style(ButtonStyle2::Subtle) .into_element(), ) + } + + pub fn render_project_name(&self, cx: &mut ViewContext) -> impl Element { + let name = { + let mut names = self.project.read(cx).visible_worktrees(cx).map(|worktree| { + let worktree = worktree.read(cx); + worktree.root_name() + }); - // add lock if you are in a locked project + names.next().unwrap_or("") + }; + + let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH); + + Button::new("project_name_trigger", name) + .style(ButtonStyle2::Subtle) + .into_element() + } + + pub fn render_project_branch(&self, cx: &mut ViewContext) -> Option { + let entry = { + let mut names_and_branches = + self.project.read(cx).visible_worktrees(cx).map(|worktree| { + let worktree = worktree.read(cx); + worktree.root_git_entry() + }); + + names_and_branches.next().flatten() + }; + + let branch_name = entry + .as_ref() + .and_then(RepositoryEntry::branch) + .map(|branch| util::truncate_and_trailoff(&branch, MAX_BRANCH_NAME_LENGTH))?; + + Some( + Button::new("project_branch_trigger", branch_name) + .style(ButtonStyle2::Subtle) + .into_element(), + ) } // fn collect_title_root_names( From 5eb89781e3c10792c9899e79f0f183b4b1237588 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 13:11:20 -0500 Subject: [PATCH 07/13] Clean up left side titlebar buttons --- crates/collab_ui2/src/collab_titlebar_item.rs | 124 +++++++----------- crates/ui2/src/components/popover_menu.rs | 15 ++- 2 files changed, 63 insertions(+), 76 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index 38cdb73f85544ed9ec610b1df6fc1f0790043a95..bb49011f245acb5fd84c23167a060be075c318d5 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -39,7 +39,7 @@ use project::{Project, RepositoryEntry}; use theme::ActiveTheme; use ui::{ h_stack, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, IconElement, - KeyBinding, Tooltip, + KeyBinding, PopoverMenu, Tooltip, }; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -155,58 +155,6 @@ impl Render for CollabTitlebarItem { }) .child(self.render_project_name(cx)) .children(self.render_project_branch(cx)), - // TODO - Add player menu - // .when(is_in_room, |this| { - // this.child( - // div() - // .border() - // .border_color(gpui::red()) - // .id("project_owner_indicator") - // .child( - // Button::new("project_owner", "project_owner") - // .style(ButtonStyle2::Subtle) - // .color(Some(Color::Player(0))), - // ) - // .tooltip(move |cx| Tooltip::text("Toggle following", cx)), - // ) - // }) - // TODO - Add project menu - // .child( - // div() - // .border() - // .border_color(gpui::red()) - // .id("titlebar_project_menu_button") - // .child( - // Button::new("project_name", "project_name") - // .style(ButtonStyle2::Subtle), - // ) - // .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), - // ) - // TODO - Add git menu - // .child( - // div() - // .border() - // .border_color(gpui::red()) - // .id("titlebar_git_menu_button") - // .child( - // Button::new("branch_name", "branch_name") - // .style(ButtonStyle2::Subtle) - // .color(Some(Color::Muted)), - // ) - // .tooltip(move |cx| { - // cx.build_view(|_| { - // Tooltip::new("Recent Branches") - // .key_binding(KeyBinding::new(gpui::KeyBinding::new( - // "cmd-b", - // // todo!() Replace with real action. - // gpui::NoAction, - // None, - // ))) - // .meta("Only local branches shown") - // }) - // .into() - // }), - // ), ) .when_some( users.zip(current_user.clone()), @@ -340,15 +288,27 @@ impl Render for CollabTitlebarItem { if let Some(user) = current_user { this.when_some(user.avatar.clone(), |this, avatar| { this.child( - ButtonLike::new("user-menu") - .child( - h_stack().gap_0p5().child(Avatar::data(avatar)).child( + PopoverMenu::new( + ButtonLike::new("user-menu") + .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( IconElement::new(Icon::ChevronDown).color(Color::Muted), - ), - ) - .style(ButtonStyle2::Subtle) - .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + )) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) + .into_any_element(), + ) + .children(vec![div().w_96().h_96().bg(gpui::red())]), ) + // this.child( + // ButtonLike::new("user-menu") + // .child( + // h_stack().gap_0p5().child(Avatar::data(avatar)).child( + // IconElement::new(Icon::ChevronDown).color(Color::Muted), + // ), + // ) + // .style(ButtonStyle2::Subtle) + // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + // ) }) } else { this.child(Button::new("sign_in", "Sign in").on_click(move |_, cx| { @@ -517,13 +477,15 @@ impl CollabTitlebarItem { } }; Some( - Button::new( - "project_owner_trigger", - format!("{user_name} ({})", !is_shared), - ) - .color(Color::Player(participant_index)) - .style(ButtonStyle2::Subtle) - .into_element(), + div().border().border_color(gpui::red()).child( + Button::new( + "project_owner_trigger", + format!("{user_name} ({})", !is_shared), + ) + .color(Color::Player(participant_index)) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle following", cx)), + ), ) } @@ -539,9 +501,11 @@ impl CollabTitlebarItem { let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH); - Button::new("project_name_trigger", name) - .style(ButtonStyle2::Subtle) - .into_element() + div().border().border_color(gpui::red()).child( + Button::new("project_name_trigger", name) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), + ) } pub fn render_project_branch(&self, cx: &mut ViewContext) -> Option { @@ -561,9 +525,23 @@ impl CollabTitlebarItem { .map(|branch| util::truncate_and_trailoff(&branch, MAX_BRANCH_NAME_LENGTH))?; Some( - Button::new("project_branch_trigger", branch_name) - .style(ButtonStyle2::Subtle) - .into_element(), + div().border().border_color(gpui::red()).child( + Button::new("project_branch_trigger", branch_name) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| { + cx.build_view(|_| { + Tooltip::new("Recent Branches") + .key_binding(KeyBinding::new(gpui::KeyBinding::new( + "cmd-b", + // todo!() Replace with real action. + gpui::NoAction, + None, + ))) + .meta("Local branches only") + }) + .into() + }), + ), ) } diff --git a/crates/ui2/src/components/popover_menu.rs b/crates/ui2/src/components/popover_menu.rs index 17354e6ec6b1f527aa46bd2035fc2cf13246ae52..c00bfed92120eb2363afb0c2a2da451b6fd292ea 100644 --- a/crates/ui2/src/components/popover_menu.rs +++ b/crates/ui2/src/components/popover_menu.rs @@ -1,4 +1,4 @@ -use gpui::{div, overlay, AnyElement, Div, ParentElement, RenderOnce, Styled, WindowContext}; +use gpui::{div, overlay, px, AnyElement, Div, ParentElement, RenderOnce, Styled, WindowContext}; use smallvec::SmallVec; use crate::{prelude::*, Popover}; @@ -16,9 +16,18 @@ impl RenderOnce for PopoverMenu { fn render(self, _cx: &mut WindowContext) -> Self::Rendered { div() + .bg(gpui::green()) .relative() - .child(self.trigger) - .child(overlay().child(Popover::new().children(self.children))) + .child(div().bg(gpui::blue()).child(self.trigger)) + .child( + overlay() + .position(gpui::Point { + x: px(100.), + y: px(100.), + }) + .anchor(gpui::AnchorCorner::TopRight) + .child(Popover::new().children(self.children)), + ) } } From 5fdfdb046cbe9dc6da8017b54af80f62cdfbd3be Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 13:13:22 -0500 Subject: [PATCH 08/13] Remove unused import --- crates/collab_ui2/src/collab_titlebar_item.rs | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index bb49011f245acb5fd84c23167a060be075c318d5..ab042d6f0db26414a8b2ba185691ee47ad2ede96 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -39,7 +39,7 @@ use project::{Project, RepositoryEntry}; use theme::ActiveTheme; use ui::{ h_stack, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, IconElement, - KeyBinding, PopoverMenu, Tooltip, + KeyBinding, Tooltip, }; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -287,28 +287,30 @@ impl Render for CollabTitlebarItem { .child(h_stack().px_1p5().map(|this| { if let Some(user) = current_user { this.when_some(user.avatar.clone(), |this, avatar| { - this.child( - PopoverMenu::new( - ButtonLike::new("user-menu") - .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( - IconElement::new(Icon::ChevronDown).color(Color::Muted), - )) - .style(ButtonStyle2::Subtle) - .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) - .into_any_element(), - ) - .children(vec![div().w_96().h_96().bg(gpui::red())]), - ) + // TODO: Finish implementing user menu popover + // // this.child( - // ButtonLike::new("user-menu") - // .child( - // h_stack().gap_0p5().child(Avatar::data(avatar)).child( + // PopoverMenu::new( + // ButtonLike::new("user-menu") + // .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( // IconElement::new(Icon::ChevronDown).color(Color::Muted), - // ), - // ) - // .style(ButtonStyle2::Subtle) - // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + // )) + // .style(ButtonStyle2::Subtle) + // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) + // .into_any_element(), + // ) + // .children(vec![div().w_96().h_96().bg(gpui::red())]), // ) + this.child( + ButtonLike::new("user-menu") + .child( + h_stack().gap_0p5().child(Avatar::data(avatar)).child( + IconElement::new(Icon::ChevronDown).color(Color::Muted), + ), + ) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + ) }) } else { this.child(Button::new("sign_in", "Sign in").on_click(move |_, cx| { From 180ba42456ed8d86164158b237ffc82f76998e54 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 14:54:44 -0500 Subject: [PATCH 09/13] WIP update popover_menu --- crates/collab_ui2/src/collab_titlebar_item.rs | 41 +++++------ crates/ui2/src/components/popover_menu.rs | 71 ++++++++++++++++--- 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index ab042d6f0db26414a8b2ba185691ee47ad2ede96..d1d560fcddd863dd1e55a7faa3cc4d5e9ea2505b 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -39,7 +39,7 @@ use project::{Project, RepositoryEntry}; use theme::ActiveTheme; use ui::{ h_stack, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, IconElement, - KeyBinding, Tooltip, + KeyBinding, PopoverMenu, Tooltip, }; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -289,28 +289,29 @@ impl Render for CollabTitlebarItem { this.when_some(user.avatar.clone(), |this, avatar| { // TODO: Finish implementing user menu popover // - // this.child( - // PopoverMenu::new( - // ButtonLike::new("user-menu") - // .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( - // IconElement::new(Icon::ChevronDown).color(Color::Muted), - // )) - // .style(ButtonStyle2::Subtle) - // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) - // .into_any_element(), - // ) - // .children(vec![div().w_96().h_96().bg(gpui::red())]), - // ) this.child( - ButtonLike::new("user-menu") - .child( - h_stack().gap_0p5().child(Avatar::data(avatar)).child( + PopoverMenu::new( + ButtonLike::new("user-menu") + .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( IconElement::new(Icon::ChevronDown).color(Color::Muted), - ), - ) - .style(ButtonStyle2::Subtle) - .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + )) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) + .into_any_element(), + ) + .anchor(gpui::AnchorCorner::TopRight) + .children(vec![div().w_96().h_96().bg(gpui::red())]), ) + // this.child( + // ButtonLike::new("user-menu") + // .child( + // h_stack().gap_0p5().child(Avatar::data(avatar)).child( + // IconElement::new(Icon::ChevronDown).color(Color::Muted), + // ), + // ) + // .style(ButtonStyle2::Subtle) + // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + // ) }) } else { this.child(Button::new("sign_in", "Sign in").on_click(move |_, cx| { diff --git a/crates/ui2/src/components/popover_menu.rs b/crates/ui2/src/components/popover_menu.rs index c00bfed92120eb2363afb0c2a2da451b6fd292ea..9e393ffb34211ba90ee7c6ee2db22c624a0aa659 100644 --- a/crates/ui2/src/components/popover_menu.rs +++ b/crates/ui2/src/components/popover_menu.rs @@ -1,33 +1,70 @@ -use gpui::{div, overlay, px, AnyElement, Div, ParentElement, RenderOnce, Styled, WindowContext}; +use gpui::{ + div, overlay, rems, AnchorCorner, AnyElement, Div, ParentElement, RenderOnce, Styled, + WindowContext, +}; use smallvec::SmallVec; use crate::{prelude::*, Popover}; -// 🚧 Under Construction - #[derive(IntoElement)] pub struct PopoverMenu { + /// The element that triggers the popover menu when clicked + /// Usually a button trigger: AnyElement, + /// The content of the popover menu + /// This will automatically be wrapped in a [Popover] element children: SmallVec<[AnyElement; 2]>, + /// The direction the popover menu will open by default + /// + /// When not enough space is available in the default direction, + /// the popover menu will follow the rules of [gpui2::elements::overlay] + anchor: AnchorCorner, + /// Whether the popover menu is currently open + show_menu: bool, } impl RenderOnce for PopoverMenu { type Rendered = Div; fn render(self, _cx: &mut WindowContext) -> Self::Rendered { + // Default offset = 4px padding + 1px border + let offset = 5. / 16.; + + let (top, right, bottom, left) = match self.anchor { + AnchorCorner::TopRight => (None, Some(-offset), Some(-offset), None), + AnchorCorner::TopLeft => (None, None, Some(-offset), Some(-offset)), + AnchorCorner::BottomRight => (Some(-offset), Some(-offset), None, None), + AnchorCorner::BottomLeft => (Some(-offset), None, None, Some(-offset)), + }; + div() + .flex() + .flex_none() .bg(gpui::green()) .relative() - .child(div().bg(gpui::blue()).child(self.trigger)) .child( - overlay() - .position(gpui::Point { - x: px(100.), - y: px(100.), - }) - .anchor(gpui::AnchorCorner::TopRight) - .child(Popover::new().children(self.children)), + div() + .flex_none() + .relative() + .bg(gpui::blue()) + .child(self.trigger), ) + .when(self.show_menu, |this| { + this.child( + div() + .absolute() + .size_0() + .when_some(top, |this, t| this.top(rems(t))) + .when_some(right, |this, r| this.right(rems(r))) + .when_some(bottom, |this, b| this.bottom(rems(b))) + .when_some(left, |this, l| this.left(rems(l))) + .child( + overlay() + .anchor(AnchorCorner::TopRight) + .child(Popover::new().children(self.children)), + ), + ) + }) } } @@ -36,8 +73,20 @@ impl PopoverMenu { Self { trigger, children: SmallVec::new(), + anchor: AnchorCorner::TopLeft, + show_menu: false, } } + + pub fn anchor(mut self, anchor: AnchorCorner) -> Self { + self.anchor = anchor; + self + } + + pub fn show_menu(mut self, show_menu: bool) -> Self { + self.show_menu = show_menu; + self + } } impl ParentElement for PopoverMenu { From 164084c61cf1bd6a22530273e2a9a390c1c62b7e Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 30 Nov 2023 14:55:59 -0500 Subject: [PATCH 10/13] Update collab_titlebar_item.rs --- crates/collab_ui2/src/collab_titlebar_item.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index d1d560fcddd863dd1e55a7faa3cc4d5e9ea2505b..6af63301b9a3596e18449a94a64b21470dba0737 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -300,6 +300,8 @@ impl Render for CollabTitlebarItem { .into_any_element(), ) .anchor(gpui::AnchorCorner::TopRight) + // TODO: Show when trigger is clicked + .show_menu(true) .children(vec![div().w_96().h_96().bg(gpui::red())]), ) // this.child( From ebbbeca9a6122e6abdf127d8d70d881fe831d733 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 30 Nov 2023 16:13:44 -0700 Subject: [PATCH 11/13] Flesh out a popover control --- crates/collab_ui2/src/collab_titlebar_item.rs | 31 +- .../ui2/src/components/button/button_like.rs | 6 +- crates/ui2/src/components/popover_menu.rs | 285 +++++++++++++----- 3 files changed, 231 insertions(+), 91 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index 6af63301b9a3596e18449a94a64b21470dba0737..e4ca42867835aeab69eb8ba9cd2d30f8c2a4249c 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -38,8 +38,8 @@ use gpui::{ use project::{Project, RepositoryEntry}; use theme::ActiveTheme; use ui::{ - h_stack, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, Icon, IconButton, IconElement, - KeyBinding, PopoverMenu, Tooltip, + h_stack, popover_menu, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, ContextMenu, Icon, + IconButton, IconElement, KeyBinding, Tooltip, }; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -290,19 +290,20 @@ impl Render for CollabTitlebarItem { // TODO: Finish implementing user menu popover // this.child( - PopoverMenu::new( - ButtonLike::new("user-menu") - .child(h_stack().gap_0p5().child(Avatar::data(avatar)).child( - IconElement::new(Icon::ChevronDown).color(Color::Muted), - )) - .style(ButtonStyle2::Subtle) - .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)) - .into_any_element(), - ) - .anchor(gpui::AnchorCorner::TopRight) - // TODO: Show when trigger is clicked - .show_menu(true) - .children(vec![div().w_96().h_96().bg(gpui::red())]), + popover_menu("user-menu") + .menu(|cx| ContextMenu::build(cx, |menu, cx| menu.header("ADADA"))) + .trigger( + ButtonLike::new("user-menu") + .child( + h_stack().gap_0p5().child(Avatar::data(avatar)).child( + IconElement::new(Icon::ChevronDown) + .color(Color::Muted), + ), + ) + .style(ButtonStyle2::Subtle) + .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + ) + .anchor(gpui::AnchorCorner::TopRight), ) // this.child( // ButtonLike::new("user-menu") diff --git a/crates/ui2/src/components/button/button_like.rs b/crates/ui2/src/components/button/button_like.rs index 3c36feb59fa1c65ce0dcdc89badeb005ce710455..6885ac86e1679ade99379601ac102813e2538027 100644 --- a/crates/ui2/src/components/button/button_like.rs +++ b/crates/ui2/src/components/button/button_like.rs @@ -261,7 +261,11 @@ impl RenderOnce for ButtonLike { |this, on_click| this.on_click(move |event, cx| (on_click)(event, cx)), ) .when_some(self.tooltip, |this, tooltip| { - this.tooltip(move |cx| tooltip(cx)) + if !self.selected { + this.tooltip(move |cx| tooltip(cx)) + } else { + this + } }) .children(self.children) } diff --git a/crates/ui2/src/components/popover_menu.rs b/crates/ui2/src/components/popover_menu.rs index 9e393ffb34211ba90ee7c6ee2db22c624a0aa659..4b5144e7c7de468e823cd7e60d062083ea065386 100644 --- a/crates/ui2/src/components/popover_menu.rs +++ b/crates/ui2/src/components/popover_menu.rs @@ -1,96 +1,231 @@ +use std::{cell::RefCell, rc::Rc}; + use gpui::{ - div, overlay, rems, AnchorCorner, AnyElement, Div, ParentElement, RenderOnce, Styled, - WindowContext, + overlay, point, px, rems, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase, + Element, ElementId, InteractiveBounds, IntoElement, LayoutId, ManagedView, MouseDownEvent, + ParentElement, Pixels, Point, View, VisualContext, WindowContext, }; -use smallvec::SmallVec; - -use crate::{prelude::*, Popover}; - -#[derive(IntoElement)] -pub struct PopoverMenu { - /// The element that triggers the popover menu when clicked - /// Usually a button - trigger: AnyElement, - /// The content of the popover menu - /// This will automatically be wrapped in a [Popover] element - children: SmallVec<[AnyElement; 2]>, - /// The direction the popover menu will open by default - /// - /// When not enough space is available in the default direction, - /// the popover menu will follow the rules of [gpui2::elements::overlay] - anchor: AnchorCorner, - /// Whether the popover menu is currently open - show_menu: bool, -} -impl RenderOnce for PopoverMenu { - type Rendered = Div; +use crate::{Clickable, Selectable}; - fn render(self, _cx: &mut WindowContext) -> Self::Rendered { - // Default offset = 4px padding + 1px border - let offset = 5. / 16.; +pub trait PopoverTrigger: IntoElement + Clickable + Selectable + 'static {} - let (top, right, bottom, left) = match self.anchor { - AnchorCorner::TopRight => (None, Some(-offset), Some(-offset), None), - AnchorCorner::TopLeft => (None, None, Some(-offset), Some(-offset)), - AnchorCorner::BottomRight => (Some(-offset), Some(-offset), None, None), - AnchorCorner::BottomLeft => (Some(-offset), None, None, Some(-offset)), - }; +impl PopoverTrigger for T {} - div() - .flex() - .flex_none() - .bg(gpui::green()) - .relative() - .child( - div() - .flex_none() - .relative() - .bg(gpui::blue()) - .child(self.trigger), - ) - .when(self.show_menu, |this| { - this.child( - div() - .absolute() - .size_0() - .when_some(top, |this, t| this.top(rems(t))) - .when_some(right, |this, r| this.right(rems(r))) - .when_some(bottom, |this, b| this.bottom(rems(b))) - .when_some(left, |this, l| this.left(rems(l))) - .child( - overlay() - .anchor(AnchorCorner::TopRight) - .child(Popover::new().children(self.children)), - ), - ) - }) - } +pub struct PopoverMenu { + id: ElementId, + child_builder: Option< + Box< + dyn FnOnce( + Rc>>>, + Option View + 'static>>, + ) -> AnyElement + + 'static, + >, + >, + menu_builder: Option View + 'static>>, + anchor: AnchorCorner, + attach: Option, + offset: Option>, } -impl PopoverMenu { - pub fn new(trigger: AnyElement) -> Self { - Self { - trigger, - children: SmallVec::new(), - anchor: AnchorCorner::TopLeft, - show_menu: false, - } +impl PopoverMenu { + pub fn menu(mut self, f: impl Fn(&mut WindowContext) -> View + 'static) -> Self { + self.menu_builder = Some(Rc::new(f)); + self + } + + pub fn trigger(mut self, t: T) -> Self { + self.child_builder = Some(Box::new(|menu, builder| { + let open = menu.borrow().is_some(); + t.selected(open) + .when_some(builder, |el, builder| { + el.on_click({ + move |_, cx| { + let new_menu = (builder)(cx); + let menu2 = menu.clone(); + let previous_focus_handle = cx.focused(); + + cx.subscribe(&new_menu, move |modal, _: &DismissEvent, cx| { + if modal.focus_handle(cx).contains_focused(cx) { + if previous_focus_handle.is_some() { + cx.focus(&previous_focus_handle.as_ref().unwrap()) + } + } + *menu2.borrow_mut() = None; + cx.notify(); + }) + .detach(); + cx.focus_view(&new_menu); + *menu.borrow_mut() = Some(new_menu); + } + }) + }) + .into_any_element() + })); + self } + /// anchor defines which corner of the menu to anchor to the attachment point + /// (by default the cursor position, but see attach) pub fn anchor(mut self, anchor: AnchorCorner) -> Self { self.anchor = anchor; self } - pub fn show_menu(mut self, show_menu: bool) -> Self { - self.show_menu = show_menu; + /// attach defines which corner of the handle to attach the menu's anchor to + pub fn attach(mut self, attach: AnchorCorner) -> Self { + self.attach = Some(attach); self } + + /// offset offsets the position of the content by that many pixels. + pub fn offset(mut self, offset: Point) -> Self { + self.offset = Some(offset); + self + } + + fn resolved_attach(&self) -> AnchorCorner { + self.attach.unwrap_or_else(|| match self.anchor { + AnchorCorner::TopLeft => AnchorCorner::BottomLeft, + AnchorCorner::TopRight => AnchorCorner::BottomRight, + AnchorCorner::BottomLeft => AnchorCorner::TopLeft, + AnchorCorner::BottomRight => AnchorCorner::TopRight, + }) + } + + fn resolved_offset(&self, cx: &WindowContext) -> Point { + self.offset.unwrap_or_else(|| { + // Default offset = 4px padding + 1px border + let offset = rems(5. / 16.) * cx.rem_size(); + match self.anchor { + AnchorCorner::TopRight | AnchorCorner::BottomRight => point(offset, px(0.)), + AnchorCorner::TopLeft | AnchorCorner::BottomLeft => point(-offset, px(0.)), + } + }) + } +} + +pub fn popover_menu(id: impl Into) -> PopoverMenu { + PopoverMenu { + id: id.into(), + child_builder: None, + menu_builder: None, + anchor: AnchorCorner::TopLeft, + attach: None, + offset: None, + } +} + +pub struct PopoverMenuState { + child_layout_id: Option, + child_element: Option, + child_bounds: Option>, + menu_element: Option, + menu: Rc>>>, +} + +impl Element for PopoverMenu { + type State = PopoverMenuState; + + fn layout( + &mut self, + element_state: Option, + cx: &mut WindowContext, + ) -> (gpui::LayoutId, Self::State) { + let mut menu_layout_id = None; + + let (menu, child_bounds) = if let Some(element_state) = element_state { + (element_state.menu, element_state.child_bounds) + } else { + (Rc::default(), None) + }; + + let menu_element = menu.borrow_mut().as_mut().map(|menu| { + let mut overlay = overlay().snap_to_window().anchor(self.anchor); + + if let Some(child_bounds) = child_bounds { + overlay = overlay.position( + self.resolved_attach().corner(child_bounds) + self.resolved_offset(cx), + ); + } + + let mut element = overlay.child(menu.clone()).into_any(); + menu_layout_id = Some(element.layout(cx)); + element + }); + + let mut child_element = self + .child_builder + .take() + .map(|child_builder| (child_builder)(menu.clone(), self.menu_builder.clone())); + + let child_layout_id = child_element + .as_mut() + .map(|child_element| child_element.layout(cx)); + + let layout_id = cx.request_layout( + &gpui::Style::default(), + menu_layout_id.into_iter().chain(child_layout_id), + ); + + ( + layout_id, + PopoverMenuState { + menu, + child_element, + child_layout_id, + menu_element, + child_bounds, + }, + ) + } + + fn paint( + self, + _: Bounds, + element_state: &mut Self::State, + cx: &mut WindowContext, + ) { + if let Some(child) = element_state.child_element.take() { + child.paint(cx); + } + + if let Some(child_layout_id) = element_state.child_layout_id.take() { + element_state.child_bounds = Some(cx.layout_bounds(child_layout_id)); + } + + if let Some(menu) = element_state.menu_element.take() { + menu.paint(cx); + + if let Some(child_bounds) = element_state.child_bounds { + let interactive_bounds = InteractiveBounds { + bounds: child_bounds, + stacking_order: cx.stacking_order().clone(), + }; + + // Mouse-downing outside the menu dismisses it, so we don't + // want a click on the toggle to re-open it. + cx.on_mouse_event(move |e: &MouseDownEvent, phase, cx| { + if phase == DispatchPhase::Bubble + && interactive_bounds.visibly_contains(&e.position, cx) + { + cx.stop_propagation() + } + }) + } + } + } } -impl ParentElement for PopoverMenu { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { - &mut self.children +impl IntoElement for PopoverMenu { + type Element = Self; + + fn element_id(&self) -> Option { + Some(self.id.clone()) + } + + fn into_element(self) -> Self::Element { + self } } From e1c8369b3dbc0e6188f3b758971069d16782f5c2 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 30 Nov 2023 16:39:43 -0700 Subject: [PATCH 12/13] Rename `menu_handle` to `right_click_menu` and `child` to `trigger` This makes things more in-line with `popover_menu`. --- crates/collab_ui2/src/collab_titlebar_item.rs | 2 +- crates/ui2/src/components.rs | 2 + crates/ui2/src/components/context_menu.rs | 178 +---------------- crates/ui2/src/components/right_click_menu.rs | 185 ++++++++++++++++++ .../src/components/stories/context_menu.rs | 42 +--- crates/workspace2/src/dock.rs | 12 +- 6 files changed, 206 insertions(+), 215 deletions(-) create mode 100644 crates/ui2/src/components/right_click_menu.rs diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index e4ca42867835aeab69eb8ba9cd2d30f8c2a4249c..a04b6a50aa7faed72b50d45d61ed31dedfeb5346 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -291,7 +291,7 @@ impl Render for CollabTitlebarItem { // this.child( popover_menu("user-menu") - .menu(|cx| ContextMenu::build(cx, |menu, cx| menu.header("ADADA"))) + .menu(|cx| ContextMenu::build(cx, |menu, _| menu.header("ADADA"))) .trigger( ButtonLike::new("user-menu") .child( diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index 28dc8f3f06a65f9e091ca49146e320c741c162f6..17271de48d4993c111c5cececd50499c6ef801b3 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -10,6 +10,7 @@ mod label; mod list; mod popover; mod popover_menu; +mod right_click_menu; mod stack; mod tooltip; @@ -28,6 +29,7 @@ pub use label::*; pub use list::*; pub use popover::*; pub use popover_menu::*; +pub use right_click_menu::*; pub use stack::*; pub use tooltip::*; diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index f071d188a12f8dc1b892215c11ba5e4c0ff650f5..562639ec5890a131918a411e239d3f886b196d4d 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -2,12 +2,11 @@ use crate::{ h_stack, prelude::*, v_stack, KeyBinding, Label, List, ListItem, ListSeparator, ListSubHeader, }; use gpui::{ - overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, DismissEvent, DispatchPhase, - Div, EventEmitter, FocusHandle, FocusableView, IntoElement, LayoutId, ManagedView, MouseButton, - MouseDownEvent, Pixels, Point, Render, View, VisualContext, + px, Action, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView, + IntoElement, Render, View, VisualContext, }; use menu::{SelectFirst, SelectLast, SelectNext, SelectPrev}; -use std::{cell::RefCell, rc::Rc}; +use std::rc::Rc; pub enum ContextMenuItem { Separator, @@ -208,174 +207,3 @@ impl Render for ContextMenu { ) } } - -pub struct MenuHandle { - id: ElementId, - child_builder: Option AnyElement + 'static>>, - menu_builder: Option View + 'static>>, - anchor: Option, - attach: Option, -} - -impl MenuHandle { - pub fn menu(mut self, f: impl Fn(&mut WindowContext) -> View + 'static) -> Self { - self.menu_builder = Some(Rc::new(f)); - self - } - - pub fn child(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self { - self.child_builder = Some(Box::new(|b| f(b).into_element().into_any())); - self - } - - /// anchor defines which corner of the menu to anchor to the attachment point - /// (by default the cursor position, but see attach) - pub fn anchor(mut self, anchor: AnchorCorner) -> Self { - self.anchor = Some(anchor); - self - } - - /// attach defines which corner of the handle to attach the menu's anchor to - pub fn attach(mut self, attach: AnchorCorner) -> Self { - self.attach = Some(attach); - self - } -} - -pub fn menu_handle(id: impl Into) -> MenuHandle { - MenuHandle { - id: id.into(), - child_builder: None, - menu_builder: None, - anchor: None, - attach: None, - } -} - -pub struct MenuHandleState { - menu: Rc>>>, - position: Rc>>, - child_layout_id: Option, - child_element: Option, - menu_element: Option, -} - -impl Element for MenuHandle { - type State = MenuHandleState; - - fn layout( - &mut self, - element_state: Option, - cx: &mut WindowContext, - ) -> (gpui::LayoutId, Self::State) { - let (menu, position) = if let Some(element_state) = element_state { - (element_state.menu, element_state.position) - } else { - (Rc::default(), Rc::default()) - }; - - let mut menu_layout_id = None; - - let menu_element = menu.borrow_mut().as_mut().map(|menu| { - let mut overlay = overlay().snap_to_window(); - if let Some(anchor) = self.anchor { - overlay = overlay.anchor(anchor); - } - overlay = overlay.position(*position.borrow()); - - let mut element = overlay.child(menu.clone()).into_any(); - menu_layout_id = Some(element.layout(cx)); - element - }); - - let mut child_element = self - .child_builder - .take() - .map(|child_builder| (child_builder)(menu.borrow().is_some())); - - let child_layout_id = child_element - .as_mut() - .map(|child_element| child_element.layout(cx)); - - let layout_id = cx.request_layout( - &gpui::Style::default(), - menu_layout_id.into_iter().chain(child_layout_id), - ); - - ( - layout_id, - MenuHandleState { - menu, - position, - child_element, - child_layout_id, - menu_element, - }, - ) - } - - fn paint( - self, - bounds: Bounds, - element_state: &mut Self::State, - cx: &mut WindowContext, - ) { - if let Some(child) = element_state.child_element.take() { - child.paint(cx); - } - - if let Some(menu) = element_state.menu_element.take() { - menu.paint(cx); - return; - } - - let Some(builder) = self.menu_builder else { - return; - }; - let menu = element_state.menu.clone(); - let position = element_state.position.clone(); - let attach = self.attach.clone(); - let child_layout_id = element_state.child_layout_id.clone(); - - cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| { - if phase == DispatchPhase::Bubble - && event.button == MouseButton::Right - && bounds.contains_point(&event.position) - { - cx.stop_propagation(); - cx.prevent_default(); - - let new_menu = (builder)(cx); - let menu2 = menu.clone(); - cx.subscribe(&new_menu, move |_modal, _: &DismissEvent, cx| { - *menu2.borrow_mut() = None; - cx.notify(); - }) - .detach(); - cx.focus_view(&new_menu); - *menu.borrow_mut() = Some(new_menu); - - *position.borrow_mut() = if attach.is_some() && child_layout_id.is_some() { - attach - .unwrap() - .corner(cx.layout_bounds(child_layout_id.unwrap())) - } else { - cx.mouse_position() - }; - cx.notify(); - } - }); - } -} - -impl IntoElement for MenuHandle { - type Element = Self; - - fn element_id(&self) -> Option { - Some(self.id.clone()) - } - - fn into_element(self) -> Self::Element { - self - } -} diff --git a/crates/ui2/src/components/right_click_menu.rs b/crates/ui2/src/components/right_click_menu.rs new file mode 100644 index 0000000000000000000000000000000000000000..27c4fdab960f93bf9ac950c455d62d90f4ce049e --- /dev/null +++ b/crates/ui2/src/components/right_click_menu.rs @@ -0,0 +1,185 @@ +use std::{cell::RefCell, rc::Rc}; + +use gpui::{ + overlay, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase, Element, ElementId, + IntoElement, LayoutId, ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, + View, VisualContext, WindowContext, +}; + +pub struct RightClickMenu { + id: ElementId, + child_builder: Option AnyElement + 'static>>, + menu_builder: Option View + 'static>>, + anchor: Option, + attach: Option, +} + +impl RightClickMenu { + pub fn menu(mut self, f: impl Fn(&mut WindowContext) -> View + 'static) -> Self { + self.menu_builder = Some(Rc::new(f)); + self + } + + pub fn trigger(mut self, e: E) -> Self { + self.child_builder = Some(Box::new(move |_| e.into_any_element())); + self + } + + /// anchor defines which corner of the menu to anchor to the attachment point + /// (by default the cursor position, but see attach) + pub fn anchor(mut self, anchor: AnchorCorner) -> Self { + self.anchor = Some(anchor); + self + } + + /// attach defines which corner of the handle to attach the menu's anchor to + pub fn attach(mut self, attach: AnchorCorner) -> Self { + self.attach = Some(attach); + self + } +} + +pub fn right_click_menu(id: impl Into) -> RightClickMenu { + RightClickMenu { + id: id.into(), + child_builder: None, + menu_builder: None, + anchor: None, + attach: None, + } +} + +pub struct MenuHandleState { + menu: Rc>>>, + position: Rc>>, + child_layout_id: Option, + child_element: Option, + menu_element: Option, +} + +impl Element for RightClickMenu { + type State = MenuHandleState; + + fn layout( + &mut self, + element_state: Option, + cx: &mut WindowContext, + ) -> (gpui::LayoutId, Self::State) { + let (menu, position) = if let Some(element_state) = element_state { + (element_state.menu, element_state.position) + } else { + (Rc::default(), Rc::default()) + }; + + let mut menu_layout_id = None; + + let menu_element = menu.borrow_mut().as_mut().map(|menu| { + let mut overlay = overlay().snap_to_window(); + if let Some(anchor) = self.anchor { + overlay = overlay.anchor(anchor); + } + overlay = overlay.position(*position.borrow()); + + let mut element = overlay.child(menu.clone()).into_any(); + menu_layout_id = Some(element.layout(cx)); + element + }); + + let mut child_element = self + .child_builder + .take() + .map(|child_builder| (child_builder)(menu.borrow().is_some())); + + let child_layout_id = child_element + .as_mut() + .map(|child_element| child_element.layout(cx)); + + let layout_id = cx.request_layout( + &gpui::Style::default(), + menu_layout_id.into_iter().chain(child_layout_id), + ); + + ( + layout_id, + MenuHandleState { + menu, + position, + child_element, + child_layout_id, + menu_element, + }, + ) + } + + fn paint( + self, + bounds: Bounds, + element_state: &mut Self::State, + cx: &mut WindowContext, + ) { + if let Some(child) = element_state.child_element.take() { + child.paint(cx); + } + + if let Some(menu) = element_state.menu_element.take() { + menu.paint(cx); + return; + } + + let Some(builder) = self.menu_builder else { + return; + }; + let menu = element_state.menu.clone(); + let position = element_state.position.clone(); + let attach = self.attach.clone(); + let child_layout_id = element_state.child_layout_id.clone(); + + cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| { + if phase == DispatchPhase::Bubble + && event.button == MouseButton::Right + && bounds.contains_point(&event.position) + { + cx.stop_propagation(); + cx.prevent_default(); + + let new_menu = (builder)(cx); + let menu2 = menu.clone(); + let previous_focus_handle = cx.focused(); + + cx.subscribe(&new_menu, move |modal, _: &DismissEvent, cx| { + if modal.focus_handle(cx).contains_focused(cx) { + if previous_focus_handle.is_some() { + cx.focus(&previous_focus_handle.as_ref().unwrap()) + } + } + *menu2.borrow_mut() = None; + cx.notify(); + }) + .detach(); + cx.focus_view(&new_menu); + *menu.borrow_mut() = Some(new_menu); + + *position.borrow_mut() = if attach.is_some() && child_layout_id.is_some() { + attach + .unwrap() + .corner(cx.layout_bounds(child_layout_id.unwrap())) + } else { + cx.mouse_position() + }; + cx.notify(); + } + }); + } +} + +impl IntoElement for RightClickMenu { + type Element = Self; + + fn element_id(&self) -> Option { + Some(self.id.clone()) + } + + fn into_element(self) -> Self::Element { + self + } +} diff --git a/crates/ui2/src/components/stories/context_menu.rs b/crates/ui2/src/components/stories/context_menu.rs index d5fb94df4f0f413dd117e3bc2321e5251c6dffda..dd1fe8d565adcd479e3605c14eda6e1c5b6e4125 100644 --- a/crates/ui2/src/components/stories/context_menu.rs +++ b/crates/ui2/src/components/stories/context_menu.rs @@ -2,7 +2,7 @@ use gpui::{actions, Action, AnchorCorner, Div, Render, View}; use story::Story; use crate::prelude::*; -use crate::{menu_handle, ContextMenu, Label}; +use crate::{right_click_menu, ContextMenu, Label}; actions!(PrintCurrentDate, PrintBestFood); @@ -45,25 +45,13 @@ impl Render for ContextMenuStory { .flex_col() .justify_between() .child( - menu_handle("test2") - .child(|is_open| { - Label::new(if is_open { - "TOP LEFT" - } else { - "RIGHT CLICK ME" - }) - }) + right_click_menu("test2") + .trigger(Label::new("TOP LEFT")) .menu(move |cx| build_menu(cx, "top left")), ) .child( - menu_handle("test1") - .child(|is_open| { - Label::new(if is_open { - "BOTTOM LEFT" - } else { - "RIGHT CLICK ME" - }) - }) + right_click_menu("test1") + .trigger(Label::new("BOTTOM LEFT")) .anchor(AnchorCorner::BottomLeft) .attach(AnchorCorner::TopLeft) .menu(move |cx| build_menu(cx, "bottom left")), @@ -75,26 +63,14 @@ impl Render for ContextMenuStory { .flex_col() .justify_between() .child( - menu_handle("test3") - .child(|is_open| { - Label::new(if is_open { - "TOP RIGHT" - } else { - "RIGHT CLICK ME" - }) - }) + right_click_menu("test3") + .trigger(Label::new("TOP RIGHT")) .anchor(AnchorCorner::TopRight) .menu(move |cx| build_menu(cx, "top right")), ) .child( - menu_handle("test4") - .child(|is_open| { - Label::new(if is_open { - "BOTTOM RIGHT" - } else { - "RIGHT CLICK ME" - }) - }) + right_click_menu("test4") + .trigger(Label::new("BOTTOM RIGHT")) .anchor(AnchorCorner::BottomRight) .attach(AnchorCorner::TopRight) .menu(move |cx| build_menu(cx, "bottom right")), diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index 06fdf7f9c160407b47d9102daeac97f9cd9d00a1..437e7c01926a460bed320f17b6e943966d714d48 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -7,8 +7,8 @@ use gpui::{ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; -use ui::prelude::*; -use ui::{h_stack, menu_handle, ContextMenu, IconButton, Tooltip}; +use ui::{h_stack, ContextMenu, IconButton, Tooltip}; +use ui::{prelude::*, right_click_menu}; pub enum PanelEvent { ChangePosition, @@ -702,7 +702,7 @@ impl Render for PanelButtons { }; Some( - menu_handle(name) + right_click_menu(name) .menu(move |cx| { const POSITIONS: [DockPosition; 3] = [ DockPosition::Left, @@ -726,14 +726,14 @@ impl Render for PanelButtons { }) .anchor(menu_anchor) .attach(menu_attach) - .child(move |_is_open| { + .trigger( IconButton::new(name, icon) .selected(is_active_button) .action(action.boxed_clone()) .tooltip(move |cx| { Tooltip::for_action(tooltip.clone(), &*action, cx) - }) - }), + }), + ), ) }); From ab75dbe7aff021461be71735fef7f0016ca58d8f Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 1 Dec 2023 10:52:11 -0500 Subject: [PATCH 13/13] Update collab_titlebar_item.rs --- crates/collab_ui2/src/collab_titlebar_item.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index a04b6a50aa7faed72b50d45d61ed31dedfeb5346..2cdf32ca366b0fdeb8ed8fd44a84861df23daa84 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -38,7 +38,7 @@ use gpui::{ use project::{Project, RepositoryEntry}; use theme::ActiveTheme; use ui::{ - h_stack, popover_menu, prelude::*, Avatar, Button, ButtonLike, ButtonStyle2, ContextMenu, Icon, + h_stack, popover_menu, prelude::*, Avatar, Button, ButtonLike, ButtonStyle, ContextMenu, Icon, IconButton, IconElement, KeyBinding, Tooltip, }; use util::ResultExt; @@ -204,11 +204,11 @@ impl Render for CollabTitlebarItem { "toggle_sharing", if is_shared { "Unshare" } else { "Share" }, ) - .style(ButtonStyle2::Subtle), + .style(ButtonStyle::Subtle), ) .child( IconButton::new("leave-call", ui::Icon::Exit) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .on_click({ let workspace = workspace.clone(); move |_, cx| { @@ -233,7 +233,7 @@ impl Render for CollabTitlebarItem { ui::Icon::Mic }, ) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .selected(is_muted) .on_click({ let workspace = workspace.clone(); @@ -248,7 +248,7 @@ impl Render for CollabTitlebarItem { ) .child( IconButton::new("mute-sound", speakers_icon) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .selected(is_deafened.clone()) .tooltip(move |cx| { Tooltip::with_meta( @@ -271,7 +271,7 @@ impl Render for CollabTitlebarItem { ) .child( IconButton::new("screen-share", ui::Icon::Screen) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .on_click(move |_, cx| { workspace .update(cx, |this, cx| { @@ -300,7 +300,7 @@ impl Render for CollabTitlebarItem { .color(Color::Muted), ), ) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), ) .anchor(gpui::AnchorCorner::TopRight), @@ -312,7 +312,7 @@ impl Render for CollabTitlebarItem { // IconElement::new(Icon::ChevronDown).color(Color::Muted), // ), // ) - // .style(ButtonStyle2::Subtle) + // .style(ButtonStyle::Subtle) // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), // ) }) @@ -489,7 +489,7 @@ impl CollabTitlebarItem { format!("{user_name} ({})", !is_shared), ) .color(Color::Player(participant_index)) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .tooltip(move |cx| Tooltip::text("Toggle following", cx)), ), ) @@ -509,7 +509,7 @@ impl CollabTitlebarItem { div().border().border_color(gpui::red()).child( Button::new("project_name_trigger", name) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .tooltip(move |cx| Tooltip::text("Recent Projects", cx)), ) } @@ -533,7 +533,7 @@ impl CollabTitlebarItem { Some( div().border().border_color(gpui::red()).child( Button::new("project_branch_trigger", branch_name) - .style(ButtonStyle2::Subtle) + .style(ButtonStyle::Subtle) .tooltip(move |cx| { cx.build_view(|_| { Tooltip::new("Recent Branches")