guise/input/
radiogroup.rs1use std::rc::Rc;
8
9use gpui::prelude::*;
10use gpui::{div, px, App, IntoElement, SharedString, Window};
11
12use super::Radio;
13use crate::devtools::Probed;
14use crate::reactive::Binding;
15use crate::theme::{theme, ColorName, Size};
16
17type GroupHandler = Rc<dyn Fn(usize, &mut Window, &mut App) + 'static>;
18
19#[derive(IntoElement)]
21pub struct RadioGroup {
22 options: Vec<SharedString>,
23 value: Option<usize>,
24 color: ColorName,
25 size: Size,
26 label: Option<SharedString>,
27 binding: Option<Binding<usize>>,
28 on_change: Option<GroupHandler>,
29}
30
31impl RadioGroup {
32 pub fn new() -> Self {
33 RadioGroup {
34 options: Vec::new(),
35 value: None,
36 color: ColorName::Blue,
37 size: Size::Sm,
38 label: None,
39 binding: None,
40 on_change: None,
41 }
42 }
43
44 pub fn options<I, S>(mut self, options: I) -> Self
45 where
46 I: IntoIterator<Item = S>,
47 S: Into<SharedString>,
48 {
49 self.options = options.into_iter().map(Into::into).collect();
50 self
51 }
52
53 pub fn value(mut self, value: usize) -> Self {
55 self.value = Some(value);
56 self
57 }
58
59 pub fn color(mut self, color: ColorName) -> Self {
60 self.color = color;
61 self
62 }
63
64 pub fn size(mut self, size: Size) -> Self {
65 self.size = size;
66 self
67 }
68
69 pub fn label(mut self, label: impl Into<SharedString>) -> Self {
70 self.label = Some(label.into());
71 self
72 }
73
74 pub fn bind(mut self, binding: Binding<usize>) -> Self {
77 self.binding = Some(binding);
78 self
79 }
80
81 pub fn on_change(mut self, handler: impl Fn(usize, &mut Window, &mut App) + 'static) -> Self {
83 self.on_change = Some(Rc::new(handler));
84 self
85 }
86}
87
88impl Default for RadioGroup {
89 fn default() -> Self {
90 RadioGroup::new()
91 }
92}
93
94impl RenderOnce for RadioGroup {
95 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
96 let t = theme(cx);
97 let gap = t.spacing(Size::Xs);
98 let text = t.text().hsla();
99 let font = t.font_size(Size::Sm);
100 let value = self
101 .binding
102 .as_ref()
103 .map_or(self.value, |b| Some(b.get(cx)));
104
105 let mut column = div().flex().flex_col().gap(px(gap));
106 if let Some(label) = self.label.clone() {
107 column = column.child(div().text_size(px(font)).text_color(text).child(label));
108 }
109
110 for (i, option) in self.options.iter().enumerate() {
111 let mut radio = Radio::new(("guise-radiogroup", i))
112 .label(option.clone())
113 .checked(value == Some(i))
114 .color(self.color)
115 .size(self.size);
116 if self.binding.is_some() || self.on_change.is_some() {
117 let binding = self.binding.clone();
118 let handler = self.on_change.clone();
119 radio = radio.on_change(move |_ev, window, cx| {
120 if let Some(binding) = &binding {
121 binding.set(cx, i);
122 }
123 if let Some(handler) = &handler {
124 handler(i, window, cx);
125 }
126 });
127 }
128 column = column.child(radio);
129 }
130 column.probe("RadioGroup")
131 }
132}