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