@@ -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| {
@@ -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;
@@ -36,17 +40,68 @@ pub enum IconPosition {
End,
}
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
+pub enum TintColor {
+ #[default]
+ Accent,
+ Negative,
+ Warning,
+}
+
+impl TintColor {
+ fn button_like_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,
+ },
+ 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<TintColor> 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<ButtonStyle> 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
/// 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,12 +141,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- 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(),
@@ -115,12 +165,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- 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(),
@@ -146,12 +191,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- 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(),
@@ -178,12 +218,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- 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,
@@ -208,12 +243,7 @@ impl ButtonStyle {
label_color: Color::Disabled.color(cx),
icon_color: Color::Disabled.color(cx),
},
- 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,
@@ -264,6 +294,7 @@ pub struct ButtonLike {
pub(super) style: ButtonStyle,
pub(super) disabled: bool,
pub(super) selected: bool,
+ pub(super) selected_style: Option<ButtonStyle>,
pub(super) width: Option<DefiniteLength>,
size: ButtonSize,
rounding: Option<ButtonLikeRounding>,
@@ -280,6 +311,7 @@ impl ButtonLike {
style: ButtonStyle::default(),
disabled: false,
selected: false,
+ selected_style: None,
width: None,
size: ButtonSize::Default,
rounding: Some(ButtonLikeRounding::All),
@@ -309,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));
@@ -364,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())
@@ -382,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),