@@ -12,6 +12,7 @@ pub(super) struct ButtonIcon {
disabled: bool,
selected: bool,
selected_icon: Option<Icon>,
+ selected_style: Option<ButtonStyle>,
}
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 {
@@ -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<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
@@ -266,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>,
@@ -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),
@@ -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),
)
@@ -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};