gpui_base/questionnaire/
control.rs1use gpui::{
2 ElementId, Entity, InteractiveElement as _, SharedString, StatefulInteractiveElement as _,
3 prelude::FluentBuilder as _,
4};
5
6use super::QuestionnaireState;
7use crate::{Checkbox, CheckboxState, Radio};
8
9#[allow(clippy::large_enum_variant)]
19pub enum QuestionnaireChoiceControl {
20 Checkbox(Checkbox),
21 Radio(Radio),
22}
23
24impl QuestionnaireChoiceControl {
25 pub fn new(
27 state: &Entity<QuestionnaireState>,
28 item: impl Into<SharedString>,
29 value: impl Into<SharedString>,
30 id: impl Into<ElementId>,
31 cx: &gpui::App,
32 ) -> Option<Self> {
33 let item = item.into();
34 let value = value.into();
35 let snapshot = state.read(cx);
36 let choice = snapshot.choice_state(&item, &value)?;
37 let multiple = snapshot.item_state(&item)?.is_multiple();
38 let definition = snapshot.choice_definition(&item, &value)?;
39 let label = definition.accessibility_label().clone();
40 let description = definition.description().cloned();
41 let position = snapshot.choice_position(&item, &value);
42 let focus_handle = snapshot.choice_focus_handle(&item, &value).cloned();
43 let selected = choice.is_selected();
44 let disabled = choice.is_disabled();
45
46 let confirm_state = state.clone();
49 let confirm =
50 move |event: &gpui::KeyDownEvent, window: &mut gpui::Window, cx: &mut gpui::App| {
51 if selected
52 && !window.default_prevented()
53 && !event.is_held
54 && event.keystroke.key == "enter"
55 && event.keystroke.modifiers.number_of_modifiers() == 0
56 && confirm_state.update(cx, |state, cx| state.confirm_current(window, cx))
57 {
58 window.prevent_default();
59 }
60 };
61
62 let id = id.into();
63 Some(if multiple {
64 let change_state = state.clone();
65 let change_item = item.clone();
66 let change_value = value.clone();
67 Self::Checkbox(
68 Checkbox::new(id)
69 .state(if selected {
70 CheckboxState::Checked
71 } else {
72 CheckboxState::Unchecked
73 })
74 .disabled(disabled)
75 .accessibility_label(label)
76 .when_some(description, |this, description| {
77 this.aria_description(description)
78 })
79 .when_some(position, |this, (position, total)| {
80 this.aria_position_in_set(position).aria_size_of_set(total)
81 })
82 .when_some(focus_handle, |this, focus_handle| {
83 this.track_focus(&focus_handle)
84 })
85 .capture_key_down(confirm)
86 .on_change(move |_, _, window, cx| {
87 let _ = change_state.update(cx, |state, cx| {
88 let result = state.activate_choice(&change_item, &change_value, cx);
89 state.focus_choice(&change_item, &change_value, window, cx);
90 result
91 });
92 }),
93 )
94 } else {
95 let change_state = state.clone();
96 Self::Radio(
97 Radio::new(id)
98 .checked(selected)
99 .disabled(disabled)
100 .accessibility_label(label)
101 .when_some(description, |this, description| {
102 this.aria_description(description)
103 })
104 .when_some(position, |this, (position, total)| {
105 this.set_position(position, total)
106 })
107 .when_some(focus_handle, |this, focus_handle| {
108 this.track_focus(&focus_handle)
109 })
110 .capture_key_down(confirm)
111 .on_change(move |_, _, window, cx| {
112 let _ = change_state.update(cx, |state, cx| {
113 let result = state.activate_choice(&item, &value, cx);
114 state.focus_choice(&item, &value, window, cx);
115 result
116 });
117 }),
118 )
119 })
120 }
121}