From f129854686a243a742b12273a0c4659212c6ae89 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Sun, 16 Nov 2025 23:28:43 +0100 Subject: [PATCH] Fix assorted Clippy lints --- editor/src/dispatcher.rs | 8 +- .../messages/layout/layout_message_handler.rs | 8 +- .../layout/utility_types/layout_widget.rs | 47 ++- .../document_node_derive.rs | 8 +- .../node_graph/node_graph_message_handler.rs | 23 +- .../document/node_graph/node_properties.rs | 2 +- .../document/overlays/grid_overlays.rs | 8 +- .../utility_types/document_metadata.rs | 18 +- .../utility_types/network_interface.rs | 320 +++++++++--------- .../messages/portfolio/document_migration.rs | 42 ++- .../portfolio/portfolio_message_handler.rs | 42 +-- .../shape_gizmos/grid_rows_columns_gizmo.rs | 4 +- .../shape_gizmos/number_of_points_dial.rs | 16 +- .../tool/common_functionality/shape_editor.rs | 78 +++-- .../tool/common_functionality/snapping.rs | 24 +- .../snapping/alignment_snapper.rs | 58 ++-- .../transformation_cage.rs | 22 +- .../common_functionality/utility_functions.rs | 8 +- .../messages/tool/tool_messages/brush_tool.rs | 24 +- .../tool/tool_messages/freehand_tool.rs | 26 +- .../tool/tool_messages/gradient_tool.rs | 19 +- .../messages/tool/tool_messages/path_tool.rs | 79 ++--- .../messages/tool/tool_messages/pen_tool.rs | 89 +++-- .../tool/tool_messages/select_tool.rs | 97 +++--- .../messages/tool/tool_messages/text_tool.rs | 148 ++++---- editor/src/node_graph_executor.rs | 4 +- node-graph/graph-craft/src/document.rs | 104 +++--- .../interpreted-executor/src/node_registry.rs | 8 +- .../node-macro/src/derive_choice_type.rs | 14 +- node-graph/node-macro/src/parsing.rs | 33 +- 30 files changed, 678 insertions(+), 703 deletions(-) diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs index 4119eb0aa9..4018c0d00b 100644 --- a/editor/src/dispatcher.rs +++ b/editor/src/dispatcher.rs @@ -290,10 +290,10 @@ impl Dispatcher { list.extend(self.message_handlers.input_preprocessor_message_handler.actions()); list.extend(self.message_handlers.key_mapping_message_handler.actions()); list.extend(self.message_handlers.debug_message_handler.actions()); - if let Some(document) = self.message_handlers.portfolio_message_handler.active_document() { - if !document.graph_view_overlay_open { - list.extend(self.message_handlers.tool_message_handler.actions()); - } + if let Some(document) = self.message_handlers.portfolio_message_handler.active_document() + && !document.graph_view_overlay_open + { + list.extend(self.message_handlers.tool_message_handler.actions()); } list.extend(self.message_handlers.portfolio_message_handler.actions()); list diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index 587c0e8303..a80fa887cb 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -156,10 +156,10 @@ impl LayoutMessageHandler { let blue = color.get("blue").and_then(|x| x.as_f64()).map(|x| x as f32); let alpha = color.get("alpha").and_then(|x| x.as_f64()).map(|x| x as f32); - if let (Some(red), Some(green), Some(blue), Some(alpha)) = (red, green, blue, alpha) { - if let Some(color) = Color::from_rgbaf32(red, green, blue, alpha) { - return Some(color); - } + if let (Some(red), Some(green), Some(blue), Some(alpha)) = (red, green, blue, alpha) + && let Some(color) = Color::from_rgbaf32(red, green, blue, alpha) + { + return Some(color); } None }; diff --git a/editor/src/messages/layout/utility_types/layout_widget.rs b/editor/src/messages/layout/utility_types/layout_widget.rs index c81e5e264c..446b09ec0d 100644 --- a/editor/src/messages/layout/utility_types/layout_widget.rs +++ b/editor/src/messages/layout/utility_types/layout_widget.rs @@ -508,23 +508,22 @@ impl WidgetHolder { /// Diffing updates self (where self is old) based on new, updating the list of modifications as it does so. pub fn diff(&mut self, new: Self, widget_path: &mut [usize], widget_diffs: &mut Vec) { - if let (Widget::PopoverButton(button1), Widget::PopoverButton(button2)) = (&mut self.widget, &new.widget) { - if button1.disabled == button2.disabled - && button1.style == button2.style - && button1.menu_direction == button2.menu_direction - && button1.icon == button2.icon - && button1.tooltip == button2.tooltip - && button1.tooltip_shortcut == button2.tooltip_shortcut - && button1.popover_min_width == button2.popover_min_width - { - let mut new_widget_path = widget_path.to_vec(); - for (i, (a, b)) in button1.popover_layout.iter_mut().zip(button2.popover_layout.iter()).enumerate() { - new_widget_path.push(i); - a.diff(b.clone(), &mut new_widget_path, widget_diffs); - new_widget_path.pop(); - } - return; + if let (Widget::PopoverButton(button1), Widget::PopoverButton(button2)) = (&mut self.widget, &new.widget) + && button1.disabled == button2.disabled + && button1.style == button2.style + && button1.menu_direction == button2.menu_direction + && button1.icon == button2.icon + && button1.tooltip == button2.tooltip + && button1.tooltip_shortcut == button2.tooltip_shortcut + && button1.popover_min_width == button2.popover_min_width + { + let mut new_widget_path = widget_path.to_vec(); + for (i, (a, b)) in button1.popover_layout.iter_mut().zip(button2.popover_layout.iter()).enumerate() { + new_widget_path.push(i); + a.diff(b.clone(), &mut new_widget_path, widget_diffs); + new_widget_path.pop(); } + return; } // If there have been changes to the actual widget (not just the id) @@ -621,15 +620,15 @@ impl DiffUpdate { let apply_shortcut_to_tooltip = |tooltip_shortcut: &mut ActionKeys, tooltip: &mut String| { let shortcut_text = tooltip_shortcut.to_keys(action_input_mapping); - if let ActionKeys::Keys(_keys) = tooltip_shortcut { - if !shortcut_text.is_empty() { - if !tooltip.is_empty() { - tooltip.push(' '); - } - tooltip.push('('); - tooltip.push_str(&shortcut_text); - tooltip.push(')'); + if let ActionKeys::Keys(_keys) = tooltip_shortcut + && !shortcut_text.is_empty() + { + if !tooltip.is_empty() { + tooltip.push(' '); } + tooltip.push('('); + tooltip.push_str(&shortcut_text); + tooltip.push(')'); } }; diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs index f9db802ac5..a0e09e1296 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs @@ -14,10 +14,10 @@ pub(super) fn post_process_nodes(mut custom: Vec) -> Vec .. } = node_template; - if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = implementation { - if let Some((new_name, _suffix)) = name.rsplit_once("<") { - *name = Cow::Owned(new_name.to_string()) - } + if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = implementation + && let Some((new_name, _suffix)) = name.rsplit_once("<") + { + *name = Cow::Owned(new_name.to_string()) }; } diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 379da12328..401140f988 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -1011,10 +1011,11 @@ impl<'a> MessageHandler> for NodeG // Disconnect if the wire was previously connected to an input if let Some(disconnecting) = &self.disconnecting { let mut disconnect_root_node = false; - if let Previewing::Yes { root_node_to_restore } = network_interface.previewing(selection_network_path) { - if root_node_to_restore.is_some() && *disconnecting == InputConnector::Export(0) { - disconnect_root_node = true; - } + if let Previewing::Yes { root_node_to_restore } = network_interface.previewing(selection_network_path) + && root_node_to_restore.is_some() + && *disconnecting == InputConnector::Export(0) + { + disconnect_root_node = true; } if disconnect_root_node { responses.add(NodeGraphMessage::DisconnectRootNode); @@ -1168,13 +1169,13 @@ impl<'a> MessageHandler> for NodeG responses.add(NodeGraphMessage::TogglePreview { node_id: preview_node }); self.preview_on_mouse_up = None; } - if let Some(node_to_deselect) = self.deselect_on_pointer_up.take() { - if !self.drag_start.as_ref().is_some_and(|t| t.1) { - let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone(); - new_selected_nodes.remove(node_to_deselect); - responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_selected_nodes }); - return; - } + if let Some(node_to_deselect) = self.deselect_on_pointer_up.take() + && !self.drag_start.as_ref().is_some_and(|t| t.1) + { + let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone(); + new_selected_nodes.remove(node_to_deselect); + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_selected_nodes }); + return; } let point = network_metadata .persistent_metadata diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 184df8bf34..20bc85a508 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -492,7 +492,7 @@ pub fn footprint_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widg ); } - let widgets = vec![ + let widgets = [ LayoutGroup::Row { widgets: location_widgets }, LayoutGroup::Row { widgets: scale_widgets }, LayoutGroup::Row { widgets: resolution_widgets }, diff --git a/editor/src/messages/portfolio/document/overlays/grid_overlays.rs b/editor/src/messages/portfolio/document/overlays/grid_overlays.rs index d54a5f2ad0..b02a61eda1 100644 --- a/editor/src/messages/portfolio/document/overlays/grid_overlays.rs +++ b/editor/src/messages/portfolio/document/overlays/grid_overlays.rs @@ -213,10 +213,10 @@ pub fn overlay_options(grid: &GridSnapping) -> Vec { } let update_origin = |grid, update: fn(&mut GridSnapping) -> Option<&mut f64>| { update_val::(grid, move |grid, val| { - if let Some(val) = val.value { - if let Some(update) = update(grid) { - *update = val; - } + if let Some(val) = val.value + && let Some(update) = update(grid) + { + *update = val; } }) }; diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index 63b2d865b7..7ba8eaa7ae 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -91,16 +91,14 @@ impl DocumentMetadata { let mut use_local = true; let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, network_interface); - if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path") { - if let Some(&source) = self.first_element_source_ids.get(&layer.to_node()) { - if !network_interface - .upstream_flow_back_from_nodes(vec![path_node], &[], FlowType::HorizontalFlow) - .any(|upstream| Some(upstream) == source) - { - use_local = false; - info!("Local transform is invalid — using the identity for the local transform instead") - } - } + if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path") + && let Some(&source) = self.first_element_source_ids.get(&layer.to_node()) + && !network_interface + .upstream_flow_back_from_nodes(vec![path_node], &[], FlowType::HorizontalFlow) + .any(|upstream| Some(upstream) == source) + { + use_local = false; + info!("Local transform is invalid — using the identity for the local transform instead") } let local_transform = use_local.then(|| self.local_transforms.get(&layer.to_node()).copied()).flatten().unwrap_or_default(); diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index 2920cc360e..4f576aabd8 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -79,10 +79,11 @@ impl NodeNetworkInterface { if let Some(network) = node.implementation.get_network_mut() { fix_network(network); } - if let DocumentNodeImplementation::ProtoNode(protonode) = &node.implementation { - if protonode.name.contains("PathModifyNode") && node.inputs.len() < 3 { - node.inputs.push(NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath)); - } + if let DocumentNodeImplementation::ProtoNode(protonode) = &node.implementation + && protonode.name.contains("PathModifyNode") + && node.inputs.len() < 3 + { + node.inputs.push(NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath)); } } } @@ -1450,21 +1451,20 @@ impl NodeNetworkInterface { .all_layers() .filter(|layer| include_artboards || !self.is_artboard(&layer.to_node(), &[])) .filter_map(|layer| { - if !self.is_artboard(&layer.to_node(), &[]) { - if let Some(artboard_node_identifier) = layer + if !self.is_artboard(&layer.to_node(), &[]) + && let Some(artboard_node_identifier) = layer .ancestors(self.document_metadata()) .find(|ancestor| *ancestor != LayerNodeIdentifier::ROOT_PARENT && self.is_artboard(&ancestor.to_node(), &[])) + { + let artboard = self.document_node(&artboard_node_identifier.to_node(), &[]); + let clip_input = artboard.unwrap().inputs.get(5).unwrap(); + if let NodeInput::Value { tagged_value, .. } = clip_input + && tagged_value.clone().deref() == &TaggedValue::Bool(true) { - let artboard = self.document_node(&artboard_node_identifier.to_node(), &[]); - let clip_input = artboard.unwrap().inputs.get(5).unwrap(); - if let NodeInput::Value { tagged_value, .. } = clip_input { - if tagged_value.clone().deref() == &TaggedValue::Bool(true) { - return Some(Quad::clip( - self.document_metadata.bounding_box_document(layer).unwrap_or_default(), - self.document_metadata.bounding_box_document(artboard_node_identifier).unwrap_or_default(), - )); - } - } + return Some(Quad::clip( + self.document_metadata.bounding_box_document(layer).unwrap_or_default(), + self.document_metadata.bounding_box_document(artboard_node_identifier).unwrap_or_default(), + )); } } self.document_metadata.bounding_box_document(layer) @@ -1557,7 +1557,7 @@ impl NodeNetworkInterface { log::error!("Could not get network or network_metadata in upstream_flow_back_from_nodes"); return FlowIter { stack: Vec::new(), - network: &self.document_network(), + network: self.document_network(), network_metadata: &self.network_metadata, flow_type: FlowType::UpstreamFlow, }; @@ -2535,10 +2535,8 @@ impl NodeNetworkInterface { }; // If the node is a layer, then the width and click targets need to be recalculated - if is_layer { - if let NodeTypeTransientMetadata::Layer(layer_metadata) = &mut node_metadata.transient_metadata.node_type_metadata { - layer_metadata.layer_width.unload(); - } + if is_layer && let NodeTypeTransientMetadata::Layer(layer_metadata) = &mut node_metadata.transient_metadata.node_type_metadata { + layer_metadata.layer_width.unload(); } } @@ -3484,17 +3482,17 @@ impl NodeNetworkInterface { pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option { let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self); - if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path") { - if let Some(vector) = self.document_metadata.vector_modify.get(&path_node) { - let mut modified = vector.clone(); + if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path") + && let Some(vector) = self.document_metadata.vector_modify.get(&path_node) + { + let mut modified = vector.clone(); - let path_node = self.document_network().nodes.get(&path_node); - let modification_input = path_node.and_then(|node: &DocumentNode| node.inputs.get(1)).and_then(|input| input.as_value()); - if let Some(TaggedValue::VectorModification(modification)) = modification_input { - modification.apply(&mut modified); - } - return Some(modified); + let path_node = self.document_network().nodes.get(&path_node); + let modification_input = path_node.and_then(|node: &DocumentNode| node.inputs.get(1)).and_then(|input| input.as_value()); + if let Some(TaggedValue::VectorModification(modification)) = modification_input { + modification.apply(&mut modified); } + return Some(modified); } self.document_metadata @@ -3701,10 +3699,11 @@ impl NodeNetworkInterface { let mut encapsulating_path = network_path.to_vec(); // Set the parent node (if it exists) to be a non layer if it is no longer eligible to be a layer - if let Some(parent_id) = encapsulating_path.pop() { - if !self.is_eligible_to_be_layer(&parent_id, &encapsulating_path) && self.is_layer(&parent_id, &encapsulating_path) { - self.set_to_node_or_layer(&parent_id, &encapsulating_path, false); - } + if let Some(parent_id) = encapsulating_path.pop() + && !self.is_eligible_to_be_layer(&parent_id, &encapsulating_path) + && self.is_layer(&parent_id, &encapsulating_path) + { + self.set_to_node_or_layer(&parent_id, &encapsulating_path, false); }; // There will not be an encapsulating node if the network is the document network @@ -4170,12 +4169,12 @@ impl NodeNetworkInterface { /// Used to ensure the display name is the reference name in case it is empty. pub fn validate_display_name_metadata(&mut self, node_id: &NodeId, network_path: &[NodeId]) { let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return }; - if metadata.persistent_metadata.display_name.is_empty() { - if let Some(reference) = metadata.persistent_metadata.reference.clone() { - // Keep the name for merge nodes as empty - if reference != "Merge" { - metadata.persistent_metadata.display_name = reference; - } + if metadata.persistent_metadata.display_name.is_empty() + && let Some(reference) = metadata.persistent_metadata.reference.clone() + { + // Keep the name for merge nodes as empty + if reference != "Merge" { + metadata.persistent_metadata.display_name = reference; } } } @@ -4245,10 +4244,10 @@ impl NodeNetworkInterface { } // If the previous input is connected to a chain node, then set all upstream chain nodes to absolute position - if let NodeInput::Node { node_id: previous_upstream_id, .. } = &previous_input { - if self.is_chain(previous_upstream_id, network_path) { - self.set_upstream_chain_to_absolute(previous_upstream_id, network_path); - } + if let NodeInput::Node { node_id: previous_upstream_id, .. } = &previous_input + && self.is_chain(previous_upstream_id, network_path) + { + self.set_upstream_chain_to_absolute(previous_upstream_id, network_path); } if let NodeInput::Node { node_id: new_upstream_id, .. } = &new_input { // If the new input is connected to a chain node, then break its chain @@ -4424,11 +4423,11 @@ impl NodeNetworkInterface { }; // If it is a layer and is connected to a single layer, set its position to stack at its previous y position if old_upstream_node_is_layer && outward_wires.len() == 1 && outward_wires[0].input_index() == 0 { - if let Some(downstream_node_id) = outward_wires[0].node_id() { - if self.is_layer(&downstream_node_id, network_path) { - self.set_stack_position_calculated_offset(&old_upstream_node_id, &downstream_node_id, network_path); - self.unload_upstream_node_click_targets(vec![old_upstream_node_id], network_path); - } + if let Some(downstream_node_id) = outward_wires[0].node_id() + && self.is_layer(&downstream_node_id, network_path) + { + self.set_stack_position_calculated_offset(&old_upstream_node_id, &downstream_node_id, network_path); + self.unload_upstream_node_click_targets(vec![old_upstream_node_id], network_path); } } // If it is a node and is eligible to be in a chain, then set it to chain positioning @@ -4488,18 +4487,16 @@ impl NodeNetworkInterface { return; }; let mut other_outward_wires = outward_wires.iter().filter(|outward_wire| *outward_wire != input_connector); - if let Some(other_outward_wire) = other_outward_wires.next().cloned() { - if other_outward_wires.next().is_none() { - if let InputConnector::Node { - node_id: downstream_node_id, - input_index, - } = other_outward_wire - { - if self.is_layer(&downstream_node_id, network_path) && input_index == 0 { - self.set_stack_position_calculated_offset(upstream_node_id, &downstream_node_id, network_path); - } - } - } + if let Some(other_outward_wire) = other_outward_wires.next().cloned() + && other_outward_wires.next().is_none() + && let InputConnector::Node { + node_id: downstream_node_id, + input_index, + } = other_outward_wire + && self.is_layer(&downstream_node_id, network_path) + && input_index == 0 + { + self.set_stack_position_calculated_offset(upstream_node_id, &downstream_node_id, network_path); } } } @@ -4625,10 +4622,10 @@ impl NodeNetworkInterface { let Some(downstream_node) = self.document_node(deleted_node_id, network_path) else { continue }; let Some(input) = downstream_node.inputs.first() else { continue }; - if let NodeInput::Node { node_id, .. } = input { - if *node_id == current_node_id { - stack.push(OutputConnector::node(*deleted_node_id, 0)); - } + if let NodeInput::Node { node_id, .. } = input + && *node_id == current_node_id + { + stack.push(OutputConnector::node(*deleted_node_id, 0)); } } } @@ -4719,12 +4716,12 @@ impl NodeNetworkInterface { for downstream_input in &downstream_inputs_to_disconnect { self.disconnect_input(downstream_input, network_path); // Prevent reconnecting export to import until https://github.com/GraphiteEditor/Graphite/issues/1762 is solved - if !(matches!(reconnect_to_input, Some(NodeInput::Import { .. })) && matches!(downstream_input, InputConnector::Export(_))) { - if let Some(reconnect_input) = &reconnect_to_input { - reconnect_node = reconnect_input.as_node().and_then(|node_id| if self.is_stack(&node_id, network_path) { Some(node_id) } else { None }); - self.disconnect_input(&InputConnector::node(*node_id, 0), network_path); - self.set_input(downstream_input, reconnect_input.clone(), network_path); - } + if !(matches!(reconnect_to_input, Some(NodeInput::Import { .. })) && matches!(downstream_input, InputConnector::Export(_))) + && let Some(reconnect_input) = &reconnect_to_input + { + reconnect_node = reconnect_input.as_node().and_then(|node_id| if self.is_stack(&node_id, network_path) { Some(node_id) } else { None }); + self.disconnect_input(&InputConnector::node(*node_id, 0), network_path); + self.set_input(downstream_input, reconnect_input.clone(), network_path); } } @@ -5296,11 +5293,9 @@ impl NodeNetworkInterface { if let Some(outward_wires) = self .outward_wires(network_path) .and_then(|outward_wires| outward_wires.get(&OutputConnector::node(*node_id, 0))) - .cloned() + .cloned() && outward_wires.len() == 1 { - if outward_wires.len() == 1 { - self.try_set_upstream_to_chain(&outward_wires[0], network_path) - } + self.try_set_upstream_to_chain(&outward_wires[0], network_path) } } @@ -5400,13 +5395,13 @@ impl NodeNetworkInterface { }; if !shift_without_push { for node_id in node_ids.clone() { - if self.is_layer(&node_id, network_path) { - if let Some(owned_nodes) = self.owned_nodes(&node_id, network_path) { - for owned_node in owned_nodes { - node_ids.remove(owned_node); - } - }; - } + if self.is_layer(&node_id, network_path) + && let Some(owned_nodes) = self.owned_nodes(&node_id, network_path) + { + for owned_node in owned_nodes { + node_ids.remove(owned_node); + } + }; } } @@ -5428,22 +5423,22 @@ impl NodeNetworkInterface { log::error!("Could not get node metadata for node {node_id} in shift_selected_nodes"); return; }; - if let NodeTypePersistentMetadata::Layer(layer_metadata) = &node_metadata.persistent_metadata.node_type_metadata { - if let LayerPosition::Stack(offset) = layer_metadata.position { - // If the upstream layer is selected, then skip - let Some(outward_wires) = self.outward_wires(network_path).and_then(|outward_wires| outward_wires.get(&OutputConnector::node(*node_id, 0))) else { - log::error!("Could not get outward wires in shift_selected_nodes"); - return; - }; - if let Some(upstream_node) = outward_wires.first() { - if node_ids.contains(&upstream_node.node_id().expect("Stack layer should have downstream layer")) { - continue; - } - } - // Offset cannot be negative, so cancel the shift - if offset == 0 { - return; - } + if let NodeTypePersistentMetadata::Layer(layer_metadata) = &node_metadata.persistent_metadata.node_type_metadata + && let LayerPosition::Stack(offset) = layer_metadata.position + { + // If the upstream layer is selected, then skip + let Some(outward_wires) = self.outward_wires(network_path).and_then(|outward_wires| outward_wires.get(&OutputConnector::node(*node_id, 0))) else { + log::error!("Could not get outward wires in shift_selected_nodes"); + return; + }; + if let Some(upstream_node) = outward_wires.first() + && node_ids.contains(&upstream_node.node_id().expect("Stack layer should have downstream layer")) + { + continue; + } + // Offset cannot be negative, so cancel the shift + if offset == 0 { + return; } } } @@ -5528,11 +5523,11 @@ impl NodeNetworkInterface { log::error!("Could not get nested network_metadata in export_ports"); continue; }; - if let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents { - if let Some(LayerOwner::None(offset)) = stack_dependents.get_mut(node_id) { - *offset += shift_sign; - self.transaction_modified(); - }; + if let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents + && let Some(LayerOwner::None(offset)) = stack_dependents.get_mut(node_id) + { + *offset += shift_sign; + self.transaction_modified(); }; // Shift the upstream layer so that it stays in the same place @@ -5804,14 +5799,13 @@ impl NodeNetworkInterface { // A layer is considered to be the height of that layer plus the height to the upstream layer sibling // If a non artboard layer is attempted to be connected to the exports, and there is already an artboard connected, then connect the layer to the artboard. - if let Some(first_layer) = LayerNodeIdentifier::ROOT_PARENT.children(&self.document_metadata).next() { - if parent == LayerNodeIdentifier::ROOT_PARENT - && self.reference(&layer.to_node(), network_path).is_none_or(|reference| *reference != Some("Artboard".to_string())) - && self.is_artboard(&first_layer.to_node(), network_path) - { - parent = first_layer; - insert_index = 0; - } + if let Some(first_layer) = LayerNodeIdentifier::ROOT_PARENT.children(&self.document_metadata).next() + && parent == LayerNodeIdentifier::ROOT_PARENT + && self.reference(&layer.to_node(), network_path).is_none_or(|reference| *reference != Some("Artboard".to_string())) + && self.is_artboard(&first_layer.to_node(), network_path) + { + parent = first_layer; + insert_index = 0; } let Some(layer_to_move_position) = self.position(&layer.to_node(), network_path) else { @@ -5870,22 +5864,20 @@ impl NodeNetworkInterface { let mut downstream_height = 0; let inserting_into_stack = !(post_node.input_index() == 1 || matches!(post_node, InputConnector::Export(_)) || !post_node.node_id().is_some_and(|post_node_id| self.is_layer(&post_node_id, network_path))); - if inserting_into_stack { - if let Some(downstream_node) = post_node.node_id() { - let Some(downstream_node_position) = self.position(&downstream_node, network_path) else { - log::error!("Could not get downstream node position in move_layer_to_stack"); - return; - }; - let mut lowest_y_position = downstream_node_position.y + 3; + if inserting_into_stack && let Some(downstream_node) = post_node.node_id() { + let Some(downstream_node_position) = self.position(&downstream_node, network_path) else { + log::error!("Could not get downstream node position in move_layer_to_stack"); + return; + }; + let mut lowest_y_position = downstream_node_position.y + 3; - for bottom_position in self.upstream_nodes_below_layer(&downstream_node, network_path).iter().filter_map(|node_id| { - let is_layer = self.is_layer(node_id, network_path); - self.position(node_id, network_path).map(|position| position.y + if is_layer { 3 } else { 2 }) - }) { - lowest_y_position = lowest_y_position.max(bottom_position); - } - downstream_height = lowest_y_position - (downstream_node_position.y + 3); + for bottom_position in self.upstream_nodes_below_layer(&downstream_node, network_path).iter().filter_map(|node_id| { + let is_layer = self.is_layer(node_id, network_path); + self.position(node_id, network_path).map(|position| position.y + if is_layer { 3 } else { 2 }) + }) { + lowest_y_position = lowest_y_position.max(bottom_position); } + downstream_height = lowest_y_position - (downstream_node_position.y + 3); } let mut highest_y_position = layer_to_move_position.y; @@ -5933,53 +5925,53 @@ impl NodeNetworkInterface { } // If inserting into a stack with a parent, ensure the parent stack has enough space for the child stack - if parent != LayerNodeIdentifier::ROOT_PARENT { - if let Some(upstream_sibling) = parent.next_sibling(&self.document_metadata) { - let Some(parent_position) = self.position(&parent.to_node(), network_path) else { - log::error!("Could not get parent position in move_layer_to_stack"); - return; - }; - let last_child = parent.last_child(&self.document_metadata).unwrap_or(parent); - - let Some(mut last_child_position) = self.position(&last_child.to_node(), network_path) else { - log::error!("Could not get last child position in move_layer_to_stack"); - return; - }; + if parent != LayerNodeIdentifier::ROOT_PARENT + && let Some(upstream_sibling) = parent.next_sibling(&self.document_metadata) + { + let Some(parent_position) = self.position(&parent.to_node(), network_path) else { + log::error!("Could not get parent position in move_layer_to_stack"); + return; + }; + let last_child = parent.last_child(&self.document_metadata).unwrap_or(parent); - if self.is_layer(&last_child.to_node(), network_path) { - last_child_position.y += 3; - } else { - last_child_position.y += 2; - } + let Some(mut last_child_position) = self.position(&last_child.to_node(), network_path) else { + log::error!("Could not get last child position in move_layer_to_stack"); + return; + }; - // If inserting below the current last child, then the last child is layer to move - if post_node.node_id() == Some(last_child.to_node()) { - last_child_position += height_above_layer + 3 + height_below_layer; - } + if self.is_layer(&last_child.to_node(), network_path) { + last_child_position.y += 3; + } else { + last_child_position.y += 2; + } - let Some(upstream_sibling_position) = self.position(&upstream_sibling.to_node(), network_path) else { - log::error!("Could not get upstream sibling position in move_layer_to_stack"); - return; - }; + // If inserting below the current last child, then the last child is layer to move + if post_node.node_id() == Some(last_child.to_node()) { + last_child_position += height_above_layer + 3 + height_below_layer; + } - let target_gap = last_child_position.y - parent_position.y + 3; - let current_gap = upstream_sibling_position.y - parent_position.y; + let Some(upstream_sibling_position) = self.position(&upstream_sibling.to_node(), network_path) else { + log::error!("Could not get upstream sibling position in move_layer_to_stack"); + return; + }; - let upstream_nodes = self - .upstream_flow_back_from_nodes(vec![upstream_sibling.to_node()], network_path, FlowType::UpstreamFlow) - .collect::>(); - let Some(selected_nodes) = self.selected_nodes_mut(network_path) else { - log::error!("Could not get selected nodes in move_layer_to_stack"); - return; - }; - let old_selected_nodes = selected_nodes.replace_with(upstream_nodes); + let target_gap = last_child_position.y - parent_position.y + 3; + let current_gap = upstream_sibling_position.y - parent_position.y; - for _ in 0..(target_gap - current_gap).max(0) { - self.shift_selected_nodes(Direction::Down, true, network_path); - } + let upstream_nodes = self + .upstream_flow_back_from_nodes(vec![upstream_sibling.to_node()], network_path, FlowType::UpstreamFlow) + .collect::>(); + let Some(selected_nodes) = self.selected_nodes_mut(network_path) else { + log::error!("Could not get selected nodes in move_layer_to_stack"); + return; + }; + let old_selected_nodes = selected_nodes.replace_with(upstream_nodes); - let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes); + for _ in 0..(target_gap - current_gap).max(0) { + self.shift_selected_nodes(Direction::Down, true, network_path); } + + let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes); } // Connect the layer to a parent layer/node at the top of the stack, or a non layer node midway down the stack diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index 545c996a77..73cf35cfe3 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -581,11 +581,9 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_ } fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document: &mut DocumentMessageHandler, reset_node_definitions_on_open: bool) -> Option<()> { - if reset_node_definitions_on_open { - if let Some(Some(reference)) = document.network_interface.reference(node_id, network_path) { - let node_definition = resolve_document_node_type(reference)?; - document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template()); - } + if reset_node_definitions_on_open && let Some(Some(reference)) = document.network_interface.reference(node_id, network_path) { + let node_definition = resolve_document_node_type(reference)?; + document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template()); } // Upgrade old nodes to use `Context` instead of `()` or `Footprint` as their call argument @@ -1018,11 +1016,11 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], .network_interface .input_from_connector(&InputConnector::Node { node_id: *node_id, input_index: 3 }, network_path)?; - if let NodeInput::Value { tagged_value, exposed } = quantity_value { - if let TaggedValue::F64(value) = **tagged_value { - let new_quantity_value = NodeInput::value(TaggedValue::U32(value as u32), *exposed); - document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path); - } + if let NodeInput::Value { tagged_value, exposed } = quantity_value + && let TaggedValue::F64(value) = **tagged_value + { + let new_quantity_value = NodeInput::value(TaggedValue::U32(value as u32), *exposed); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), new_quantity_value, network_path); } } @@ -1037,18 +1035,18 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], let mut upgraded = false; - if let Some(NodeInput::Value { tagged_value, exposed: _ }) = index_3_value { - if matches!(*tagged_value, TaggedValue::DVec2(_)) { - // Move index 3 to the end - document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[4].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path); - - upgraded = true; - } + if let Some(NodeInput::Value { tagged_value, exposed: _ }) = index_3_value + && matches!(*tagged_value, TaggedValue::DVec2(_)) + { + // Move index 3 to the end + document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 3), old_inputs[4].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[5].clone(), network_path); + document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path); + + upgraded = true; } if !upgraded { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index f034d85a65..a1364c03bc 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -116,22 +116,22 @@ impl MessageHandler> for Portfolio self.menu_bar_message_handler.process_message(message, responses, ()); } PortfolioMessage::Document(message) => { - if let Some(document_id) = self.active_document_id { - if let Some(document) = self.documents.get_mut(&document_id) { - let document_inputs = DocumentMessageContext { - document_id, - ipp, - persistent_data: &self.persistent_data, - executor: &mut self.executor, - current_tool, - preferences, - viewport, - data_panel_open: self.data_panel_open, - layers_panel_open: self.layers_panel_open, - properties_panel_open: self.properties_panel_open, - }; - document.process_message(message, responses, document_inputs) - } + if let Some(document_id) = self.active_document_id + && let Some(document) = self.documents.get_mut(&document_id) + { + let document_inputs = DocumentMessageContext { + document_id, + ipp, + persistent_data: &self.persistent_data, + executor: &mut self.executor, + current_tool, + preferences, + viewport, + data_panel_open: self.data_panel_open, + layers_panel_open: self.layers_panel_open, + properties_panel_open: self.properties_panel_open, + }; + document.process_message(message, responses, document_inputs) } } @@ -175,11 +175,11 @@ impl MessageHandler> for Portfolio } } PortfolioMessage::AutoSaveActiveDocument => { - if let Some(document_id) = self.active_document_id { - if let Some(document) = self.active_document_mut() { - document.set_auto_save_state(true); - responses.add(PortfolioMessage::AutoSaveDocument { document_id }); - } + if let Some(document_id) = self.active_document_id + && let Some(document) = self.active_document_mut() + { + document.set_auto_save_state(true); + responses.add(PortfolioMessage::AutoSaveDocument { document_id }); } } PortfolioMessage::AutoSaveAllDocuments => { diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/grid_rows_columns_gizmo.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/grid_rows_columns_gizmo.rs index 51d6e45c94..308dbbdb48 100644 --- a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/grid_rows_columns_gizmo.rs +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/grid_rows_columns_gizmo.rs @@ -272,7 +272,7 @@ fn calculate_isometric_top_line_points(columns: u32, rows: u32, spacing: DVec2, let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(spacing.x * 0.5, 0.) }; let isometric_spacing = calculate_isometric_offset(spacing, angles); let isometric_offset = DVec2::new(0., isometric_spacing.y); - let end_isometric_offset = if columns % 2 == 0 { DVec2::ZERO } else { DVec2::new(0., isometric_spacing.y) }; + let end_isometric_offset = if columns.is_multiple_of(2) { DVec2::ZERO } else { DVec2::new(0., isometric_spacing.y) }; (top_left + offset - isometric_offset, top_right - offset - end_isometric_offset) } @@ -282,7 +282,7 @@ fn calculate_isometric_bottom_line_points(columns: u32, rows: u32, spacing: DVec let bottom_right = calculate_isometric_point(columns - 1, rows - 1, angles, spacing); let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(spacing.x * 0.5, 0.) }; - let isometric_offset = if columns % 2 == 0 { + let isometric_offset = if columns.is_multiple_of(2) { let offset = calculate_isometric_offset(spacing, angles); DVec2::new(0., offset.y) } else { diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs index fa4dbe2ed8..c6fef1fbda 100644 --- a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs @@ -108,10 +108,10 @@ impl NumberOfPointsDial { let viewport = document.metadata().transform_to_viewport(layer); let center = viewport.transform_point2(DVec2::ZERO); - if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, mouse_position, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD) { - if closest_segment.layer() == layer { - return; - } + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, mouse_position, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD) + && closest_segment.layer() == layer + { + return; } let point_on_max_radius = star_vertex_position(viewport, 0, sides, radius1, radius2); @@ -126,10 +126,10 @@ impl NumberOfPointsDial { let viewport = document.metadata().transform_to_viewport(layer); let center = viewport.transform_point2(DVec2::ZERO); - if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, mouse_position, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD) { - if closest_segment.layer() == layer { - return; - } + if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, mouse_position, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD) + && closest_segment.layer() == layer + { + return; } let point_on_max_radius = polygon_vertex_position(viewport, 0, sides, radius); diff --git a/editor/src/messages/tool/common_functionality/shape_editor.rs b/editor/src/messages/tool/common_functionality/shape_editor.rs index bc84cfa0b0..5f00d97111 100644 --- a/editor/src/messages/tool/common_functionality/shape_editor.rs +++ b/editor/src/messages/tool/common_functionality/shape_editor.rs @@ -691,10 +691,10 @@ impl ShapeState { let mut selected_stack = Vec::new(); // Find all subpaths that have been clicked for stroke in vector.stroke_bezier_paths() { - if stroke.contains_point(layer_mouse) { - if let Some(first) = stroke.manipulator_groups().first() { - selected_stack.push(first.id); - } + if stroke.contains_point(layer_mouse) + && let Some(first) = stroke.manipulator_groups().first() + { + selected_stack.push(first.id); } } state.clear_points(); @@ -929,20 +929,20 @@ impl ShapeState { ManipulatorPointId::Anchor(point) => self.move_anchor(point, &vector, delta, layer, None, responses), ManipulatorPointId::PrimaryHandle(segment) => { self.move_primary(segment, delta, layer, responses); - if let Some(handle) = point.as_handle() { - if let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) { - let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false }; - responses.add(GraphOperationMessage::Vector { layer, modification_type }); - } + if let Some(handle) = point.as_handle() + && let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) + { + let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); } } ManipulatorPointId::EndHandle(segment) => { self.move_end(segment, delta, layer, responses); - if let Some(handle) = point.as_handle() { - if let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) { - let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false }; - responses.add(GraphOperationMessage::Vector { layer, modification_type }); - } + if let Some(handle) = point.as_handle() + && let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) + { + let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); } } } @@ -1078,10 +1078,10 @@ impl ShapeState { for &point in layer_state.selected_points.iter() { // Skip a point which has more than 2 segments connected (vector meshes) - if let ManipulatorPointId::Anchor(anchor) = point { - if vector.all_connected(anchor).count() > 2 { - continue; - } + if let ManipulatorPointId::Anchor(anchor) = point + && vector.all_connected(anchor).count() > 2 + { + continue; } // Here we take handles as the current handle and the most opposite non-colinear-handle @@ -1409,10 +1409,11 @@ impl ShapeState { match point { ManipulatorPointId::Anchor(anchor) => { - if let Some(handles) = Self::dissolve_anchor(anchor, responses, layer, &vector) { - if !vector.all_connected(anchor).any(|a| selected_segments.contains(&a.segment)) && vector.all_connected(anchor).count() <= 2 { - missing_anchors.insert(anchor, handles); - } + if let Some(handles) = Self::dissolve_anchor(anchor, responses, layer, &vector) + && !vector.all_connected(anchor).any(|a| selected_segments.contains(&a.segment)) + && vector.all_connected(anchor).count() <= 2 + { + missing_anchors.insert(anchor, handles); } deleted_anchors.insert(anchor); } @@ -1643,11 +1644,11 @@ impl ShapeState { responses.add(GraphOperationMessage::Vector { layer, modification_type }); } } - } else if let Some(handle) = point.as_handle() { - if let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) { - let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false }; - responses.add(GraphOperationMessage::Vector { layer, modification_type }); - } + } else if let Some(handle) = point.as_handle() + && let Some(handles) = vector.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) + { + let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); } } } @@ -1728,17 +1729,20 @@ impl ShapeState { let bezier = bezier.apply_transformation(|point| viewspace.transform_point2(point)); let valid = |handle: DVec2, control: DVec2| handle.distance_squared(control) > crate::consts::HIDE_HANDLE_DISTANCE.powi(2); - if let Some(primary_handle) = bezier.handle_start() { - if valid(primary_handle, bezier.start) && (bezier.handle_end().is_some() || valid(primary_handle, bezier.end)) && primary_handle.distance_squared(pos) <= closest_distance_squared { - closest_distance_squared = primary_handle.distance_squared(pos); - manipulator_point = Some(ManipulatorPointId::PrimaryHandle(segment_id)); - } + if let Some(primary_handle) = bezier.handle_start() + && valid(primary_handle, bezier.start) + && (bezier.handle_end().is_some() || valid(primary_handle, bezier.end)) + && primary_handle.distance_squared(pos) <= closest_distance_squared + { + closest_distance_squared = primary_handle.distance_squared(pos); + manipulator_point = Some(ManipulatorPointId::PrimaryHandle(segment_id)); } - if let Some(end_handle) = bezier.handle_end() { - if valid(end_handle, bezier.end) && end_handle.distance_squared(pos) <= closest_distance_squared { - closest_distance_squared = end_handle.distance_squared(pos); - manipulator_point = Some(ManipulatorPointId::EndHandle(segment_id)); - } + if let Some(end_handle) = bezier.handle_end() + && valid(end_handle, bezier.end) + && end_handle.distance_squared(pos) <= closest_distance_squared + { + closest_distance_squared = end_handle.distance_squared(pos); + manipulator_point = Some(ManipulatorPointId::EndHandle(segment_id)); } } diff --git a/editor/src/messages/tool/common_functionality/snapping.rs b/editor/src/messages/tool/common_functionality/snapping.rs index 63d79d95ba..9b53cce626 100644 --- a/editor/src/messages/tool/common_functionality/snapping.rs +++ b/editor/src/messages/tool/common_functionality/snapping.rs @@ -276,22 +276,22 @@ impl SnapManager { snapped_points.push(closest_curve.clone()); } - if document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Line)) { - if let Some(closest_line) = get_closest_line(&snap_results.grid_lines) { - snapped_points.push(closest_line.clone()); - } + if document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Line)) + && let Some(closest_line) = get_closest_line(&snap_results.grid_lines) + { + snapped_points.push(closest_line.clone()); } if !constrained { - if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::IntersectionPoint)) { - if let Some(closest_curves_intersection) = get_closest_intersection(point.document_point, &snap_results.curves) { - snapped_points.push(closest_curves_intersection); - } + if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::IntersectionPoint)) + && let Some(closest_curves_intersection) = get_closest_intersection(point.document_point, &snap_results.curves) + { + snapped_points.push(closest_curves_intersection); } - if document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Intersection)) { - if let Some(closest_grid_intersection) = get_grid_intersection(point.document_point, &snap_results.grid_lines) { - snapped_points.push(closest_grid_intersection); - } + if document.snapping_state.target_enabled(SnapTarget::Grid(GridSnapTarget::Intersection)) + && let Some(closest_grid_intersection) = get_grid_intersection(point.document_point, &snap_results.grid_lines) + { + snapped_points.push(closest_grid_intersection); } } diff --git a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs index 4d5645e539..bd88c9d851 100644 --- a/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs +++ b/editor/src/messages/tool/common_functionality/snapping/alignment_snapper.rs @@ -67,34 +67,36 @@ impl AlignmentSnapper { let target_position = target_point.document_point; // Perpendicular snap for line's endpoints - if let Some(quad) = target_point.quad.map(|q| q.0) { - if quad[0] == quad[3] && quad[1] == quad[2] && quad[0] == target_point.document_point { - let [p1, p2, ..] = quad; - let Some(direction) = (p2 - p1).try_normalize() else { return }; - let normal = DVec2::new(-direction.y, direction.x); - - for endpoint in [p1, p2] { - if let Some(perpendicular_snap) = Quad::intersect_rays(point.document_point, direction, endpoint, normal) { - let distance_squared = point.document_point.distance_squared(perpendicular_snap); - if distance_squared < tolerance_squared { - let distance = distance_squared.sqrt(); - let distance_to_align_target = perpendicular_snap.distance_squared(endpoint).sqrt(); - - let snap_point = SnappedPoint { - snapped_point_document: perpendicular_snap, - source: point.source, - target: SnapTarget::Alignment(AlignmentSnapTarget::PerpendicularToEndpoint), - target_bounds: Some(Quad(quad)), - distance, - tolerance, - distance_to_align_target, - fully_constrained: false, - at_intersection: true, - alignment_target_horizontal: Some(endpoint), - ..Default::default() - }; - snap_results.points.push(snap_point); - } + if let Some(quad) = target_point.quad.map(|q| q.0) + && quad[0] == quad[3] + && quad[1] == quad[2] + && quad[0] == target_point.document_point + { + let [p1, p2, ..] = quad; + let Some(direction) = (p2 - p1).try_normalize() else { return }; + let normal = DVec2::new(-direction.y, direction.x); + + for endpoint in [p1, p2] { + if let Some(perpendicular_snap) = Quad::intersect_rays(point.document_point, direction, endpoint, normal) { + let distance_squared = point.document_point.distance_squared(perpendicular_snap); + if distance_squared < tolerance_squared { + let distance = distance_squared.sqrt(); + let distance_to_align_target = perpendicular_snap.distance_squared(endpoint).sqrt(); + + let snap_point = SnappedPoint { + snapped_point_document: perpendicular_snap, + source: point.source, + target: SnapTarget::Alignment(AlignmentSnapTarget::PerpendicularToEndpoint), + target_bounds: Some(Quad(quad)), + distance, + tolerance, + distance_to_align_target, + fully_constrained: false, + at_intersection: true, + alignment_target_horizontal: Some(endpoint), + ..Default::default() + }; + snap_results.points.push(snap_point); } } } diff --git a/editor/src/messages/tool/common_functionality/transformation_cage.rs b/editor/src/messages/tool/common_functionality/transformation_cage.rs index 58bac688ef..dba65b4080 100644 --- a/editor/src/messages/tool/common_functionality/transformation_cage.rs +++ b/editor/src/messages/tool/common_functionality/transformation_cage.rs @@ -769,17 +769,17 @@ impl BoundingBoxManager { let edges = self.check_selected_edges(input.mouse.position); let is_near_square = edges.is_some_and(|hover_edge| self.over_extended_edge_midpoint(input.mouse.position, hover_edge)); - if dragging_bounds && is_near_square { - if let Some(skew_edge) = skew_edge { - if self.check_skew_handle(input.mouse.position, skew_edge) { - if skew_edge.0 || skew_edge.1 { - return MouseCursorIcon::EWResize; - } else if skew_edge.2 || skew_edge.3 { - return MouseCursorIcon::NSResize; - } - } - }; - } + if dragging_bounds + && is_near_square + && let Some(skew_edge) = skew_edge + && self.check_skew_handle(input.mouse.position, skew_edge) + { + if skew_edge.0 || skew_edge.1 { + return MouseCursorIcon::EWResize; + } else if skew_edge.2 || skew_edge.3 { + return MouseCursorIcon::NSResize; + } + }; match edges { Some((top, bottom, left, right)) => match (top, bottom, left, right) { diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index ada904527e..b19b3dac4f 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -588,10 +588,10 @@ pub fn make_path_editable_is_allowed(network_interface: &mut NodeNetworkInterfac // Must not already have an existing Path node, in the right-most part of the layer chain, which has an empty set of modifications // (otherwise users could repeatedly keep running this command and stacking up empty Path nodes) - if let Some(TaggedValue::VectorModification(modifications)) = NodeGraphLayer::new(first_layer, network_interface).find_input("Path", 1) { - if modifications.as_ref() == &VectorModification::default() { - return None; - } + if let Some(TaggedValue::VectorModification(modifications)) = NodeGraphLayer::new(first_layer, network_interface).find_input("Path", 1) + && modifications.as_ref() == &VectorModification::default() + { + return None; } Some(first_layer) diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index 650031acc0..459432bb12 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -411,18 +411,18 @@ impl Fsm for BrushToolFsmState { } (BrushToolFsmState::Drawing, BrushToolMessage::PointerMove) => { - if let Some(layer) = tool_data.layer { - if let Some(stroke) = tool_data.strokes.last_mut() { - let layer_position = document - .network_interface - .document_metadata() - .downstream_transform_to_viewport(layer) - .inverse() - .transform_point2(input.mouse.position); - let layer_position = tool_data.transform.inverse().transform_point2(layer_position); - - stroke.trace.push(BrushInputSample { position: layer_position }) - } + if let Some(layer) = tool_data.layer + && let Some(stroke) = tool_data.strokes.last_mut() + { + let layer_position = document + .network_interface + .document_metadata() + .downstream_transform_to_viewport(layer) + .inverse() + .transform_point2(input.mouse.position); + let layer_position = tool_data.transform.inverse().transform_point2(layer_position); + + stroke.trace.push(BrushInputSample { position: layer_position }) } tool_data.update_strokes(responses); diff --git a/editor/src/messages/tool/tool_messages/freehand_tool.rs b/editor/src/messages/tool/tool_messages/freehand_tool.rs index 3a0664c9a7..e7291a0999 100644 --- a/editor/src/messages/tool/tool_messages/freehand_tool.rs +++ b/editor/src/messages/tool/tool_messages/freehand_tool.rs @@ -367,20 +367,18 @@ fn extend_path_with_next_segment(tool_data: &mut FreehandToolData, position: DVe modification_type: VectorModificationType::InsertPoint { id, position }, }); - if extend { - if let Some((_, previous_position)) = tool_data.end_point { - let next_id = SegmentId::generate(); - let points = [previous_position, id]; - - responses.add(GraphOperationMessage::Vector { - layer, - modification_type: VectorModificationType::InsertSegment { - id: next_id, - points, - handles: [None, None], - }, - }); - } + if extend && let Some((_, previous_position)) = tool_data.end_point { + let next_id = SegmentId::generate(); + let points = [previous_position, id]; + + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::InsertSegment { + id: next_id, + points, + handles: [None, None], + }, + }); } tool_data.dragged = true; diff --git a/editor/src/messages/tool/tool_messages/gradient_tool.rs b/editor/src/messages/tool/tool_messages/gradient_tool.rs index eb974ae454..721a8152f8 100644 --- a/editor/src/messages/tool/tool_messages/gradient_tool.rs +++ b/editor/src/messages/tool/tool_messages/gradient_tool.rs @@ -474,10 +474,10 @@ impl Fsm for GradientToolFsmState { } (GradientToolFsmState::Drawing, GradientToolMessage::PointerOutsideViewport { .. }) => { // Auto-panning - if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) { - if let Some(selected_gradient) = &mut tool_data.selected_gradient { - selected_gradient.transform.translation += shift; - } + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) + && let Some(selected_gradient) = &mut tool_data.selected_gradient + { + selected_gradient.transform.translation += shift; } GradientToolFsmState::Drawing @@ -497,12 +497,11 @@ impl Fsm for GradientToolFsmState { tool_data.snap_manager.cleanup(responses); let was_dragging = tool_data.selected_gradient.is_some(); - if !was_dragging { - if let Some(selected_layer) = document.click(input, viewport) { - if let Some(gradient) = get_gradient(selected_layer, &document.network_interface) { - tool_data.selected_gradient = Some(SelectedGradient::new(gradient, selected_layer, document)); - } - } + if !was_dragging + && let Some(selected_layer) = document.click(input, viewport) + && let Some(gradient) = get_gradient(selected_layer, &document.network_interface) + { + tool_data.selected_gradient = Some(SelectedGradient::new(gradient, selected_layer, document)); } GradientToolFsmState::Ready } diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 4d76501940..158847ddf8 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -750,8 +750,8 @@ impl PathToolData { // If the point is already selected and shift (`extend_selection`) is used, keep the selection unchanged. // Otherwise, select the first point within the threshold. - if !(already_selected && extend_selection) { - if let Some(updated_selection_info) = shape_editor.change_point_selection( + if !(already_selected && extend_selection) + && let Some(updated_selection_info) = shape_editor.change_point_selection( &document.network_interface, input.mouse.position, SELECTION_THRESHOLD, @@ -759,8 +759,7 @@ impl PathToolData { path_overlay_mode, self.frontier_handles_info.as_ref(), ) { - selection_info = updated_selection_info; - } + selection_info = updated_selection_info; } if let Some(selected_points) = selection_info { @@ -778,28 +777,26 @@ impl PathToolData { self.saved_selection_before_handle_drag = old_selection; } - if handle_drag_from_anchor { - if let Some((layer, point)) = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) { - // Check that selected point is an anchor - if let (Some(point_id), Some(vector)) = (point.as_anchor(), document.network_interface.compute_modified_vector(layer)) { - let handles = vector.all_connected(point_id).collect::>(); - self.alt_clicked_on_anchor = true; - for handle in &handles { - let modification_type = handle.set_relative_position(DVec2::ZERO); - responses.add(GraphOperationMessage::Vector { layer, modification_type }); - for &handles in &vector.colinear_manipulators { - if handles.contains(handle) { - let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; - responses.add(GraphOperationMessage::Vector { layer, modification_type }); - } + if handle_drag_from_anchor && let Some((layer, point)) = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) { + // Check that selected point is an anchor + if let (Some(point_id), Some(vector)) = (point.as_anchor(), document.network_interface.compute_modified_vector(layer)) { + let handles = vector.all_connected(point_id).collect::>(); + self.alt_clicked_on_anchor = true; + for handle in &handles { + let modification_type = handle.set_relative_position(DVec2::ZERO); + responses.add(GraphOperationMessage::Vector { layer, modification_type }); + for &handles in &vector.colinear_manipulators { + if handles.contains(handle) { + let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false }; + responses.add(GraphOperationMessage::Vector { layer, modification_type }); } } - - let manipulator_point_id = handles[0].to_manipulator_point(); - shape_editor.deselect_all_points(); - shape_editor.select_point_by_layer_and_id(manipulator_point_id, layer); - responses.add(PathToolMessage::SelectedPointUpdated); } + + let manipulator_point_id = handles[0].to_manipulator_point(); + shape_editor.deselect_all_points(); + shape_editor.select_point_by_layer_and_id(manipulator_point_id, layer); + responses.add(PathToolMessage::SelectedPointUpdated); } } @@ -2098,19 +2095,19 @@ impl Fsm for PathToolFsmState { let break_molding = input.keyboard.get(break_colinear_molding as usize); // Logic for molding segment - if let Some(segment) = &mut tool_data.segment { - if let Some(molding_segment_handles) = tool_data.molding_info { - tool_data.temporary_adjacent_handles_while_molding = segment.mold_handle_positions( - document, - responses, - molding_segment_handles, - input.mouse.position, - break_molding, - tool_data.temporary_adjacent_handles_while_molding, - ); + if let Some(segment) = &mut tool_data.segment + && let Some(molding_segment_handles) = tool_data.molding_info + { + tool_data.temporary_adjacent_handles_while_molding = segment.mold_handle_positions( + document, + responses, + molding_segment_handles, + input.mouse.position, + break_molding, + tool_data.temporary_adjacent_handles_while_molding, + ); - return PathToolFsmState::Dragging(tool_data.dragging_state); - } + return PathToolFsmState::Dragging(tool_data.dragging_state); } let anchor_and_handle_toggled = input.keyboard.get(move_anchor_with_handles as usize); @@ -3384,15 +3381,13 @@ fn update_dynamic_hints( let at_least_one_point_selected = shape_editor.selected_points().count() >= 1; let mut single_colinear_anchor_selected = false; - if single_anchor_selected { - if let (Some(anchor), Some(layer)) = ( + if single_anchor_selected + && let (Some(anchor), Some(layer)) = ( shape_editor.selected_points().next(), document.network_interface.selected_nodes().selected_layers(document.metadata()).next(), - ) { - if let Some(vector) = document.network_interface.compute_modified_vector(layer) { - single_colinear_anchor_selected = vector.colinear(*anchor) - } - } + ) && let Some(vector) = document.network_interface.compute_modified_vector(layer) + { + single_colinear_anchor_selected = vector.colinear(*anchor) } let drag_selected_hints = vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]; diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 445c12b8f6..319ea938c0 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -728,8 +728,8 @@ impl PenToolData { // Store the segment let id = SegmentId::generate(); - if self.path_closed { - if let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::PreviewInHandle, &vector) { + if self.path_closed + && let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::PreviewInHandle, &vector) { TargetHandle::PriorOutHandle(segment) => { let handles = [HandleId::end(id), HandleId::primary(segment)]; let handle1_pos = handles[1].to_manipulator_point().get_position(&vector); @@ -742,15 +742,14 @@ impl PenToolData { } _ => None, } { - let angle = (handle_end - next_point).angle_to(handle1_pos - next_point); - let pi = std::f64::consts::PI; - let colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6; - responses.add(GraphOperationMessage::Vector { - layer, - modification_type: VectorModificationType::SetG1Continuous { handles, enabled: colinear }, - }); - self.cleanup(responses); - } + let angle = (handle_end - next_point).angle_to(handle1_pos - next_point); + let pi = std::f64::consts::PI; + let colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6; + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: VectorModificationType::SetG1Continuous { handles, enabled: colinear }, + }); + self.cleanup(responses); } self.prior_segment = Some(id); @@ -938,10 +937,10 @@ impl PenToolData { } fn move_anchor_and_handles(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque, vector: &Vector) { - if self.handle_end.is_none() { - if let Some(latest_pt) = self.latest_point_mut() { - latest_pt.pos += delta; - } + if self.handle_end.is_none() + && let Some(latest_pt) = self.latest_point_mut() + { + latest_pt.pos += delta; } let Some(end_point) = self.prior_segment_endpoint else { return }; @@ -1210,10 +1209,11 @@ impl PenToolData { snap.update_indicator(snapped); } - if let Some(relative) = relative.map(|layer| transform.transform_point2(layer)) { - if (relative - document_pos) != DVec2::ZERO && (relative - document_pos).length_squared() > f64::EPSILON * 100. { - self.angle = -(relative - document_pos).angle_to(DVec2::X) - } + if let Some(relative) = relative.map(|layer| transform.transform_point2(layer)) + && (relative - document_pos) != DVec2::ZERO + && (relative - document_pos).length_squared() > f64::EPSILON * 100. + { + self.angle = -(relative - document_pos).angle_to(DVec2::X) } transform.inverse().transform_point2(document_pos) @@ -1245,20 +1245,20 @@ impl PenToolData { self.current_layer = Some(layer); self.extend_existing_path(document, layer, point, position); return; - } else if preferences.vector_meshes { - if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport_vec, tolerance) { - let (point, segments) = closest_segment.adjusted_insert(responses); - let layer = closest_segment.layer(); - let position = closest_segment.closest_point_document(); + } else if preferences.vector_meshes + && let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport_vec, tolerance) + { + let (point, segments) = closest_segment.adjusted_insert(responses); + let layer = closest_segment.layer(); + let position = closest_segment.closest_point_document(); - // Setting any one of the new segments created as the previous segment - self.prior_segment_endpoint = Some(point); - self.prior_segment_layer = Some(layer); - self.prior_segments = Some(segments.to_vec()); + // Setting any one of the new segments created as the previous segment + self.prior_segment_endpoint = Some(point); + self.prior_segment_layer = Some(layer); + self.prior_segments = Some(segments.to_vec()); - self.extend_existing_path(document, layer, point, position); - return; - } + self.extend_existing_path(document, layer, point, position); + return; } if append { @@ -1629,13 +1629,14 @@ impl Fsm for PenToolFsmState { let viewport_vec = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); let close_to_point = closest_point(document, viewport_vec, tolerance, document.metadata().all_layers(), |_| false, preferences).is_some(); - if preferences.vector_meshes && !close_to_point { - if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport_vec, tolerance) { - let pos = closest_segment.closest_point_to_viewport(); - let perp = closest_segment.calculate_perp(document); - overlay_context.manipulator_anchor(pos, true, None); - overlay_context.line(pos - perp * SEGMENT_OVERLAY_SIZE, pos + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); - } + if preferences.vector_meshes + && !close_to_point + && let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport_vec, tolerance) + { + let pos = closest_segment.closest_point_to_viewport(); + let perp = closest_segment.calculate_perp(document); + overlay_context.manipulator_anchor(pos, true, None); + overlay_context.line(pos - perp * SEGMENT_OVERLAY_SIZE, pos + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); } tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context); self @@ -1758,13 +1759,11 @@ impl Fsm for PenToolFsmState { let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input, viewport), &point, SnapTypeConfiguration::default()); let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); let close_to_point = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences).is_some(); - if !close_to_point { - if let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport, tolerance) { - let pos = closest_segment.closest_point_to_viewport(); - let perp = closest_segment.calculate_perp(document); - overlay_context.manipulator_anchor(pos, true, None); - overlay_context.line(pos - perp * SEGMENT_OVERLAY_SIZE, pos + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); - } + if !close_to_point && let Some(closest_segment) = shape_editor.upper_closest_segment(&document.network_interface, viewport, tolerance) { + let pos = closest_segment.closest_point_to_viewport(); + let perp = closest_segment.calculate_perp(document); + overlay_context.manipulator_anchor(pos, true, None); + overlay_context.line(pos - perp * SEGMENT_OVERLAY_SIZE, pos + perp * SEGMENT_OVERLAY_SIZE, Some(COLOR_OVERLAY_BLUE), None); } } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 3fcf2b5fb2..be36c1e166 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -776,19 +776,19 @@ impl Fsm for SelectToolFsmState { let is_resizing_or_rotating = matches!(self, SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. } | SelectToolFsmState::RotatingBounds); - if overlay_context.visibility_settings.transform_cage() { - if let Some(bounds) = tool_data.bounding_box_manager.as_mut() { - let edges = bounds.check_selected_edges(input.mouse.position); - let is_skewing = matches!(self, SelectToolFsmState::SkewingBounds { .. }); - let is_near_square = edges.is_some_and(|hover_edge| bounds.over_extended_edge_midpoint(input.mouse.position, hover_edge)); - if is_skewing || (dragging_bounds && is_near_square && !is_resizing_or_rotating) { - bounds.render_skew_gizmos(&mut overlay_context, tool_data.skew_edge); - } - if !is_skewing && dragging_bounds { - if let Some(edges) = edges { - tool_data.skew_edge = bounds.get_closest_edge(edges, input.mouse.position); - } - } + if overlay_context.visibility_settings.transform_cage() + && let Some(bounds) = tool_data.bounding_box_manager.as_mut() + { + let edges = bounds.check_selected_edges(input.mouse.position); + let is_skewing = matches!(self, SelectToolFsmState::SkewingBounds { .. }); + let is_near_square = edges.is_some_and(|hover_edge| bounds.over_extended_edge_midpoint(input.mouse.position, hover_edge)); + if is_skewing || (dragging_bounds && is_near_square && !is_resizing_or_rotating) { + bounds.render_skew_gizmos(&mut overlay_context, tool_data.skew_edge); + } + if !is_skewing + && dragging_bounds && let Some(edges) = edges + { + tool_data.skew_edge = bounds.get_closest_edge(edges, input.mouse.position); } } @@ -887,33 +887,32 @@ impl Fsm for SelectToolFsmState { compass_rose_state.axis_type().and_then(|axis| axis.is_constraint().then_some((axis, true))) }; - if show_compass_with_ring.is_some() { - if let Some((axis, hover)) = axis_state { - if axis.is_constraint() { - let e0 = tool_data - .bounding_box_manager - .as_ref() - .map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds)) - .map_or(DVec2::X, |quad| (quad.top_left() - quad.top_right()).normalize_or(DVec2::X)); - - let (direction, color) = match axis { - Axis::X => (e0, COLOR_OVERLAY_RED), - Axis::Y => (e0.perp(), COLOR_OVERLAY_GREEN), - _ => unreachable!(), - }; - - let viewport_diagonal = viewport.size().into_dvec2().length(); - - let color = if !hover { - color - } else { - let color_string = &graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).to_rgba_hex_srgb(); - &format!("#{color_string}") - }; - let line_center = tool_data.line_center; - overlay_context.line(line_center - direction * viewport_diagonal, line_center + direction * viewport_diagonal, Some(color), None); - } - } + if show_compass_with_ring.is_some() + && let Some((axis, hover)) = axis_state + && axis.is_constraint() + { + let e0 = tool_data + .bounding_box_manager + .as_ref() + .map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds)) + .map_or(DVec2::X, |quad| (quad.top_left() - quad.top_right()).normalize_or(DVec2::X)); + + let (direction, color) = match axis { + Axis::X => (e0, COLOR_OVERLAY_RED), + Axis::Y => (e0.perp(), COLOR_OVERLAY_GREEN), + _ => unreachable!(), + }; + + let viewport_diagonal = viewport.size().into_dvec2().length(); + + let color = if !hover { + color + } else { + let color_string = &graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).to_rgba_hex_srgb(); + &format!("#{color_string}") + }; + let line_center = tool_data.line_center; + overlay_context.line(line_center - direction * viewport_diagonal, line_center + direction * viewport_diagonal, Some(color), None); } if axis_state.is_none_or(|(axis, _)| !axis.is_constraint()) && tool_data.axis_align { @@ -1369,11 +1368,11 @@ impl Fsm for SelectToolFsmState { } (SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport { .. }) => { // Auto-panning - if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) { - if let Some(bounds) = &mut tool_data.bounding_box_manager { - bounds.center_of_transformation += shift; - bounds.original_bound_transform.translation += shift; - } + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) + && let Some(bounds) = &mut tool_data.bounding_box_manager + { + bounds.center_of_transformation += shift; + bounds.original_bound_transform.translation += shift; } self @@ -1499,10 +1498,10 @@ impl Fsm for SelectToolFsmState { tool_data.axis_align = false; tool_data.snap_manager.cleanup(responses); - if !matches!(self, SelectToolFsmState::DraggingPivot) { - if let Some(bounds) = &mut tool_data.bounding_box_manager { - bounds.original_transforms.clear(); - } + if !matches!(self, SelectToolFsmState::DraggingPivot) + && let Some(bounds) = &mut tool_data.bounding_box_manager + { + bounds.original_transforms.clear(); } let selection = tool_data.nested_selection_behavior; diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 867d5b3626..1386941814 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -560,10 +560,10 @@ impl Fsm for TextToolFsmState { bounding_box_manager.render_quad(&mut overlay_context); // Draw red overlay if text is clipped let transformed_quad = layer_transform * bounds; - if let Some((text, font, typesetting, _)) = graph_modification_utils::get_text(layer.unwrap(), &document.network_interface) { - if lines_clipping(text.as_str(), font, font_cache, typesetting) { - overlay_context.line(transformed_quad.0[2], transformed_quad.0[3], Some(COLOR_OVERLAY_RED), Some(3.)); - } + if let Some((text, font, typesetting, _)) = graph_modification_utils::get_text(layer.unwrap(), &document.network_interface) + && lines_clipping(text.as_str(), font, font_cache, typesetting) + { + overlay_context.line(transformed_quad.0[2], transformed_quad.0[3], Some(COLOR_OVERLAY_RED), Some(3.)); } bounding_box_manager.render_overlays(&mut overlay_context, false); @@ -697,63 +697,63 @@ impl Fsm for TextToolFsmState { TextToolFsmState::Dragging } (TextToolFsmState::ResizingBounds, TextToolMessage::PointerMove { center, lock_ratio }) => { - if let Some(bounds) = &mut tool_data.bounding_box_manager { - if let Some(movement) = &mut bounds.selected_edges { - let (centered, constrain) = (input.keyboard.key(center), input.keyboard.key(lock_ratio)); - let center_position = centered.then_some(bounds.center_of_transformation); - - let Some(dragging_layer) = tool_data.layer_dragging else { return TextToolFsmState::Ready }; - let Some(node_id) = graph_modification_utils::get_text_id(dragging_layer.id, &document.network_interface) else { - warn!("Cannot get text node id"); - tool_data.layer_dragging.take(); - return TextToolFsmState::Ready; - }; - - let selected = vec![dragging_layer.id]; - let snap = Some(SizeSnapData { - manager: &mut tool_data.resize.snap_manager, - points: &mut tool_data.snap_candidates, - snap_data: SnapData::ignore(document, input, viewport, &selected), - }); - - let (position, size) = movement.new_size(input.mouse.position, bounds.original_bound_transform, center_position, constrain, snap); - // Normalize so the size is always positive - let (position, size) = (position.min(position + size), size.abs()); - - // Compute the offset needed for the top left in bounds space - let original_position = movement.bounds[0].min(movement.bounds[1]); - let translation_bounds_space = position - original_position; - - // Compute a transformation from bounds->viewport->layer - let transform_to_layer = document.metadata().transform_to_viewport(dragging_layer.id).inverse() * bounds.original_bound_transform; - let size_layer = transform_to_layer.transform_vector2(size); - - // Find the translation necessary from the original position in viewport space - let translation_viewport = bounds.original_bound_transform.transform_vector2(translation_bounds_space); - - responses.add(NodeGraphMessage::SetInput { - input_connector: InputConnector::node(node_id, 6), - input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.x)), false), - }); - responses.add(NodeGraphMessage::SetInput { - input_connector: InputConnector::node(node_id, 7), - input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.y)), false), - }); - responses.add(GraphOperationMessage::TransformSet { - layer: dragging_layer.id, - transform: DAffine2::from_translation(translation_viewport) * document.metadata().document_to_viewport * dragging_layer.original_transform, - transform_in: TransformIn::Viewport, - skip_rerender: false, - }); - responses.add(NodeGraphMessage::RunDocumentGraph); - - // Auto-panning - let messages = [ - TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(), - TextToolMessage::PointerMove { center, lock_ratio }.into(), - ]; - tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses); - } + if let Some(bounds) = &mut tool_data.bounding_box_manager + && let Some(movement) = &mut bounds.selected_edges + { + let (centered, constrain) = (input.keyboard.key(center), input.keyboard.key(lock_ratio)); + let center_position = centered.then_some(bounds.center_of_transformation); + + let Some(dragging_layer) = tool_data.layer_dragging else { return TextToolFsmState::Ready }; + let Some(node_id) = graph_modification_utils::get_text_id(dragging_layer.id, &document.network_interface) else { + warn!("Cannot get text node id"); + tool_data.layer_dragging.take(); + return TextToolFsmState::Ready; + }; + + let selected = vec![dragging_layer.id]; + let snap = Some(SizeSnapData { + manager: &mut tool_data.resize.snap_manager, + points: &mut tool_data.snap_candidates, + snap_data: SnapData::ignore(document, input, viewport, &selected), + }); + + let (position, size) = movement.new_size(input.mouse.position, bounds.original_bound_transform, center_position, constrain, snap); + // Normalize so the size is always positive + let (position, size) = (position.min(position + size), size.abs()); + + // Compute the offset needed for the top left in bounds space + let original_position = movement.bounds[0].min(movement.bounds[1]); + let translation_bounds_space = position - original_position; + + // Compute a transformation from bounds->viewport->layer + let transform_to_layer = document.metadata().transform_to_viewport(dragging_layer.id).inverse() * bounds.original_bound_transform; + let size_layer = transform_to_layer.transform_vector2(size); + + // Find the translation necessary from the original position in viewport space + let translation_viewport = bounds.original_bound_transform.transform_vector2(translation_bounds_space); + + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 6), + input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.x)), false), + }); + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(node_id, 7), + input: NodeInput::value(TaggedValue::OptionalF64(Some(size_layer.y)), false), + }); + responses.add(GraphOperationMessage::TransformSet { + layer: dragging_layer.id, + transform: DAffine2::from_translation(translation_viewport) * document.metadata().document_to_viewport * dragging_layer.original_transform, + transform_in: TransformIn::Viewport, + skip_rerender: false, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + + // Auto-panning + let messages = [ + TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(), + TextToolMessage::PointerMove { center, lock_ratio }.into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, viewport, &messages, responses); } TextToolFsmState::ResizingBounds } @@ -771,11 +771,11 @@ impl Fsm for TextToolFsmState { } (TextToolFsmState::ResizingBounds | TextToolFsmState::Dragging, TextToolMessage::PointerOutsideViewport { .. }) => { // Auto-panning - if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) { - if let Some(bounds) = &mut tool_data.bounding_box_manager { - bounds.center_of_transformation += shift; - bounds.original_bound_transform.translation += shift; - } + if let Some(shift) = tool_data.auto_panning.shift_viewport(input, viewport, responses) + && let Some(bounds) = &mut tool_data.bounding_box_manager + { + bounds.center_of_transformation += shift; + bounds.original_bound_transform.translation += shift; } self @@ -808,11 +808,9 @@ impl Fsm for TextToolFsmState { let has_dragged = (start - end).length_squared() > DRAG_THRESHOLD * DRAG_THRESHOLD; // Check if the user has clicked (no dragging) on some existing text - if !has_dragged { - if let Some(clicked_text_layer_path) = TextToolData::check_click(document, input, font_cache) { - tool_data.start_editing_layer(clicked_text_layer_path, self, document, font_cache, responses); - return TextToolFsmState::Editing; - } + if !has_dragged && let Some(clicked_text_layer_path) = TextToolData::check_click(document, input, font_cache) { + tool_data.start_editing_layer(clicked_text_layer_path, self, document, font_cache, responses); + return TextToolFsmState::Editing; } // Otherwise create some new text @@ -846,11 +844,9 @@ impl Fsm for TextToolFsmState { bounds.original_transforms.clear(); } - if drag_too_small { - if let Some(layer_info) = &tool_data.layer_dragging { - tool_data.start_editing_layer(layer_info.id, self, document, font_cache, responses); - return TextToolFsmState::Editing; - } + if drag_too_small && let Some(layer_info) = &tool_data.layer_dragging { + tool_data.start_editing_layer(layer_info.id, self, document, font_cache, responses); + return TextToolFsmState::Editing; } tool_data.layer_dragging.take(); diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 709f14bb8b..fe118e9ecc 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -272,7 +272,7 @@ impl NodeGraphExecutor { use image::{ImageFormat, RgbImage, RgbaImage}; let Some(image) = RgbaImage::from_raw(width, height, data) else { - return Err(format!("Failed to create image buffer for export")); + return Err("Failed to create image buffer for export".to_string()); }; let mut encoded = Vec::new(); @@ -298,7 +298,7 @@ impl NodeGraphExecutor { } } FileType::Svg => { - return Err(format!("SVG cannot be exported from an image buffer")); + return Err("SVG cannot be exported from an image buffer".to_string()); } } diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index dc6265a2a7..39609d80ff 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -686,10 +686,10 @@ impl NodeNetwork { fn replace_node_inputs(&mut self, node_id: NodeId, old_input: (NodeId, usize), new_input: (NodeId, usize)) { let Some(node) = self.nodes.get_mut(&node_id) else { return }; node.inputs.iter_mut().for_each(|input| { - if let NodeInput::Node { node_id: input_id, output_index, .. } = input { - if (*input_id, *output_index) == old_input { - (*input_id, *output_index) = new_input; - } + if let NodeInput::Node { node_id: input_id, output_index, .. } = input + && (*input_id, *output_index) == old_input + { + (*input_id, *output_index) = new_input; } }); } @@ -738,10 +738,10 @@ impl NodeNetwork { let mut are_inputs_used = vec![false; number_of_inputs]; for node in &self.nodes { for node_input in &node.1.inputs { - if let NodeInput::Import { import_index, .. } = node_input { - if let Some(is_used) = are_inputs_used.get_mut(*import_index) { - *is_used = true; - } + if let NodeInput::Import { import_index, .. } = node_input + && let Some(is_used) = are_inputs_used.get_mut(*import_index) + { + *is_used = true; } } } @@ -937,50 +937,48 @@ impl NodeNetwork { fn remove_id_node(&mut self, id: NodeId) -> Result<(), String> { let node = self.nodes.get(&id).ok_or_else(|| format!("Node with id {id} does not exist"))?.clone(); - if let DocumentNodeImplementation::ProtoNode(ident) = &node.implementation { - if ident.name == "graphene_core::ops::IdentityNode" { - assert_eq!(node.inputs.len(), 1, "Id node has more than one input"); - if let NodeInput::Node { node_id, output_index, .. } = node.inputs[0] { - let node_input_output_index = output_index; - // TODO fix - if let Some(input_node) = self.nodes.get_mut(&node_id) { - for &dep in &node.original_location.dependants[0] { - input_node.original_location.dependants[output_index].push(dep); - } + if let DocumentNodeImplementation::ProtoNode(ident) = &node.implementation + && *ident == graphene_core::ops::identity::IDENTIFIER + { + assert_eq!(node.inputs.len(), 1, "Id node has more than one input"); + if let NodeInput::Node { node_id, output_index, .. } = node.inputs[0] { + let node_input_output_index = output_index; + // TODO fix + if let Some(input_node) = self.nodes.get_mut(&node_id) { + for &dep in &node.original_location.dependants[0] { + input_node.original_location.dependants[output_index].push(dep); } + } - let input_node_id = node_id; - for output in self.nodes.values_mut() { - for (index, input) in output.inputs.iter_mut().enumerate() { - if let NodeInput::Node { - node_id: output_node_id, - output_index: output_output_index, - .. - } = input - { - if *output_node_id == id { - *output_node_id = input_node_id; - *output_output_index = node_input_output_index; - - let input_source = &mut output.original_location.inputs_source; - for source in node.original_location.inputs(index) { - input_source.insert(source, index); - } - } + let input_node_id = node_id; + for output in self.nodes.values_mut() { + for (index, input) in output.inputs.iter_mut().enumerate() { + if let NodeInput::Node { + node_id: output_node_id, + output_index: output_output_index, + .. + } = input && *output_node_id == id + { + *output_node_id = input_node_id; + *output_output_index = node_input_output_index; + + let input_source = &mut output.original_location.inputs_source; + for source in node.original_location.inputs(index) { + input_source.insert(source, index); } } - for node_input in self.exports.iter_mut() { - if let NodeInput::Node { node_id, output_index, .. } = node_input { - if *node_id == id { - *node_id = input_node_id; - *output_index = node_input_output_index; - } - } + } + for node_input in self.exports.iter_mut() { + if let NodeInput::Node { node_id, output_index, .. } = node_input + && *node_id == id + { + *node_id = input_node_id; + *output_index = node_input_output_index; } } } - self.nodes.remove(&id); } + self.nodes.remove(&id); } Ok(()) } @@ -1047,15 +1045,15 @@ impl NodeNetwork { let nodes: Vec<_> = self.nodes.into_iter().map(|(id, node)| (id, node.resolve_proto_node())).collect(); // Create a network to evaluate each output - if self.exports.len() == 1 { - if let NodeInput::Node { node_id, .. } = self.exports[0] { - return vec![ProtoNetwork { - inputs: Vec::new(), - output: node_id, - nodes, - }] - .into_iter(); - } + if self.exports.len() == 1 + && let NodeInput::Node { node_id, .. } = self.exports[0] + { + return vec![ProtoNetwork { + inputs: Vec::new(), + output: node_id, + nodes, + }] + .into_iter(); } // Create a network to evaluate each output diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index ab5fde8110..1104cd704f 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -308,10 +308,10 @@ fn node_registry() -> HashMap syn::Resul }) }) .transpose()?; - if let Some(range) = &number_mode_range { - if range.elems.len() != 2 { - return Err(Error::new_spanned(range, "Expected a tuple of two values for `range` for the min and max, respectively")); - } + if let Some(range) = &number_mode_range + && range.elems.len() != 2 + { + return Err(Error::new_spanned(range, "Expected a tuple of two values for `range` for the min and max, respectively")); } let unit = extract_attribute(attrs, "unit") @@ -641,20 +641,19 @@ fn parse_field(pat_ident: PatIdent, ty: Type, attrs: &[Attribute]) -> syn::Resul fn parse_node_type(ty: &Type) -> (bool, Option, Option) { if let Type::ImplTrait(impl_trait) = ty { for bound in &impl_trait.bounds { - if let syn::TypeParamBound::Trait(trait_bound) = bound { - if trait_bound.path.segments.last().is_some_and(|seg| seg.ident == "Node") { - if let syn::PathArguments::AngleBracketed(args) = &trait_bound.path.segments.last().unwrap().arguments { - let input_type = args.args.iter().find_map(|arg| if let syn::GenericArgument::Type(ty) = arg { Some(ty.clone()) } else { None }); - let output_type = args.args.iter().find_map(|arg| { - if let syn::GenericArgument::AssocType(assoc_type) = arg { - if assoc_type.ident == "Output" { Some(assoc_type.ty.clone()) } else { None } - } else { - None - } - }); - return (true, input_type, output_type); + if let syn::TypeParamBound::Trait(trait_bound) = bound + && trait_bound.path.segments.last().is_some_and(|seg| seg.ident == "Node") + && let syn::PathArguments::AngleBracketed(args) = &trait_bound.path.segments.last().unwrap().arguments + { + let input_type = args.args.iter().find_map(|arg| if let syn::GenericArgument::Type(ty) = arg { Some(ty.clone()) } else { None }); + let output_type = args.args.iter().find_map(|arg| { + if let syn::GenericArgument::AssocType(assoc_type) = arg { + if assoc_type.ident == "Output" { Some(assoc_type.ty.clone()) } else { None } + } else { + None } - } + }); + return (true, input_type, output_type); } } }