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