From 83aecf129378e81dc9a9f6967c50cd111e95ba71 Mon Sep 17 00:00:00 2001
From: xda <150917089+xda2023@users.noreply.github.com>
Date: Fri, 6 Sep 2024 10:32:10 +0800
Subject: [PATCH] Add ButtonGroup (#221)
---------
Co-authored-by: Jason Lee
---
crates/story/src/button_story.rs | 33 +++++++++++
crates/ui/src/button.rs | 54 ++++++++++++++----
crates/ui/src/button_group.rs | 98 ++++++++++++++++++++++++++++++++
crates/ui/src/lib.rs | 1 +
4 files changed, 175 insertions(+), 11 deletions(-)
create mode 100644 crates/ui/src/button_group.rs
diff --git a/crates/story/src/button_story.rs b/crates/story/src/button_story.rs
index 06d4c0a8..18a392b7 100644
--- a/crates/story/src/button_story.rs
+++ b/crates/story/src/button_story.rs
@@ -5,6 +5,7 @@ use gpui::{
use ui::{
button::{Button, ButtonCustomStyle},
+ button_group::ButtonGroup,
checkbox::Checkbox,
h_flex,
prelude::FluentBuilder,
@@ -405,6 +406,38 @@ impl Render for ButtonStory {
),
),
)
+ .child(
+ section("Button Group", cx).child(
+ ButtonGroup::new("button-group")
+ .child(
+ Button::new("button-one", cx)
+ .label("One")
+ .disabled(disabled)
+ .selected(selected)
+ .loading(loading)
+ .when(compact, |this| this.compact())
+ .on_click(Self::on_click),
+ )
+ .child(
+ Button::new("button-two", cx)
+ .label("Two")
+ .disabled(disabled)
+ .selected(selected)
+ .loading(loading)
+ .when(compact, |this| this.compact())
+ .on_click(Self::on_click),
+ )
+ .child(
+ Button::new("button-three", cx)
+ .label("Three")
+ .disabled(disabled)
+ .selected(selected)
+ .loading(loading)
+ .when(compact, |this| this.compact())
+ .on_click(Self::on_click),
+ ),
+ ),
+ )
.child(
section("Icon Button", cx)
.child(
diff --git a/crates/ui/src/button.rs b/crates/ui/src/button.rs
index 17f0dfd5..1085b2f3 100644
--- a/crates/ui/src/button.rs
+++ b/crates/ui/src/button.rs
@@ -6,9 +6,9 @@ use crate::{
Disableable, Icon, Selectable, Sizable, Size,
};
use gpui::{
- div, prelude::FluentBuilder as _, px, relative, AnyElement, ClickEvent, Div, ElementId,
- FocusHandle, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels,
- RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, WindowContext,
+ div, prelude::FluentBuilder as _, px, relative, AnyElement, ClickEvent, Corners, Div, Edges,
+ ElementId, FocusHandle, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement,
+ Pixels, RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, WindowContext,
};
pub enum ButtonRounded {
@@ -109,6 +109,8 @@ pub struct Button {
selected: bool,
style: ButtonStyle,
rounded: ButtonRounded,
+ border_corners: Corners,
+ border_edges: Edges,
size: Size,
compact: bool,
tooltip: Option,
@@ -134,6 +136,8 @@ impl Button {
selected: false,
style: ButtonStyle::Secondary,
rounded: ButtonRounded::Medium,
+ border_corners: Corners::all(true),
+ border_edges: Edges::all(true),
size: Size::Medium,
tooltip: None,
on_click: None,
@@ -191,6 +195,18 @@ impl Button {
self
}
+ /// Set the border corners side of the Button.
+ pub(crate) fn border_corners(mut self, corners: impl Into>) -> Self {
+ self.border_corners = corners.into();
+ self
+ }
+
+ /// Set the border edges of the Button.
+ pub(crate) fn border_edges(mut self, edges: impl Into>) -> Self {
+ self.border_edges = edges.into();
+ self
+ }
+
/// Set label to the Button, if no label is set, the button will be in Icon Button mode.
pub fn label(mut self, label: impl Into) -> Self {
self.label = Some(label.into());
@@ -310,13 +326,30 @@ impl RenderOnce for Button {
}
}
})
- .map(|this| match self.rounded {
- ButtonRounded::Small => this.rounded(px(cx.theme().radius * 0.5)),
- ButtonRounded::Medium => this.rounded(px(cx.theme().radius)),
- ButtonRounded::Large => this.rounded(px(cx.theme().radius * 2.0)),
- ButtonRounded::Size(px) => this.rounded(px),
- ButtonRounded::None => this.rounded_none(),
- })
+ .when(
+ self.border_corners.top_left && self.border_corners.bottom_left,
+ |this| match self.rounded {
+ ButtonRounded::Small => this.rounded_l(px(cx.theme().radius * 0.5)),
+ ButtonRounded::Medium => this.rounded_l(px(cx.theme().radius)),
+ ButtonRounded::Large => this.rounded_l(px(cx.theme().radius * 2.0)),
+ ButtonRounded::Size(px) => this.rounded_l(px),
+ ButtonRounded::None => this.rounded_none(),
+ },
+ )
+ .when(
+ self.border_corners.top_right && self.border_corners.bottom_right,
+ |this| match self.rounded {
+ ButtonRounded::Small => this.rounded_r(px(cx.theme().radius * 0.5)),
+ ButtonRounded::Medium => this.rounded_r(px(cx.theme().radius)),
+ ButtonRounded::Large => this.rounded_r(px(cx.theme().radius * 2.0)),
+ ButtonRounded::Size(px) => this.rounded_r(px),
+ ButtonRounded::None => this.rounded_none(),
+ },
+ )
+ .when(self.border_edges.left, |this| this.border_l_1())
+ .when(self.border_edges.right, |this| this.border_r_1())
+ .when(self.border_edges.top, |this| this.border_t_1())
+ .when(self.border_edges.bottom, |this| this.border_b_1())
.text_color(normal_style.fg)
.when(self.selected, |this| {
let selected_style = style.selected(cx);
@@ -361,7 +394,6 @@ impl RenderOnce for Button {
.text_color(disabled_style.fg)
.border_color(disabled_style.border)
})
- .border_1()
.child({
h_flex()
.id("label")
diff --git a/crates/ui/src/button_group.rs b/crates/ui/src/button_group.rs
new file mode 100644
index 00000000..15080921
--- /dev/null
+++ b/crates/ui/src/button_group.rs
@@ -0,0 +1,98 @@
+use gpui::{
+ div, Corners, Div, Edges, ElementId, InteractiveElement, IntoElement, ParentElement,
+ RenderOnce, Styled, WindowContext,
+};
+
+use crate::button::Button;
+
+#[derive(IntoElement)]
+pub struct ButtonGroup {
+ pub base: Div,
+ id: ElementId,
+ children: Vec