button_like.rs

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