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)]
21pub enum QuestionnaireChoiceControl {
22 Checkbox(Checkbox),
23 Radio(Radio),
24}
25
26impl QuestionnaireChoiceControl {
27 pub fn new(
29 state: &Entity<QuestionnaireState>,
30 item: impl Into<SharedString>,
31 value: impl Into<SharedString>,
32 id: impl Into<ElementId>,
33 cx: &gpui::App,
34 ) -> Option<Self> {
35 let item = item.into();
36 let value = value.into();
37 let snapshot = state.read(cx);
38 let choice = snapshot.choice_state(&item, &value)?;
39 let multiple = snapshot.item_state(&item)?.is_multiple();
40 let definition = snapshot.choice_definition(&item, &value)?;
41 let label = definition.accessibility_label().clone();
42 let description = definition.description().cloned();
43 let position = snapshot.choice_position(&item, &value);
44 let focus_handle = snapshot.choice_focus_handle(&item, &value).cloned();
45 let selected = choice.is_selected();
46 let disabled = choice.is_disabled();
47
48 let confirm_state = state.clone();
51 let confirm =
52 move |event: &gpui::KeyDownEvent, window: &mut gpui::Window, cx: &mut gpui::App| {
53 if selected
54 && !window.default_prevented()
55 && !event.is_held
56 && event.keystroke.key == "enter"
57 && event.keystroke.modifiers.number_of_modifiers() == 0
58 && confirm_state.update(cx, |state, cx| state.confirm_current(window, cx))
59 {
60 window.prevent_default();
61 }
62 };
63
64 let id = id.into();
65 Some(if multiple {
66 let change_state = state.clone();
67 let change_item = item.clone();
68 let change_value = value.clone();
69 Self::Checkbox(
70 Checkbox::new(id)
71 .state(if selected {
72 CheckboxState::Checked
73 } else {
74 CheckboxState::Unchecked
75 })
76 .disabled(disabled)
77 .accessibility_label(label)
78 .when_some(description, |this, description| {
79 this.aria_description(description)
80 })
81 .when_some(position, |this, (position, total)| {
82 this.aria_position_in_set(position).aria_size_of_set(total)
83 })
84 .when_some(focus_handle, |this, focus_handle| {
85 this.track_focus(&focus_handle)
86 })
87 .capture_key_down(confirm)
88 .on_change(move |_, _, window, cx| {
89 let _ = change_state.update(cx, |state, cx| {
90 state.choose(&change_item, &change_value, window, cx)
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 .when(!disabled, |this| {
114 this.on_click(move |_, window, cx| {
115 let _ = change_state
116 .update(cx, |state, cx| state.choose(&item, &value, window, cx));
117 })
118 }),
119 )
120 })
121 }
122}