gpui_component/setting/fields/
mod.rs1mod bool;
2mod dropdown;
3mod element;
4mod number;
5mod string;
6
7pub(crate) use bool::*;
8pub(crate) use dropdown::*;
9pub(crate) use element::*;
10pub(crate) use number::*;
11pub(crate) use string::*;
12
13pub use element::SettingFieldElement;
14pub use number::NumberFieldOptions;
15
16use gpui::{AnyElement, App, IntoElement, SharedString, StyleRefinement, Styled, Window};
17use std::{any::Any, rc::Rc};
18
19use crate::setting::RenderOptions;
20
21pub(crate) trait SettingFieldRender {
22 #[allow(clippy::too_many_arguments)]
23 fn render(
24 &self,
25 field: Rc<dyn AnySettingField>,
26 options: &RenderOptions,
27 style: &StyleRefinement,
28 window: &mut Window,
29 cx: &mut App,
30 ) -> AnyElement;
31}
32
33pub(crate) fn get_value<T: Clone + 'static>(field: &Rc<dyn AnySettingField>, cx: &mut App) -> T {
34 let setting_field = field
35 .as_any()
36 .downcast_ref::<SettingField<T>>()
37 .expect("Failed to downcast setting field");
38 (setting_field.value)(cx)
39}
40
41pub(crate) fn set_value<T: Clone + 'static>(
42 field: &Rc<dyn AnySettingField>,
43 _cx: &mut App,
44) -> Rc<dyn Fn(T, &mut App)> {
45 let setting_field = field
46 .as_any()
47 .downcast_ref::<SettingField<T>>()
48 .expect("Failed to downcast setting field");
49 setting_field.set_value.clone()
50}
51
52#[derive(Clone)]
54pub enum SettingFieldType {
55 Switch,
56 Checkbox,
57 NumberInput {
58 options: NumberFieldOptions,
59 },
60 Input,
61 Dropdown {
62 options: Vec<(SharedString, SharedString)>,
63 },
64 Element {
65 element: Rc<dyn SettingFieldElement<Element = AnyElement>>,
66 },
67}
68
69impl SettingFieldType {
70 #[inline]
71 pub(crate) fn is_switch(&self) -> bool {
72 matches!(self, SettingFieldType::Switch)
73 }
74
75 #[inline]
76 pub(crate) fn is_number_input(&self) -> bool {
77 matches!(self, SettingFieldType::NumberInput { .. })
78 }
79
80 #[inline]
81 pub(crate) fn is_input(&self) -> bool {
82 matches!(self, SettingFieldType::Input)
83 }
84
85 #[inline]
86 pub(crate) fn is_dropdown(&self) -> bool {
87 matches!(self, SettingFieldType::Dropdown { .. })
88 }
89
90 #[inline]
91 pub(crate) fn is_element(&self) -> bool {
92 matches!(self, SettingFieldType::Element { .. })
93 }
94
95 #[inline]
96 pub(super) fn dropdown_options(&self) -> Option<&Vec<(SharedString, SharedString)>> {
97 match self {
98 SettingFieldType::Dropdown { options } => Some(options),
99 _ => None,
100 }
101 }
102
103 #[inline]
104 pub(super) fn number_input_options(&self) -> Option<&NumberFieldOptions> {
105 match self {
106 SettingFieldType::NumberInput { options } => Some(options),
107 _ => None,
108 }
109 }
110
111 #[inline]
112 pub(super) fn element(&self) -> Rc<dyn SettingFieldElement<Element = AnyElement>> {
113 match self {
114 SettingFieldType::Element { element } => element.clone(),
115 _ => unreachable!("element_render called on non-element field"),
116 }
117 }
118}
119
120pub struct SettingField<T> {
122 pub(crate) field_type: SettingFieldType,
123 pub(crate) style: StyleRefinement,
124 pub(crate) value: Rc<dyn Fn(&App) -> T>,
126 pub(crate) set_value: Rc<dyn Fn(T, &mut App)>,
128 pub(crate) default_value: Option<T>,
129}
130
131impl SettingField<bool> {
132 pub fn switch<V, S>(value: V, set_value: S) -> Self
134 where
135 V: Fn(&App) -> bool + 'static,
136 S: Fn(bool, &mut App) + 'static,
137 {
138 Self::new(SettingFieldType::Switch, value, set_value)
139 }
140
141 pub fn checkbox<V, S>(value: V, set_value: S) -> Self
143 where
144 V: Fn(&App) -> bool + 'static,
145 S: Fn(bool, &mut App) + 'static,
146 {
147 Self::new(SettingFieldType::Checkbox, value, set_value)
148 }
149}
150
151impl SettingField<SharedString> {
152 pub fn input<V, S>(value: V, set_value: S) -> Self
154 where
155 V: Fn(&App) -> SharedString + 'static,
156 S: Fn(SharedString, &mut App) + 'static,
157 {
158 Self::new(SettingFieldType::Input, value, set_value)
159 }
160
161 pub fn dropdown<V, S>(
163 options: Vec<(SharedString, SharedString)>,
164 value: V,
165 set_value: S,
166 ) -> Self
167 where
168 V: Fn(&App) -> SharedString + 'static,
169 S: Fn(SharedString, &mut App) + 'static,
170 {
171 Self::new(SettingFieldType::Dropdown { options }, value, set_value)
172 }
173
174 pub fn element<E>(element: E) -> Self
178 where
179 E: SettingFieldElement + 'static,
180 {
181 Self::new(
182 SettingFieldType::Element {
183 element: Rc::new(AnySettingFieldElement(element)),
184 },
185 |_| SharedString::default(),
186 |_, _| {},
187 )
188 }
189
190 pub fn render<E, R>(element_render: R) -> Self
194 where
195 E: IntoElement + 'static,
196 R: Fn(&RenderOptions, &mut Window, &mut App) -> E + 'static,
197 {
198 Self::element(
199 move |options: &RenderOptions, window: &mut Window, cx: &mut App| {
200 (element_render)(options, window, cx).into_any_element()
201 },
202 )
203 }
204}
205
206impl SettingField<f64> {
207 pub fn number_input<V, S>(options: NumberFieldOptions, value: V, set_value: S) -> Self
209 where
210 V: Fn(&App) -> f64 + 'static,
211 S: Fn(f64, &mut App) + 'static,
212 {
213 Self::new(SettingFieldType::NumberInput { options }, value, set_value)
214 }
215}
216
217impl<T> SettingField<T> {
218 fn new<V, S>(field_type: SettingFieldType, value: V, set_value: S) -> Self
220 where
221 V: Fn(&App) -> T + 'static,
222 S: Fn(T, &mut App) + 'static,
223 {
224 Self {
225 field_type,
226 style: StyleRefinement::default(),
227 value: Rc::new(value),
228 set_value: Rc::new(set_value),
229 default_value: None,
230 }
231 }
232
233 pub fn default_value(mut self, default_value: impl Into<T>) -> Self {
238 self.default_value = Some(default_value.into());
239 self
240 }
241}
242
243impl<T> Styled for SettingField<T> {
244 fn style(&mut self) -> &mut StyleRefinement {
245 &mut self.style
246 }
247}
248
249pub trait AnySettingField {
251 fn as_any(&self) -> &dyn std::any::Any;
252 fn type_name(&self) -> &'static str;
253 fn type_id(&self) -> std::any::TypeId;
254 fn field_type(&self) -> &SettingFieldType;
255 fn style(&self) -> &StyleRefinement;
256 fn is_resettable(&self, cx: &App) -> bool;
257 fn reset(&self, window: &mut Window, cx: &mut App);
258}
259
260impl<T: Clone + PartialEq + Send + Sync + 'static> AnySettingField for SettingField<T> {
261 fn as_any(&self) -> &dyn Any {
262 self
263 }
264
265 fn type_name(&self) -> &'static str {
266 std::any::type_name::<T>()
267 }
268
269 fn type_id(&self) -> std::any::TypeId {
270 std::any::TypeId::of::<T>()
271 }
272
273 fn field_type(&self) -> &SettingFieldType {
274 &self.field_type
275 }
276
277 fn style(&self) -> &StyleRefinement {
278 &self.style
279 }
280
281 fn is_resettable(&self, cx: &App) -> bool {
282 let Some(default_value) = self.default_value.as_ref() else {
283 return false;
284 };
285
286 &(self.value)(cx) != default_value
287 }
288
289 fn reset(&self, _: &mut Window, cx: &mut App) {
290 let Some(default_value) = self.default_value.as_ref() else {
291 return;
292 };
293
294 (self.set_value)(default_value.clone(), cx)
295 }
296}