Skip to content

Commit d716dd4

Browse files
authored
Merge branch 'master' into safari-click-and-drag-fix
2 parents dd3a529 + 99966d8 commit d716dd4

16 files changed

Lines changed: 280 additions & 85 deletions

File tree

editor/src/messages/layout/layout_message_handler.rs

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,10 @@ impl LayoutMessageHandler {
123123
let callback_message = match action {
124124
WidgetValueAction::Commit => (breadcrumb_trail_buttons.on_commit.callback)(&()),
125125
WidgetValueAction::Update => {
126-
let update_value = value.as_u64().expect("BreadcrumbTrailButtons update was not of type: u64");
126+
let Some(update_value) = value.as_u64() else {
127+
error!("BreadcrumbTrailButtons update was not of type: u64");
128+
return;
129+
};
127130
(breadcrumb_trail_buttons.on_update.callback)(&update_value)
128131
}
129132
};
@@ -133,7 +136,10 @@ impl LayoutMessageHandler {
133136
let callback_message = match action {
134137
WidgetValueAction::Commit => (checkbox_input.on_commit.callback)(&()),
135138
WidgetValueAction::Update => {
136-
let update_value = value.as_bool().expect("CheckboxInput update was not of type: bool");
139+
let Some(update_value) = value.as_bool() else {
140+
error!("CheckboxInput update was not of type: bool");
141+
return;
142+
};
137143
checkbox_input.checked = update_value;
138144
(checkbox_input.on_update.callback)(checkbox_input)
139145
}
@@ -208,7 +214,10 @@ impl LayoutMessageHandler {
208214
let callback_message = match action {
209215
WidgetValueAction::Commit => (curve_input.on_commit.callback)(&()),
210216
WidgetValueAction::Update => {
211-
let curve = serde_json::from_value(value).expect("CurveInput event data could not be deserialized");
217+
let Some(curve) = serde_json::from_value(value).ok() else {
218+
error!("CurveInput event data could not be deserialized");
219+
return;
220+
};
212221
curve_input.value = curve;
213222
(curve_input.on_update.callback)(curve_input)
214223
}
@@ -219,13 +228,27 @@ impl LayoutMessageHandler {
219228
Widget::DropdownInput(dropdown_input) => {
220229
let callback_message = match action {
221230
WidgetValueAction::Commit => {
222-
let update_value = value.as_u64().unwrap_or_else(|| panic!("DropdownInput commit was not of type `u64`, found {value:?}"));
223-
(dropdown_input.entries.iter().flatten().nth(update_value as usize).unwrap().on_commit.callback)(&())
231+
let Some(update_value) = value.as_u64() else {
232+
error!("DropdownInput commit was not of type `u64`, found {value:?}");
233+
return;
234+
};
235+
let Some(entry) = dropdown_input.entries.iter().flatten().nth(update_value as usize) else {
236+
error!("DropdownInput commit was not able to find entry for index {update_value}");
237+
return;
238+
};
239+
(entry.on_commit.callback)(&())
224240
}
225241
WidgetValueAction::Update => {
226-
let update_value = value.as_u64().unwrap_or_else(|| panic!("DropdownInput update was not of type `u64`, found {value:?}"));
242+
let Some(update_value) = value.as_u64() else {
243+
error!("DropdownInput update was not of type `u64`, found {value:?}");
244+
return;
245+
};
227246
dropdown_input.selected_index = Some(update_value as u32);
228-
(dropdown_input.entries.iter().flatten().nth(update_value as usize).unwrap().on_update.callback)(&())
247+
let Some(entry) = dropdown_input.entries.iter().flatten().nth(update_value as usize) else {
248+
error!("DropdownInput update was not able to find entry for index {update_value}");
249+
return;
250+
};
251+
(entry.on_update.callback)(&())
229252
}
230253
};
231254

@@ -235,12 +258,27 @@ impl LayoutMessageHandler {
235258
let callback_message = match action {
236259
WidgetValueAction::Commit => (font_input.on_commit.callback)(&()),
237260
WidgetValueAction::Update => {
238-
let update_value = value.as_object().expect("FontInput update was not of type: object");
239-
let font_family_value = update_value.get("fontFamily").expect("FontInput update does not have a fontFamily");
240-
let font_style_value = update_value.get("fontStyle").expect("FontInput update does not have a fontStyle");
261+
let Some(update_value) = value.as_object() else {
262+
error!("FontInput update was not of type: object");
263+
return;
264+
};
265+
let Some(font_family_value) = update_value.get("fontFamily") else {
266+
error!("FontInput update does not have a fontFamily");
267+
return;
268+
};
269+
let Some(font_style_value) = update_value.get("fontStyle") else {
270+
error!("FontInput update does not have a fontStyle");
271+
return;
272+
};
241273

242-
let font_family = font_family_value.as_str().expect("FontInput update fontFamily was not of type: string");
243-
let font_style = font_style_value.as_str().expect("FontInput update fontStyle was not of type: string");
274+
let Some(font_family) = font_family_value.as_str() else {
275+
error!("FontInput update fontFamily was not of type: string");
276+
return;
277+
};
278+
let Some(font_style) = font_style_value.as_str() else {
279+
error!("FontInput update fontStyle was not of type: string");
280+
return;
281+
};
244282

245283
font_input.font_family = font_family.into();
246284
font_input.font_style = font_style.into();
@@ -285,7 +323,10 @@ impl LayoutMessageHandler {
285323
responses.add(callback_message);
286324
}
287325
WidgetValueAction::Update => {
288-
let value = value.as_str().expect("NodeCatalog update was not of type String").to_string();
326+
let Some(value) = value.as_str().map(|s| s.to_string()) else {
327+
error!("NodeCatalog update was not of type String");
328+
return;
329+
};
289330
let callback_message = (node_type_input.on_update.callback)(&value);
290331
responses.add(callback_message);
291332
}
@@ -296,8 +337,11 @@ impl LayoutMessageHandler {
296337
responses.add(callback_message);
297338
}
298339
WidgetValueAction::Update => match value {
299-
Value::Number(num) => {
300-
let update_value = num.as_f64().unwrap();
340+
Value::Number(ref num) => {
341+
let Some(update_value) = num.as_f64() else {
342+
error!("NumberInput update was not of type: f64, found {value:?}");
343+
return;
344+
};
301345
number_input.value = Some(update_value);
302346
let callback_message = (number_input.on_update.callback)(number_input);
303347
responses.add(callback_message);
@@ -323,7 +367,10 @@ impl LayoutMessageHandler {
323367
let callback_message = match action {
324368
WidgetValueAction::Commit => (reference_point_input.on_commit.callback)(&()),
325369
WidgetValueAction::Update => {
326-
let update_value = value.as_str().expect("ReferencePointInput update was not of type: u64");
370+
let Some(update_value) = value.as_str() else {
371+
error!("ReferencePointInput update was not of type: u64");
372+
return;
373+
};
327374
reference_point_input.value = update_value.into();
328375
(reference_point_input.on_update.callback)(reference_point_input)
329376
}
@@ -333,7 +380,10 @@ impl LayoutMessageHandler {
333380
}
334381
Widget::PopoverButton(_) => {}
335382
Widget::RadioInput(radio_input) => {
336-
let update_value = value.as_u64().expect("RadioInput update was not of type: u64");
383+
let Some(update_value) = value.as_u64() else {
384+
error!("RadioInput update was not of type: u64");
385+
return;
386+
};
337387
radio_input.selected_index = Some(update_value as u32);
338388
let callback_message = match action {
339389
WidgetValueAction::Commit => (radio_input.entries[update_value as usize].on_commit.callback)(&()),
@@ -347,7 +397,10 @@ impl LayoutMessageHandler {
347397
let callback_message = match action {
348398
WidgetValueAction::Commit => (text_area_input.on_commit.callback)(&()),
349399
WidgetValueAction::Update => {
350-
let update_value = value.as_str().expect("TextAreaInput update was not of type: string");
400+
let Some(update_value) = value.as_str() else {
401+
error!("TextAreaInput update was not of type: string");
402+
return;
403+
};
351404
text_area_input.value = update_value.into();
352405
(text_area_input.on_update.callback)(text_area_input)
353406
}
@@ -367,7 +420,10 @@ impl LayoutMessageHandler {
367420
let callback_message = match action {
368421
WidgetValueAction::Commit => (text_input.on_commit.callback)(&()),
369422
WidgetValueAction::Update => {
370-
let update_value = value.as_str().expect("TextInput update was not of type: string");
423+
let Some(update_value) = value.as_str() else {
424+
error!("TextInput update was not of type: string");
425+
return;
426+
};
371427
text_input.value = update_value.into();
372428
(text_input.on_update.callback)(text_input)
373429
}
@@ -411,10 +467,11 @@ impl LayoutMessageHandler {
411467
self.layouts[layout_target as usize] = new_layout;
412468

413469
// Update the UI
414-
responses.add(FrontendMessage::UpdateMenuBarLayout {
415-
layout_target,
416-
layout: self.layouts[layout_target as usize].clone().unwrap_menu_layout(action_input_mapping).layout,
417-
});
470+
let Some(layout) = self.layouts[layout_target as usize].clone().as_menu_layout(action_input_mapping).map(|x| x.layout) else {
471+
error!("Called unwrap_menu_layout on a widget layout");
472+
return;
473+
};
474+
responses.add(FrontendMessage::UpdateMenuBarLayout { layout_target, layout });
418475
}
419476
}
420477
}

editor/src/messages/layout/utility_types/layout_widget.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,14 @@ pub enum Layout {
109109
}
110110

111111
impl Layout {
112-
pub fn unwrap_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) -> MenuLayout {
112+
pub fn as_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) -> Option<MenuLayout> {
113113
if let Self::MenuLayout(mut menu) = self {
114114
menu.layout
115115
.iter_mut()
116116
.for_each(|menu_column| menu_column.children.fill_in_shortcut_actions_with_keys(action_input_mapping));
117-
menu
117+
Some(menu)
118118
} else {
119-
panic!("Called unwrap_menu_layout on a widget layout");
119+
None
120120
}
121121
}
122122

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
12221222
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_width), false),
12231223
NodeInput::value(TaggedValue::OptionalF64(TypesettingConfig::default().max_height), false),
12241224
NodeInput::value(TaggedValue::F64(TypesettingConfig::default().tilt), false),
1225+
NodeInput::value(TaggedValue::Bool(false), false),
12251226
],
12261227
..Default::default()
12271228
},
@@ -1281,14 +1282,15 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
12811282
),
12821283
InputMetadata::with_name_description_override(
12831284
"Tilt",
1284-
"Faux italic",
1285+
"Faux italic.",
12851286
WidgetOverride::Number(NumberInputSettings {
12861287
min: Some(-85.),
12871288
max: Some(85.),
12881289
unit: Some("°".to_string()),
12891290
..Default::default()
12901291
}),
12911292
),
1293+
("Per-Glyph Instances", "Splits each text glyph into its own instance, i.e. row in the table of vector data.").into(),
12921294
],
12931295
output_names: vec!["Vector".to_string()],
12941296
..Default::default()

editor/src/messages/portfolio/document_migration.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
635635
}
636636

637637
// Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016
638-
if reference == "Text" && inputs_count != 9 {
638+
if reference == "Text" && inputs_count != 10 {
639639
let mut template = resolve_document_node_type(reference)?.default_node_template();
640640
document.network_interface.replace_implementation(node_id, network_path, &mut template);
641641
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template)?;
@@ -689,6 +689,15 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
689689
},
690690
network_path,
691691
);
692+
document.network_interface.set_input(
693+
&InputConnector::node(*node_id, 9),
694+
if inputs_count >= 10 {
695+
old_inputs[9].clone()
696+
} else {
697+
NodeInput::value(TaggedValue::Bool(false), false)
698+
},
699+
network_path,
700+
);
692701
}
693702

694703
// Upgrade Sine, Cosine, and Tangent nodes to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default
@@ -960,6 +969,22 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
960969
}
961970
}
962971

972+
// Add the "Depth" parameter to the "Instance Index" node
973+
if reference == "Instance Index" && inputs_count == 0 {
974+
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
975+
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
976+
977+
let mut node_path = network_path.to_vec();
978+
node_path.push(*node_id);
979+
980+
document.network_interface.add_import(TaggedValue::None, false, 0, "Primary", "", &node_path);
981+
document.network_interface.add_import(TaggedValue::U32(0), false, 1, "Loop Level", "TODO", &node_path);
982+
}
983+
984+
// ==================================
985+
// PUT ALL MIGRATIONS ABOVE THIS LINE
986+
// ==================================
987+
963988
// Ensure layers are positioned as stacks if they are upstream siblings of another layer
964989
document.network_interface.load_structure();
965990
let all_layers = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::<Vec<_>>();

editor/src/messages/tool/common_functionality/graph_modification_utils.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkIn
357357
}
358358

359359
/// Gets properties from the Text node
360-
pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, TypesettingConfig)> {
360+
pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, TypesettingConfig, bool)> {
361361
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Text")?;
362362

363363
let Some(TaggedValue::String(text)) = &inputs[1].as_value() else { return None };
@@ -368,6 +368,9 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
368368
let Some(&TaggedValue::OptionalF64(max_width)) = inputs[6].as_value() else { return None };
369369
let Some(&TaggedValue::OptionalF64(max_height)) = inputs[7].as_value() else { return None };
370370
let Some(&TaggedValue::F64(tilt)) = inputs[8].as_value() else { return None };
371+
let Some(TaggedValue::Bool(per_glyph_instances)) = &inputs[9].as_value() else {
372+
return None;
373+
};
371374

372375
let typesetting = TypesettingConfig {
373376
font_size,
@@ -377,7 +380,7 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
377380
max_height,
378381
tilt,
379382
};
380-
Some((text, font, typesetting))
383+
Some((text, font, typesetting, *per_glyph_instances))
381384
}
382385

383386
pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {

editor/src/messages/tool/common_functionality/utility_functions.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,22 @@ where
6666

6767
/// Calculates the bounding box of the layer's text, based on the settings for max width and height specified in the typesetting config.
6868
pub fn text_bounding_box(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, font_cache: &FontCache) -> Quad {
69-
let Some((text, font, typesetting)) = get_text(layer, &document.network_interface) else {
69+
let Some((text, font, typesetting, per_glyph_instances)) = get_text(layer, &document.network_interface) else {
7070
return Quad::from_box([DVec2::ZERO, DVec2::ZERO]);
7171
};
7272

7373
let font_data = font_cache.get(font).map(|data| load_font(data));
7474
let far = graphene_std::text::bounding_box(text, font_data, typesetting, false);
7575

76-
Quad::from_box([DVec2::ZERO, far])
76+
// TODO: Once the instances refactor is complete and per_glyph_instances can be removed (since it'll be the default),
77+
// TODO: remove this because the top of the dashed bounding overlay should no longer be based on the first line's baseline.
78+
let vertical_offset = if per_glyph_instances {
79+
DVec2::NEG_Y * typesetting.font_size * (1. + (typesetting.line_height_ratio - 1.) / 2.)
80+
} else {
81+
DVec2::ZERO
82+
};
83+
84+
Quad::from_box([DVec2::ZERO + vertical_offset, far + vertical_offset])
7785
}
7886

7987
pub fn calculate_segment_angle(anchor: PointId, segment: SegmentId, vector_data: &VectorData, prefer_handle_direction: bool) -> Option<f64> {

editor/src/messages/tool/tool_messages/text_tool.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ impl TextToolData {
329329
fn load_layer_text_node(&mut self, document: &DocumentMessageHandler) -> Option<()> {
330330
let transform = document.metadata().transform_to_viewport(self.layer);
331331
let color = graph_modification_utils::get_fill_color(self.layer, &document.network_interface).unwrap_or(Color::BLACK);
332-
let (text, font, typesetting) = graph_modification_utils::get_text(self.layer, &document.network_interface)?;
332+
let (text, font, typesetting, _) = graph_modification_utils::get_text(self.layer, &document.network_interface)?;
333333
self.editing_text = Some(EditingText {
334334
text: text.clone(),
335335
font: font.clone(),
@@ -524,7 +524,7 @@ impl Fsm for TextToolFsmState {
524524
bounding_box_manager.render_quad(&mut overlay_context);
525525
// Draw red overlay if text is clipped
526526
let transformed_quad = layer_transform * bounds;
527-
if let Some((text, font, typesetting)) = graph_modification_utils::get_text(layer.unwrap(), &document.network_interface) {
527+
if let Some((text, font, typesetting, _)) = graph_modification_utils::get_text(layer.unwrap(), &document.network_interface) {
528528
let font_data = font_cache.get(font).map(|data| load_font(data));
529529
if lines_clipping(text.as_str(), font_data, typesetting) {
530530
overlay_context.line(transformed_quad.0[2], transformed_quad.0[3], Some(COLOR_OVERLAY_RED), Some(3.));

editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::consts::{ANGLE_MEASURE_RADIUS_FACTOR, ARC_MEASURE_RADIUS_FACTOR_RANGE, COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GRAY_25, SLOWING_DIVISOR};
1+
use crate::consts::{ANGLE_MEASURE_RADIUS_FACTOR, ARC_MEASURE_RADIUS_FACTOR_RANGE, COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GRAY, SLOWING_DIVISOR};
22
use crate::messages::input_mapper::utility_types::input_mouse::{DocumentPosition, ViewportPosition};
33
use crate::messages::portfolio::document::overlays::utility_types::{OverlayProvider, Pivot};
44
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
@@ -177,7 +177,7 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
177177

178178
if using_path_tool {
179179
for (outline, transform) in &self.ghost_outline {
180-
overlay_context.outline(outline.iter(), *transform, Some(COLOR_OVERLAY_GRAY_25));
180+
overlay_context.outline(outline.iter(), *transform, Some(COLOR_OVERLAY_GRAY));
181181
}
182182
}
183183

@@ -407,6 +407,10 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
407407
TransformLayerMessage::BeginRotate => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Rotate }),
408408
TransformLayerMessage::BeginScale => responses.add_front(TransformLayerMessage::BeginGRS { operation: TransformType::Scale }),
409409
TransformLayerMessage::CancelTransformOperation => {
410+
if using_path_tool {
411+
self.ghost_outline.clear();
412+
}
413+
410414
if using_pen_tool {
411415
self.typing.clear();
412416

@@ -416,8 +420,6 @@ impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for
416420

417421
responses.add(PenToolMessage::Abort);
418422
responses.add(ToolMessage::UpdateHints);
419-
} else if using_path_tool {
420-
self.ghost_outline.clear();
421423
} else {
422424
selected.original_transforms.clear();
423425
self.typing.clear();

0 commit comments

Comments
 (0)