From 6f140c8ae3582b4480ffc8345acb0b0120016432 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 4 Jan 2024 11:15:53 -0500 Subject: [PATCH 1/4] WIP tinted buttons --- .../ui/src/components/button/button_like.rs | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/crates/ui/src/components/button/button_like.rs b/crates/ui/src/components/button/button_like.rs index f255104432816f090aad741fdcb5800d589ff74b..47aae89dfd983df876bcf7bfe4d86c656ed73f18 100644 --- a/crates/ui/src/components/button/button_like.rs +++ b/crates/ui/src/components/button/button_like.rs @@ -36,17 +36,43 @@ pub enum IconPosition { End, } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] +pub enum TintColor { + #[default] + Accent, + Negative, + Positive, + Warning, +} + +impl TintColor { + fn button_style(self, cx: &mut WindowContext) -> ButtonLikeStyles { + match self { + TintColor::Accent => ButtonLikeStyles { + background: cx.theme().status().info_background, + border_color: cx.theme().status().info_border, + label_color: cx.theme().colors().text, + icon_color: cx.theme().colors().text, + }, + _ => ButtonLikeStyles { + background: gpui::red(), + border_color: gpui::red(), + label_color: gpui::red(), + icon_color: gpui::red(), + }, + } + } +} + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] pub enum ButtonStyle { /// A filled button with a solid background color. Provides emphasis versus /// the more common subtle button. Filled, - /// 🚧 Under construction 🚧 - /// /// Used to emphasize a button in some way, like a selected state, or a semantic /// coloring like an error or success button. - Tinted, + Tinted(TintColor), /// The default button style, used for most buttons. Has a transparent background, /// but has a background color to indicate states like hover and active. @@ -86,7 +112,9 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted => ButtonLikeStyles { + ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), + // TODO: Finish tint colors + ButtonStyle::Tinted(_) => ButtonLikeStyles { background: gpui::red(), border_color: gpui::red(), label_color: gpui::red(), @@ -115,7 +143,9 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted => ButtonLikeStyles { + ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), + // TODO: Finish tint colors + ButtonStyle::Tinted(_) => ButtonLikeStyles { background: gpui::red(), border_color: gpui::red(), label_color: gpui::red(), @@ -146,7 +176,9 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted => ButtonLikeStyles { + ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), + // TODO: Finish tint colors + ButtonStyle::Tinted(_) => ButtonLikeStyles { background: gpui::red(), border_color: gpui::red(), label_color: gpui::red(), @@ -178,7 +210,9 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted => ButtonLikeStyles { + ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), + // TODO: Finish tint colors + ButtonStyle::Tinted(_) => ButtonLikeStyles { background: gpui::red(), border_color: gpui::red(), label_color: gpui::red(), @@ -208,7 +242,9 @@ impl ButtonStyle { label_color: Color::Disabled.color(cx), icon_color: Color::Disabled.color(cx), }, - ButtonStyle::Tinted => ButtonLikeStyles { + ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), + // TODO: Finish tint colors + ButtonStyle::Tinted(_) => ButtonLikeStyles { background: gpui::red(), border_color: gpui::red(), label_color: gpui::red(), From e5af1cb9a26ba4cb426074bcca7e907d38be76be Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 4 Jan 2024 17:35:18 -0500 Subject: [PATCH 2/4] Remove unneeded branches --- .../ui/src/components/button/button_like.rs | 48 +++---------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/crates/ui/src/components/button/button_like.rs b/crates/ui/src/components/button/button_like.rs index 47aae89dfd983df876bcf7bfe4d86c656ed73f18..c3d871fe154a3b3d510f23b9d7d184a88793ebd8 100644 --- a/crates/ui/src/components/button/button_like.rs +++ b/crates/ui/src/components/button/button_like.rs @@ -46,7 +46,7 @@ pub enum TintColor { } impl TintColor { - fn button_style(self, cx: &mut WindowContext) -> ButtonLikeStyles { + fn button_like_style(self, cx: &mut WindowContext) -> ButtonLikeStyles { match self { TintColor::Accent => ButtonLikeStyles { background: cx.theme().status().info_background, @@ -54,6 +54,7 @@ impl TintColor { label_color: cx.theme().colors().text, icon_color: cx.theme().colors().text, }, + // TODO: Finish tint colors. _ => ButtonLikeStyles { background: gpui::red(), border_color: gpui::red(), @@ -112,14 +113,7 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), - // TODO: Finish tint colors - ButtonStyle::Tinted(_) => ButtonLikeStyles { - background: gpui::red(), - border_color: gpui::red(), - label_color: gpui::red(), - icon_color: gpui::red(), - }, + ButtonStyle::Tinted(tint) => tint.button_like_style(cx), ButtonStyle::Subtle => ButtonLikeStyles { background: cx.theme().colors().ghost_element_background, border_color: transparent_black(), @@ -143,14 +137,7 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), - // TODO: Finish tint colors - ButtonStyle::Tinted(_) => ButtonLikeStyles { - background: gpui::red(), - border_color: gpui::red(), - label_color: gpui::red(), - icon_color: gpui::red(), - }, + ButtonStyle::Tinted(tint) => tint.button_like_style(cx), ButtonStyle::Subtle => ButtonLikeStyles { background: cx.theme().colors().ghost_element_hover, border_color: transparent_black(), @@ -176,14 +163,7 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), - // TODO: Finish tint colors - ButtonStyle::Tinted(_) => ButtonLikeStyles { - background: gpui::red(), - border_color: gpui::red(), - label_color: gpui::red(), - icon_color: gpui::red(), - }, + ButtonStyle::Tinted(tint) => tint.button_like_style(cx), ButtonStyle::Subtle => ButtonLikeStyles { background: cx.theme().colors().ghost_element_active, border_color: transparent_black(), @@ -210,14 +190,7 @@ impl ButtonStyle { label_color: Color::Default.color(cx), icon_color: Color::Default.color(cx), }, - ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), - // TODO: Finish tint colors - ButtonStyle::Tinted(_) => ButtonLikeStyles { - background: gpui::red(), - border_color: gpui::red(), - label_color: gpui::red(), - icon_color: gpui::red(), - }, + ButtonStyle::Tinted(tint) => tint.button_like_style(cx), ButtonStyle::Subtle => ButtonLikeStyles { background: cx.theme().colors().ghost_element_background, border_color: cx.theme().colors().border_focused, @@ -242,14 +215,7 @@ impl ButtonStyle { label_color: Color::Disabled.color(cx), icon_color: Color::Disabled.color(cx), }, - ButtonStyle::Tinted(TintColor::Accent) => TintColor::Accent.button_style(cx), - // TODO: Finish tint colors - ButtonStyle::Tinted(_) => ButtonLikeStyles { - background: gpui::red(), - border_color: gpui::red(), - label_color: gpui::red(), - icon_color: gpui::red(), - }, + ButtonStyle::Tinted(tint) => tint.button_like_style(cx), ButtonStyle::Subtle => ButtonLikeStyles { background: cx.theme().colors().ghost_element_disabled, border_color: cx.theme().colors().border_disabled, From 9d4d58a915e9d26f95f1b763652bb6167981bc70 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 5 Jan 2024 11:19:58 -0500 Subject: [PATCH 3/4] Implement Tinted buttons and selected_style for buttons --- crates/ui/src/components/button/button.rs | 7 +++ .../ui/src/components/button/button_icon.rs | 11 ++++ .../ui/src/components/button/button_like.rs | 62 ++++++++++++++++--- .../ui/src/components/button/icon_button.rs | 11 +++- .../ui/src/components/button/toggle_button.rs | 7 +++ crates/ui/src/prelude.rs | 2 +- 6 files changed, 88 insertions(+), 12 deletions(-) diff --git a/crates/ui/src/components/button/button.rs b/crates/ui/src/components/button/button.rs index 958aa66ede0809ca0fde22d09e27654aff34791e..1e60aae03b11e84eda1a2041565c6b75a5fae79f 100644 --- a/crates/ui/src/components/button/button.rs +++ b/crates/ui/src/components/button/button.rs @@ -92,6 +92,13 @@ impl Selectable for Button { } } +impl SelectableButton for Button { + fn selected_style(mut self, style: ButtonStyle) -> Self { + self.base = self.base.selected_style(style); + self + } +} + impl Disableable for Button { fn disabled(mut self, disabled: bool) -> Self { self.base = self.base.disabled(disabled); diff --git a/crates/ui/src/components/button/button_icon.rs b/crates/ui/src/components/button/button_icon.rs index 29b23747b22eed50a112ba2a378b9620c4021443..15538bb24d79b9f17c3fcef8c4de37466e84fc66 100644 --- a/crates/ui/src/components/button/button_icon.rs +++ b/crates/ui/src/components/button/button_icon.rs @@ -12,6 +12,7 @@ pub(super) struct ButtonIcon { disabled: bool, selected: bool, selected_icon: Option, + selected_style: Option, } impl ButtonIcon { @@ -23,6 +24,7 @@ impl ButtonIcon { disabled: false, selected: false, selected_icon: None, + selected_style: None, } } @@ -62,6 +64,13 @@ impl Selectable for ButtonIcon { } } +impl SelectableButton for ButtonIcon { + fn selected_style(mut self, style: ButtonStyle) -> Self { + self.selected_style = Some(style); + self + } +} + impl RenderOnce for ButtonIcon { fn render(self, _cx: &mut WindowContext) -> impl IntoElement { let icon = self @@ -71,6 +80,8 @@ impl RenderOnce for ButtonIcon { let icon_color = if self.disabled { Color::Disabled + } else if self.selected_style.is_some() && self.selected { + self.selected_style.unwrap().into() } else if self.selected { Color::Selected } else { diff --git a/crates/ui/src/components/button/button_like.rs b/crates/ui/src/components/button/button_like.rs index c3d871fe154a3b3d510f23b9d7d184a88793ebd8..431286073fb33b263fd08c27ba1c07e44fe82c01 100644 --- a/crates/ui/src/components/button/button_like.rs +++ b/crates/ui/src/components/button/button_like.rs @@ -4,6 +4,10 @@ use smallvec::SmallVec; use crate::prelude::*; +pub trait SelectableButton: Selectable { + fn selected_style(self, style: ButtonStyle) -> Self; +} + pub trait ButtonCommon: Clickable + Disableable { /// A unique element ID to identify the button. fn id(&self) -> &ElementId; @@ -41,7 +45,6 @@ pub enum TintColor { #[default] Accent, Negative, - Positive, Warning, } @@ -54,17 +57,42 @@ impl TintColor { label_color: cx.theme().colors().text, icon_color: cx.theme().colors().text, }, - // TODO: Finish tint colors. - _ => ButtonLikeStyles { - background: gpui::red(), - border_color: gpui::red(), - label_color: gpui::red(), - icon_color: gpui::red(), + TintColor::Negative => ButtonLikeStyles { + background: cx.theme().status().error_background, + border_color: cx.theme().status().error_border, + label_color: cx.theme().colors().text, + icon_color: cx.theme().colors().text, + }, + TintColor::Warning => ButtonLikeStyles { + background: cx.theme().status().warning_background, + border_color: cx.theme().status().warning_border, + label_color: cx.theme().colors().text, + icon_color: cx.theme().colors().text, }, } } } +impl From for Color { + fn from(tint: TintColor) -> Self { + match tint { + TintColor::Accent => Color::Accent, + TintColor::Negative => Color::Error, + TintColor::Warning => Color::Warning, + } + } +} + +// Used to go from ButtonStyle -> Color through tint colors. +impl From for Color { + fn from(style: ButtonStyle) -> Self { + match style { + ButtonStyle::Tinted(tint) => tint.into(), + _ => Color::Default, + } + } +} + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] pub enum ButtonStyle { /// A filled button with a solid background color. Provides emphasis versus @@ -266,6 +294,7 @@ pub struct ButtonLike { pub(super) style: ButtonStyle, pub(super) disabled: bool, pub(super) selected: bool, + pub(super) selected_style: Option, pub(super) width: Option, size: ButtonSize, rounding: Option, @@ -282,6 +311,7 @@ impl ButtonLike { style: ButtonStyle::default(), disabled: false, selected: false, + selected_style: None, width: None, size: ButtonSize::Default, rounding: Some(ButtonLikeRounding::All), @@ -311,6 +341,13 @@ impl Selectable for ButtonLike { } } +impl SelectableButton for ButtonLike { + fn selected_style(mut self, style: ButtonStyle) -> Self { + self.selected_style = Some(style); + self + } +} + impl Clickable for ButtonLike { fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self { self.on_click = Some(Box::new(handler)); @@ -366,6 +403,11 @@ impl ParentElement for ButtonLike { impl RenderOnce for ButtonLike { fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let style = self + .selected_style + .filter(|_| self.selected) + .unwrap_or(self.style); + self.base .h_flex() .id(self.id.clone()) @@ -384,12 +426,12 @@ impl RenderOnce for ButtonLike { ButtonSize::Default | ButtonSize::Compact => this.px_1(), ButtonSize::None => this, }) - .bg(self.style.enabled(cx).background) + .bg(style.enabled(cx).background) .when(self.disabled, |this| this.cursor_not_allowed()) .when(!self.disabled, |this| { this.cursor_pointer() - .hover(|hover| hover.bg(self.style.hovered(cx).background)) - .active(|active| active.bg(self.style.active(cx).background)) + .hover(|hover| hover.bg(style.hovered(cx).background)) + .active(|active| active.bg(style.active(cx).background)) }) .when_some( self.on_click.filter(|_| !self.disabled), diff --git a/crates/ui/src/components/button/icon_button.rs b/crates/ui/src/components/button/icon_button.rs index 0a75f361cfe10eae59c7da0d0540cac46c81e9c8..d9ed6ccb5d86a2c5122ef6cd2fd364be235566bc 100644 --- a/crates/ui/src/components/button/icon_button.rs +++ b/crates/ui/src/components/button/icon_button.rs @@ -1,6 +1,6 @@ use gpui::{AnyView, DefiniteLength}; -use crate::prelude::*; +use crate::{prelude::*, SelectableButton}; use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconSize}; use super::button_icon::ButtonIcon; @@ -55,6 +55,13 @@ impl Selectable for IconButton { } } +impl SelectableButton for IconButton { + fn selected_style(mut self, style: ButtonStyle) -> Self { + self.base = self.base.selected_style(style); + self + } +} + impl Clickable for IconButton { fn on_click( mut self, @@ -109,12 +116,14 @@ impl RenderOnce for IconButton { fn render(self, _cx: &mut WindowContext) -> impl IntoElement { let is_disabled = self.base.disabled; let is_selected = self.base.selected; + let selected_style = self.base.selected_style; self.base.child( ButtonIcon::new(self.icon) .disabled(is_disabled) .selected(is_selected) .selected_icon(self.selected_icon) + .when_some(selected_style, |this, style| this.selected_style(style)) .size(self.icon_size) .color(self.icon_color), ) diff --git a/crates/ui/src/components/button/toggle_button.rs b/crates/ui/src/components/button/toggle_button.rs index f97498b0d837539f7a46a9def47e8040d8a429dc..e458c636eceab71b889fd008ab78934b6b243e0b 100644 --- a/crates/ui/src/components/button/toggle_button.rs +++ b/crates/ui/src/components/button/toggle_button.rs @@ -63,6 +63,13 @@ impl Selectable for ToggleButton { } } +impl SelectableButton for ToggleButton { + fn selected_style(mut self, style: ButtonStyle) -> Self { + self.base.selected_style = Some(style); + self + } +} + impl Disableable for ToggleButton { fn disabled(mut self, disabled: bool) -> Self { self.base = self.base.disabled(disabled); diff --git a/crates/ui/src/prelude.rs b/crates/ui/src/prelude.rs index dbf3c79b7173c1c6d018216cb4e11aab444d2e54..63d6c4b46a498bbce2573814cd645ec1d1b7bccd 100644 --- a/crates/ui/src/prelude.rs +++ b/crates/ui/src/prelude.rs @@ -12,7 +12,7 @@ pub use crate::selectable::*; pub use crate::styles::{vh, vw}; pub use crate::visible_on_hover::*; pub use crate::{h_stack, v_stack}; -pub use crate::{Button, ButtonSize, ButtonStyle, IconButton}; +pub use crate::{Button, ButtonSize, ButtonStyle, IconButton, SelectableButton}; pub use crate::{ButtonCommon, Color, StyledExt}; pub use crate::{Icon, IconElement, IconPosition, IconSize}; pub use crate::{Label, LabelCommon, LabelSize, LineHeightStyle}; From 6c4350933f768143d6616e0a90684b52dd93d2de Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 5 Jan 2024 11:20:24 -0500 Subject: [PATCH 4/4] Update titlebar call status icons --- crates/collab_ui/src/collab_titlebar_item.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 8150fe1e4ddf19bb422697d17cf0edf4ade0aed5..c013f8d43221476279c08df8eeec496f473d90e4 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -14,7 +14,7 @@ use std::sync::Arc; use theme::{ActiveTheme, PlayerColors}; use ui::{ h_stack, popover_menu, prelude::*, Avatar, Button, ButtonLike, ButtonStyle, ContextMenu, Icon, - IconButton, IconElement, Tooltip, + IconButton, IconElement, TintColor, Tooltip, }; use util::ResultExt; use vcs_menu::{build_branch_list, BranchList, OpenRecent as ToggleVcsMenu}; @@ -183,6 +183,8 @@ impl Render for CollabTitlebarItem { if is_shared { "Unshare" } else { "Share" }, ) .style(ButtonStyle::Subtle) + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) + .selected(is_shared) .label_size(LabelSize::Small) .on_click(cx.listener( move |this, _, cx| { @@ -215,6 +217,7 @@ impl Render for CollabTitlebarItem { }, ) .style(ButtonStyle::Subtle) + .selected_style(ButtonStyle::Tinted(TintColor::Negative)) .icon_size(IconSize::Small) .selected(is_muted) .on_click(move |_, cx| crate::toggle_mute(&Default::default(), cx)), @@ -229,6 +232,7 @@ impl Render for CollabTitlebarItem { }, ) .style(ButtonStyle::Subtle) + .selected_style(ButtonStyle::Tinted(TintColor::Negative)) .icon_size(IconSize::Small) .selected(is_deafened) .tooltip(move |cx| { @@ -239,6 +243,7 @@ impl Render for CollabTitlebarItem { .child( IconButton::new("screen-share", ui::Icon::Screen) .style(ButtonStyle::Subtle) + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .icon_size(IconSize::Small) .selected(is_screen_sharing) .on_click(move |_, cx| {