button.rs
1 //! Heavily inspired on https://github.com/longbridge/gpui-component/blob/main/crates/ui/src/button/button.rs 2 3 use std::rc::Rc; 4 5 use gpui::{prelude::*, *}; 6 7 #[derive(IntoElement)] 8 pub struct Button { 9 base: Stateful<Div>, 10 label: Option<SharedString>, 11 on_click: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App)>>, 12 loading: bool, 13 disabled: bool, 14 stop_propagation: bool, 15 w_full: bool, 16 } 17 18 impl Button { 19 pub fn new(id: impl Into<ElementId>) -> Self { 20 Self { 21 base: div().id(id.into()).flex_shrink_0(), 22 label: None, 23 on_click: None, 24 loading: false, 25 disabled: false, 26 stop_propagation: true, 27 w_full: false, 28 } 29 } 30 31 /// Set label to the Button, if no label is set, the button will be in Icon Button mode. 32 pub fn label(mut self, label: impl Into<SharedString>) -> Self { 33 self.label = Some(label.into()); 34 self 35 } 36 37 /// Add click handler. 38 pub fn on_click( 39 mut self, 40 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static, 41 ) -> Self { 42 self.on_click = Some(Rc::new(handler)); 43 self 44 } 45 46 /// Whether the button should extends to its fullest. 47 pub fn w_full(mut self) -> Self { 48 self.w_full = true; 49 self 50 } 51 52 /// Set true to show the loading indicator. 53 pub fn loading(mut self, loading: bool) -> Self { 54 self.loading = loading; 55 self 56 } 57 58 pub fn disabled(mut self, disabled: bool) -> Self { 59 self.disabled = disabled; 60 self 61 } 62 63 #[inline] 64 fn clickable(&self) -> bool { 65 !(self.disabled || self.loading) && self.on_click.is_some() 66 } 67 } 68 69 impl RenderOnce for Button { 70 fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement { 71 self 72 .base 73 .cursor_pointer() 74 .flex() 75 .items_center() 76 .justify_center() 77 .bg(rgb(0x5865f2)) 78 .rounded_lg() 79 .border_1() 80 .border_color(rgba(0xffffff14)) 81 .px_4() 82 .py_3() 83 .hover(|this| this.bg(rgb(0x4452BB))) 84 .active(|this| this.bg(rgb(0x3A48A3))) 85 .when(self.w_full, |this| this.w_full()) 86 .when_some( 87 self.on_click.filter(|_| !self.disabled && !self.loading), 88 |this, on_click| { 89 let stop_propagation = self.stop_propagation; 90 this 91 .on_mouse_down(MouseButton::Left, move |_, window, cx| { 92 window.prevent_default(); 93 if stop_propagation { 94 cx.stop_propagation(); 95 } 96 }) 97 .on_click(move |event, window, cx| { 98 (on_click)(event, window, cx); 99 }) 100 }, 101 ) 102 .when_some(self.label, |this, label| { 103 this.child( 104 div() 105 .text_color(gpui::white()) 106 .text_size(px(16.)) 107 .font_weight(FontWeight::MEDIUM) 108 .flex_none() 109 .line_height(relative(1.)) 110 .child(label), 111 ) 112 }) 113 } 114 }