button_group: Add vertical (#1537)

Adds a vertical option to the button group

Also added an example of the vertical button group to the story

Also fixed button rounding only working when both tl/bl and tr/br are
both set, now they can be set individually

I'm not sure if the justify_center in `.when(self.vertical, |this|
this.flex_col().justify_center())` is needed, but I added it to match
the behaviour of `.items_center()` when the flex direction is row.
This commit is contained in:
Moulberry 2025-11-07 16:48:14 +08:00 committed by GitHub
parent 001107438f
commit c78811c4b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 66 additions and 31 deletions

View file

@ -1,5 +1,5 @@
use gpui::{ use gpui::{
Action, App, AppContext as _, ClickEvent, Context, Corner, Entity, Focusable, Action, App, AppContext as _, Axis, ClickEvent, Context, Corner, Entity, Focusable,
InteractiveElement, IntoElement, ParentElement as _, Render, Styled as _, Window, InteractiveElement, IntoElement, ParentElement as _, Render, Styled as _, Window,
prelude::FluentBuilder, px, prelude::FluentBuilder, px,
}; };
@ -612,6 +612,38 @@ impl Render for ButtonStory {
), ),
), ),
) )
.child(
section("Button Group (Vertical)").child(
ButtonGroup::new("button-group-vertical")
.outline()
.layout(Axis::Vertical)
.disabled(disabled)
.child(
Button::new("button-one")
.label("One")
.disabled(disabled)
.selected(selected)
.when(compact, |this| this.compact())
.on_click(Self::on_click),
)
.child(
Button::new("button-two")
.label("Two")
.disabled(disabled)
.selected(selected)
.when(compact, |this| this.compact())
.on_click(Self::on_click),
)
.child(
Button::new("button-three")
.label("Three")
.disabled(disabled)
.selected(selected)
.when(compact, |this| this.compact())
.on_click(Self::on_click),
),
),
)
.child( .child(
section("Toggle Button Group") section("Toggle Button Group")
.sub_title( .sub_title(

View file

@ -430,6 +430,14 @@ impl RenderOnce for Button {
.clone(); .clone();
let is_focused = focus_handle.is_focused(window); let is_focused = focus_handle.is_focused(window);
let rounding = match self.rounded {
ButtonRounded::Small => cx.theme().radius * 0.5,
ButtonRounded::Medium => cx.theme().radius,
ButtonRounded::Large => cx.theme().radius * 2.0,
ButtonRounded::Size(px) => px,
ButtonRounded::None => Pixels::ZERO,
};
self.base self.base
.when(!self.disabled, |this| { .when(!self.disabled, |this| {
this.track_focus( this.track_focus(
@ -467,26 +475,10 @@ impl RenderOnce for Button {
} }
} }
}) })
.when( .when(self.border_corners.top_left, |this| this.rounded_tl(rounding))
self.border_corners.top_left && self.border_corners.bottom_left, .when(self.border_corners.top_right, |this| this.rounded_tr(rounding))
|this| match self.rounded { .when(self.border_corners.bottom_left, |this| this.rounded_bl(rounding))
ButtonRounded::Small => this.rounded_l(cx.theme().radius * 0.5), .when(self.border_corners.bottom_right, |this| this.rounded_br(rounding))
ButtonRounded::Medium => this.rounded_l(cx.theme().radius),
ButtonRounded::Large => this.rounded_l(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(cx.theme().radius * 0.5),
ButtonRounded::Medium => this.rounded_r(cx.theme().radius),
ButtonRounded::Large => this.rounded_r(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.left, |this| this.border_l_1())
.when(self.border_edges.right, |this| this.border_r_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.top, |this| this.border_t_1())

View file

@ -1,5 +1,5 @@
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, App, Corners, Edges, ElementId, InteractiveElement, div, prelude::FluentBuilder as _, App, Axis, Corners, Edges, ElementId, InteractiveElement,
IntoElement, ParentElement, RenderOnce, StatefulInteractiveElement as _, StyleRefinement, IntoElement, ParentElement, RenderOnce, StatefulInteractiveElement as _, StyleRefinement,
Styled, Window, Styled, Window,
}; };
@ -18,6 +18,7 @@ pub struct ButtonGroup {
children: Vec<Button>, children: Vec<Button>,
pub(super) multiple: bool, pub(super) multiple: bool,
pub(super) disabled: bool, pub(super) disabled: bool,
pub(super) layout: Axis,
// The button props // The button props
pub(super) compact: bool, pub(super) compact: bool,
@ -48,6 +49,7 @@ impl ButtonGroup {
outline: false, outline: false,
multiple: false, multiple: false,
disabled: false, disabled: false,
layout: Axis::Horizontal,
on_click: None, on_click: None,
} }
} }
@ -70,6 +72,12 @@ impl ButtonGroup {
self self
} }
/// Set the layout of the button group. Default is `Axis::Horizontal`.
pub fn layout(mut self, layout: Axis) -> Self {
self.layout = layout;
self
}
/// With the compact mode for the ButtonGroup. /// With the compact mode for the ButtonGroup.
/// ///
/// See also: [`Button::compact()`] /// See also: [`Button::compact()`]
@ -150,10 +158,13 @@ impl RenderOnce for ButtonGroup {
} }
} }
let vertical = self.layout == Axis::Vertical;
div() div()
.id(self.id) .id(self.id)
.flex() .flex()
.items_center() .when(vertical, |this| this.flex_col().justify_center())
.when(!vertical, |this| this.items_center())
.refine_style(&self.style) .refine_style(&self.style)
.children( .children(
self.children self.children
@ -168,8 +179,8 @@ impl RenderOnce for ButtonGroup {
child child
.border_corners(Corners { .border_corners(Corners {
top_left: true, top_left: true,
top_right: false, top_right: vertical,
bottom_left: true, bottom_left: !vertical,
bottom_right: false, bottom_right: false,
}) })
.border_edges(Edges { .border_edges(Edges {
@ -182,15 +193,15 @@ impl RenderOnce for ButtonGroup {
// Last // Last
child child
.border_edges(Edges { .border_edges(Edges {
left: false, left: vertical,
top: true, top: !vertical,
right: true, right: true,
bottom: true, bottom: true,
}) })
.border_corners(Corners { .border_corners(Corners {
top_left: false, top_left: false,
top_right: true, top_right: !vertical,
bottom_left: false, bottom_left: vertical,
bottom_right: true, bottom_right: true,
}) })
} else { } else {
@ -198,8 +209,8 @@ impl RenderOnce for ButtonGroup {
child child
.border_corners(Corners::all(false)) .border_corners(Corners::all(false))
.border_edges(Edges { .border_edges(Edges {
left: false, left: vertical,
top: true, top: !vertical,
right: true, right: true,
bottom: true, bottom: true,
}) })