1use documented::Documented;
2use gpui::{
3 AnyElement, AnyView, ClickEvent, CursorStyle, DefiniteLength, Hsla, MouseButton,
4 MouseClickEvent, MouseDownEvent, MouseUpEvent, Rems, StyleRefinement, relative,
5 transparent_black,
6};
7use smallvec::SmallVec;
8
9use crate::{DynamicSpacing, ElevationIndex, prelude::*};
10
11/// A trait for buttons that can be Selected. Enables setting the [`ButtonStyle`] of a button when it is selected.
12pub trait SelectableButton: Toggleable {
13 fn selected_style(self, style: ButtonStyle) -> Self;
14}
15
16/// A common set of traits all buttons must implement.
17pub trait ButtonCommon: Clickable + Disableable {
18 /// A unique element ID to identify the button.
19 fn id(&self) -> &ElementId;
20
21 /// The visual style of the button.
22 ///
23 /// Most commonly will be [`ButtonStyle::Subtle`], or [`ButtonStyle::Filled`]
24 /// for an emphasized button.
25 fn style(self, style: ButtonStyle) -> Self;
26
27 /// The size of the button.
28 ///
29 /// Most buttons will use the default size.
30 ///
31 /// [`ButtonSize`] can also be used to help build non-button elements
32 /// that are consistently sized with buttons.
33 fn size(self, size: ButtonSize) -> Self;
34
35 /// The tooltip that shows when a user hovers over the button.
36 ///
37 /// Nearly all interactable elements should have a tooltip. Some example
38 /// exceptions might a scroll bar, or a slider.
39 fn tooltip(self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self;
40
41 fn tab_index(self, tab_index: impl Into<isize>) -> Self;
42
43 fn layer(self, elevation: ElevationIndex) -> Self;
44}
45
46#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
47pub enum IconPosition {
48 #[default]
49 Start,
50 End,
51}
52
53#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
54pub enum KeybindingPosition {
55 Start,
56 #[default]
57 End,
58}
59
60#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
61pub enum TintColor {
62 #[default]
63 Accent,
64 Error,
65 Warning,
66 Success,
67}
68
69impl TintColor {
70 fn button_like_style(self, cx: &mut App) -> ButtonLikeStyles {
71 match self {
72 TintColor::Accent => ButtonLikeStyles {
73 background: cx.theme().status().info_background,
74 border_color: cx.theme().status().info_border,
75 label_color: cx.theme().colors().text,
76 icon_color: cx.theme().colors().text,
77 },
78 TintColor::Error => ButtonLikeStyles {
79 background: cx.theme().status().error_background,
80 border_color: cx.theme().status().error_border,
81 label_color: cx.theme().colors().text,
82 icon_color: cx.theme().colors().text,
83 },
84 TintColor::Warning => ButtonLikeStyles {
85 background: cx.theme().status().warning_background,
86 border_color: cx.theme().status().warning_border,
87 label_color: cx.theme().colors().text,
88 icon_color: cx.theme().colors().text,
89 },
90 TintColor::Success => ButtonLikeStyles {
91 background: cx.theme().status().success_background,
92 border_color: cx.theme().status().success_border,
93 label_color: cx.theme().colors().text,
94 icon_color: cx.theme().colors().text,
95 },
96 }
97 }
98}
99
100impl From<TintColor> for Color {
101 fn from(tint: TintColor) -> Self {
102 match tint {
103 TintColor::Accent => Color::Accent,
104 TintColor::Error => Color::Error,
105 TintColor::Warning => Color::Warning,
106 TintColor::Success => Color::Success,
107 }
108 }
109}
110
111// Used to go from ButtonStyle -> Color through tint colors.
112impl From<ButtonStyle> for Color {
113 fn from(style: ButtonStyle) -> Self {
114 match style {
115 ButtonStyle::Tinted(tint) => tint.into(),
116 _ => Color::Default,
117 }
118 }
119}
120
121/// The visual appearance of a button.
122#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
123pub enum ButtonStyle {
124 /// A filled button with a solid background color. Provides emphasis versus
125 /// the more common subtle button.
126 Filled,
127
128 /// Used to emphasize a button in some way, like a selected state, or a semantic
129 /// coloring like an error or success button.
130 Tinted(TintColor),
131
132 /// Usually used as a secondary action that should have more emphasis than
133 /// a fully transparent button.
134 Outlined,
135
136 /// The default button style, used for most buttons. Has a transparent background,
137 /// but has a background color to indicate states like hover and active.
138 #[default]
139 Subtle,
140
141 /// Used for buttons that only change foreground color on hover and active states.
142 ///
143 /// TODO: Better docs for this.
144 Transparent,
145}
146
147#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
148pub(crate) enum ButtonLikeRounding {
149 All,
150 Left,
151 Right,
152}
153
154#[derive(Debug, Clone)]
155pub(crate) struct ButtonLikeStyles {
156 pub background: Hsla,
157 #[allow(unused)]
158 pub border_color: Hsla,
159 #[allow(unused)]
160 pub label_color: Hsla,
161 #[allow(unused)]
162 pub icon_color: Hsla,
163}
164
165fn element_bg_from_elevation(elevation: Option<ElevationIndex>, cx: &mut App) -> Hsla {
166 match elevation {
167 Some(ElevationIndex::Background) => cx.theme().colors().element_background,
168 Some(ElevationIndex::ElevatedSurface) => cx.theme().colors().elevated_surface_background,
169 Some(ElevationIndex::Surface) => cx.theme().colors().surface_background,
170 Some(ElevationIndex::ModalSurface) => cx.theme().colors().background,
171 _ => cx.theme().colors().element_background,
172 }
173}
174
175impl ButtonStyle {
176 pub(crate) fn enabled(
177 self,
178 elevation: Option<ElevationIndex>,
179
180 cx: &mut App,
181 ) -> ButtonLikeStyles {
182 match self {
183 ButtonStyle::Filled => ButtonLikeStyles {
184 background: element_bg_from_elevation(elevation, cx),
185 border_color: transparent_black(),
186 label_color: Color::Default.color(cx),
187 icon_color: Color::Default.color(cx),
188 },
189 ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
190 ButtonStyle::Outlined => ButtonLikeStyles {
191 background: element_bg_from_elevation(elevation, cx),
192 border_color: cx.theme().colors().border_variant,
193 label_color: Color::Default.color(cx),
194 icon_color: Color::Default.color(cx),
195 },
196 ButtonStyle::Subtle => ButtonLikeStyles {
197 background: cx.theme().colors().ghost_element_background,
198 border_color: transparent_black(),
199 label_color: Color::Default.color(cx),
200 icon_color: Color::Default.color(cx),
201 },
202 ButtonStyle::Transparent => ButtonLikeStyles {
203 background: transparent_black(),
204 border_color: transparent_black(),
205 label_color: Color::Default.color(cx),
206 icon_color: Color::Default.color(cx),
207 },
208 }
209 }
210
211 pub(crate) fn hovered(
212 self,
213 elevation: Option<ElevationIndex>,
214
215 cx: &mut App,
216 ) -> ButtonLikeStyles {
217 match self {
218 ButtonStyle::Filled => {
219 let mut filled_background = element_bg_from_elevation(elevation, cx);
220 filled_background.fade_out(0.5);
221
222 ButtonLikeStyles {
223 background: filled_background,
224 border_color: transparent_black(),
225 label_color: Color::Default.color(cx),
226 icon_color: Color::Default.color(cx),
227 }
228 }
229 ButtonStyle::Tinted(tint) => {
230 let mut styles = tint.button_like_style(cx);
231 let theme = cx.theme();
232 styles.background = theme.darken(styles.background, 0.05, 0.2);
233 styles
234 }
235 ButtonStyle::Outlined => ButtonLikeStyles {
236 background: cx.theme().colors().ghost_element_hover,
237 border_color: cx.theme().colors().border,
238 label_color: Color::Default.color(cx),
239 icon_color: Color::Default.color(cx),
240 },
241 ButtonStyle::Subtle => ButtonLikeStyles {
242 background: cx.theme().colors().ghost_element_hover,
243 border_color: transparent_black(),
244 label_color: Color::Default.color(cx),
245 icon_color: Color::Default.color(cx),
246 },
247 ButtonStyle::Transparent => ButtonLikeStyles {
248 background: transparent_black(),
249 border_color: transparent_black(),
250 // TODO: These are not great
251 label_color: Color::Muted.color(cx),
252 // TODO: These are not great
253 icon_color: Color::Muted.color(cx),
254 },
255 }
256 }
257
258 pub(crate) fn active(self, cx: &mut App) -> ButtonLikeStyles {
259 match self {
260 ButtonStyle::Filled => ButtonLikeStyles {
261 background: cx.theme().colors().element_active,
262 border_color: transparent_black(),
263 label_color: Color::Default.color(cx),
264 icon_color: Color::Default.color(cx),
265 },
266 ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
267 ButtonStyle::Subtle => ButtonLikeStyles {
268 background: cx.theme().colors().ghost_element_active,
269 border_color: transparent_black(),
270 label_color: Color::Default.color(cx),
271 icon_color: Color::Default.color(cx),
272 },
273 ButtonStyle::Outlined => ButtonLikeStyles {
274 background: cx.theme().colors().element_active,
275 border_color: cx.theme().colors().border_variant,
276 label_color: Color::Default.color(cx),
277 icon_color: Color::Default.color(cx),
278 },
279 ButtonStyle::Transparent => ButtonLikeStyles {
280 background: transparent_black(),
281 border_color: transparent_black(),
282 // TODO: These are not great
283 label_color: Color::Muted.color(cx),
284 // TODO: These are not great
285 icon_color: Color::Muted.color(cx),
286 },
287 }
288 }
289
290 #[allow(unused)]
291 pub(crate) fn focused(self, window: &mut Window, cx: &mut App) -> ButtonLikeStyles {
292 match self {
293 ButtonStyle::Filled => ButtonLikeStyles {
294 background: cx.theme().colors().element_background,
295 border_color: cx.theme().colors().border_focused,
296 label_color: Color::Default.color(cx),
297 icon_color: Color::Default.color(cx),
298 },
299 ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
300 ButtonStyle::Subtle => ButtonLikeStyles {
301 background: cx.theme().colors().ghost_element_background,
302 border_color: cx.theme().colors().border_focused,
303 label_color: Color::Default.color(cx),
304 icon_color: Color::Default.color(cx),
305 },
306 ButtonStyle::Outlined => ButtonLikeStyles {
307 background: cx.theme().colors().ghost_element_background,
308 border_color: cx.theme().colors().border,
309 label_color: Color::Default.color(cx),
310 icon_color: Color::Default.color(cx),
311 },
312 ButtonStyle::Transparent => ButtonLikeStyles {
313 background: transparent_black(),
314 border_color: cx.theme().colors().border_focused,
315 label_color: Color::Accent.color(cx),
316 icon_color: Color::Accent.color(cx),
317 },
318 }
319 }
320
321 #[allow(unused)]
322 pub(crate) fn disabled(
323 self,
324 elevation: Option<ElevationIndex>,
325 window: &mut Window,
326 cx: &mut App,
327 ) -> ButtonLikeStyles {
328 match self {
329 ButtonStyle::Filled => ButtonLikeStyles {
330 background: cx.theme().colors().element_disabled,
331 border_color: cx.theme().colors().border_disabled,
332 label_color: Color::Disabled.color(cx),
333 icon_color: Color::Disabled.color(cx),
334 },
335 ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
336 ButtonStyle::Subtle => ButtonLikeStyles {
337 background: cx.theme().colors().ghost_element_disabled,
338 border_color: cx.theme().colors().border_disabled,
339 label_color: Color::Disabled.color(cx),
340 icon_color: Color::Disabled.color(cx),
341 },
342 ButtonStyle::Outlined => ButtonLikeStyles {
343 background: cx.theme().colors().element_disabled,
344 border_color: cx.theme().colors().border_disabled,
345 label_color: Color::Default.color(cx),
346 icon_color: Color::Default.color(cx),
347 },
348 ButtonStyle::Transparent => ButtonLikeStyles {
349 background: transparent_black(),
350 border_color: transparent_black(),
351 label_color: Color::Disabled.color(cx),
352 icon_color: Color::Disabled.color(cx),
353 },
354 }
355 }
356}
357
358/// The height of a button.
359///
360/// Can also be used to size non-button elements to align with [`Button`]s.
361#[derive(Default, PartialEq, Clone, Copy)]
362pub enum ButtonSize {
363 Large,
364 Medium,
365 #[default]
366 Default,
367 Compact,
368 None,
369}
370
371impl ButtonSize {
372 pub fn rems(self) -> Rems {
373 match self {
374 ButtonSize::Large => rems_from_px(32.),
375 ButtonSize::Medium => rems_from_px(28.),
376 ButtonSize::Default => rems_from_px(22.),
377 ButtonSize::Compact => rems_from_px(18.),
378 ButtonSize::None => rems_from_px(16.),
379 }
380 }
381}
382
383/// A button-like element that can be used to create a custom button when
384/// prebuilt buttons are not sufficient. Use this sparingly, as it is
385/// unconstrained and may make the UI feel less consistent.
386///
387/// This is also used to build the prebuilt buttons.
388#[derive(IntoElement, Documented, RegisterComponent)]
389pub struct ButtonLike {
390 pub(super) base: Div,
391 id: ElementId,
392 pub(super) style: ButtonStyle,
393 pub(super) disabled: bool,
394 pub(super) selected: bool,
395 pub(super) selected_style: Option<ButtonStyle>,
396 pub(super) width: Option<DefiniteLength>,
397 pub(super) height: Option<DefiniteLength>,
398 pub(super) layer: Option<ElevationIndex>,
399 tab_index: Option<isize>,
400 size: ButtonSize,
401 rounding: Option<ButtonLikeRounding>,
402 tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView>>,
403 hoverable_tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView>>,
404 cursor_style: CursorStyle,
405 on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
406 on_right_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
407 children: SmallVec<[AnyElement; 2]>,
408}
409
410impl ButtonLike {
411 pub fn new(id: impl Into<ElementId>) -> Self {
412 Self {
413 base: div(),
414 id: id.into(),
415 style: ButtonStyle::default(),
416 disabled: false,
417 selected: false,
418 selected_style: None,
419 width: None,
420 height: None,
421 size: ButtonSize::Default,
422 rounding: Some(ButtonLikeRounding::All),
423 tooltip: None,
424 hoverable_tooltip: None,
425 children: SmallVec::new(),
426 cursor_style: CursorStyle::PointingHand,
427 on_click: None,
428 on_right_click: None,
429 layer: None,
430 tab_index: None,
431 }
432 }
433
434 pub fn new_rounded_left(id: impl Into<ElementId>) -> Self {
435 Self::new(id).rounding(ButtonLikeRounding::Left)
436 }
437
438 pub fn new_rounded_right(id: impl Into<ElementId>) -> Self {
439 Self::new(id).rounding(ButtonLikeRounding::Right)
440 }
441
442 pub fn new_rounded_all(id: impl Into<ElementId>) -> Self {
443 Self::new(id).rounding(ButtonLikeRounding::All)
444 }
445
446 pub fn opacity(mut self, opacity: f32) -> Self {
447 self.base = self.base.opacity(opacity);
448 self
449 }
450
451 pub fn height(mut self, height: DefiniteLength) -> Self {
452 self.height = Some(height);
453 self
454 }
455
456 pub(crate) fn rounding(mut self, rounding: impl Into<Option<ButtonLikeRounding>>) -> Self {
457 self.rounding = rounding.into();
458 self
459 }
460
461 pub fn on_right_click(
462 mut self,
463 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
464 ) -> Self {
465 self.on_right_click = Some(Box::new(handler));
466 self
467 }
468
469 pub fn hoverable_tooltip(
470 mut self,
471 tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
472 ) -> Self {
473 self.hoverable_tooltip = Some(Box::new(tooltip));
474 self
475 }
476}
477
478impl Disableable for ButtonLike {
479 fn disabled(mut self, disabled: bool) -> Self {
480 self.disabled = disabled;
481 self
482 }
483}
484
485impl Toggleable for ButtonLike {
486 fn toggle_state(mut self, selected: bool) -> Self {
487 self.selected = selected;
488 self
489 }
490}
491
492impl SelectableButton for ButtonLike {
493 fn selected_style(mut self, style: ButtonStyle) -> Self {
494 self.selected_style = Some(style);
495 self
496 }
497}
498
499impl Clickable for ButtonLike {
500 fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
501 self.on_click = Some(Box::new(handler));
502 self
503 }
504
505 fn cursor_style(mut self, cursor_style: CursorStyle) -> Self {
506 self.cursor_style = cursor_style;
507 self
508 }
509}
510
511impl FixedWidth for ButtonLike {
512 fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
513 self.width = Some(width.into());
514 self
515 }
516
517 fn full_width(mut self) -> Self {
518 self.width = Some(relative(1.));
519 self
520 }
521}
522
523impl ButtonCommon for ButtonLike {
524 fn id(&self) -> &ElementId {
525 &self.id
526 }
527
528 fn style(mut self, style: ButtonStyle) -> Self {
529 self.style = style;
530 self
531 }
532
533 fn size(mut self, size: ButtonSize) -> Self {
534 self.size = size;
535 self
536 }
537
538 fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
539 self.tooltip = Some(Box::new(tooltip));
540 self
541 }
542
543 fn tab_index(mut self, tab_index: impl Into<isize>) -> Self {
544 self.tab_index = Some(tab_index.into());
545 self
546 }
547
548 fn layer(mut self, elevation: ElevationIndex) -> Self {
549 self.layer = Some(elevation);
550 self
551 }
552}
553
554impl VisibleOnHover for ButtonLike {
555 fn visible_on_hover(mut self, group_name: impl Into<SharedString>) -> Self {
556 self.base = self.base.visible_on_hover(group_name);
557 self
558 }
559}
560
561impl ParentElement for ButtonLike {
562 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
563 self.children.extend(elements)
564 }
565}
566
567impl RenderOnce for ButtonLike {
568 fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
569 let style = self
570 .selected_style
571 .filter(|_| self.selected)
572 .unwrap_or(self.style);
573
574 self.base
575 .h_flex()
576 .id(self.id.clone())
577 .when_some(self.tab_index, |this, tab_index| this.tab_index(tab_index))
578 .font_ui(cx)
579 .group("")
580 .flex_none()
581 .h(self.height.unwrap_or(self.size.rems().into()))
582 .when_some(self.width, |this, width| {
583 this.w(width).justify_center().text_center()
584 })
585 .when(matches!(self.style, ButtonStyle::Outlined), |this| {
586 this.border_1()
587 })
588 .when_some(self.rounding, |this, rounding| match rounding {
589 ButtonLikeRounding::All => this.rounded_sm(),
590 ButtonLikeRounding::Left => this.rounded_l_sm(),
591 ButtonLikeRounding::Right => this.rounded_r_sm(),
592 })
593 .gap(DynamicSpacing::Base04.rems(cx))
594 .map(|this| match self.size {
595 ButtonSize::Large | ButtonSize::Medium => this.px(DynamicSpacing::Base06.rems(cx)),
596 ButtonSize::Default | ButtonSize::Compact => {
597 this.px(DynamicSpacing::Base04.rems(cx))
598 }
599 ButtonSize::None => this,
600 })
601 .border_color(style.enabled(self.layer, cx).border_color)
602 .bg(style.enabled(self.layer, cx).background)
603 .when(self.disabled, |this| {
604 if self.cursor_style == CursorStyle::PointingHand {
605 this.cursor_not_allowed()
606 } else {
607 this.cursor(self.cursor_style)
608 }
609 })
610 .when(!self.disabled, |this| {
611 let hovered_style = style.hovered(self.layer, cx);
612 let focus_color =
613 |refinement: StyleRefinement| refinement.bg(hovered_style.background);
614 this.cursor(self.cursor_style)
615 .hover(focus_color)
616 .focus(focus_color)
617 .active(|active| active.bg(style.active(cx).background))
618 })
619 .when_some(
620 self.on_right_click.filter(|_| !self.disabled),
621 |this, on_right_click| {
622 this.on_mouse_down(MouseButton::Right, |_event, window, cx| {
623 window.prevent_default();
624 cx.stop_propagation();
625 })
626 .on_mouse_up(
627 MouseButton::Right,
628 move |event, window, cx| {
629 cx.stop_propagation();
630 let click_event = ClickEvent::Mouse(MouseClickEvent {
631 down: MouseDownEvent {
632 button: MouseButton::Right,
633 position: event.position,
634 modifiers: event.modifiers,
635 click_count: 1,
636 first_mouse: false,
637 },
638 up: MouseUpEvent {
639 button: MouseButton::Right,
640 position: event.position,
641 modifiers: event.modifiers,
642 click_count: 1,
643 },
644 });
645 (on_right_click)(&click_event, window, cx)
646 },
647 )
648 },
649 )
650 .when_some(
651 self.on_click.filter(|_| !self.disabled),
652 |this, on_click| {
653 this.on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
654 .on_click(move |event, window, cx| {
655 cx.stop_propagation();
656 (on_click)(event, window, cx)
657 })
658 },
659 )
660 .when_some(self.tooltip, |this, tooltip| {
661 this.tooltip(move |window, cx| tooltip(window, cx))
662 })
663 .when_some(self.hoverable_tooltip, |this, tooltip| {
664 this.hoverable_tooltip(move |window, cx| tooltip(window, cx))
665 })
666 .children(self.children)
667 }
668}
669
670impl Component for ButtonLike {
671 fn scope() -> ComponentScope {
672 ComponentScope::Input
673 }
674
675 fn sort_name() -> &'static str {
676 // ButtonLike should be at the bottom of the button list
677 "ButtonZ"
678 }
679
680 fn description() -> Option<&'static str> {
681 Some(ButtonLike::DOCS)
682 }
683
684 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
685 Some(
686 v_flex()
687 .gap_6()
688 .children(vec![
689 example_group(vec![
690 single_example(
691 "Default",
692 ButtonLike::new("default")
693 .child(Label::new("Default"))
694 .into_any_element(),
695 ),
696 single_example(
697 "Filled",
698 ButtonLike::new("filled")
699 .style(ButtonStyle::Filled)
700 .child(Label::new("Filled"))
701 .into_any_element(),
702 ),
703 single_example(
704 "Subtle",
705 ButtonLike::new("outline")
706 .style(ButtonStyle::Subtle)
707 .child(Label::new("Subtle"))
708 .into_any_element(),
709 ),
710 single_example(
711 "Tinted",
712 ButtonLike::new("tinted_accent_style")
713 .style(ButtonStyle::Tinted(TintColor::Accent))
714 .child(Label::new("Accent"))
715 .into_any_element(),
716 ),
717 single_example(
718 "Transparent",
719 ButtonLike::new("transparent")
720 .style(ButtonStyle::Transparent)
721 .child(Label::new("Transparent"))
722 .into_any_element(),
723 ),
724 ]),
725 example_group_with_title(
726 "Button Group Constructors",
727 vec![
728 single_example(
729 "Left Rounded",
730 ButtonLike::new_rounded_left("left_rounded")
731 .child(Label::new("Left Rounded"))
732 .style(ButtonStyle::Filled)
733 .into_any_element(),
734 ),
735 single_example(
736 "Right Rounded",
737 ButtonLike::new_rounded_right("right_rounded")
738 .child(Label::new("Right Rounded"))
739 .style(ButtonStyle::Filled)
740 .into_any_element(),
741 ),
742 single_example(
743 "Button Group",
744 h_flex()
745 .gap_px()
746 .child(
747 ButtonLike::new_rounded_left("bg_left")
748 .child(Label::new("Left"))
749 .style(ButtonStyle::Filled),
750 )
751 .child(
752 ButtonLike::new_rounded_right("bg_right")
753 .child(Label::new("Right"))
754 .style(ButtonStyle::Filled),
755 )
756 .into_any_element(),
757 ),
758 ],
759 ),
760 ])
761 .into_any_element(),
762 )
763 }
764}