use std::rc::Rc; use crate::{ h_flex, indicator::Indicator, tooltip::Tooltip, ActiveTheme, Colorize as _, Disableable, FocusableExt as _, Icon, Selectable, Sizable, Size, StyleSized, StyledExt, }; use gpui::{ div, prelude::FluentBuilder as _, px, relative, Action, AnyElement, App, ClickEvent, Corners, Div, Edges, ElementId, Hsla, InteractiveElement, Interactivity, IntoElement, ParentElement, Pixels, RenderOnce, SharedString, Stateful, StatefulInteractiveElement as _, StyleRefinement, Styled, Window, }; #[derive(Default, Clone, Copy)] pub enum ButtonRounded { None, Small, #[default] Medium, Large, Size(Pixels), } impl From for ButtonRounded { fn from(px: Pixels) -> Self { ButtonRounded::Size(px) } } #[derive(Clone, Copy, PartialEq, Eq)] pub struct ButtonCustomVariant { color: Hsla, foreground: Hsla, border: Hsla, shadow: bool, hover: Hsla, active: Hsla, } pub trait ButtonVariants: Sized { fn with_variant(self, variant: ButtonVariant) -> Self; /// With the primary style for the Button. fn primary(self) -> Self { self.with_variant(ButtonVariant::Primary) } /// With the danger style for the Button. fn danger(self) -> Self { self.with_variant(ButtonVariant::Danger) } /// With the warning style for the Button. fn warning(self) -> Self { self.with_variant(ButtonVariant::Warning) } /// With the success style for the Button. fn success(self) -> Self { self.with_variant(ButtonVariant::Success) } /// With the info style for the Button. fn info(self) -> Self { self.with_variant(ButtonVariant::Info) } /// With the ghost style for the Button. fn ghost(self) -> Self { self.with_variant(ButtonVariant::Ghost) } /// With the link style for the Button. fn link(self) -> Self { self.with_variant(ButtonVariant::Link) } /// With the text style for the Button, it will no padding look like a normal text. fn text(self) -> Self { self.with_variant(ButtonVariant::Text) } /// With the custom style for the Button. fn custom(self, style: ButtonCustomVariant) -> Self { self.with_variant(ButtonVariant::Custom(style)) } } impl ButtonCustomVariant { pub fn new(cx: &App) -> Self { Self { color: cx.theme().transparent, foreground: cx.theme().foreground, border: cx.theme().transparent, hover: cx.theme().transparent, active: cx.theme().transparent, shadow: false, } } /// Set background color, default is transparent. pub fn color(mut self, color: Hsla) -> Self { self.color = color; self } /// Set foreground color, default is theme foreground. pub fn foreground(mut self, color: Hsla) -> Self { self.foreground = color; self } /// Set border color, default is transparent. pub fn border(mut self, color: Hsla) -> Self { self.border = color; self } /// Set hover background color, default is transparent. pub fn hover(mut self, color: Hsla) -> Self { self.hover = color; self } /// Set active background color, default is transparent. pub fn active(mut self, color: Hsla) -> Self { self.active = color; self } /// Set shadow, default is false. pub fn shadow(mut self, shadow: bool) -> Self { self.shadow = shadow; self } } /// The veriant of the Button. #[derive(Clone, Copy, PartialEq, Eq, Default)] pub enum ButtonVariant { Primary, #[default] Secondary, Danger, Info, Success, Warning, Ghost, Link, Text, Custom(ButtonCustomVariant), } impl ButtonVariant { #[inline] pub fn is_link(&self) -> bool { matches!(self, Self::Link) } #[inline] pub fn is_text(&self) -> bool { matches!(self, Self::Text) } #[inline] pub fn is_ghost(&self) -> bool { matches!(self, Self::Ghost) } #[inline] fn no_padding(&self) -> bool { self.is_link() || self.is_text() } } /// A Button element. #[derive(IntoElement)] pub struct Button { id: ElementId, base: Stateful
, style: StyleRefinement, icon: Option, label: Option, children: Vec, disabled: bool, pub(crate) selected: bool, variant: ButtonVariant, rounded: ButtonRounded, outline: bool, border_corners: Corners, border_edges: Edges, size: Size, compact: bool, tooltip: Option<( SharedString, Option<(Rc>, Option)>, )>, on_click: Option>, on_hover: Option>, loading: bool, loading_icon: Option, tab_index: isize, tab_stop: bool, } impl From