1use gpui::prelude::*;
4use gpui::{div, px, App, ClickEvent, ElementId, IntoElement, SharedString, Window};
5
6use super::{control_box_size, ClickHandler};
7use crate::theme::{theme, ColorName, Size};
8
9#[derive(IntoElement)]
12pub struct Radio {
13 id: ElementId,
14 checked: bool,
15 label: Option<SharedString>,
16 size: Size,
17 color: ColorName,
18 disabled: bool,
19 on_change: Option<ClickHandler>,
20}
21
22impl Radio {
23 pub fn new(id: impl Into<ElementId>) -> Self {
24 Radio {
25 id: id.into(),
26 checked: false,
27 label: None,
28 size: Size::Sm,
29 color: ColorName::Blue,
30 disabled: false,
31 on_change: None,
32 }
33 }
34
35 pub fn checked(mut self, checked: bool) -> Self {
36 self.checked = checked;
37 self
38 }
39
40 pub fn label(mut self, label: impl Into<SharedString>) -> Self {
41 self.label = Some(label.into());
42 self
43 }
44
45 pub fn size(mut self, size: Size) -> Self {
46 self.size = size;
47 self
48 }
49
50 pub fn color(mut self, color: ColorName) -> Self {
51 self.color = color;
52 self
53 }
54
55 pub fn disabled(mut self, disabled: bool) -> Self {
56 self.disabled = disabled;
57 self
58 }
59
60 pub fn on_change(
61 mut self,
62 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
63 ) -> Self {
64 self.on_change = Some(Box::new(handler));
65 self
66 }
67}
68
69impl RenderOnce for Radio {
70 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
71 let t = theme(cx);
72 let outer = control_box_size(self.size);
73 let accent = t.color(self.color, t.primary_shade());
74
75 let mut ring = div()
76 .w(px(outer))
77 .h(px(outer))
78 .rounded(px(outer))
79 .flex()
80 .items_center()
81 .justify_center();
82 if self.checked {
83 ring = ring.bg(accent.hsla()).child(
84 div()
85 .w(px(outer * 0.36))
86 .h(px(outer * 0.36))
87 .rounded(px(outer))
88 .bg(t.white.hsla()),
89 );
90 } else {
91 ring = ring
92 .bg(t.surface().hsla())
93 .border_1()
94 .border_color(t.border().hsla());
95 }
96
97 let mut row = div()
98 .id(self.id)
99 .flex()
100 .items_center()
101 .gap(px(8.0))
102 .child(ring);
103 if let Some(label) = self.label {
104 row = row.child(
105 div()
106 .text_size(px(t.font_size(self.size)))
107 .text_color(t.text().hsla())
108 .child(label),
109 );
110 }
111
112 if self.disabled {
113 row.opacity(0.5)
114 } else {
115 if let Some(handler) = self.on_change {
116 row = row.on_click(handler);
117 }
118 row
119 }
120 }
121}