Skip to content

Commit c467833

Browse files
authored
Add support for clicking checkboxes via their labels (#2667)
1 parent 80f38d9 commit c467833

File tree

13 files changed

+320
-163
lines changed

13 files changed

+320
-163
lines changed

editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,14 @@ impl LayoutHolder for ExportDialogMessageHandler {
143143
DropdownInput::new(entries).selected_index(Some(index as u32)).widget_holder(),
144144
];
145145

146+
let mut checkbox_id = CheckboxId::default();
146147
let transparent_background = vec![
147-
TextLabel::new("Transparency").table_align(true).min_width(100).widget_holder(),
148+
TextLabel::new("Transparency").table_align(true).min_width(100).for_checkbox(&mut checkbox_id).widget_holder(),
148149
Separator::new(SeparatorType::Unrelated).widget_holder(),
149150
CheckboxInput::new(self.transparent_background)
150151
.disabled(self.file_type == FileType::Jpg)
151152
.on_update(move |value: &CheckboxInput| ExportDialogMessage::TransparentBackground(value.checked).into())
153+
.for_label(checkbox_id.clone())
152154
.widget_holder(),
153155
];
154156

editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
7777
.widget_holder(),
7878
];
7979

80+
let mut checkbox_id = CheckboxId::default();
8081
let infinite = vec![
81-
TextLabel::new("Infinite Canvas").table_align(true).min_width(90).widget_holder(),
82+
TextLabel::new("Infinite Canvas").table_align(true).min_width(90).for_checkbox(&mut checkbox_id).widget_holder(),
8283
Separator::new(SeparatorType::Unrelated).widget_holder(),
8384
CheckboxInput::new(self.infinite)
8485
.on_update(|checkbox_input: &CheckboxInput| NewDocumentDialogMessage::Infinite(checkbox_input.checked).into())
86+
.for_label(checkbox_id.clone())
8587
.widget_holder(),
8688
];
8789

editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ impl PreferencesDialogMessageHandler {
6666
.widget_holder(),
6767
];
6868

69+
let mut checkbox_id = CheckboxId::default();
6970
let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)";
7071
let zoom_with_scroll = vec![
7172
Separator::new(SeparatorType::Unrelated).widget_holder(),
@@ -78,8 +79,13 @@ impl PreferencesDialogMessageHandler {
7879
}
7980
.into()
8081
})
82+
.for_label(checkbox_id.clone())
83+
.widget_holder(),
84+
TextLabel::new("Zoom with Scroll")
85+
.table_align(true)
86+
.tooltip(zoom_with_scroll_tooltip)
87+
.for_checkbox(&mut checkbox_id)
8188
.widget_holder(),
82-
TextLabel::new("Zoom with Scroll").table_align(true).tooltip(zoom_with_scroll_tooltip).widget_holder(),
8389
];
8490

8591
// =======
@@ -161,6 +167,7 @@ impl PreferencesDialogMessageHandler {
161167
graph_wire_style,
162168
];
163169

170+
let mut checkbox_id = CheckboxId::default();
164171
let vello_tooltip = "Use the experimental Vello renderer (your browser must support WebGPU)";
165172
let use_vello = vec![
166173
Separator::new(SeparatorType::Unrelated).widget_holder(),
@@ -169,23 +176,31 @@ impl PreferencesDialogMessageHandler {
169176
.tooltip(vello_tooltip)
170177
.disabled(!preferences.supports_wgpu())
171178
.on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::UseVello { use_vello: checkbox_input.checked }.into())
179+
.for_label(checkbox_id.clone())
172180
.widget_holder(),
173181
TextLabel::new("Vello Renderer")
174182
.table_align(true)
175183
.tooltip(vello_tooltip)
176184
.disabled(!preferences.supports_wgpu())
185+
.for_checkbox(&mut checkbox_id)
177186
.widget_holder(),
178187
];
179188

189+
let mut checkbox_id = CheckboxId::default();
180190
let vector_mesh_tooltip = "Allow tools to produce vector meshes, where more than two segments can connect to an anchor point.\n\nCurrently this does not properly handle line joins and fills.";
181191
let vector_meshes = vec![
182192
Separator::new(SeparatorType::Unrelated).widget_holder(),
183193
Separator::new(SeparatorType::Unrelated).widget_holder(),
184194
CheckboxInput::new(preferences.vector_meshes)
185195
.tooltip(vector_mesh_tooltip)
186196
.on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::VectorMeshes { enabled: checkbox_input.checked }.into())
197+
.for_label(checkbox_id.clone())
198+
.widget_holder(),
199+
TextLabel::new("Vector Meshes")
200+
.table_align(true)
201+
.tooltip(vector_mesh_tooltip)
202+
.for_checkbox(&mut checkbox_id)
187203
.widget_holder(),
188-
TextLabel::new("Vector Meshes").table_align(true).tooltip(vector_mesh_tooltip).widget_holder(),
189204
];
190205

191206
// TODO: Reenable when Imaginate is restored

editor/src/messages/layout/utility_types/widgets/input_widgets.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use graphene_core::Color;
55
use graphene_core::raster::curve::Curve;
66
use graphene_std::transform::ReferencePoint;
77
use graphite_proc_macros::WidgetBuilder;
8+
use once_cell::sync::OnceCell;
9+
use std::sync::Arc;
810

911
#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)]
1012
#[derivative(Debug, PartialEq)]
@@ -18,6 +20,9 @@ pub struct CheckboxInput {
1820

1921
pub tooltip: String,
2022

23+
#[serde(rename = "forLabel", skip_serializing_if = "checkbox_id_is_empty")]
24+
pub for_label: CheckboxId,
25+
2126
#[serde(skip)]
2227
pub tooltip_shortcut: Option<ActionKeys>,
2328

@@ -39,12 +44,51 @@ impl Default for CheckboxInput {
3944
icon: "Checkmark".into(),
4045
tooltip: Default::default(),
4146
tooltip_shortcut: Default::default(),
47+
for_label: CheckboxId::default(),
4248
on_update: Default::default(),
4349
on_commit: Default::default(),
4450
}
4551
}
4652
}
4753

54+
#[derive(Clone, Default, Debug, Eq, PartialEq)]
55+
pub struct CheckboxId(Arc<OnceCell<u64>>);
56+
57+
impl CheckboxId {
58+
pub fn fill(&mut self) {
59+
let _ = self.0.set(graphene_core::uuid::generate_uuid());
60+
}
61+
}
62+
impl specta::Type for CheckboxId {
63+
fn inline(_type_map: &mut specta::TypeCollection, _generics: specta::Generics) -> specta::datatype::DataType {
64+
// TODO: This might not be right, but it works for now. We just need the type `bigint | undefined`.
65+
specta::datatype::DataType::Primitive(specta::datatype::PrimitiveType::u64)
66+
}
67+
}
68+
impl serde::Serialize for CheckboxId {
69+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
70+
where
71+
S: serde::Serializer,
72+
{
73+
self.0.get().copied().serialize(serializer)
74+
}
75+
}
76+
impl<'a> serde::Deserialize<'a> for CheckboxId {
77+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78+
where
79+
D: serde::Deserializer<'a>,
80+
{
81+
let id = u64::deserialize(deserializer)?;
82+
let checkbox_id = CheckboxId(OnceCell::new().into());
83+
checkbox_id.0.set(id).map_err(serde::de::Error::custom)?;
84+
Ok(checkbox_id)
85+
}
86+
}
87+
88+
fn checkbox_id_is_empty(id: &CheckboxId) -> bool {
89+
id.0.get().is_none()
90+
}
91+
4892
#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)]
4993
#[derivative(Debug, PartialEq, Default)]
5094
pub struct DropdownInput {

editor/src/messages/layout/utility_types/widgets/label_widgets.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::input_widgets::CheckboxId;
12
use derivative::*;
23
use graphite_proc_macros::WidgetBuilder;
34

@@ -56,9 +57,21 @@ pub struct TextLabel {
5657

5758
pub tooltip: String,
5859

60+
#[serde(rename = "checkboxId")]
61+
#[widget_builder(skip)]
62+
pub checkbox_id: CheckboxId,
63+
5964
// Body
6065
#[widget_builder(constructor)]
6166
pub value: String,
6267
}
6368

69+
impl TextLabel {
70+
pub fn for_checkbox(mut self, id: &mut CheckboxId) -> Self {
71+
id.fill();
72+
self.checkbox_id = id.clone();
73+
self
74+
}
75+
}
76+
6477
// TODO: Add UserInputLabel

0 commit comments

Comments
 (0)