From 8b614f1e787ac5fdfc9e5ec38ec0030d5a564d85 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 18 Jun 2025 07:47:06 +0530 Subject: [PATCH 01/54] add origin --- editor/src/consts.rs | 1 + .../graph_operation_message.rs | 4 + .../graph_operation_message_handler.rs | 9 + .../document/graph_operation/utility_types.rs | 6 + .../node_graph/document_node_definitions.rs | 12 ++ .../document/overlays/utility_types.rs | 32 +++- .../graph_modification_utils.rs | 16 ++ .../messages/tool/common_functionality/mod.rs | 1 + .../tool/common_functionality/origin.rs | 154 ++++++++++++++++++ .../tool/tool_messages/select_tool.rs | 52 +++++- 10 files changed, 281 insertions(+), 6 deletions(-) create mode 100644 editor/src/messages/tool/common_functionality/origin.rs diff --git a/editor/src/consts.rs b/editor/src/consts.rs index 144ddd6757..1d4db200f6 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -61,6 +61,7 @@ pub const SELECTION_DRAG_ANGLE: f64 = 90.; pub const PIVOT_CROSSHAIR_THICKNESS: f64 = 1.; pub const PIVOT_CROSSHAIR_LENGTH: f64 = 9.; pub const PIVOT_DIAMETER: f64 = 5.; +pub const DOWEL_PIN_RADIUS: f64 = 5.; // COMPASS ROSE pub const COMPASS_ROSE_RING_INNER_DIAMETER: f64 = 13.; diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs index 7aa1bd775d..2fd673046f 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs @@ -56,6 +56,10 @@ pub enum GraphOperationMessage { layer: LayerNodeIdentifier, pivot: DVec2, }, + TransformSetOrigin { + layer: LayerNodeIdentifier, + origin: DVec2, + }, Vector { layer: LayerNodeIdentifier, modification_type: VectorModificationType, diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index 8600555dae..f8e6ecda7e 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -98,6 +98,15 @@ impl MessageHandler> for Gr modify_inputs.pivot_set(pivot); } } + GraphOperationMessage::TransformSetOrigin { layer, origin } => { + if layer == LayerNodeIdentifier::ROOT_PARENT { + log::error!("Cannot run TransformSetOrigin on ROOT_PARENT"); + return; + } + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { + modify_inputs.origin_set(origin); + } + } GraphOperationMessage::Vector { layer, modification_type } => { if layer == LayerNodeIdentifier::ROOT_PARENT { log::error!("Cannot run Vector on ROOT_PARENT"); diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index 56b94ef76e..81698a87df 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -456,6 +456,12 @@ impl<'a> ModifyInputsContext<'a> { self.set_input_with_refresh(InputConnector::node(transform_node_id, 5), NodeInput::value(TaggedValue::DVec2(new_pivot), false), false); } + pub fn origin_set(&mut self, new_origin: DVec2) { + let Some(transform_node_id) = self.existing_node_id("Transform", true) else { return }; + + self.set_input_with_refresh(InputConnector::node(transform_node_id, 6), NodeInput::value(TaggedValue::DVec2(new_origin), false), false); + } + pub fn vector_modify(&mut self, modification_type: VectorModificationType) { let Some(path_node_id) = self.existing_node_id("Path", true) else { return }; self.network_interface.vector_modify(&path_node_id, modification_type); diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index 239e4e894e..99dcf4ab45 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -1628,6 +1628,7 @@ fn static_nodes() -> Vec { NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false), NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), NodeInput::value(TaggedValue::DVec2(DVec2::splat(0.5)), false), + NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), ], implementation: DocumentNodeImplementation::Network(NodeNetwork { exports: vec![NodeInput::node(NodeId(1), 0)], @@ -1647,6 +1648,7 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(DVec2), 3), NodeInput::network(concrete!(DVec2), 4), NodeInput::network(concrete!(DVec2), 5), + NodeInput::network(concrete!(DVec2), 6), ], manual_composition: Some(concrete!(Context)), implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::TransformNode")), @@ -1715,6 +1717,16 @@ fn static_nodes() -> Vec { ), PropertiesRow::with_override("Skew", "TODO", WidgetOverride::Custom("transform_skew".to_string())), PropertiesRow::with_override("Pivot", "TODO", WidgetOverride::Hidden), + PropertiesRow::with_override( + "Origin Offset", + "TODO", + WidgetOverride::Vec2(Vec2InputSettings { + x: "X".to_string(), + y: "Y".to_string(), + unit: " px".to_string(), + ..Default::default() + }), + ), ], output_names: vec!["Data".to_string()], ..Default::default() diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index c1b1649baa..367a3432fd 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,7 +1,7 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, - COMPASS_ROSE_RING_INNER_DIAMETER, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, + COMPASS_ROSE_RING_INNER_DIAMETER, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, DOWEL_PIN_RADIUS }; use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; @@ -550,6 +550,36 @@ impl OverlayContext { self.end_dpi_aware_transform(); } + pub fn draw_origin(&mut self, position: DVec2) { + use std::f64::consts::PI; + let (x, y) = (position.round() - DVec2::splat(0.5)).into(); + + self.start_dpi_aware_transform(); + + // Draw the background circle with a white fill and blue outline + self.render_context.begin_path(); + self.render_context.arc(x, y, DOWEL_PIN_RADIUS, 0., TAU).expect("Failed to draw the circle"); + self.render_context.set_fill_style_str(COLOR_OVERLAY_WHITE); + self.render_context.fill(); + self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE); + self.render_context.stroke(); + + // Draw the two blue filled sectors + self.render_context.begin_path(); + // Top-left sector + self.render_context.move_to(x, y); + self.render_context.arc(x, y, DOWEL_PIN_RADIUS, FRAC_PI_2, PI).expect("Failed to draw arc"); + self.render_context.close_path(); + // Bottom-right sector + self.render_context.move_to(x, y); + self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2, TAU).expect("Failed to draw arc"); + self.render_context.close_path(); + self.render_context.set_fill_style_str(COLOR_OVERLAY_BLUE); + self.render_context.fill(); + + self.end_dpi_aware_transform(); + } + /// Used by the Pen and Path tools to outline the path of the shape. pub fn outline_vector(&mut self, vector_data: &VectorData, transform: DAffine2) { self.start_dpi_aware_transform(); diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index e06d34b9e2..7559b73e0c 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -253,12 +253,28 @@ pub fn get_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInte } } +/// Locate the origin of the transform node +pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + let origin_node_input_index = 6; + if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", origin_node_input_index)? { + Some(*origin) + } else { + None + } +} + pub fn get_viewport_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 { let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer); let pivot = get_pivot(layer, network_interface).unwrap_or(DVec2::splat(0.5)); network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * pivot) } +pub fn get_viewport_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 { + let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer); + let origin = get_origin(layer, network_interface).unwrap_or(DVec2::ZERO); + network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * origin) +} + /// Get the current gradient of a layer from the closest "Fill" node. pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { let fill_index = 1; diff --git a/editor/src/messages/tool/common_functionality/mod.rs b/editor/src/messages/tool/common_functionality/mod.rs index 9bc2236061..eb32ac4010 100644 --- a/editor/src/messages/tool/common_functionality/mod.rs +++ b/editor/src/messages/tool/common_functionality/mod.rs @@ -9,3 +9,4 @@ pub mod shape_editor; pub mod snapping; pub mod transformation_cage; pub mod utility_functions; +pub mod origin; diff --git a/editor/src/messages/tool/common_functionality/origin.rs b/editor/src/messages/tool/common_functionality/origin.rs new file mode 100644 index 0000000000..d4c917b606 --- /dev/null +++ b/editor/src/messages/tool/common_functionality/origin.rs @@ -0,0 +1,154 @@ +//! Handler for the origin overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale and origin of the layer. + +use super::graph_modification_utils; +use crate::consts::DOWEL_PIN_RADIUS; +use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::prelude::*; +use glam::{DAffine2, DVec2}; +use graphene_std::transform::ReferencePoint; +use std::collections::VecDeque; + +#[derive(Clone, Debug)] +pub struct Origin { + /// Origin between (0,0) and (1,1) + normalized_origin: DVec2, + /// Transform to get from normalized origin to viewspace + transform_from_normalized: DAffine2, + /// The viewspace origin position (if applicable) + origin: Option, + /// The old origin position in the GUI, used to reduce refreshes of the document bar + old_origin_position: ReferencePoint, + /// Used to enable and disable the origin + active: bool, +} + +impl Default for Origin { + fn default() -> Self { + Self { + normalized_origin: DVec2::ZERO, + transform_from_normalized: Default::default(), + origin: Default::default(), + old_origin_position: ReferencePoint::Center, + active: true, + } + } +} + +impl Origin { + /// Calculates the transform that gets from normalized origin to viewspace. + fn get_layer_origin_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { + let [min, max] = document.metadata().nonzero_bounding_box(layer); + + let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + let layer_transform = document.metadata().transform_to_viewport(layer); + layer_transform * bounds_transform + } + + /// Recomputes the origin position and transform. + fn recalculate_origin(&mut self, document: &DocumentMessageHandler) { + if !self.active { + return; + } + + let selected_nodes = document.network_interface.selected_nodes(); + let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); + let Some(first) = layers.next() else { + // If no layers are selected then we revert things back to default + self.normalized_origin = DVec2::ZERO; + self.origin = None; + return; + }; + + // Add one because the first item is consumed above. + let selected_layers_count = layers.count() + 1; + + // If just one layer is selected we can use its inner transform (as it accounts for rotation) + if selected_layers_count == 1 { + let normalized_origin = graph_modification_utils::get_origin(first, &document.network_interface).unwrap_or(DVec2::ZERO); + self.normalized_origin = normalized_origin; + self.transform_from_normalized = Self::get_layer_origin_transform(first, document); + self.origin = Some(self.transform_from_normalized.transform_point2(normalized_origin)); + } else { + // If more than one layer is selected we use the AABB with the mean of the origins + let xy_summation = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .map(|layer| graph_modification_utils::get_viewport_origin(layer, &document.network_interface)) + .reduce(|a, b| a + b) + .unwrap_or_default(); + + let origin = xy_summation / selected_layers_count as f64; + self.origin = Some(origin); + let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); + self.normalized_origin = (origin - min) / (max - min); + + self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + } + } + + pub fn update_origin(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { + if !overlay_context.visibility_settings.pivot() { + self.active = false; + return; + } else { + self.active = true; + } + + self.recalculate_origin(document); + if let Some(origin) = self.origin { + overlay_context.draw_origin(origin); + } + } + + /// Answers if the origin widget has changed (so we should refresh the tool bar at the top of the canvas). + pub fn should_refresh_origin_position(&mut self) -> bool { + if !self.active { + return false; + } + + let new = self.to_origin_position(); + let should_refresh = new != self.old_origin_position; + self.old_origin_position = new; + should_refresh + } + + pub fn to_origin_position(&self) -> ReferencePoint { + self.normalized_origin.into() + } + + /// Sets the viewport position of the origin for all selected layers. + pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + if !self.active { + return; + } + + for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { + let transform = Self::get_layer_origin_transform(layer, document); + // Only update the origin when computed position is finite. + if transform.matrix2.determinant().abs() <= f64::EPSILON { + return; + }; + let origin = transform.inverse().transform_point2(position); + responses.add(GraphOperationMessage::TransformSetOrigin { layer, origin }); + } + } + + /// Set the origin using the normalized transform that is set above. + pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + if !self.active { + return; + } + + self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, responses); + } + + /// Answers if the pointer is currently positioned over the origin. + pub fn is_over(&self, mouse: DVec2) -> bool { + if !self.active { + return false; + } + self.origin.filter(|&origin| mouse.distance_squared(origin) < (DOWEL_PIN_RADIUS).powi(2)).is_some() + } +} diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 3ce536cc50..60226a1190 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -18,6 +18,7 @@ use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRose}; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; use crate::messages::tool::common_functionality::measure; +use crate::messages::tool::common_functionality::origin::Origin; use crate::messages::tool::common_functionality::pivot::Pivot; use crate::messages::tool::common_functionality::shape_editor::SelectionShapeType; use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager}; @@ -99,6 +100,9 @@ pub enum SelectToolMessage { SetPivot { position: ReferencePoint, }, + SetOrigin { + position: ReferencePoint, + }, } impl ToolMetadata for SelectTool { @@ -312,6 +316,7 @@ enum SelectToolFsmState { }, RotatingBounds, DraggingPivot, + DraggingOrigin, } impl Default for SelectToolFsmState { @@ -336,6 +341,7 @@ struct SelectToolData { snap_manager: SnapManager, cursor: MouseCursorIcon, pivot: Pivot, + origin: Origin, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -716,6 +722,7 @@ impl Fsm for SelectToolFsmState { // Update pivot tool_data.pivot.update_pivot(document, &mut overlay_context, Some((angle,))); + tool_data.origin.update_origin(document, &mut overlay_context); // Update compass rose if overlay_context.visibility_settings.compass_rose() { @@ -904,6 +911,7 @@ impl Fsm for SelectToolFsmState { let mouse_position = input.mouse.position; let compass_rose_state = tool_data.compass_rose.compass_rose_state(mouse_position, angle); let is_over_pivot = tool_data.pivot.is_over(mouse_position); + let is_over_origin = tool_data.origin.is_over(mouse_position); let show_compass = bounds.is_some_and(|quad| quad.all_sides_at_least_width(COMPASS_ROSE_HOVER_RING_DIAMETER) && quad.contains(mouse_position)); let can_grab_compass_rose = compass_rose_state.can_grab() && (show_compass || bounds.is_none()); @@ -922,6 +930,9 @@ impl Fsm for SelectToolFsmState { // tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]); SelectToolFsmState::DraggingPivot + } else if is_over_origin { + responses.add(DocumentMessage::StartTransaction); + SelectToolFsmState::DraggingOrigin } // Dragging one (or two, forming a corner) of the transform cage bounding box edges else if dragging_bounds.is_some() && !is_flat_layer { @@ -1052,6 +1063,12 @@ impl Fsm for SelectToolFsmState { let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } } + (SelectToolFsmState::DraggingOrigin, SelectToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + + let selection = tool_data.nested_selection_behavior; + SelectToolFsmState::Ready { selection } + } ( SelectToolFsmState::Dragging { axis, @@ -1255,6 +1272,20 @@ impl Fsm for SelectToolFsmState { SelectToolFsmState::DraggingPivot } + (SelectToolFsmState::DraggingOrigin, SelectToolMessage::PointerMove(modifier_keys)) => { + let mouse_position = input.mouse.position; + let snapped_mouse_position = mouse_position; + tool_data.origin.set_viewport_position(snapped_mouse_position, document, responses); + + // Auto-panning + let messages = [ + SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), + SelectToolMessage::PointerMove(modifier_keys).into(), + ]; + tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); + + SelectToolFsmState::DraggingOrigin + } (SelectToolFsmState::Drawing { selection_shape, has_drawn }, SelectToolMessage::PointerMove(modifier_keys)) => { if !has_drawn { responses.add(ToolMessage::UpdateHints); @@ -1289,7 +1320,9 @@ impl Fsm for SelectToolFsmState { .map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge))); // Dragging the pivot overrules the other operations - if tool_data.pivot.is_over(input.mouse.position) { + let mouse = input.mouse.position; + let is_over_override = tool_data.pivot.is_over(mouse) || tool_data.origin.is_over(mouse); + if is_over_override { cursor = MouseCursorIcon::Move; } @@ -1339,7 +1372,7 @@ impl Fsm for SelectToolFsmState { self } - (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport(_)) => { + (SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin, SelectToolMessage::PointerOutsideViewport(_)) => { // Auto-panning let _ = tool_data.auto_panning.shift_viewport(input, responses); @@ -1437,7 +1470,8 @@ impl Fsm for SelectToolFsmState { | SelectToolFsmState::SkewingBounds { .. } | SelectToolFsmState::RotatingBounds | SelectToolFsmState::Dragging { .. } - | SelectToolFsmState::DraggingPivot, + | SelectToolFsmState::DraggingPivot + | SelectToolFsmState::DraggingOrigin, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter, ) => { let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON; @@ -1446,7 +1480,7 @@ impl Fsm for SelectToolFsmState { tool_data.axis_align = false; tool_data.snap_manager.cleanup(responses); - if !matches!(self, SelectToolFsmState::DraggingPivot) { + if !matches!(self, SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin) { if let Some(bounds) = &mut tool_data.bounding_box_manager { bounds.original_transforms.clear(); } @@ -1581,6 +1615,14 @@ impl Fsm for SelectToolFsmState { self } + (_, SelectToolMessage::SetOrigin { position }) => { + responses.add(DocumentMessage::StartTransaction); + + let pos: Option = position.into(); + tool_data.origin.set_normalized_position(pos.unwrap(), document, responses); + + self + } _ => self, } } @@ -1680,7 +1722,7 @@ impl Fsm for SelectToolFsmState { ]); responses.add(FrontendMessage::UpdateInputHints { hint_data }); } - SelectToolFsmState::DraggingPivot => { + SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin => { let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]); responses.add(FrontendMessage::UpdateInputHints { hint_data }); } From 5394417a58e36bf5405a06aa593ce234005dcde7 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 19 Jun 2025 07:23:58 +0530 Subject: [PATCH 02/54] cleanup pivot --- .../graph_operation_message.rs | 4 - .../graph_operation_message_handler.rs | 9 -- .../document/graph_operation/utility_types.rs | 8 +- .../node_graph/document_node_definitions.rs | 2 - .../document/utility_types/transformation.rs | 2 +- .../graph_modification_utils.rs | 18 +--- .../messages/tool/common_functionality/mod.rs | 2 +- .../tool/common_functionality/origin.rs | 2 +- .../tool/common_functionality/pivot.rs | 93 ++++++------------- .../tool/tool_messages/select_tool.rs | 40 +++++--- .../messages/tool/tool_messages/text_tool.rs | 2 +- 11 files changed, 65 insertions(+), 117 deletions(-) diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs index 2fd673046f..2e2fda25c4 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs @@ -52,10 +52,6 @@ pub enum GraphOperationMessage { transform_in: TransformIn, skip_rerender: bool, }, - TransformSetPivot { - layer: LayerNodeIdentifier, - pivot: DVec2, - }, TransformSetOrigin { layer: LayerNodeIdentifier, origin: DVec2, diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index f8e6ecda7e..bfb741b7ec 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -89,15 +89,6 @@ impl MessageHandler> for Gr modify_inputs.transform_set(transform, transform_in, skip_rerender); } } - GraphOperationMessage::TransformSetPivot { layer, pivot } => { - if layer == LayerNodeIdentifier::ROOT_PARENT { - log::error!("Cannot run TransformSetPivot on ROOT_PARENT"); - return; - } - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { - modify_inputs.pivot_set(pivot); - } - } GraphOperationMessage::TransformSetOrigin { layer, origin } => { if layer == LayerNodeIdentifier::ROOT_PARENT { log::error!("Cannot run TransformSetOrigin on ROOT_PARENT"); diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index 81698a87df..c64ae739ba 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -450,16 +450,10 @@ impl<'a> ModifyInputsContext<'a> { } } - pub fn pivot_set(&mut self, new_pivot: DVec2) { - let Some(transform_node_id) = self.existing_node_id("Transform", true) else { return }; - - self.set_input_with_refresh(InputConnector::node(transform_node_id, 5), NodeInput::value(TaggedValue::DVec2(new_pivot), false), false); - } - pub fn origin_set(&mut self, new_origin: DVec2) { let Some(transform_node_id) = self.existing_node_id("Transform", true) else { return }; - self.set_input_with_refresh(InputConnector::node(transform_node_id, 6), NodeInput::value(TaggedValue::DVec2(new_origin), false), false); + self.set_input_with_refresh(InputConnector::node(transform_node_id, 5), NodeInput::value(TaggedValue::DVec2(new_origin), false), false); } pub fn vector_modify(&mut self, modification_type: VectorModificationType) { diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index 99dcf4ab45..951d6735e3 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -1627,7 +1627,6 @@ fn static_nodes() -> Vec { NodeInput::value(TaggedValue::F64(0.), false), NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false), NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), - NodeInput::value(TaggedValue::DVec2(DVec2::splat(0.5)), false), NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), ], implementation: DocumentNodeImplementation::Network(NodeNetwork { @@ -1648,7 +1647,6 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(DVec2), 3), NodeInput::network(concrete!(DVec2), 4), NodeInput::network(concrete!(DVec2), 5), - NodeInput::network(concrete!(DVec2), 6), ], manual_composition: Some(concrete!(Context)), implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::TransformNode")), diff --git a/editor/src/messages/portfolio/document/utility_types/transformation.rs b/editor/src/messages/portfolio/document/utility_types/transformation.rs index 4970433e7a..b8fe6e2682 100644 --- a/editor/src/messages/portfolio/document/utility_types/transformation.rs +++ b/editor/src/messages/portfolio/document/utility_types/transformation.rs @@ -531,7 +531,7 @@ impl<'a> Selected<'a> { let xy_summation = self .selected .iter() - .map(|&layer| graph_modification_utils::get_viewport_pivot(layer, self.network_interface)) + .map(|&layer| graph_modification_utils::get_viewport_origin(layer, self.network_interface)) .reduce(|a, b| a + b) .unwrap_or_default(); diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 7559b73e0c..81cc9c4bd1 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -243,19 +243,9 @@ pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerN LayerNodeIdentifier::new_unchecked(id) } -/// Locate the final pivot from the transform (TODO: decide how the pivot should actually work) -pub fn get_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let pivot_node_input_index = 5; - if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", pivot_node_input_index)? { - Some(*pivot) - } else { - None - } -} - /// Locate the origin of the transform node pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let origin_node_input_index = 6; + let origin_node_input_index = 5; if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", origin_node_input_index)? { Some(*origin) } else { @@ -263,12 +253,6 @@ pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInt } } -pub fn get_viewport_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 { - let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer); - let pivot = get_pivot(layer, network_interface).unwrap_or(DVec2::splat(0.5)); - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * pivot) -} - pub fn get_viewport_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 { let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer); let origin = get_origin(layer, network_interface).unwrap_or(DVec2::ZERO); diff --git a/editor/src/messages/tool/common_functionality/mod.rs b/editor/src/messages/tool/common_functionality/mod.rs index eb32ac4010..a7a52e6ce3 100644 --- a/editor/src/messages/tool/common_functionality/mod.rs +++ b/editor/src/messages/tool/common_functionality/mod.rs @@ -3,10 +3,10 @@ pub mod color_selector; pub mod compass_rose; pub mod graph_modification_utils; pub mod measure; +pub mod origin; pub mod pivot; pub mod resize; pub mod shape_editor; pub mod snapping; pub mod transformation_cage; pub mod utility_functions; -pub mod origin; diff --git a/editor/src/messages/tool/common_functionality/origin.rs b/editor/src/messages/tool/common_functionality/origin.rs index d4c917b606..320cfcdbc9 100644 --- a/editor/src/messages/tool/common_functionality/origin.rs +++ b/editor/src/messages/tool/common_functionality/origin.rs @@ -88,7 +88,7 @@ impl Origin { } } - pub fn update_origin(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { + pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { if !overlay_context.visibility_settings.pivot() { self.active = false; return; diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 67ce7f5dc5..5552bff4d7 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -1,13 +1,10 @@ -//! Handler for the pivot overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale and origin of the layer. +//! Handler for the pivot overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale. -use super::graph_modification_utils; use crate::consts::PIVOT_DIAMETER; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; -use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; use glam::{DAffine2, DVec2}; use graphene_std::transform::ReferencePoint; -use std::collections::VecDeque; #[derive(Clone, Debug)] pub struct Pivot { @@ -15,7 +12,7 @@ pub struct Pivot { normalized_pivot: DVec2, /// Transform to get from normalized pivot to viewspace transform_from_normalized: DAffine2, - /// The viewspace pivot position (if applicable) + /// The viewspace pivot position pivot: Option, /// The old pivot position in the GUI, used to reduce refreshes of the document bar old_pivot_position: ReferencePoint, @@ -36,59 +33,28 @@ impl Default for Pivot { } impl Pivot { - /// Calculates the transform that gets from normalized pivot to viewspace. - fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { - let [min, max] = document.metadata().nonzero_bounding_box(layer); - - let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - let layer_transform = document.metadata().transform_to_viewport(layer); - layer_transform * bounds_transform - } - /// Recomputes the pivot position and transform. - fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { + fn recalculate_transform(&mut self, document: &DocumentMessageHandler) { if !self.active { + self.pivot = None; return; } - let selected_nodes = document.network_interface.selected_nodes(); - let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); - let Some(first) = layers.next() else { - // If no layers are selected then we revert things back to default - self.normalized_pivot = DVec2::splat(0.5); + if !document.network_interface.selected_nodes().has_selected_nodes() { self.pivot = None; return; - }; + } - // Add one because the first item is consumed above. - let selected_layers_count = layers.count() + 1; + let Some([min, max]) = document.selected_visible_and_unlock_layers_bounding_box_viewport() else { + self.pivot = None; + return; + }; - // If just one layer is selected we can use its inner transform (as it accounts for rotation) - if selected_layers_count == 1 { - let normalized_pivot = graph_modification_utils::get_pivot(first, &document.network_interface).unwrap_or(DVec2::splat(0.5)); - self.normalized_pivot = normalized_pivot; - self.transform_from_normalized = Self::get_layer_pivot_transform(first, document); - self.pivot = Some(self.transform_from_normalized.transform_point2(normalized_pivot)); - } else { - // If more than one layer is selected we use the AABB with the mean of the pivots - let xy_summation = document - .network_interface - .selected_nodes() - .selected_visible_and_unlocked_layers(&document.network_interface) - .map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network_interface)) - .reduce(|a, b| a + b) - .unwrap_or_default(); - - let pivot = xy_summation / selected_layers_count as f64; - self.pivot = Some(pivot); - let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); - self.normalized_pivot = (pivot - min) / (max - min); - - self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - } + self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } - pub fn update_pivot(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) { + pub fn update(&mut self, _document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) { if !overlay_context.visibility_settings.pivot() { self.active = false; return; @@ -96,7 +62,7 @@ impl Pivot { self.active = true; } - self.recalculate_pivot(document); + // self.recalculate_pivot(document); if let (Some(pivot), Some(data)) = (self.pivot, draw_data) { overlay_context.pivot(pivot, data.0); } @@ -118,30 +84,31 @@ impl Pivot { self.normalized_pivot.into() } - /// Sets the viewport position of the pivot for all selected layers. - pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + pub fn position(&self) -> Option { + self.pivot + } + + /// Sets the viewport position of the pivot. + pub fn set_viewport_position(&mut self, position: DVec2) { if !self.active { return; } - for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { - let transform = Self::get_layer_pivot_transform(layer, document); - // Only update the pivot when computed position is finite. - if transform.matrix2.determinant().abs() <= f64::EPSILON { - return; - }; - let pivot = transform.inverse().transform_point2(position); - responses.add(GraphOperationMessage::TransformSetPivot { layer, pivot }); - } + if self.transform_from_normalized.matrix2.determinant().abs() <= f64::EPSILON { + return; + }; + + self.normalized_pivot = self.transform_from_normalized.inverse().transform_point2(position); + self.pivot = Some(position); } - /// Set the pivot using the normalized transform that is set above. - pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { + /// Set the pivot using a normalized position. + pub fn set_normalized_position(&mut self, position: DVec2) { if !self.active { return; } - - self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, responses); + self.normalized_pivot = position; + self.pivot = Some(self.transform_from_normalized.transform_point2(position)); } /// Answers if the pointer is currently positioned over the pivot. diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 60226a1190..33b70c0a6d 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -57,6 +57,13 @@ pub enum NestedSelectionBehavior { Deepest, } +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +enum DotType { + #[default] + Origin, + Pivot, +} + impl fmt::Display for NestedSelectionBehavior { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -342,6 +349,7 @@ struct SelectToolData { cursor: MouseCursorIcon, pivot: Pivot, origin: Origin, + dot_type: Option, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -507,6 +515,14 @@ impl SelectToolData { responses.add(NodeGraphMessage::SendGraph); self.layers_dragging = original; } + + fn is_over(&self, mouse: DVec2) -> bool { + let Some(dot_type) = self.dot_type else { return false }; + match dot_type { + DotType::Pivot => self.pivot.is_over(mouse), + DotType::Origin => self.origin.is_over(mouse), + } + } } impl Fsm for SelectToolFsmState { @@ -516,6 +532,7 @@ impl Fsm for SelectToolFsmState { fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque) -> Self { let ToolActionHandlerData { document, input, font_cache, .. } = tool_action_data; + tool_data.dot_type = Some(DotType::Pivot); let ToolMessage::Select(event) = event else { return self }; match (self, event) { (_, SelectToolMessage::Overlays(mut overlay_context)) => { @@ -721,8 +738,11 @@ impl Fsm for SelectToolFsmState { }); // Update pivot - tool_data.pivot.update_pivot(document, &mut overlay_context, Some((angle,))); - tool_data.origin.update_origin(document, &mut overlay_context); + match tool_data.dot_type { + Some(DotType::Pivot) => tool_data.pivot.update(document, &mut overlay_context, Some((angle,))), + Some(DotType::Origin) => tool_data.origin.update(document, &mut overlay_context), + _ => (), + }; // Update compass rose if overlay_context.visibility_settings.compass_rose() { @@ -910,8 +930,6 @@ impl Fsm for SelectToolFsmState { let angle = bounds.map_or(0., |quad| (quad.top_left() - quad.top_right()).to_angle()); let mouse_position = input.mouse.position; let compass_rose_state = tool_data.compass_rose.compass_rose_state(mouse_position, angle); - let is_over_pivot = tool_data.pivot.is_over(mouse_position); - let is_over_origin = tool_data.origin.is_over(mouse_position); let show_compass = bounds.is_some_and(|quad| quad.all_sides_at_least_width(COMPASS_ROSE_HOVER_RING_DIAMETER) && quad.contains(mouse_position)); let can_grab_compass_rose = compass_rose_state.can_grab() && (show_compass || bounds.is_none()); @@ -923,16 +941,16 @@ impl Fsm for SelectToolFsmState { let state = // Dragging the pivot - if is_over_pivot { + if tool_data.is_over(input.mouse.position) { responses.add(DocumentMessage::StartTransaction); // tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true); // tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]); - SelectToolFsmState::DraggingPivot - } else if is_over_origin { - responses.add(DocumentMessage::StartTransaction); - SelectToolFsmState::DraggingOrigin + match tool_data.dot_type.unwrap_or_default(){ + DotType::Pivot => SelectToolFsmState::DraggingPivot, + DotType::Origin => SelectToolFsmState::DraggingOrigin, + } } // Dragging one (or two, forming a corner) of the transform cage bounding box edges else if dragging_bounds.is_some() && !is_flat_layer { @@ -1261,7 +1279,7 @@ impl Fsm for SelectToolFsmState { (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => { let mouse_position = input.mouse.position; let snapped_mouse_position = mouse_position; - tool_data.pivot.set_viewport_position(snapped_mouse_position, document, responses); + tool_data.pivot.set_viewport_position(snapped_mouse_position); // Auto-panning let messages = [ @@ -1611,7 +1629,7 @@ impl Fsm for SelectToolFsmState { responses.add(DocumentMessage::StartTransaction); let pos: Option = position.into(); - tool_data.pivot.set_normalized_position(pos.unwrap(), document, responses); + tool_data.pivot.set_normalized_position(pos.unwrap()); self } diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 44814fc39b..b205f3bb84 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -524,7 +524,7 @@ impl Fsm for TextToolFsmState { } bounding_box_manager.render_overlays(&mut overlay_context, false); - tool_data.pivot.update_pivot(document, &mut overlay_context, None); + // tool_data.pivot.update_pivot(document, &mut overlay_context, None); } } else { tool_data.bounding_box_manager.take(); From 90e8859db10855d6c8f63649081ebde9703ffafa Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Tue, 24 Jun 2025 12:55:33 +0530 Subject: [PATCH 03/54] a lot of stuff --- .../document/overlays/utility_types.rs | 2 +- .../tool/common_functionality/origin.rs | 4 + .../tool/common_functionality/pivot.rs | 4 +- .../tool/tool_messages/select_tool.rs | 100 ++++++++++++++---- .../transform_layer_message.rs | 1 + .../transform_layer_message_handler.rs | 5 +- node-graph/gcore/src/vector/vector_nodes.rs | 3 +- 7 files changed, 91 insertions(+), 28 deletions(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 367a3432fd..41b184f81a 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,7 +1,7 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, - COMPASS_ROSE_RING_INNER_DIAMETER, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, DOWEL_PIN_RADIUS + COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, }; use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; diff --git a/editor/src/messages/tool/common_functionality/origin.rs b/editor/src/messages/tool/common_functionality/origin.rs index 320cfcdbc9..31c25e9509 100644 --- a/editor/src/messages/tool/common_functionality/origin.rs +++ b/editor/src/messages/tool/common_functionality/origin.rs @@ -102,6 +102,10 @@ impl Origin { } } + pub fn position(&self) -> Option { + self.origin + } + /// Answers if the origin widget has changed (so we should refresh the tool bar at the top of the canvas). pub fn should_refresh_origin_position(&mut self) -> bool { if !self.active { diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 5552bff4d7..7cef82c4d5 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -54,7 +54,7 @@ impl Pivot { self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } - pub fn update(&mut self, _document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) { + pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) { if !overlay_context.visibility_settings.pivot() { self.active = false; return; @@ -62,7 +62,7 @@ impl Pivot { self.active = true; } - // self.recalculate_pivot(document); + self.recalculate_transform(document); if let (Some(pivot), Some(data)) = (self.pivot, draw_data) { overlay_context.pivot(pivot, data.0); } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 33b70c0a6d..98b3712374 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -48,6 +48,7 @@ pub struct SelectOptions { #[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SelectOptionsUpdate { NestedSelectionBehavior(NestedSelectionBehavior), + DotType(DotType), } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] @@ -58,10 +59,21 @@ pub enum NestedSelectionBehavior { } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] -enum DotType { +pub enum DotType { #[default] Origin, Pivot, + Off, +} + +impl fmt::Display for DotType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DotType::Off => write!(f, "Bounding Box Center"), + DotType::Pivot => write!(f, "Pivot"), + DotType::Origin => write!(f, "Origin"), + } + } } impl fmt::Display for NestedSelectionBehavior { @@ -147,6 +159,25 @@ impl SelectTool { .disabled(disabled) .widget_holder() } + fn dot_type_widget(&self) -> WidgetHolder { + let dot_type_entries = [DotType::Off, DotType::Pivot, DotType::Origin] + .iter() + .map(|dot_type| { + MenuListEntry::new(format!("{dot_type:?}")) + .label(dot_type.to_string()) + .on_commit(move |_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::DotType(*dot_type)).into()) + }) + .collect(); + + DropdownInput::new(vec![dot_type_entries]) + .selected_index(Some(match self.tool_data.dot_type { + DotType::Off => 0, + DotType::Pivot => 1, + DotType::Origin => 2, + })) + .tooltip("Choose between bounding box center, pivot point, or origin point for transformations") + .widget_holder() + } fn alignment_widgets(&self, disabled: bool) -> impl Iterator + use<> { [AlignAxis::X, AlignAxis::Y] @@ -218,9 +249,13 @@ impl LayoutHolder for SelectTool { // Select mode (Deep/Shallow) widgets.push(self.deep_selection_widget()); + // Dot Type (Pivot/Origin/Off) + widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + widgets.push(self.dot_type_widget()); + // Pivot widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0)); + widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0 || self.tool_data.dot_type != DotType::Pivot)); // Align let disabled = self.tool_data.selected_layers_count < 2; @@ -259,14 +294,26 @@ impl LayoutHolder for SelectTool { impl<'a> MessageHandler> for SelectTool { fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { - if let ToolMessage::Select(SelectToolMessage::SelectOptions(SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior))) = message { - self.tool_data.nested_selection_behavior = nested_selection_behavior; - responses.add(ToolMessage::UpdateHints); + let mut redraw_ref_pivot = false; + if let ToolMessage::Select(SelectToolMessage::SelectOptions(ref option_update)) = message { + match option_update { + SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior) => { + self.tool_data.nested_selection_behavior = *nested_selection_behavior; + responses.add(ToolMessage::UpdateHints); + } + SelectOptionsUpdate::DotType(dot_type) => { + self.tool_data.dot_type = *dot_type; + responses.add(ToolMessage::UpdateHints); + let center = self.tool_data.get_pivot_position(); + responses.add(TransformLayerMessage::SetCenter { center }); + redraw_ref_pivot = true; + } + } } self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false); - if self.tool_data.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed { + if self.tool_data.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed || redraw_ref_pivot { // Send the layout containing the updated pivot position (a bit ugly to do it here not in the fsm but that doesn't have SelectTool) self.send_layout(responses, LayoutTarget::ToolOptions); self.tool_data.selected_layers_changed = false; @@ -349,7 +396,7 @@ struct SelectToolData { cursor: MouseCursorIcon, pivot: Pivot, origin: Origin, - dot_type: Option, + dot_type: DotType, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -516,11 +563,19 @@ impl SelectToolData { self.layers_dragging = original; } - fn is_over(&self, mouse: DVec2) -> bool { - let Some(dot_type) = self.dot_type else { return false }; - match dot_type { - DotType::Pivot => self.pivot.is_over(mouse), - DotType::Origin => self.origin.is_over(mouse), + fn state_from_dot(&self, mouse: DVec2) -> Option { + match self.dot_type { + DotType::Pivot => self.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), + DotType::Origin => self.origin.is_over(mouse).then_some(SelectToolFsmState::DraggingOrigin), + _ => None, + } + } + + fn get_pivot_position(&self) -> Option { + match self.dot_type { + DotType::Origin => None, + DotType::Pivot => self.pivot.position().or(Some(DVec2::splat(0.5))), + _ => Some(DVec2::splat(0.5)), } } } @@ -532,7 +587,6 @@ impl Fsm for SelectToolFsmState { fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque) -> Self { let ToolActionHandlerData { document, input, font_cache, .. } = tool_action_data; - tool_data.dot_type = Some(DotType::Pivot); let ToolMessage::Select(event) = event else { return self }; match (self, event) { (_, SelectToolMessage::Overlays(mut overlay_context)) => { @@ -739,8 +793,8 @@ impl Fsm for SelectToolFsmState { // Update pivot match tool_data.dot_type { - Some(DotType::Pivot) => tool_data.pivot.update(document, &mut overlay_context, Some((angle,))), - Some(DotType::Origin) => tool_data.origin.update(document, &mut overlay_context), + DotType::Pivot => tool_data.pivot.update(document, &mut overlay_context, Some((angle,))), + DotType::Origin => tool_data.origin.update(document, &mut overlay_context), _ => (), }; @@ -941,22 +995,20 @@ impl Fsm for SelectToolFsmState { let state = // Dragging the pivot - if tool_data.is_over(input.mouse.position) { + if let Some(state) = tool_data.state_from_dot(input.mouse.position) { responses.add(DocumentMessage::StartTransaction); // tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true); // tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]); - match tool_data.dot_type.unwrap_or_default(){ - DotType::Pivot => SelectToolFsmState::DraggingPivot, - DotType::Origin => SelectToolFsmState::DraggingOrigin, - } + state } // Dragging one (or two, forming a corner) of the transform cage bounding box edges else if dragging_bounds.is_some() && !is_flat_layer { responses.add(DocumentMessage::StartTransaction); tool_data.layers_dragging = selected; + let center = tool_data.get_pivot_position(); if let Some(bounds) = &mut tool_data.bounding_box_manager { bounds.original_bound_transform = bounds.transform; @@ -980,7 +1032,7 @@ impl Fsm for SelectToolFsmState { &ToolType::Select, None ); - bounds.center_of_transformation = selected.mean_average_of_pivots(); + bounds.center_of_transformation = center.unwrap_or(selected.mean_average_of_pivots()); // Check if we're hovering over a skew triangle let edges = bounds.check_selected_edges(input.mouse.position); @@ -1018,6 +1070,7 @@ impl Fsm for SelectToolFsmState { else if rotating_bounds { responses.add(DocumentMessage::StartTransaction); + let center = tool_data.get_pivot_position(); if let Some(bounds) = &mut tool_data.bounding_box_manager { tool_data.layers_dragging.retain(|layer| { if *layer != LayerNodeIdentifier::ROOT_PARENT { @@ -1038,7 +1091,7 @@ impl Fsm for SelectToolFsmState { None ); - bounds.center_of_transformation = selected.mean_average_of_pivots(); + bounds.center_of_transformation = center.unwrap_or(selected.mean_average_of_pivots()); } tool_data.layers_dragging = selected; @@ -1630,6 +1683,8 @@ impl Fsm for SelectToolFsmState { let pos: Option = position.into(); tool_data.pivot.set_normalized_position(pos.unwrap()); + let center = tool_data.pivot.position(); + responses.add(TransformLayerMessage::SetCenter { center }); self } @@ -1638,6 +1693,7 @@ impl Fsm for SelectToolFsmState { let pos: Option = position.into(); tool_data.origin.set_normalized_position(pos.unwrap(), document, responses); + responses.add(TransformLayerMessage::SetCenter { center: None }); self } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs index dfc45c1e05..ea02f61ad9 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -15,6 +15,7 @@ pub enum TransformLayerMessage { BeginGrab, BeginRotate, BeginScale, + SetCenter { center: Option }, BeginGRS { transform_type: TransformType }, BeginGrabPen { last_point: DVec2, handle: DVec2 }, BeginRotatePen { last_point: DVec2, handle: DVec2 }, diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 5797d3a136..b0e482fbb6 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -34,6 +34,7 @@ pub struct TransformLayerMessageHandler { start_mouse: ViewportPosition, original_transforms: OriginalTransforms, + pivot_from_select: Option, pivot: ViewportPosition, local_pivot: DocumentPosition, @@ -176,7 +177,8 @@ impl MessageHandler> for TransformLayer } if !using_path_tool { - *selected.pivot = selected.mean_average_of_pivots(); + debug!("{:?}", self.pivot_from_select); + *selected.pivot = self.pivot_from_select.unwrap_or(selected.mean_average_of_pivots()); self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(selected.mean_average_of_pivots()); } else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { @@ -686,6 +688,7 @@ impl MessageHandler> for TransformLayer self.initial_transform, ) } + TransformLayerMessage::SetCenter { center: pivot } => self.pivot_from_select = pivot, } } diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 79d768ff15..30727f78d5 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -355,8 +355,7 @@ where let transform = DAffine2::from_scale_angle_translation(DVec2::splat(scale), rotation, translation); for mut instance in instance.instance_ref_iter().map(|instance| instance.to_instance_cloned()) { - let local_matrix = DAffine2::from_mat2(instance.transform.matrix2); - instance.transform = transform * local_matrix; + instance.transform = transform * instance.transform; result_table.push(instance); } From 4a035e14b3d687e0af8b8612a812edc38b4eb956 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 25 Jun 2025 13:00:40 +0530 Subject: [PATCH 04/54] reset pivot --- .../tool/common_functionality/pivot.rs | 2 +- .../messages/tool/tool_messages/select_tool.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 7cef82c4d5..10b64e58ea 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -15,7 +15,7 @@ pub struct Pivot { /// The viewspace pivot position pivot: Option, /// The old pivot position in the GUI, used to reduce refreshes of the document bar - old_pivot_position: ReferencePoint, + pub old_pivot_position: ReferencePoint, /// Used to enable and disable the pivot active: bool, } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index f6641b96d7..e076ccb623 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -968,8 +968,7 @@ impl Fsm for SelectToolFsmState { let show_compass = bounds.is_some_and(|quad| quad.all_sides_at_least_width(COMPASS_ROSE_HOVER_RING_DIAMETER) && quad.contains(mouse_position)); let can_grab_compass_rose = compass_rose_state.can_grab() && (show_compass || bounds.is_none()); - let state = - if let Some(state) = tool_data.state_from_dot(input.mouse.position) { + let state = if let Some(state) = tool_data.state_from_dot(input.mouse.position) { responses.add(DocumentMessage::StartTransaction); // tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true); @@ -996,6 +995,9 @@ impl Fsm for SelectToolFsmState { } tool_data.layers_dragging = selected; + responses.add(SelectToolMessage::SetPivot { + position: tool_data.pivot.old_pivot_position, + }); tool_data.get_snap_candidates(document, input); let (axis, using_compass) = { @@ -1021,6 +1023,10 @@ impl Fsm for SelectToolFsmState { if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); + + responses.add(SelectToolMessage::SetPivot { + position: tool_data.pivot.old_pivot_position, + }); } if let Some(intersection) = intersection { @@ -1050,13 +1056,7 @@ impl Fsm for SelectToolFsmState { state } - (SelectToolFsmState::DraggingPivot, SelectToolMessage::Abort) => { - responses.add(DocumentMessage::AbortTransaction); - - let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } - } - (SelectToolFsmState::DraggingOrigin, SelectToolMessage::Abort) => { + (SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin, SelectToolMessage::Abort) => { responses.add(DocumentMessage::AbortTransaction); let selection = tool_data.nested_selection_behavior; From eacd277a556e5e8aec1685382dfb0d6b4255991e Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 25 Jun 2025 14:53:20 +0530 Subject: [PATCH 05/54] fix transform with pivot issues --- .../tool/common_functionality/origin.rs | 3 +- .../tool/common_functionality/pivot.rs | 54 +++++++++++++++---- .../common_functionality/utility_functions.rs | 5 +- .../tool/tool_messages/select_tool.rs | 38 ++++++++----- .../messages/tool/tool_messages/shape_tool.rs | 2 +- 5 files changed, 74 insertions(+), 28 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/origin.rs b/editor/src/messages/tool/common_functionality/origin.rs index 31c25e9509..28e8319687 100644 --- a/editor/src/messages/tool/common_functionality/origin.rs +++ b/editor/src/messages/tool/common_functionality/origin.rs @@ -88,7 +88,7 @@ impl Origin { } } - pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { + pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw: bool) { if !overlay_context.visibility_settings.pivot() { self.active = false; return; @@ -97,6 +97,7 @@ impl Origin { } self.recalculate_origin(document); + if !draw {return}; if let Some(origin) = self.origin { overlay_context.draw_origin(origin); } diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 10b64e58ea..8088934b4b 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -2,6 +2,7 @@ use crate::consts::PIVOT_DIAMETER; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; use glam::{DAffine2, DVec2}; use graphene_std::transform::ReferencePoint; @@ -34,27 +35,54 @@ impl Default for Pivot { impl Pivot { /// Recomputes the pivot position and transform. - fn recalculate_transform(&mut self, document: &DocumentMessageHandler) { + // fn recalculate_transform(&mut self, document: &DocumentMessageHandler) { + // if !self.active { + // self.pivot = None; + // return; + // } + // + // if !document.network_interface.selected_nodes().has_selected_nodes() { + // self.pivot = None; + // return; + // } + // + // let Some([min, max]) = document.selected_visible_and_unlock_layers_bounding_box_viewport() else { + // self.pivot = None; + // return; + // }; + // + // self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + // self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + // } + + fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { if !self.active { - self.pivot = None; - return; - } - - if !document.network_interface.selected_nodes().has_selected_nodes() { - self.pivot = None; return; } - let Some([min, max]) = document.selected_visible_and_unlock_layers_bounding_box_viewport() else { + let selected_nodes = document.network_interface.selected_nodes(); + let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); + let Some(first) = layers.next() else { + // If no layers are selected then we revert things back to default + self.normalized_pivot = DVec2::ZERO; self.pivot = None; return; }; - self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + // If just one layer is selected we can use its inner transform (as it accounts for rotation) + self.transform_from_normalized = Self::get_layer_origin_transform(first, document); self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } - pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) { + fn get_layer_origin_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { + let [min, max] = document.metadata().nonzero_bounding_box(layer); + + let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + let layer_transform = document.metadata().transform_to_viewport(layer); + layer_transform * bounds_transform + } + + pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>, draw: bool) { if !overlay_context.visibility_settings.pivot() { self.active = false; return; @@ -62,7 +90,11 @@ impl Pivot { self.active = true; } - self.recalculate_transform(document); + // self.recalculate_transform(document); + self.recalculate_pivot(document); + if !draw { + return; + }; if let (Some(pivot), Some(data)) = (self.pivot, draw_data) { overlay_context.pivot(pivot, data.0); } diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index c6974d5009..32ec2561b6 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -326,6 +326,7 @@ pub fn transforming_transform_cage( input: &InputPreprocessorMessageHandler, responses: &mut VecDeque, layers_dragging: &mut Vec, + pos: Option ) -> (bool, bool, bool) { let dragging_bounds = bounding_box_manager.as_mut().and_then(|bounding_box| { let edges = bounding_box.check_selected_edges(input.mouse.position); @@ -372,7 +373,7 @@ pub fn transforming_transform_cage( &ToolType::Select, None, ); - bounds.center_of_transformation = selected.mean_average_of_pivots(); + bounds.center_of_transformation = pos.unwrap_or(selected.mean_average_of_pivots()); // Check if we're hovering over a skew triangle let edges = bounds.check_selected_edges(input.mouse.position); @@ -413,7 +414,7 @@ pub fn transforming_transform_cage( None, ); - bounds.center_of_transformation = selected.mean_average_of_pivots(); + bounds.center_of_transformation = pos.unwrap_or(selected.mean_average_of_pivots()); } *layers_dragging = selected; diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index e076ccb623..b9e965cbfa 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -62,6 +62,16 @@ pub enum DotType { Off, } +impl DotType { + pub fn is_pivot(self) -> bool { + self == Self::Pivot + } + + pub fn is_origin(self) -> bool { + self == Self::Pivot + } +} + impl fmt::Display for DotType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -787,12 +797,8 @@ impl Fsm for SelectToolFsmState { .flatten() }); - // Update pivot - match tool_data.dot_type { - DotType::Pivot => tool_data.pivot.update(document, &mut overlay_context, Some((angle,))), - DotType::Origin => tool_data.origin.update(document, &mut overlay_context), - _ => (), - }; + tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), tool_data.dot_type.is_pivot()); + tool_data.origin.update(document, &mut overlay_context, tool_data.dot_type.is_origin()); // Update compass rose if overlay_context.visibility_settings.compass_rose() { @@ -918,6 +924,7 @@ impl Fsm for SelectToolFsmState { (SelectionShapeType::Lasso, _) => overlay_context.polygon(polygon, None, fill_color), } } + self } (_, SelectToolMessage::EditLayer) => { @@ -949,7 +956,8 @@ impl Fsm for SelectToolFsmState { let intersection_list = document.click_list(input).collect::>(); let intersection = document.find_deepest(&intersection_list); - let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging); + let pos = tool_data.get_pivot_position(); + let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, pos); // If the user is dragging the bounding box bounds, go into ResizingBounds mode. // If the user is dragging the rotate trigger, go into RotatingBounds mode. @@ -995,9 +1003,11 @@ impl Fsm for SelectToolFsmState { } tool_data.layers_dragging = selected; - responses.add(SelectToolMessage::SetPivot { - position: tool_data.pivot.old_pivot_position, - }); + if tool_data.dot_type.is_pivot() && !tool_data.layers_dragging.is_empty() { + responses.add(SelectToolMessage::SetPivot { + position: tool_data.pivot.old_pivot_position, + }); + } tool_data.get_snap_candidates(document, input); let (axis, using_compass) = { @@ -1024,9 +1034,11 @@ impl Fsm for SelectToolFsmState { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); - responses.add(SelectToolMessage::SetPivot { - position: tool_data.pivot.old_pivot_position, - }); + if tool_data.dot_type.is_pivot() && false { + responses.add(SelectToolMessage::SetPivot { + position: tool_data.pivot.old_pivot_position, + }); + } } if let Some(intersection) = intersection { diff --git a/editor/src/messages/tool/tool_messages/shape_tool.rs b/editor/src/messages/tool/tool_messages/shape_tool.rs index a6b79a1139..ac5d46996a 100644 --- a/editor/src/messages/tool/tool_messages/shape_tool.rs +++ b/editor/src/messages/tool/tool_messages/shape_tool.rs @@ -597,7 +597,7 @@ impl Fsm for ShapeToolFsmState { } } - let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging); + let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, None); if !input.keyboard.key(Key::Control) { match (resize, rotate, skew) { From 23cbea26aafda526480050e3b74714fea88a7fbf Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 26 Jun 2025 07:41:07 +0530 Subject: [PATCH 06/54] fixes --- .../tool/common_functionality/pivot.rs | 53 +++++++++++-------- .../tool/tool_messages/select_tool.rs | 2 +- .../messages/tool/tool_messages/text_tool.rs | 2 +- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 8088934b4b..00ea05bf2b 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -35,26 +35,6 @@ impl Default for Pivot { impl Pivot { /// Recomputes the pivot position and transform. - // fn recalculate_transform(&mut self, document: &DocumentMessageHandler) { - // if !self.active { - // self.pivot = None; - // return; - // } - // - // if !document.network_interface.selected_nodes().has_selected_nodes() { - // self.pivot = None; - // return; - // } - // - // let Some([min, max]) = document.selected_visible_and_unlock_layers_bounding_box_viewport() else { - // self.pivot = None; - // return; - // }; - // - // self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - // self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); - // } - fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { if !self.active { return; @@ -69,12 +49,39 @@ impl Pivot { return; }; + + // Add one because the first item is consumed above. + let selected_layers_count = layers.count() + 1; + // If just one layer is selected we can use its inner transform (as it accounts for rotation) - self.transform_from_normalized = Self::get_layer_origin_transform(first, document); - self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + if selected_layers_count == 1 { + self.transform_from_normalized = Self::get_layer_pivot_transform(first, document); + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + } else { + // If more than one layer is selected we use the AABB with the mean of the pivots + let get_viewport = |layer: LayerNodeIdentifier| { + let [min, max] = document.network_interface.document_metadata().nonzero_bounding_box(layer); + let pivot = self.normalized_pivot; + document.network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * pivot) + }; + let xy_summation = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .map(get_viewport) + .reduce(|a, b| a + b) + .unwrap_or_default(); + + let pivot = xy_summation / selected_layers_count as f64; + self.pivot = Some(pivot); + let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); + self.normalized_pivot = (pivot - min) / (max - min); + + self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + } } - fn get_layer_origin_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { + fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { let [min, max] = document.metadata().nonzero_bounding_box(layer); let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index b9e965cbfa..cd9319e834 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -68,7 +68,7 @@ impl DotType { } pub fn is_origin(self) -> bool { - self == Self::Pivot + self == Self::Origin } } diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index b205f3bb84..9ce1d85262 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -524,7 +524,7 @@ impl Fsm for TextToolFsmState { } bounding_box_manager.render_overlays(&mut overlay_context, false); - // tool_data.pivot.update_pivot(document, &mut overlay_context, None); + tool_data.pivot.update(document, &mut overlay_context, None, true); } } else { tool_data.bounding_box_manager.take(); From a7847ec9ade23c592481ebc7e75fa75aa75ef715 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 26 Jun 2025 07:58:04 +0530 Subject: [PATCH 07/54] some more cleanup --- .../tool/common_functionality/pivot.rs | 47 ++----------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 00ea05bf2b..b86a88faf2 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -2,7 +2,6 @@ use crate::consts::PIVOT_DIAMETER; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; -use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; use glam::{DAffine2, DVec2}; use graphene_std::transform::ReferencePoint; @@ -40,53 +39,15 @@ impl Pivot { return; } - let selected_nodes = document.network_interface.selected_nodes(); - let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); - let Some(first) = layers.next() else { - // If no layers are selected then we revert things back to default + if !document.network_interface.selected_nodes().has_selected_nodes() { self.normalized_pivot = DVec2::ZERO; self.pivot = None; return; }; - - // Add one because the first item is consumed above. - let selected_layers_count = layers.count() + 1; - - // If just one layer is selected we can use its inner transform (as it accounts for rotation) - if selected_layers_count == 1 { - self.transform_from_normalized = Self::get_layer_pivot_transform(first, document); - self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); - } else { - // If more than one layer is selected we use the AABB with the mean of the pivots - let get_viewport = |layer: LayerNodeIdentifier| { - let [min, max] = document.network_interface.document_metadata().nonzero_bounding_box(layer); - let pivot = self.normalized_pivot; - document.network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * pivot) - }; - let xy_summation = document - .network_interface - .selected_nodes() - .selected_visible_and_unlocked_layers(&document.network_interface) - .map(get_viewport) - .reduce(|a, b| a + b) - .unwrap_or_default(); - - let pivot = xy_summation / selected_layers_count as f64; - self.pivot = Some(pivot); - let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); - self.normalized_pivot = (pivot - min) / (max - min); - - self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - } - } - - fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { - let [min, max] = document.metadata().nonzero_bounding_box(layer); - - let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - let layer_transform = document.metadata().transform_to_viewport(layer); - layer_transform * bounds_transform + let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); + self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>, draw: bool) { From 519d84aa9c025b6553938dc7449fbcd6100ac2d4 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 26 Jun 2025 09:30:34 +0530 Subject: [PATCH 08/54] fixes --- .../tool/common_functionality/pivot.rs | 27 ++++++++++++++++--- .../tool/tool_messages/select_tool.rs | 8 +----- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index b86a88faf2..11ad7ef71d 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -39,15 +39,34 @@ impl Pivot { return; } - if !document.network_interface.selected_nodes().has_selected_nodes() { + let selected_nodes = document.network_interface.selected_nodes(); + let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); + let Some(first) = layers.next() else { + // If no layers are selected then we revert things back to default self.normalized_pivot = DVec2::ZERO; self.pivot = None; return; }; - let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); - self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + // Add one because the first item is consumed above. + let selected_layers_count = layers.count() + 1; + + // If just one layer is selected we can use its inner transform (as it accounts for rotation) + if selected_layers_count == 1 { + let [min, max] = document.metadata().nonzero_bounding_box(first); + self.transform_from_normalized = { + let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + let layer_transform = document.metadata().transform_to_viewport(first); + layer_transform * bounds_transform + }; + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + } else { + let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); + debug!("[{} {}]", min, max); + self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + debug!("{:?}", self.pivot); + } } pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>, draw: bool) { diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index cd9319e834..005884e119 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -56,8 +56,8 @@ pub enum NestedSelectionBehavior { #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum DotType { - #[default] Origin, + #[default] Pivot, Off, } @@ -1033,12 +1033,6 @@ impl Fsm for SelectToolFsmState { if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); - - if tool_data.dot_type.is_pivot() && false { - responses.add(SelectToolMessage::SetPivot { - position: tool_data.pivot.old_pivot_position, - }); - } } if let Some(intersection) = intersection { From bb7a847cc9b89031486a04f06a02add359f2d636 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 26 Jun 2025 12:26:40 +0530 Subject: [PATCH 09/54] finally works --- .../document/document_message_handler.rs | 8 +++++ .../tool/common_functionality/pivot.rs | 35 +++++++------------ .../tool/tool_messages/select_tool.rs | 1 + 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 8e7b1c39cd..d9fd25909c 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1737,6 +1737,14 @@ impl DocumentMessageHandler { .reduce(graphene_std::renderer::Quad::combine_bounds) } + pub fn selected_visible_and_unlock_layers_bounding_box_document(&self) -> Option<[DVec2; 2]> { + self.network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&self.network_interface) + .map(|layer| self.metadata().nonzero_bounding_box(layer)) + .reduce(graphene_std::renderer::Quad::combine_bounds) + } + pub fn document_network(&self) -> &NodeNetwork { self.network_interface.document_network() } diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 11ad7ef71d..b6a84a492f 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -39,34 +39,23 @@ impl Pivot { return; } - let selected_nodes = document.network_interface.selected_nodes(); - let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); - let Some(first) = layers.next() else { - // If no layers are selected then we revert things back to default + if !document.network_interface.selected_nodes().has_selected_nodes() { self.normalized_pivot = DVec2::ZERO; self.pivot = None; return; }; - // Add one because the first item is consumed above. - let selected_layers_count = layers.count() + 1; - - // If just one layer is selected we can use its inner transform (as it accounts for rotation) - if selected_layers_count == 1 { - let [min, max] = document.metadata().nonzero_bounding_box(first); - self.transform_from_normalized = { - let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - let layer_transform = document.metadata().transform_to_viewport(first); - layer_transform * bounds_transform - }; - self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); - } else { - let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); - debug!("[{} {}]", min, max); - self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); - debug!("{:?}", self.pivot); - } + let transform = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface)) + .unwrap_or_default(); + + let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_document().unwrap_or([DVec2::ZERO, DVec2::ONE]); + self.transform_from_normalized = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>, draw: bool) { diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 005884e119..831dbea733 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1003,6 +1003,7 @@ impl Fsm for SelectToolFsmState { } tool_data.layers_dragging = selected; + debug!("done"); if tool_data.dot_type.is_pivot() && !tool_data.layers_dragging.is_empty() { responses.add(SelectToolMessage::SetPivot { position: tool_data.pivot.old_pivot_position, From 8e1ba2943a6c7f99ea5e72fa0f7463f168433dde Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 08:50:20 +0530 Subject: [PATCH 10/54] origin fixes --- .../graph_operation_message.rs | 6 +- .../graph_operation_message_handler.rs | 9 - .../document/graph_operation/utility_types.rs | 8 +- .../node_graph/document_node_definitions.rs | 13 -- .../document/overlays/utility_types.rs | 5 +- .../document/utility_types/transformation.rs | 27 ++- .../graph_modification_utils.rs | 7 +- .../messages/tool/common_functionality/mod.rs | 1 - .../tool/common_functionality/origin.rs | 159 ------------------ .../tool/tool_messages/select_tool.rs | 54 ++---- .../transform_layer_message_handler.rs | 1 - node-graph/gcore/src/transform.rs | 1 - 12 files changed, 38 insertions(+), 253 deletions(-) delete mode 100644 editor/src/messages/tool/common_functionality/origin.rs diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs index 2e2fda25c4..e6e363eb68 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs @@ -3,7 +3,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate; use crate::messages::prelude::*; use bezier_rs::Subpath; -use glam::{DAffine2, DVec2, IVec2}; +use glam::{DAffine2, IVec2}; use graph_craft::document::NodeId; use graphene_std::Artboard; use graphene_std::raster::BlendMode; @@ -52,10 +52,6 @@ pub enum GraphOperationMessage { transform_in: TransformIn, skip_rerender: bool, }, - TransformSetOrigin { - layer: LayerNodeIdentifier, - origin: DVec2, - }, Vector { layer: LayerNodeIdentifier, modification_type: VectorModificationType, diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index bfb741b7ec..b330f44985 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -89,15 +89,6 @@ impl MessageHandler> for Gr modify_inputs.transform_set(transform, transform_in, skip_rerender); } } - GraphOperationMessage::TransformSetOrigin { layer, origin } => { - if layer == LayerNodeIdentifier::ROOT_PARENT { - log::error!("Cannot run TransformSetOrigin on ROOT_PARENT"); - return; - } - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { - modify_inputs.origin_set(origin); - } - } GraphOperationMessage::Vector { layer, modification_type } => { if layer == LayerNodeIdentifier::ROOT_PARENT { log::error!("Cannot run Vector on ROOT_PARENT"); diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index c64ae739ba..47f3726521 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -4,7 +4,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, OutputConnector}; use crate::messages::prelude::*; use bezier_rs::Subpath; -use glam::{DAffine2, DVec2, IVec2}; +use glam::{DAffine2, IVec2}; use graph_craft::concrete; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput}; @@ -450,12 +450,6 @@ impl<'a> ModifyInputsContext<'a> { } } - pub fn origin_set(&mut self, new_origin: DVec2) { - let Some(transform_node_id) = self.existing_node_id("Transform", true) else { return }; - - self.set_input_with_refresh(InputConnector::node(transform_node_id, 5), NodeInput::value(TaggedValue::DVec2(new_origin), false), false); - } - pub fn vector_modify(&mut self, modification_type: VectorModificationType) { let Some(path_node_id) = self.existing_node_id("Path", true) else { return }; self.network_interface.vector_modify(&path_node_id, modification_type); diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index dcdbdbb4fa..419f8e42e4 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -1627,7 +1627,6 @@ fn static_nodes() -> Vec { NodeInput::value(TaggedValue::F64(0.), false), NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false), NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), - NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), ], implementation: DocumentNodeImplementation::Network(NodeNetwork { exports: vec![NodeInput::node(NodeId(1), 0)], @@ -1646,7 +1645,6 @@ fn static_nodes() -> Vec { NodeInput::network(concrete!(f64), 2), NodeInput::network(concrete!(DVec2), 3), NodeInput::network(concrete!(DVec2), 4), - NodeInput::network(concrete!(DVec2), 5), ], manual_composition: Some(concrete!(Context)), implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::TransformNode")), @@ -1714,17 +1712,6 @@ fn static_nodes() -> Vec { }), ), PropertiesRow::with_override("Skew", "TODO", WidgetOverride::Custom("transform_skew".to_string())), - PropertiesRow::with_override("Pivot", "TODO", WidgetOverride::Hidden), - PropertiesRow::with_override( - "Origin Offset", - "TODO", - WidgetOverride::Vec2(Vec2InputSettings { - x: "X".to_string(), - y: "Y".to_string(), - unit: " px".to_string(), - ..Default::default() - }), - ), ], output_names: vec!["Data".to_string()], ..Default::default() diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 41b184f81a..db3f4dba0d 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -6,7 +6,7 @@ use crate::consts::{ use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; use core::borrow::Borrow; -use core::f64::consts::{FRAC_PI_2, TAU}; +use core::f64::consts::{FRAC_PI_2, PI, TAU}; use glam::{DAffine2, DVec2}; use graphene_std::Color; use graphene_std::renderer::ClickTargetType; @@ -550,8 +550,7 @@ impl OverlayContext { self.end_dpi_aware_transform(); } - pub fn draw_origin(&mut self, position: DVec2) { - use std::f64::consts::PI; + pub fn dowel_pin(&mut self, position: DVec2) { let (x, y) = (position.round() - DVec2::splat(0.5)).into(); self.start_dpi_aware_transform(); diff --git a/editor/src/messages/portfolio/document/utility_types/transformation.rs b/editor/src/messages/portfolio/document/utility_types/transformation.rs index b8fe6e2682..158bcee343 100644 --- a/editor/src/messages/portfolio/document/utility_types/transformation.rs +++ b/editor/src/messages/portfolio/document/utility_types/transformation.rs @@ -484,6 +484,24 @@ impl TransformOperation { } } +pub trait MeanAverage { + fn mean_average_origin(self, network_interface: &NodeNetworkInterface) -> DVec2; +} + +impl MeanAverage for &[LayerNodeIdentifier] { + fn mean_average_origin(self, network_interface: &NodeNetworkInterface) -> DVec2 { + if self.is_empty() { + return DVec2::default(); + } + + self.iter() + .map(|&layer| graph_modification_utils::get_viewport_origin(layer, network_interface)) + .reduce(|a, b| a + b) + .unwrap_or_default() + / self.len() as f64 + } +} + pub struct Selected<'a> { pub selected: &'a [LayerNodeIdentifier], pub responses: &'a mut VecDeque, @@ -528,14 +546,7 @@ impl<'a> Selected<'a> { } pub fn mean_average_of_pivots(&mut self) -> DVec2 { - let xy_summation = self - .selected - .iter() - .map(|&layer| graph_modification_utils::get_viewport_origin(layer, self.network_interface)) - .reduce(|a, b| a + b) - .unwrap_or_default(); - - xy_summation / self.selected.len() as f64 + self.selected.mean_average_origin(&self.network_interface) } pub fn center_of_aabb(&mut self) -> DVec2 { diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 81cc9c4bd1..3257ab804a 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -245,7 +245,7 @@ pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerN /// Locate the origin of the transform node pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let origin_node_input_index = 5; + let origin_node_input_index = 1; if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", origin_node_input_index)? { Some(*origin) } else { @@ -254,9 +254,8 @@ pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInt } pub fn get_viewport_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 { - let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer); - let origin = get_origin(layer, network_interface).unwrap_or(DVec2::ZERO); - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * origin) + let origin = get_origin(layer, network_interface).unwrap_or_default(); + network_interface.document_metadata().document_to_viewport.transform_point2(origin) } /// Get the current gradient of a layer from the closest "Fill" node. diff --git a/editor/src/messages/tool/common_functionality/mod.rs b/editor/src/messages/tool/common_functionality/mod.rs index 5d50f6baf5..4a003d0254 100644 --- a/editor/src/messages/tool/common_functionality/mod.rs +++ b/editor/src/messages/tool/common_functionality/mod.rs @@ -3,7 +3,6 @@ pub mod color_selector; pub mod compass_rose; pub mod graph_modification_utils; pub mod measure; -pub mod origin; pub mod pivot; pub mod resize; pub mod shape_editor; diff --git a/editor/src/messages/tool/common_functionality/origin.rs b/editor/src/messages/tool/common_functionality/origin.rs deleted file mode 100644 index 28e8319687..0000000000 --- a/editor/src/messages/tool/common_functionality/origin.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! Handler for the origin overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale and origin of the layer. - -use super::graph_modification_utils; -use crate::consts::DOWEL_PIN_RADIUS; -use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; -use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; -use crate::messages::prelude::*; -use glam::{DAffine2, DVec2}; -use graphene_std::transform::ReferencePoint; -use std::collections::VecDeque; - -#[derive(Clone, Debug)] -pub struct Origin { - /// Origin between (0,0) and (1,1) - normalized_origin: DVec2, - /// Transform to get from normalized origin to viewspace - transform_from_normalized: DAffine2, - /// The viewspace origin position (if applicable) - origin: Option, - /// The old origin position in the GUI, used to reduce refreshes of the document bar - old_origin_position: ReferencePoint, - /// Used to enable and disable the origin - active: bool, -} - -impl Default for Origin { - fn default() -> Self { - Self { - normalized_origin: DVec2::ZERO, - transform_from_normalized: Default::default(), - origin: Default::default(), - old_origin_position: ReferencePoint::Center, - active: true, - } - } -} - -impl Origin { - /// Calculates the transform that gets from normalized origin to viewspace. - fn get_layer_origin_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { - let [min, max] = document.metadata().nonzero_bounding_box(layer); - - let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - let layer_transform = document.metadata().transform_to_viewport(layer); - layer_transform * bounds_transform - } - - /// Recomputes the origin position and transform. - fn recalculate_origin(&mut self, document: &DocumentMessageHandler) { - if !self.active { - return; - } - - let selected_nodes = document.network_interface.selected_nodes(); - let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); - let Some(first) = layers.next() else { - // If no layers are selected then we revert things back to default - self.normalized_origin = DVec2::ZERO; - self.origin = None; - return; - }; - - // Add one because the first item is consumed above. - let selected_layers_count = layers.count() + 1; - - // If just one layer is selected we can use its inner transform (as it accounts for rotation) - if selected_layers_count == 1 { - let normalized_origin = graph_modification_utils::get_origin(first, &document.network_interface).unwrap_or(DVec2::ZERO); - self.normalized_origin = normalized_origin; - self.transform_from_normalized = Self::get_layer_origin_transform(first, document); - self.origin = Some(self.transform_from_normalized.transform_point2(normalized_origin)); - } else { - // If more than one layer is selected we use the AABB with the mean of the origins - let xy_summation = document - .network_interface - .selected_nodes() - .selected_visible_and_unlocked_layers(&document.network_interface) - .map(|layer| graph_modification_utils::get_viewport_origin(layer, &document.network_interface)) - .reduce(|a, b| a + b) - .unwrap_or_default(); - - let origin = xy_summation / selected_layers_count as f64; - self.origin = Some(origin); - let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); - self.normalized_origin = (origin - min) / (max - min); - - self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - } - } - - pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw: bool) { - if !overlay_context.visibility_settings.pivot() { - self.active = false; - return; - } else { - self.active = true; - } - - self.recalculate_origin(document); - if !draw {return}; - if let Some(origin) = self.origin { - overlay_context.draw_origin(origin); - } - } - - pub fn position(&self) -> Option { - self.origin - } - - /// Answers if the origin widget has changed (so we should refresh the tool bar at the top of the canvas). - pub fn should_refresh_origin_position(&mut self) -> bool { - if !self.active { - return false; - } - - let new = self.to_origin_position(); - let should_refresh = new != self.old_origin_position; - self.old_origin_position = new; - should_refresh - } - - pub fn to_origin_position(&self) -> ReferencePoint { - self.normalized_origin.into() - } - - /// Sets the viewport position of the origin for all selected layers. - pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { - if !self.active { - return; - } - - for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { - let transform = Self::get_layer_origin_transform(layer, document); - // Only update the origin when computed position is finite. - if transform.matrix2.determinant().abs() <= f64::EPSILON { - return; - }; - let origin = transform.inverse().transform_point2(position); - responses.add(GraphOperationMessage::TransformSetOrigin { layer, origin }); - } - } - - /// Set the origin using the normalized transform that is set above. - pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { - if !self.active { - return; - } - - self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, responses); - } - - /// Answers if the pointer is currently positioned over the origin. - pub fn is_over(&self, mouse: DVec2) -> bool { - if !self.active { - return false; - } - self.origin.filter(|&origin| mouse.distance_squared(origin) < (DOWEL_PIN_RADIUS).powi(2)).is_some() - } -} diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 831dbea733..74d5e2241d 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -9,12 +9,12 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{Doc use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType}; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; +use crate::messages::portfolio::document::utility_types::transformation::MeanAverage; use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRose}; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; use crate::messages::tool::common_functionality::measure; -use crate::messages::tool::common_functionality::origin::Origin; use crate::messages::tool::common_functionality::pivot::Pivot; use crate::messages::tool::common_functionality::shape_editor::SelectionShapeType; use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager}; @@ -56,8 +56,8 @@ pub enum NestedSelectionBehavior { #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum DotType { - Origin, #[default] + Origin, Pivot, Off, } @@ -125,9 +125,6 @@ pub enum SelectToolMessage { SetPivot { position: ReferencePoint, }, - SetOrigin { - position: ReferencePoint, - }, } impl ToolMetadata for SelectTool { @@ -376,7 +373,6 @@ enum SelectToolFsmState { }, RotatingBounds, DraggingPivot, - DraggingOrigin, } impl Default for SelectToolFsmState { @@ -401,7 +397,6 @@ struct SelectToolData { snap_manager: SnapManager, cursor: MouseCursorIcon, pivot: Pivot, - origin: Origin, dot_type: DotType, compass_rose: CompassRose, line_center: DVec2, @@ -572,7 +567,6 @@ impl SelectToolData { fn state_from_dot(&self, mouse: DVec2) -> Option { match self.dot_type { DotType::Pivot => self.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), - DotType::Origin => self.origin.is_over(mouse).then_some(SelectToolFsmState::DraggingOrigin), _ => None, } } @@ -798,7 +792,10 @@ impl Fsm for SelectToolFsmState { }); tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), tool_data.dot_type.is_pivot()); - tool_data.origin.update(document, &mut overlay_context, tool_data.dot_type.is_origin()); + if tool_data.dot_type.is_origin() { + let origin = tool_data.layers_dragging.mean_average_origin(&document.network_interface); + overlay_context.dowel_pin(origin); + } // Update compass rose if overlay_context.visibility_settings.compass_rose() { @@ -1003,7 +1000,6 @@ impl Fsm for SelectToolFsmState { } tool_data.layers_dragging = selected; - debug!("done"); if tool_data.dot_type.is_pivot() && !tool_data.layers_dragging.is_empty() { responses.add(SelectToolMessage::SetPivot { position: tool_data.pivot.old_pivot_position, @@ -1063,7 +1059,7 @@ impl Fsm for SelectToolFsmState { state } - (SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin, SelectToolMessage::Abort) => { + (SelectToolFsmState::DraggingPivot, SelectToolMessage::Abort) => { responses.add(DocumentMessage::AbortTransaction); let selection = tool_data.nested_selection_behavior; @@ -1201,20 +1197,6 @@ impl Fsm for SelectToolFsmState { SelectToolFsmState::DraggingPivot } - (SelectToolFsmState::DraggingOrigin, SelectToolMessage::PointerMove(modifier_keys)) => { - let mouse_position = input.mouse.position; - let snapped_mouse_position = mouse_position; - tool_data.origin.set_viewport_position(snapped_mouse_position, document, responses); - - // Auto-panning - let messages = [ - SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), - SelectToolMessage::PointerMove(modifier_keys).into(), - ]; - tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); - - SelectToolFsmState::DraggingOrigin - } (SelectToolFsmState::Drawing { selection_shape, has_drawn }, SelectToolMessage::PointerMove(modifier_keys)) => { if !has_drawn { responses.add(ToolMessage::UpdateHints); @@ -1249,9 +1231,7 @@ impl Fsm for SelectToolFsmState { .map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge))); // Dragging the pivot overrules the other operations - let mouse = input.mouse.position; - let is_over_override = tool_data.pivot.is_over(mouse) || tool_data.origin.is_over(mouse); - if is_over_override { + if tool_data.pivot.is_over(input.mouse.position) { cursor = MouseCursorIcon::Move; } @@ -1301,7 +1281,7 @@ impl Fsm for SelectToolFsmState { self } - (SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin, SelectToolMessage::PointerOutsideViewport(_)) => { + (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport(_)) => { // Auto-panning let _ = tool_data.auto_panning.shift_viewport(input, responses); @@ -1399,8 +1379,7 @@ impl Fsm for SelectToolFsmState { | SelectToolFsmState::SkewingBounds { .. } | SelectToolFsmState::RotatingBounds | SelectToolFsmState::Dragging { .. } - | SelectToolFsmState::DraggingPivot - | SelectToolFsmState::DraggingOrigin, + | SelectToolFsmState::DraggingPivot, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter, ) => { let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON; @@ -1409,7 +1388,7 @@ impl Fsm for SelectToolFsmState { tool_data.axis_align = false; tool_data.snap_manager.cleanup(responses); - if !matches!(self, SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin) { + if !matches!(self, SelectToolFsmState::DraggingPivot) { if let Some(bounds) = &mut tool_data.bounding_box_manager { bounds.original_transforms.clear(); } @@ -1546,15 +1525,6 @@ impl Fsm for SelectToolFsmState { self } - (_, SelectToolMessage::SetOrigin { position }) => { - responses.add(DocumentMessage::StartTransaction); - - let pos: Option = position.into(); - tool_data.origin.set_normalized_position(pos.unwrap(), document, responses); - responses.add(TransformLayerMessage::SetCenter { center: None }); - - self - } _ => self, } } @@ -1654,7 +1624,7 @@ impl Fsm for SelectToolFsmState { ]); responses.add(FrontendMessage::UpdateInputHints { hint_data }); } - SelectToolFsmState::DraggingPivot | SelectToolFsmState::DraggingOrigin => { + SelectToolFsmState::DraggingPivot => { let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]); responses.add(FrontendMessage::UpdateInputHints { hint_data }); } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 5f8c784c59..4fc3d8c835 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -178,7 +178,6 @@ impl MessageHandler> for TransformLayer } if !using_path_tool { - debug!("{:?}", self.pivot_from_select); *selected.pivot = self.pivot_from_select.unwrap_or(selected.mean_average_of_pivots()); self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(selected.mean_average_of_pivots()); diff --git a/node-graph/gcore/src/transform.rs b/node-graph/gcore/src/transform.rs index e1587ec729..b4e1dcfa2e 100644 --- a/node-graph/gcore/src/transform.rs +++ b/node-graph/gcore/src/transform.rs @@ -167,7 +167,6 @@ async fn transform( rotate: f64, scale: DVec2, shear: DVec2, - _pivot: DVec2, ) -> Instances { let matrix = DAffine2::from_scale_angle_translation(scale, rotate, translate) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]); From d4d1aa65c0533017f4aa0e917755dccc24b311d0 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 09:41:17 +0530 Subject: [PATCH 11/54] fix spaces --- .../tool/common_functionality/pivot.rs | 21 ++++++++++++++----- .../tool/tool_messages/select_tool.rs | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index b6a84a492f..f53b81bc55 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -39,21 +39,32 @@ impl Pivot { return; } - if !document.network_interface.selected_nodes().has_selected_nodes() { + let selected = document.network_interface.selected_nodes(); + if !selected.has_selected_nodes() { self.normalized_pivot = DVec2::ZERO; self.pivot = None; return; }; - let transform = document - .network_interface - .selected_nodes() + let transform = selected .selected_visible_and_unlocked_layers(&document.network_interface) .find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) .map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface)) .unwrap_or_default(); - let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_document().unwrap_or([DVec2::ZERO, DVec2::ONE]); + let bounds = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .filter_map(|layer| { + document + .metadata() + .bounding_box_with_transform(layer, transform.inverse() * document.metadata().transform_to_viewport(layer)) + }) + .reduce(graphene_std::renderer::Quad::combine_bounds); + + let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]); self.transform_from_normalized = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min); self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 74d5e2241d..4845d2bf32 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -56,8 +56,8 @@ pub enum NestedSelectionBehavior { #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum DotType { - #[default] Origin, + #[default] Pivot, Off, } From c42d4da18cc75fab3145b2cc3cf4ddaa38864684 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 10:12:52 +0530 Subject: [PATCH 12/54] fix using dragged_layers --- editor/src/messages/tool/tool_messages/select_tool.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 4845d2bf32..844c091fc9 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -793,7 +793,8 @@ impl Fsm for SelectToolFsmState { tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), tool_data.dot_type.is_pivot()); if tool_data.dot_type.is_origin() { - let origin = tool_data.layers_dragging.mean_average_origin(&document.network_interface); + let network_interface = &document.network_interface; + let origin = (network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect::>()).mean_average_origin(network_interface); overlay_context.dowel_pin(origin); } From 7139f341b2f6e044267e9a2c6e5bf29d26a820bd Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 13:01:07 +0530 Subject: [PATCH 13/54] simplify pivot logic --- .../tool/common_functionality/pivot.rs | 2 +- .../tool/tool_messages/select_tool.rs | 32 +++++++++++-------- .../transform_layer_message.rs | 2 +- .../transform_layer_message_handler.rs | 6 ++-- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index f53b81bc55..b8453d60c3 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -11,7 +11,7 @@ pub struct Pivot { /// Pivot between (0,0) and (1,1) normalized_pivot: DVec2, /// Transform to get from normalized pivot to viewspace - transform_from_normalized: DAffine2, + pub transform_from_normalized: DAffine2, /// The viewspace pivot position pivot: Option, /// The old pivot position in the GUI, used to reduce refreshes of the document bar diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 844c091fc9..dd25eb657d 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -307,8 +307,8 @@ impl<'a> MessageHandler> for SelectT SelectOptionsUpdate::DotType(dot_type) => { self.tool_data.dot_type = *dot_type; responses.add(ToolMessage::UpdateHints); - let center = self.tool_data.get_pivot_position(); - responses.add(TransformLayerMessage::SetCenter { center }); + let center = self.tool_data.get_dot_position(); + responses.add(TransformLayerMessage::SetDot { center }); redraw_ref_pivot = true; } } @@ -398,6 +398,7 @@ struct SelectToolData { cursor: MouseCursorIcon, pivot: Pivot, dot_type: DotType, + origin: DVec2, // hack because process_message doesn't have document compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -571,12 +572,13 @@ impl SelectToolData { } } - fn get_pivot_position(&self) -> Option { - match self.dot_type { - DotType::Origin => None, - DotType::Pivot => self.pivot.position().or(Some(DVec2::splat(0.5))), - _ => Some(DVec2::splat(0.5)), - } + fn get_dot_position(&self) -> DVec2 { + let dot_position = match self.dot_type { + DotType::Origin => Some(self.origin), + DotType::Pivot => self.pivot.position(), + _ => None, + }; + dot_position.unwrap_or_else(|| self.pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))) } } @@ -794,8 +796,9 @@ impl Fsm for SelectToolFsmState { tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), tool_data.dot_type.is_pivot()); if tool_data.dot_type.is_origin() { let network_interface = &document.network_interface; - let origin = (network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect::>()).mean_average_origin(network_interface); - overlay_context.dowel_pin(origin); + tool_data.origin = + (network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect::>()).mean_average_origin(network_interface); + overlay_context.dowel_pin(tool_data.origin); } // Update compass rose @@ -954,8 +957,8 @@ impl Fsm for SelectToolFsmState { let intersection_list = document.click_list(input).collect::>(); let intersection = document.find_deepest(&intersection_list); - let pos = tool_data.get_pivot_position(); - let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, pos); + let pos = tool_data.get_dot_position(); + let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, Some(pos)); // If the user is dragging the bounding box bounds, go into ResizingBounds mode. // If the user is dragging the rotate trigger, go into RotatingBounds mode. @@ -1521,8 +1524,9 @@ impl Fsm for SelectToolFsmState { let pos: Option = position.into(); tool_data.pivot.set_normalized_position(pos.unwrap()); - let center = tool_data.pivot.position(); - responses.add(TransformLayerMessage::SetCenter { center }); + let pivot = &tool_data.pivot; + let center = pivot.position().unwrap_or_else(|| pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))); + responses.add(TransformLayerMessage::SetDot { center }); self } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs index ea02f61ad9..6da2596e91 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -15,7 +15,7 @@ pub enum TransformLayerMessage { BeginGrab, BeginRotate, BeginScale, - SetCenter { center: Option }, + SetDot { center: DVec2 }, BeginGRS { transform_type: TransformType }, BeginGrabPen { last_point: DVec2, handle: DVec2 }, BeginRotatePen { last_point: DVec2, handle: DVec2 }, diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 4fc3d8c835..28deb06189 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -34,7 +34,7 @@ pub struct TransformLayerMessageHandler { start_mouse: ViewportPosition, original_transforms: OriginalTransforms, - pivot_from_select: Option, + pivot_from_select: DVec2, pivot: ViewportPosition, local_pivot: DocumentPosition, @@ -178,7 +178,7 @@ impl MessageHandler> for TransformLayer } if !using_path_tool { - *selected.pivot = self.pivot_from_select.unwrap_or(selected.mean_average_of_pivots()); + *selected.pivot = self.pivot_from_select; self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(selected.mean_average_of_pivots()); } else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { @@ -688,7 +688,7 @@ impl MessageHandler> for TransformLayer self.initial_transform, ) } - TransformLayerMessage::SetCenter { center: pivot } => self.pivot_from_select = pivot, + TransformLayerMessage::SetDot { center } => self.pivot_from_select = center, } } From 58383ad7a672cbb01bceeefbb4c8ad24ae28e6b0 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 13:53:16 +0530 Subject: [PATCH 14/54] fix bugs --- editor/src/messages/tool/common_functionality/pivot.rs | 2 +- editor/src/messages/tool/tool_messages/select_tool.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index b8453d60c3..4e0183179f 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -41,7 +41,7 @@ impl Pivot { let selected = document.network_interface.selected_nodes(); if !selected.has_selected_nodes() { - self.normalized_pivot = DVec2::ZERO; + self.normalized_pivot = DVec2::splat(0.5); self.pivot = None; return; }; diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index dd25eb657d..bb0159b046 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -794,7 +794,7 @@ impl Fsm for SelectToolFsmState { }); tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), tool_data.dot_type.is_pivot()); - if tool_data.dot_type.is_origin() { + if tool_data.dot_type.is_origin() && document.network_interface.selected_nodes().has_selected_nodes() { let network_interface = &document.network_interface; tool_data.origin = (network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect::>()).mean_average_origin(network_interface); From dad772e455718b5ba0b060655effac9666d6e0fb Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 14:32:05 +0530 Subject: [PATCH 15/54] fix the final bug --- editor/src/messages/tool/tool_messages/select_tool.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index bb0159b046..4994453b40 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1527,6 +1527,7 @@ impl Fsm for SelectToolFsmState { let pivot = &tool_data.pivot; let center = pivot.position().unwrap_or_else(|| pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))); responses.add(TransformLayerMessage::SetDot { center }); + responses.add(NodeGraphMessage::RunDocumentGraph); self } From 6a5c1d24718d106da864d42d0ff2494ae03edc6c Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 15:00:41 +0530 Subject: [PATCH 16/54] fix in select_tool --- editor/src/messages/tool/tool_messages/select_tool.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 4994453b40..381f1724e5 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1375,6 +1375,9 @@ impl Fsm for SelectToolFsmState { tool_data.snap_manager.cleanup(responses); tool_data.select_single_layer = None; + let center = tool_data.get_dot_position(); + responses.add(TransformLayerMessage::SetDot { center }); + let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } } From 7e8fe03c98b778ac23652615a9f7aabf17bdf4f1 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 27 Jun 2025 15:33:18 +0530 Subject: [PATCH 17/54] fix updates --- .../tool/common_functionality/pivot.rs | 5 ++--- .../tool/tool_messages/select_tool.rs | 16 +++++++------- .../transform_layer_message.rs | 4 +++- .../transform_layer_message_handler.rs | 21 ++++++++++++++++--- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 4e0183179f..2d3a44ade5 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -6,7 +6,7 @@ use crate::messages::prelude::*; use glam::{DAffine2, DVec2}; use graphene_std::transform::ReferencePoint; -#[derive(Clone, Debug)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct Pivot { /// Pivot between (0,0) and (1,1) normalized_pivot: DVec2, @@ -34,7 +34,7 @@ impl Default for Pivot { impl Pivot { /// Recomputes the pivot position and transform. - fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { + pub fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { if !self.active { return; } @@ -77,7 +77,6 @@ impl Pivot { self.active = true; } - // self.recalculate_transform(document); self.recalculate_pivot(document); if !draw { return; diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 381f1724e5..435da04d95 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -307,8 +307,8 @@ impl<'a> MessageHandler> for SelectT SelectOptionsUpdate::DotType(dot_type) => { self.tool_data.dot_type = *dot_type; responses.add(ToolMessage::UpdateHints); - let center = self.tool_data.get_dot_position(); - responses.add(TransformLayerMessage::SetDot { center }); + let dot = self.tool_data.get_as_dot(); + responses.add(TransformLayerMessage::SetDot { dot }); redraw_ref_pivot = true; } } @@ -580,6 +580,9 @@ impl SelectToolData { }; dot_position.unwrap_or_else(|| self.pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))) } + fn get_as_dot(&self) -> (Pivot, DotType) { + (self.pivot.clone(), self.dot_type) + } } impl Fsm for SelectToolFsmState { @@ -1375,8 +1378,8 @@ impl Fsm for SelectToolFsmState { tool_data.snap_manager.cleanup(responses); tool_data.select_single_layer = None; - let center = tool_data.get_dot_position(); - responses.add(TransformLayerMessage::SetDot { center }); + let dot = tool_data.get_as_dot(); + responses.add(TransformLayerMessage::SetDot { dot }); let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } @@ -1527,9 +1530,8 @@ impl Fsm for SelectToolFsmState { let pos: Option = position.into(); tool_data.pivot.set_normalized_position(pos.unwrap()); - let pivot = &tool_data.pivot; - let center = pivot.position().unwrap_or_else(|| pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))); - responses.add(TransformLayerMessage::SetDot { center }); + let dot = tool_data.get_as_dot(); + responses.add(TransformLayerMessage::SetDot { dot }); responses.add(NodeGraphMessage::RunDocumentGraph); self diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs index 6da2596e91..76f0c9b5e0 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -2,6 +2,8 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::transformation::TransformType; use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::pivot::Pivot; +use crate::messages::tool::tool_messages::select_tool::DotType; use glam::DVec2; #[impl_message(Message, ToolMessage, TransformLayer)] @@ -15,7 +17,7 @@ pub enum TransformLayerMessage { BeginGrab, BeginRotate, BeginScale, - SetDot { center: DVec2 }, + SetDot { dot: (Pivot, DotType) }, BeginGRS { transform_type: TransformType }, BeginGrabPen { last_point: DVec2, handle: DVec2 }, BeginRotatePen { last_point: DVec2, handle: DVec2 }, diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 28deb06189..1dd04d4445 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -3,9 +3,12 @@ use crate::messages::input_mapper::utility_types::input_mouse::{DocumentPosition use crate::messages::portfolio::document::overlays::utility_types::{OverlayProvider, Pivot}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::PTZ; +use crate::messages::portfolio::document::utility_types::transformation::MeanAverage; use crate::messages::portfolio::document::utility_types::transformation::{Axis, OriginalTransforms, Selected, TransformOperation, TransformType, Typing}; use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::pivot::Pivot as SelectToolPivot; use crate::messages::tool::common_functionality::shape_editor::ShapeState; +use crate::messages::tool::tool_messages::select_tool::DotType; use crate::messages::tool::tool_messages::tool_prelude::Key; use crate::messages::tool::utility_types::{ToolData, ToolType}; use glam::{DAffine2, DVec2}; @@ -34,7 +37,7 @@ pub struct TransformLayerMessageHandler { start_mouse: ViewportPosition, original_transforms: OriginalTransforms, - pivot_from_select: DVec2, + dot: (SelectToolPivot, DotType), pivot: ViewportPosition, local_pivot: DocumentPosition, @@ -178,7 +181,19 @@ impl MessageHandler> for TransformLayer } if !using_path_tool { - *selected.pivot = self.pivot_from_select; + self.dot.0.recalculate_pivot(document); + let dot_position = |&(ref pivot, ref dot_type): &(SelectToolPivot, DotType)| { + match dot_type { + DotType::Origin => { + let network_interface = &document.network_interface; + Some((network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect::>()).mean_average_origin(network_interface)) + } + DotType::Pivot => pivot.position(), + _ => None, + } + .unwrap_or_else(|| pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))) + }; + *selected.pivot = dot_position(&self.dot); self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(selected.mean_average_of_pivots()); } else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { @@ -688,7 +703,7 @@ impl MessageHandler> for TransformLayer self.initial_transform, ) } - TransformLayerMessage::SetDot { center } => self.pivot_from_select = center, + TransformLayerMessage::SetDot { dot } => self.dot = dot, } } From c6d320ea840d0aae572011ae5a4baaba8140b3ce Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 28 Jun 2025 13:23:08 +0530 Subject: [PATCH 18/54] some more refactors to fix misunderstanding and refactor --- .../document/document_message_handler.rs | 19 ++++++ .../document/overlays/utility_types.rs | 7 ++ .../portfolio/document/utility_types/nodes.rs | 18 +++++ .../document/utility_types/transformation.rs | 23 ------- .../graph_modification_utils.rs | 6 ++ .../common_functionality/utility_functions.rs | 37 ++++------- .../tool/tool_messages/select_tool.rs | 65 +++++++++++-------- .../transform_layer_message.rs | 5 +- .../transform_layer_message_handler.rs | 26 +++----- 9 files changed, 111 insertions(+), 95 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 21dd4cd8aa..35f6f7cff9 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1177,6 +1177,7 @@ impl MessageHandler> for DocumentMessag OverlaysType::HoverOutline => visibility_settings.hover_outline = visible, OverlaysType::SelectionOutline => visibility_settings.selection_outline = visible, OverlaysType::Pivot => visibility_settings.pivot = visible, + OverlaysType::Origin => visibility_settings.origin = visible, OverlaysType::Path => visibility_settings.path = visible, OverlaysType::Anchors => { visibility_settings.anchors = visible; @@ -2265,6 +2266,24 @@ impl DocumentMessageHandler { ] }, }, + LayoutGroup::Row { + widgets: { + let mut checkbox_id = CheckboxId::default(); + vec![ + CheckboxInput::new(self.overlays_visibility_settings.pivot) + .on_update(|optional_input: &CheckboxInput| { + DocumentMessage::SetOverlaysVisibility { + visible: optional_input.checked, + overlays_type: Some(OverlaysType::Origin), + } + .into() + }) + .for_label(checkbox_id.clone()) + .widget_holder(), + TextLabel::new("Transform Pivot".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + ] + }, + }, LayoutGroup::Row { widgets: { let mut checkbox_id = CheckboxId::default(); diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index db3f4dba0d..1d59aec76f 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -33,6 +33,7 @@ pub enum OverlaysType { HoverOutline, SelectionOutline, Pivot, + Origin, Path, Anchors, Handles, @@ -49,6 +50,7 @@ pub struct OverlaysVisibilitySettings { pub hover_outline: bool, pub selection_outline: bool, pub pivot: bool, + pub origin: bool, pub path: bool, pub anchors: bool, pub handles: bool, @@ -66,6 +68,7 @@ impl Default for OverlaysVisibilitySettings { hover_outline: true, selection_outline: true, pivot: true, + origin: true, path: true, anchors: true, handles: true, @@ -110,6 +113,10 @@ impl OverlaysVisibilitySettings { self.all && self.pivot } + pub fn origin(&self) -> bool { + self.all && self.origin + } + pub fn path(&self) -> bool { self.all && self.path } diff --git a/editor/src/messages/portfolio/document/utility_types/nodes.rs b/editor/src/messages/portfolio/document/utility_types/nodes.rs index d81f1693d7..66369026b3 100644 --- a/editor/src/messages/portfolio/document/utility_types/nodes.rs +++ b/editor/src/messages/portfolio/document/utility_types/nodes.rs @@ -1,5 +1,7 @@ use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use super::network_interface::NodeNetworkInterface; +use crate::messages::tool::common_functionality::graph_modification_utils; +use glam::DVec2; use graph_craft::document::{NodeId, NodeNetwork}; use serde::ser::SerializeStruct; @@ -98,6 +100,22 @@ impl SelectedNodes { .filter(move |&layer| self.layer_visible(layer, network_interface) && !self.layer_locked(layer, network_interface)) } + pub fn selected_visible_and_unlocked_layers_mean_average_origin<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> DVec2 { + let (sum, count) = self + .selected_visible_and_unlocked_layers(network_interface) + .map(|layer| graph_modification_utils::get_viewport_origin(layer, network_interface)) + .fold((glam::DVec2::ZERO, 0), |(sum, count), item| (sum + item, count + 1)); + if count == 0 { DVec2::ZERO } else { sum / count as f64 } + } + + pub fn selected_visible_and_unlocked_median_points<'a>(&'a self, network_interface: &'a NodeNetworkInterface) -> DVec2 { + let (sum, count) = self + .selected_visible_and_unlocked_layers(network_interface) + .map(|layer| graph_modification_utils::get_viewport_center(layer, network_interface)) + .fold((glam::DVec2::ZERO, 0), |(sum, count), item| (sum + item, count + 1)); + if count == 0 { DVec2::ZERO } else { sum / count as f64 } + } + pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator + 'a { metadata.all_layers().filter(|layer| self.0.contains(&layer.to_node())) } diff --git a/editor/src/messages/portfolio/document/utility_types/transformation.rs b/editor/src/messages/portfolio/document/utility_types/transformation.rs index 158bcee343..4ffec0eacd 100644 --- a/editor/src/messages/portfolio/document/utility_types/transformation.rs +++ b/editor/src/messages/portfolio/document/utility_types/transformation.rs @@ -4,7 +4,6 @@ use crate::messages::portfolio::document::graph_operation::transform_utils; use crate::messages::portfolio::document::graph_operation::utility_types::{ModifyInputsContext, TransformIn}; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::graph_modification_utils; use crate::messages::tool::common_functionality::shape_editor::ShapeState; use crate::messages::tool::utility_types::ToolType; use glam::{DAffine2, DMat2, DVec2}; @@ -484,24 +483,6 @@ impl TransformOperation { } } -pub trait MeanAverage { - fn mean_average_origin(self, network_interface: &NodeNetworkInterface) -> DVec2; -} - -impl MeanAverage for &[LayerNodeIdentifier] { - fn mean_average_origin(self, network_interface: &NodeNetworkInterface) -> DVec2 { - if self.is_empty() { - return DVec2::default(); - } - - self.iter() - .map(|&layer| graph_modification_utils::get_viewport_origin(layer, network_interface)) - .reduce(|a, b| a + b) - .unwrap_or_default() - / self.len() as f64 - } -} - pub struct Selected<'a> { pub selected: &'a [LayerNodeIdentifier], pub responses: &'a mut VecDeque, @@ -545,10 +526,6 @@ impl<'a> Selected<'a> { } } - pub fn mean_average_of_pivots(&mut self) -> DVec2 { - self.selected.mean_average_origin(&self.network_interface) - } - pub fn center_of_aabb(&mut self) -> DVec2 { let [min, max] = self .selected diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 3257ab804a..c728302539 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -258,6 +258,12 @@ pub fn get_viewport_origin(layer: LayerNodeIdentifier, network_interface: &NodeN network_interface.document_metadata().document_to_viewport.transform_point2(origin) } +pub fn get_viewport_center(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 { + let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer); + let center = DVec2::splat(0.5); + network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * center) +} + /// Get the current gradient of a layer from the closest "Fill" node. pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { let fill_index = 1; diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index 32ec2561b6..50d9eea5c9 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -326,7 +326,7 @@ pub fn transforming_transform_cage( input: &InputPreprocessorMessageHandler, responses: &mut VecDeque, layers_dragging: &mut Vec, - pos: Option + pos: Option, ) -> (bool, bool, bool) { let dragging_bounds = bounding_box_manager.as_mut().and_then(|bounding_box| { let edges = bounding_box.check_selected_edges(input.mouse.position); @@ -363,17 +363,12 @@ pub fn transforming_transform_cage( } }); - let mut selected = Selected::new( - &mut bounds.original_transforms, - &mut bounds.center_of_transformation, - &layers_dragging, - responses, - &document.network_interface, - None, - &ToolType::Select, - None, - ); - bounds.center_of_transformation = pos.unwrap_or(selected.mean_average_of_pivots()); + bounds.center_of_transformation = pos.unwrap_or_else(|| { + document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers_mean_average_origin(&document.network_interface) + }); // Check if we're hovering over a skew triangle let edges = bounds.check_selected_edges(input.mouse.position); @@ -403,18 +398,12 @@ pub fn transforming_transform_cage( } }); - let mut selected = Selected::new( - &mut bounds.original_transforms, - &mut bounds.center_of_transformation, - &selected, - responses, - &document.network_interface, - None, - &ToolType::Select, - None, - ); - - bounds.center_of_transformation = pos.unwrap_or(selected.mean_average_of_pivots()); + bounds.center_of_transformation = pos.unwrap_or_else(|| { + document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers_mean_average_origin(&document.network_interface) + }); } *layers_dragging = selected; diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 435da04d95..5eb883f3a5 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -9,10 +9,10 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{Doc use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType}; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; -use crate::messages::portfolio::document::utility_types::transformation::MeanAverage; use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRose}; +use crate::messages::tool::common_functionality::graph_modification_utils; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; use crate::messages::tool::common_functionality::measure; use crate::messages::tool::common_functionality::pivot::Pivot; @@ -54,22 +54,41 @@ pub enum NestedSelectionBehavior { Deepest, } +#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct Dot(Pivot, DotType); + +impl Dot { + pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 { + let network = &document.network_interface; + match self.1 { + DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), + DotType::Pivot => self.0.position(), + _ => None, + } + .unwrap_or_else(|| self.0.transform_from_normalized.transform_point2(DVec2::splat(0.5))) + } + pub fn recalculate_transform(&mut self, document: &DocumentMessageHandler) -> DAffine2 { + self.0.recalculate_pivot(document); + self.0.transform_from_normalized + } +} + #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum DotType { - Origin, + // Pivot + Off, #[default] Pivot, - Off, + // Origin + // Indidual, + Average, + // Active, } impl DotType { pub fn is_pivot(self) -> bool { self == Self::Pivot } - - pub fn is_origin(self) -> bool { - self == Self::Origin - } } impl fmt::Display for DotType { @@ -77,7 +96,8 @@ impl fmt::Display for DotType { match self { DotType::Off => write!(f, "Bounding Box Center"), DotType::Pivot => write!(f, "Pivot"), - DotType::Origin => write!(f, "Origin"), + // DotType::Indidual => write!(f, "Median Points"), + DotType::Average => write!(f, "Origin"), } } } @@ -163,7 +183,7 @@ impl SelectTool { .widget_holder() } fn dot_type_widget(&self) -> WidgetHolder { - let dot_type_entries = [DotType::Off, DotType::Pivot, DotType::Origin] + let dot_type_entries = [DotType::Off, DotType::Pivot, DotType::Average] .iter() .map(|dot_type| { MenuListEntry::new(format!("{dot_type:?}")) @@ -176,7 +196,7 @@ impl SelectTool { .selected_index(Some(match self.tool_data.dot_type { DotType::Off => 0, DotType::Pivot => 1, - DotType::Origin => 2, + DotType::Average => 2, })) .tooltip("Choose between bounding box center, pivot point, or origin point for transformations") .widget_holder() @@ -398,7 +418,6 @@ struct SelectToolData { cursor: MouseCursorIcon, pivot: Pivot, dot_type: DotType, - origin: DVec2, // hack because process_message doesn't have document compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -572,16 +591,8 @@ impl SelectToolData { } } - fn get_dot_position(&self) -> DVec2 { - let dot_position = match self.dot_type { - DotType::Origin => Some(self.origin), - DotType::Pivot => self.pivot.position(), - _ => None, - }; - dot_position.unwrap_or_else(|| self.pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))) - } - fn get_as_dot(&self) -> (Pivot, DotType) { - (self.pivot.clone(), self.dot_type) + fn get_as_dot(&self) -> Dot { + Dot(self.pivot.clone(), self.dot_type) } } @@ -797,11 +808,11 @@ impl Fsm for SelectToolFsmState { }); tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), tool_data.dot_type.is_pivot()); - if tool_data.dot_type.is_origin() && document.network_interface.selected_nodes().has_selected_nodes() { - let network_interface = &document.network_interface; - tool_data.origin = - (network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect::>()).mean_average_origin(network_interface); - overlay_context.dowel_pin(tool_data.origin); + if overlay_context.visibility_settings.origin() { + for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { + let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); + overlay_context.dowel_pin(origin); + } } // Update compass rose @@ -960,7 +971,7 @@ impl Fsm for SelectToolFsmState { let intersection_list = document.click_list(input).collect::>(); let intersection = document.find_deepest(&intersection_list); - let pos = tool_data.get_dot_position(); + let pos = tool_data.get_as_dot().position(document); let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, Some(pos)); // If the user is dragging the bounding box bounds, go into ResizingBounds mode. diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs index 76f0c9b5e0..3e56729050 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -2,8 +2,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::transformation::TransformType; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::pivot::Pivot; -use crate::messages::tool::tool_messages::select_tool::DotType; +use crate::messages::tool::tool_messages::select_tool::Dot; use glam::DVec2; #[impl_message(Message, ToolMessage, TransformLayer)] @@ -17,7 +16,7 @@ pub enum TransformLayerMessage { BeginGrab, BeginRotate, BeginScale, - SetDot { dot: (Pivot, DotType) }, + SetDot { dot: Dot }, BeginGRS { transform_type: TransformType }, BeginGrabPen { last_point: DVec2, handle: DVec2 }, BeginRotatePen { last_point: DVec2, handle: DVec2 }, diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 1dd04d4445..4fbfa45317 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -3,12 +3,10 @@ use crate::messages::input_mapper::utility_types::input_mouse::{DocumentPosition use crate::messages::portfolio::document::overlays::utility_types::{OverlayProvider, Pivot}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::PTZ; -use crate::messages::portfolio::document::utility_types::transformation::MeanAverage; use crate::messages::portfolio::document::utility_types::transformation::{Axis, OriginalTransforms, Selected, TransformOperation, TransformType, Typing}; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::pivot::Pivot as SelectToolPivot; use crate::messages::tool::common_functionality::shape_editor::ShapeState; -use crate::messages::tool::tool_messages::select_tool::DotType; +use crate::messages::tool::tool_messages::select_tool::Dot; use crate::messages::tool::tool_messages::tool_prelude::Key; use crate::messages::tool::utility_types::{ToolData, ToolType}; use glam::{DAffine2, DVec2}; @@ -37,7 +35,7 @@ pub struct TransformLayerMessageHandler { start_mouse: ViewportPosition, original_transforms: OriginalTransforms, - dot: (SelectToolPivot, DotType), + dot: Dot, pivot: ViewportPosition, local_pivot: DocumentPosition, @@ -181,21 +179,13 @@ impl MessageHandler> for TransformLayer } if !using_path_tool { - self.dot.0.recalculate_pivot(document); - let dot_position = |&(ref pivot, ref dot_type): &(SelectToolPivot, DotType)| { - match dot_type { - DotType::Origin => { - let network_interface = &document.network_interface; - Some((network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect::>()).mean_average_origin(network_interface)) - } - DotType::Pivot => pivot.position(), - _ => None, - } - .unwrap_or_else(|| pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))) - }; - *selected.pivot = dot_position(&self.dot); + self.dot.recalculate_transform(document); + let network_interface = &document.network_interface; + let mean_center_bbox = network_interface.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network_interface); + let dot_position = self.dot.position(document); + *selected.pivot = dot_position; self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); - self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(selected.mean_average_of_pivots()); + self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(mean_center_bbox); } else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { *selected.original_transforms = OriginalTransforms::default(); From d428016c43b7915c73d3f689d29cde9361565800 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 28 Jun 2025 15:15:28 +0530 Subject: [PATCH 19/54] add checkboxes --- .../tool/tool_messages/select_tool.rs | 98 ++++++++++++------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 5eb883f3a5..c051e8f466 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -45,6 +45,7 @@ pub struct SelectOptions { pub enum SelectOptionsUpdate { NestedSelectionBehavior(NestedSelectionBehavior), DotType(DotType), + ToggleDotType(bool), } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] @@ -55,17 +56,21 @@ pub enum NestedSelectionBehavior { } #[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] -pub struct Dot(Pivot, DotType); +pub struct Dot(Pivot, DotState); impl Dot { pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 { let network = &document.network_interface; - match self.1 { - DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), - DotType::Pivot => self.0.position(), - _ => None, - } - .unwrap_or_else(|| self.0.transform_from_normalized.transform_point2(DVec2::splat(0.5))) + self.1 + .enabled + .then_some({ + match self.1.dot { + DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), + DotType::Pivot => self.0.position(), + } + }) + .flatten() + .unwrap_or_else(|| self.0.transform_from_normalized.transform_point2(DVec2::splat(0.5))) } pub fn recalculate_transform(&mut self, document: &DocumentMessageHandler) -> DAffine2 { self.0.recalculate_pivot(document); @@ -76,15 +81,29 @@ impl Dot { #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum DotType { // Pivot - Off, #[default] Pivot, // Origin + // Indidual, Average, // Active, } +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct DotState { + enabled: bool, + dot: DotType, +} +impl Default for DotState { + fn default() -> Self { + Self { + enabled: true, + dot: DotType::default(), + } + } +} + impl DotType { pub fn is_pivot(self) -> bool { self == Self::Pivot @@ -94,9 +113,7 @@ impl DotType { impl fmt::Display for DotType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - DotType::Off => write!(f, "Bounding Box Center"), DotType::Pivot => write!(f, "Pivot"), - // DotType::Indidual => write!(f, "Median Points"), DotType::Average => write!(f, "Origin"), } } @@ -182,8 +199,8 @@ impl SelectTool { .disabled(disabled) .widget_holder() } - fn dot_type_widget(&self) -> WidgetHolder { - let dot_type_entries = [DotType::Off, DotType::Pivot, DotType::Average] + fn dot_type_widget(&self) -> Vec { + let dot_type_entries = [DotType::Pivot, DotType::Average] .iter() .map(|dot_type| { MenuListEntry::new(format!("{dot_type:?}")) @@ -192,14 +209,22 @@ impl SelectTool { }) .collect(); - DropdownInput::new(vec![dot_type_entries]) - .selected_index(Some(match self.tool_data.dot_type { - DotType::Off => 0, - DotType::Pivot => 1, - DotType::Average => 2, - })) - .tooltip("Choose between bounding box center, pivot point, or origin point for transformations") - .widget_holder() + vec![ + CheckboxInput::new(self.tool_data.dot_state.enabled) + .icon("Overlays") + .tooltip("Overlays") + .on_update(|optional_input: &CheckboxInput| SelectToolMessage::SelectOptions(SelectOptionsUpdate::ToggleDotType(optional_input.checked)).into()) + .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + DropdownInput::new(vec![dot_type_entries]) + .selected_index(Some(match self.tool_data.dot_state.dot { + DotType::Pivot => 0, + DotType::Average => 1, + })) + .tooltip("Choose between bounding box center, pivot point, or origin point for transformations") + .disabled(!self.tool_data.dot_state.enabled) + .widget_holder(), + ] } fn alignment_widgets(&self, disabled: bool) -> impl Iterator + use<> { @@ -274,11 +299,11 @@ impl LayoutHolder for SelectTool { // Dot Type (Pivot/Origin/Off) widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - widgets.push(self.dot_type_widget()); + widgets.extend(self.dot_type_widget()); // Pivot widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0 || self.tool_data.dot_type != DotType::Pivot)); + widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0 || !self.tool_data.dot_state.dot.is_pivot())); // Align let disabled = self.tool_data.selected_layers_count < 2; @@ -325,10 +350,17 @@ impl<'a> MessageHandler> for SelectT responses.add(ToolMessage::UpdateHints); } SelectOptionsUpdate::DotType(dot_type) => { - self.tool_data.dot_type = *dot_type; + if self.tool_data.dot_state.enabled { + self.tool_data.dot_state.dot = *dot_type; + responses.add(ToolMessage::UpdateHints); + let dot = self.tool_data.get_as_dot(); + responses.add(TransformLayerMessage::SetDot { dot }); + redraw_ref_pivot = true; + } + } + SelectOptionsUpdate::ToggleDotType(state) => { + self.tool_data.dot_state.enabled = *state; responses.add(ToolMessage::UpdateHints); - let dot = self.tool_data.get_as_dot(); - responses.add(TransformLayerMessage::SetDot { dot }); redraw_ref_pivot = true; } } @@ -417,7 +449,7 @@ struct SelectToolData { snap_manager: SnapManager, cursor: MouseCursorIcon, pivot: Pivot, - dot_type: DotType, + dot_state: DotState, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -585,14 +617,14 @@ impl SelectToolData { } fn state_from_dot(&self, mouse: DVec2) -> Option { - match self.dot_type { + match self.dot_state.dot { DotType::Pivot => self.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), _ => None, } } fn get_as_dot(&self) -> Dot { - Dot(self.pivot.clone(), self.dot_type) + Dot(self.pivot.clone(), self.dot_state) } } @@ -807,7 +839,6 @@ impl Fsm for SelectToolFsmState { .flatten() }); - tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), tool_data.dot_type.is_pivot()); if overlay_context.visibility_settings.origin() { for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); @@ -815,6 +846,9 @@ impl Fsm for SelectToolFsmState { } } + let draw_pivot = tool_data.dot_state.dot.is_pivot() && overlay_context.visibility_settings.pivot(); + tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot); + // Update compass rose if overlay_context.visibility_settings.compass_rose() { tool_data.compass_rose.refresh_position(document); @@ -1018,12 +1052,6 @@ impl Fsm for SelectToolFsmState { } tool_data.layers_dragging = selected; - if tool_data.dot_type.is_pivot() && !tool_data.layers_dragging.is_empty() { - responses.add(SelectToolMessage::SetPivot { - position: tool_data.pivot.old_pivot_position, - }); - } - tool_data.get_snap_candidates(document, input); let (axis, using_compass) = { let axis_state = compass_rose_state.axis_type().filter(|_| can_grab_compass_rose); From 5156d4f20483fe3387a31b37da000b98578d5f5c Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 28 Jun 2025 15:21:06 +0530 Subject: [PATCH 20/54] fix labels --- editor/src/messages/tool/tool_messages/select_tool.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index c051e8f466..aec7447174 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -113,8 +113,8 @@ impl DotType { impl fmt::Display for DotType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - DotType::Pivot => write!(f, "Pivot"), - DotType::Average => write!(f, "Origin"), + DotType::Pivot => write!(f, "Working Pivot"), + DotType::Average => write!(f, "Average of Origins"), } } } @@ -212,7 +212,7 @@ impl SelectTool { vec![ CheckboxInput::new(self.tool_data.dot_state.enabled) .icon("Overlays") - .tooltip("Overlays") + .tooltip("Disable Transform Pivot Point") .on_update(|optional_input: &CheckboxInput| SelectToolMessage::SelectOptions(SelectOptionsUpdate::ToggleDotType(optional_input.checked)).into()) .widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder(), @@ -221,7 +221,7 @@ impl SelectTool { DotType::Pivot => 0, DotType::Average => 1, })) - .tooltip("Choose between bounding box center, pivot point, or origin point for transformations") + .tooltip("Choose between type of Transform Pivot Point") .disabled(!self.tool_data.dot_state.enabled) .widget_holder(), ] From 12060bac7f1a64b32fb66c5c44a47e67b52b943e Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 28 Jun 2025 15:30:53 +0530 Subject: [PATCH 21/54] fix stuff which broke at merge --- node-graph/gcore/src/transform.rs | 2 +- node-graph/gcore/src/transform_nodes.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/node-graph/gcore/src/transform.rs b/node-graph/gcore/src/transform.rs index 33cd1faea6..dafd3791b7 100644 --- a/node-graph/gcore/src/transform.rs +++ b/node-graph/gcore/src/transform.rs @@ -149,4 +149,4 @@ impl ApplyTransform for T { } impl ApplyTransform for () { fn apply_transform(&mut self, &_modification: &DAffine2) {} -} \ No newline at end of file +} diff --git a/node-graph/gcore/src/transform_nodes.rs b/node-graph/gcore/src/transform_nodes.rs index 39024681e6..7b790958f3 100644 --- a/node-graph/gcore/src/transform_nodes.rs +++ b/node-graph/gcore/src/transform_nodes.rs @@ -20,7 +20,6 @@ async fn transform( rotate: f64, scale: DVec2, shear: DVec2, - _pivot: DVec2, ) -> Instances { let matrix = DAffine2::from_scale_angle_translation(scale, rotate, translate) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]); From 8d494d89811eb94d3f69ee535d9ab59809a463d8 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 28 Jun 2025 16:15:02 +0530 Subject: [PATCH 22/54] update --- .../messages/portfolio/document/overlays/utility_types.rs | 7 +++---- editor/src/messages/tool/tool_messages/select_tool.rs | 7 ++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index bb6a05b162..3f351d9648 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,7 +1,6 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ - COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, - COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER }; use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; @@ -567,7 +566,7 @@ impl OverlayContext { self.render_context.arc(x, y, DOWEL_PIN_RADIUS, 0., TAU).expect("Failed to draw the circle"); self.render_context.set_fill_style_str(COLOR_OVERLAY_WHITE); self.render_context.fill(); - self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE); + self.render_context.set_stroke_style_str(COLOR_OVERLAY_YELLOW); self.render_context.stroke(); // Draw the two blue filled sectors @@ -580,7 +579,7 @@ impl OverlayContext { self.render_context.move_to(x, y); self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2, TAU).expect("Failed to draw arc"); self.render_context.close_path(); - self.render_context.set_fill_style_str(COLOR_OVERLAY_BLUE); + self.render_context.set_fill_style_str(COLOR_OVERLAY_YELLOW); self.render_context.fill(); self.end_dpi_aware_transform(); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 05f1d9a302..060fd24e41 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -95,6 +95,7 @@ pub struct DotState { enabled: bool, dot: DotType, } + impl Default for DotState { fn default() -> Self { Self { @@ -113,7 +114,7 @@ impl DotType { impl fmt::Display for DotType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - DotType::Pivot => write!(f, "Working Pivot"), + DotType::Pivot => write!(f, "Draft Pivot"), DotType::Average => write!(f, "Average of Origins"), } } @@ -215,7 +216,7 @@ impl SelectTool { .tooltip("Disable Transform Pivot Point") .on_update(|optional_input: &CheckboxInput| SelectToolMessage::SelectOptions(SelectOptionsUpdate::ToggleDotType(optional_input.checked)).into()) .widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), DropdownInput::new(vec![dot_type_entries]) .selected_index(Some(match self.tool_data.dot_state.dot { DotType::Pivot => 0, @@ -839,7 +840,7 @@ impl Fsm for SelectToolFsmState { .flatten() }); - if overlay_context.visibility_settings.origin() { + if overlay_context.visibility_settings.origin() && !tool_data.dot_state.dot.is_pivot() { for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); overlay_context.dowel_pin(origin); From b1ccbc942b86bb4ad157d9ac58fafff1f482b4b5 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 28 Jun 2025 16:19:29 +0530 Subject: [PATCH 23/54] cargo fmt --- .../src/messages/portfolio/document/overlays/utility_types.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 3f351d9648..a7f78309ae 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,6 +1,7 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ - COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, + COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, }; use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; From a59552d0eb83a5a574554304f198f85375820c75 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 29 Jun 2025 05:34:33 +0530 Subject: [PATCH 24/54] fix serde crash --- .../src/messages/portfolio/document/document_message_handler.rs | 2 +- .../src/messages/portfolio/document/overlays/utility_types.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 8726c7a5b6..452d1f34ea 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -2282,7 +2282,7 @@ impl DocumentMessageHandler { }) .for_label(checkbox_id.clone()) .widget_holder(), - TextLabel::new("Transform Pivot".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), + TextLabel::new("Transform Origin".to_string()).for_checkbox(&mut checkbox_id).widget_holder(), ] }, }, diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index a7f78309ae..0449218074 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -50,6 +50,7 @@ pub struct OverlaysVisibilitySettings { pub hover_outline: bool, pub selection_outline: bool, pub pivot: bool, + #[serde(default)] pub origin: bool, pub path: bool, pub anchors: bool, From ea575a88f6779681095938b8ee025d34490aadf0 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 29 Jun 2025 07:36:18 +0530 Subject: [PATCH 25/54] fix pivot not updating on move --- editor/src/messages/tool/tool_messages/select_tool.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 060fd24e41..a78a7ba1af 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1234,6 +1234,7 @@ impl Fsm for SelectToolFsmState { let mouse_position = input.mouse.position; let snapped_mouse_position = mouse_position; tool_data.pivot.set_viewport_position(snapped_mouse_position); + responses.add(NodeGraphMessage::RunDocumentGraph); // Auto-panning let messages = [ @@ -1434,6 +1435,8 @@ impl Fsm for SelectToolFsmState { ) => { let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON; let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction }; + let dot = tool_data.get_as_dot(); + responses.add(TransformLayerMessage::SetDot { dot }); responses.add(response); tool_data.axis_align = false; tool_data.snap_manager.cleanup(responses); From 3578ac512874be8abf4e60170d782d11f600fc50 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 29 Jun 2025 08:31:27 +0530 Subject: [PATCH 26/54] fix pivot not becoming last active refernce --- editor/src/messages/tool/common_functionality/pivot.rs | 3 +++ editor/src/messages/tool/tool_messages/select_tool.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 2d3a44ade5..aad0d3cd25 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -16,6 +16,8 @@ pub struct Pivot { pivot: Option, /// The old pivot position in the GUI, used to reduce refreshes of the document bar pub old_pivot_position: ReferencePoint, + /// The last ReferencePoint which wasn't none + pub last_non_none_reference: ReferencePoint, /// Used to enable and disable the pivot active: bool, } @@ -27,6 +29,7 @@ impl Default for Pivot { transform_from_normalized: Default::default(), pivot: Default::default(), old_pivot_position: ReferencePoint::Center, + last_non_none_reference: ReferencePoint::Center, active: true, } } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index a78a7ba1af..2bbe78a0e5 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1076,6 +1076,8 @@ impl Fsm for SelectToolFsmState { let extend = input.keyboard.key(extend_selection); if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); + let position = tool_data.pivot.last_non_none_reference; + responses.add(SelectToolMessage::SetPivot { position }); tool_data.layers_dragging.clear(); } @@ -1571,6 +1573,7 @@ impl Fsm for SelectToolFsmState { (_, SelectToolMessage::SetPivot { position }) => { responses.add(DocumentMessage::StartTransaction); + tool_data.pivot.last_non_none_reference = position; let pos: Option = position.into(); tool_data.pivot.set_normalized_position(pos.unwrap()); let dot = tool_data.get_as_dot(); From 63d01fc619692684a9932cfeafc73c33ebb56227 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 29 Jun 2025 10:46:44 +0530 Subject: [PATCH 27/54] fix redraw issues --- .../messages/tool/tool_messages/select_tool.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 2bbe78a0e5..1cf53cc4d8 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -90,6 +90,12 @@ pub enum DotType { // Active, } +impl DotType { + pub fn is_pivot(self) -> bool { + self == Self::Pivot + } +} + #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub struct DotState { enabled: bool, @@ -105,9 +111,9 @@ impl Default for DotState { } } -impl DotType { - pub fn is_pivot(self) -> bool { - self == Self::Pivot +impl DotState { + pub fn is_pivot(&self) -> bool { + self.dot == DotType::Pivot || !self.enabled } } @@ -356,12 +362,14 @@ impl<'a> MessageHandler> for SelectT responses.add(ToolMessage::UpdateHints); let dot = self.tool_data.get_as_dot(); responses.add(TransformLayerMessage::SetDot { dot }); + responses.add(NodeGraphMessage::RunDocumentGraph); redraw_ref_pivot = true; } } SelectOptionsUpdate::ToggleDotType(state) => { self.tool_data.dot_state.enabled = *state; responses.add(ToolMessage::UpdateHints); + responses.add(NodeGraphMessage::RunDocumentGraph); redraw_ref_pivot = true; } } @@ -840,7 +848,7 @@ impl Fsm for SelectToolFsmState { .flatten() }); - if overlay_context.visibility_settings.origin() && !tool_data.dot_state.dot.is_pivot() { + if overlay_context.visibility_settings.origin() && !tool_data.dot_state.is_pivot() { for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); overlay_context.dowel_pin(origin); From 14e921aa499ced0387e618e19b8e180cdbd3c0d3 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 30 Jun 2025 12:17:35 +0530 Subject: [PATCH 28/54] add: active pivot --- editor/src/consts.rs | 1 + .../document/overlays/utility_types.rs | 7 +-- .../tool/tool_messages/select_tool.rs | 46 ++++++++++++++----- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/editor/src/consts.rs b/editor/src/consts.rs index 24e3075cda..7a68c22ee1 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -137,6 +137,7 @@ pub const COLOR_OVERLAY_BLUE: &str = "#00a8ff"; pub const COLOR_OVERLAY_YELLOW: &str = "#ffc848"; pub const COLOR_OVERLAY_GREEN: &str = "#63ce63"; pub const COLOR_OVERLAY_RED: &str = "#ef5454"; +pub const COLOR_OVERLAY_ORANGE: &str = "#e27a44"; pub const COLOR_OVERLAY_GRAY: &str = "#cccccc"; pub const COLOR_OVERLAY_WHITE: &str = "#ffffff"; pub const COLOR_OVERLAY_LABEL_BACKGROUND: &str = "#000000cc"; diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 0449218074..479900a777 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -558,8 +558,9 @@ impl OverlayContext { self.end_dpi_aware_transform(); } - pub fn dowel_pin(&mut self, position: DVec2) { + pub fn dowel_pin(&mut self, position: DVec2, color: Option<&str>) { let (x, y) = (position.round() - DVec2::splat(0.5)).into(); + let color = color.unwrap_or(COLOR_OVERLAY_YELLOW); self.start_dpi_aware_transform(); @@ -568,7 +569,7 @@ impl OverlayContext { self.render_context.arc(x, y, DOWEL_PIN_RADIUS, 0., TAU).expect("Failed to draw the circle"); self.render_context.set_fill_style_str(COLOR_OVERLAY_WHITE); self.render_context.fill(); - self.render_context.set_stroke_style_str(COLOR_OVERLAY_YELLOW); + self.render_context.set_stroke_style_str(color); self.render_context.stroke(); // Draw the two blue filled sectors @@ -581,7 +582,7 @@ impl OverlayContext { self.render_context.move_to(x, y); self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2, TAU).expect("Failed to draw arc"); self.render_context.close_path(); - self.render_context.set_fill_style_str(COLOR_OVERLAY_YELLOW); + self.render_context.set_fill_style_str(color); self.render_context.fill(); self.end_dpi_aware_transform(); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 1cf53cc4d8..10c9b2181c 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -56,7 +56,7 @@ pub enum NestedSelectionBehavior { } #[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] -pub struct Dot(Pivot, DotState); +pub struct Dot(Pivot, DotState, Option); impl Dot { pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 { @@ -67,6 +67,7 @@ impl Dot { match self.1.dot { DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), DotType::Pivot => self.0.position(), + DotType::Active => self.2.map(|layer| graph_modification_utils::get_viewport_origin(layer, network)), } }) .flatten() @@ -84,10 +85,9 @@ pub enum DotType { #[default] Pivot, // Origin - // Indidual, Average, - // Active, + Active, } impl DotType { @@ -122,6 +122,7 @@ impl fmt::Display for DotType { match self { DotType::Pivot => write!(f, "Draft Pivot"), DotType::Average => write!(f, "Average of Origins"), + DotType::Active => write!(f, "Active Object Origin"), } } } @@ -207,7 +208,7 @@ impl SelectTool { .widget_holder() } fn dot_type_widget(&self) -> Vec { - let dot_type_entries = [DotType::Pivot, DotType::Average] + let dot_type_entries = [DotType::Pivot, DotType::Average, DotType::Active] .iter() .map(|dot_type| { MenuListEntry::new(format!("{dot_type:?}")) @@ -227,6 +228,7 @@ impl SelectTool { .selected_index(Some(match self.tool_data.dot_state.dot { DotType::Pivot => 0, DotType::Average => 1, + DotType::Active => 2, })) .tooltip("Choose between type of Transform Pivot Point") .disabled(!self.tool_data.dot_state.enabled) @@ -449,7 +451,9 @@ struct SelectToolData { drag_current: ViewportPosition, lasso_polygon: Vec, selection_mode: Option, - layers_dragging: Vec, + layers_dragging: Vec, // Unordered, often used as temporary buffer + orderer_layers: Vec, // Ordered list of layers + active_layer: Option, layer_selected_on_start: Option, select_single_layer: Option, axis_align: bool, @@ -633,7 +637,15 @@ impl SelectToolData { } fn get_as_dot(&self) -> Dot { - Dot(self.pivot.clone(), self.dot_state) + Dot(self.pivot.clone(), self.dot_state, self.active_layer.clone()) + } + + fn sync_history(&mut self) { + debug!("{:?}", self.layers_dragging); + self.orderer_layers.retain(|layer| self.layers_dragging.contains(layer)); + self.orderer_layers.extend(self.layers_dragging.iter().find(|&layer| !self.orderer_layers.contains(layer))); + debug!("{:?}", self.orderer_layers); + self.active_layer = self.orderer_layers.last().map(|x| *x) } } @@ -848,12 +860,20 @@ impl Fsm for SelectToolFsmState { .flatten() }); + let mut active_origin = None; if overlay_context.visibility_settings.origin() && !tool_data.dot_state.is_pivot() { for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); - overlay_context.dowel_pin(origin); + if Some(layer) == tool_data.active_layer { + active_origin = Some(origin); + continue; + } + overlay_context.dowel_pin(origin, None); } } + if let Some(origin) = active_origin { + overlay_context.dowel_pin(origin, Some(COLOR_OVERLAY_ORANGE)); + } let draw_pivot = tool_data.dot_state.dot.is_pivot() && overlay_context.visibility_settings.pivot(); tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot); @@ -1436,11 +1456,7 @@ impl Fsm for SelectToolFsmState { SelectToolFsmState::Ready { selection } } ( - SelectToolFsmState::ResizingBounds - | SelectToolFsmState::SkewingBounds { .. } - | SelectToolFsmState::RotatingBounds - | SelectToolFsmState::Dragging { .. } - | SelectToolFsmState::DraggingPivot, + SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. } | SelectToolFsmState::RotatingBounds | SelectToolFsmState::DraggingPivot, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter, ) => { let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON; @@ -1498,6 +1514,7 @@ impl Fsm for SelectToolFsmState { NestedSelectionBehavior::Deepest => { let filtered_selections = filter_nested_selection(document.metadata(), &new_selected); tool_data.layers_dragging.extend(filtered_selections); + tool_data.sync_history(); } NestedSelectionBehavior::Shallowest => { // Find each new_selected's parent node @@ -1506,6 +1523,7 @@ impl Fsm for SelectToolFsmState { .map(|layer| layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(layer)) .collect(); tool_data.layers_dragging.extend(parent_selected.iter().copied()); + tool_data.sync_history(); } } } @@ -1760,6 +1778,7 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec } } + tool_data.sync_history(); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: tool_data .layers_dragging @@ -1811,10 +1830,13 @@ fn drag_deepest_manipulation(responses: &mut VecDeque, selected: Vec Date: Mon, 30 Jun 2025 12:25:35 +0530 Subject: [PATCH 29/54] cargo fmt --- .../src/messages/portfolio/document/overlays/utility_types.rs | 4 ++-- .../messages/tool/common_functionality/utility_functions.rs | 1 - .../tool/transform_layer/transform_layer_message_handler.rs | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index dc8d8a3d15..916589744f 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,7 +1,7 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ - COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, - COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, + COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, }; use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index 5a4d1bb043..ffac8f2283 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -437,7 +437,6 @@ pub fn transforming_transform_cage( .selected_visible_and_unlocked_layers_mean_average_origin(&document.network_interface) }); - // Check if we're hovering over a skew triangle let edges = bounds.check_selected_edges(input.mouse.position); if let Some(edges) = edges { diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 5ea7f82c72..6e4fed4dae 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -187,8 +187,8 @@ impl MessageHandler> for TransformLayer self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(mean_center_bbox); } - // Here vector data from all layers is not considered which can be a problem in pivot calculation - else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { + // Here vector data from all layers is not considered which can be a problem in pivot calculation + else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { *selected.original_transforms = OriginalTransforms::default(); let viewspace = document.metadata().transform_to_viewport(selected_layers[0]); From b47c26333456b3661f33dcdd9ea1eb1e9d1c9720 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 30 Jun 2025 15:00:58 +0530 Subject: [PATCH 30/54] fix pivot showing up in default mode --- .../messages/tool/tool_messages/select_tool.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 41fdfe2d0a..23e1407ad9 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -90,12 +90,6 @@ pub enum DotType { Active, } -impl DotType { - pub fn is_pivot(self) -> bool { - self == Self::Pivot - } -} - #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub struct DotState { enabled: bool, @@ -112,9 +106,13 @@ impl Default for DotState { } impl DotState { - pub fn is_pivot(&self) -> bool { + pub fn is_pivot_type(&self) -> bool { self.dot == DotType::Pivot || !self.enabled } + + pub fn is_pivot(&self) -> bool { + self.dot == DotType::Pivot && self.enabled + } } impl fmt::Display for DotType { @@ -312,7 +310,7 @@ impl LayoutHolder for SelectTool { // Pivot widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0 || !self.tool_data.dot_state.dot.is_pivot())); + widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0 || !self.tool_data.dot_state.is_pivot())); // Align let disabled = self.tool_data.selected_layers_count < 2; @@ -861,7 +859,7 @@ impl Fsm for SelectToolFsmState { }); let mut active_origin = None; - if overlay_context.visibility_settings.origin() && !tool_data.dot_state.is_pivot() { + if overlay_context.visibility_settings.origin() && !tool_data.dot_state.is_pivot_type() { for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); if Some(layer) == tool_data.active_layer { @@ -875,7 +873,7 @@ impl Fsm for SelectToolFsmState { overlay_context.dowel_pin(origin, Some(COLOR_OVERLAY_ORANGE)); } - let draw_pivot = tool_data.dot_state.dot.is_pivot() && overlay_context.visibility_settings.pivot(); + let draw_pivot = tool_data.dot_state.is_pivot() && overlay_context.visibility_settings.pivot(); tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot); // Update compass rose From d07eb5e1c77afa8d8badf1197c5a9726976d437d Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 2 Jul 2025 07:01:29 +0530 Subject: [PATCH 31/54] add: pivot pin --- .../tool/tool_messages/select_tool.rs | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 23e1407ad9..9435305c39 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -46,6 +46,7 @@ pub enum SelectOptionsUpdate { NestedSelectionBehavior(NestedSelectionBehavior), DotType(DotType), ToggleDotType(bool), + TogglePivotPinned(), } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] @@ -205,6 +206,16 @@ impl SelectTool { .disabled(disabled) .widget_holder() } + + fn pin_pivot_widget(&self) -> Vec { + vec![ + IconButton::new(if self.tool_data.pivot_pin_disabled() { "Overlays" } else { "Remove" }, 24) + .tooltip(if self.tool_data.pivot_pin_disabled() { "Unpin Transform Pivot" } else { "Pin Transform Pivot" }) + .on_update(|_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into()) + .widget_holder(), + ] + } + fn dot_type_widget(&self) -> Vec { let dot_type_entries = [DotType::Pivot, DotType::Average, DotType::Active] .iter() @@ -312,6 +323,9 @@ impl LayoutHolder for SelectTool { widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0 || !self.tool_data.dot_state.is_pivot())); + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + widgets.extend(self.pin_pivot_widget()); + // Align let disabled = self.tool_data.selected_layers_count < 2; widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); @@ -372,6 +386,12 @@ impl<'a> MessageHandler> for SelectT responses.add(NodeGraphMessage::RunDocumentGraph); redraw_ref_pivot = true; } + SelectOptionsUpdate::TogglePivotPinned() => { + self.tool_data.pivot_pinned = !self.tool_data.pivot_pinned; + responses.add(ToolMessage::UpdateHints); + responses.add(NodeGraphMessage::RunDocumentGraph); + redraw_ref_pivot = true; + } } } @@ -460,6 +480,7 @@ struct SelectToolData { snap_manager: SnapManager, cursor: MouseCursorIcon, pivot: Pivot, + pivot_pinned: bool, dot_state: DotState, compass_rose: CompassRose, line_center: DVec2, @@ -629,7 +650,7 @@ impl SelectToolData { fn state_from_dot(&self, mouse: DVec2) -> Option { match self.dot_state.dot { - DotType::Pivot => self.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), + DotType::Pivot if !self.pivot_pinned => self.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), _ => None, } } @@ -639,12 +660,14 @@ impl SelectToolData { } fn sync_history(&mut self) { - debug!("{:?}", self.layers_dragging); self.orderer_layers.retain(|layer| self.layers_dragging.contains(layer)); self.orderer_layers.extend(self.layers_dragging.iter().find(|&layer| !self.orderer_layers.contains(layer))); - debug!("{:?}", self.orderer_layers); self.active_layer = self.orderer_layers.last().map(|x| *x) } + + fn pivot_pin_disabled(&self) -> bool { + !self.pivot_pinned || !self.dot_state.is_pivot() + } } impl Fsm for SelectToolFsmState { From 44e1bda4a97446819652cc31bf3d3458c440eea1 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 2 Jul 2025 07:06:33 +0530 Subject: [PATCH 32/54] fix: use pin icons --- editor/src/messages/tool/tool_messages/select_tool.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 9435305c39..fdfa9346b3 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -209,8 +209,8 @@ impl SelectTool { fn pin_pivot_widget(&self) -> Vec { vec![ - IconButton::new(if self.tool_data.pivot_pin_disabled() { "Overlays" } else { "Remove" }, 24) - .tooltip(if self.tool_data.pivot_pin_disabled() { "Unpin Transform Pivot" } else { "Pin Transform Pivot" }) + IconButton::new(if self.tool_data.pin_inactive() { "PinInactive" } else { "PinActive" }, 24) + .tooltip(if self.tool_data.pin_inactive() { "Unpin Transform Pivot" } else { "Pin Transform Pivot" }) .on_update(|_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into()) .widget_holder(), ] @@ -665,7 +665,7 @@ impl SelectToolData { self.active_layer = self.orderer_layers.last().map(|x| *x) } - fn pivot_pin_disabled(&self) -> bool { + fn pin_inactive(&self) -> bool { !self.pivot_pinned || !self.dot_state.is_pivot() } } From dcc428d910346f9500ba2e88f048277f9cc005ec Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 2 Jul 2025 07:10:10 +0530 Subject: [PATCH 33/54] cargo: cargo lock update? --- Cargo.lock | 131 +++++++++++++++++++++++++++++------------------------ 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7ae0cdb13..19540af95b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -486,11 +486,11 @@ dependencies = [ [[package]] name = "block2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037" +checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" dependencies = [ - "objc2 0.6.0", + "objc2 0.6.1", ] [[package]] @@ -528,9 +528,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] @@ -1255,6 +1255,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -2109,7 +2119,7 @@ checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" dependencies = [ "bitflags 2.9.0", "gpu-descriptor-types", - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] @@ -2470,9 +2480,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "foldhash", ] @@ -2949,7 +2959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.4", "serde", ] @@ -3204,9 +3214,9 @@ dependencies = [ [[package]] name = "kurbo" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" +checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c" dependencies = [ "arrayvec", "serde", @@ -3282,7 +3292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -3506,10 +3516,10 @@ dependencies = [ "dpi", "gtk", "keyboard-types", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "once_cell", "png", "serde", @@ -3790,9 +3800,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" dependencies = [ "objc2-encode 4.1.0", "objc2-exception-helper", @@ -3805,15 +3815,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" dependencies = [ "bitflags 2.9.0", - "block2 0.6.0", + "block2 0.6.1", "libc", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-cloud-kit", "objc2-core-data", "objc2-core-foundation", "objc2-core-graphics", "objc2-core-image", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "objc2-quartz-core 0.3.0", ] @@ -3824,8 +3834,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] @@ -3835,18 +3845,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] name = "objc2-core-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "dispatch2", + "objc2 0.6.1", ] [[package]] @@ -3856,7 +3867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", "objc2-io-surface", ] @@ -3867,8 +3878,8 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56" dependencies = [ - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] @@ -3906,14 +3917,14 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ "bitflags 2.9.0", - "block2 0.6.0", + "block2 0.6.1", "libc", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", ] @@ -3924,7 +3935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", ] @@ -3960,8 +3971,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] @@ -3971,9 +3982,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", ] [[package]] @@ -3983,11 +3994,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce" dependencies = [ "bitflags 2.9.0", - "block2 0.6.0", - "objc2 0.6.0", + "block2 0.6.1", + "objc2 0.6.1", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", ] [[package]] @@ -5415,9 +5426,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -5446,9 +5457,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -5675,9 +5686,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] @@ -6005,9 +6016,9 @@ dependencies = [ "ndk 0.9.0", "ndk-context", "ndk-sys 0.6.0+11769913", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-app-kit", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "once_cell", "parking_lot", "raw-window-handle", @@ -6060,9 +6071,9 @@ dependencies = [ "log", "mime", "muda", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-app-kit", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "percent-encoding", "plist", "raw-window-handle", @@ -6266,9 +6277,9 @@ dependencies = [ "http", "jni", "log", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-app-kit", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "once_cell", "percent-encoding", "raw-window-handle", @@ -6688,11 +6699,11 @@ dependencies = [ "dirs", "libappindicator", "muda", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-app-kit", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "once_cell", "png", "serde", @@ -7556,10 +7567,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "objc2 0.6.0", + "objc2 0.6.1", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "raw-window-handle", "windows-sys 0.59.0", "windows-version", @@ -8077,7 +8088,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b19b78efae8b853c6c817e8752fc1dbf9cab8a8ffe9c30f399bd750ccf0f0730" dependencies = [ "base64 0.22.1", - "block2 0.6.0", + "block2 0.6.1", "cookie", "crossbeam-channel", "dpi", @@ -8091,10 +8102,10 @@ dependencies = [ "kuchikiki", "libc", "ndk 0.9.0", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "objc2-ui-kit", "objc2-web-kit", "once_cell", From 20cfccbe255c4354468ce0dffc1b6cd7cdf561bd Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 2 Jul 2025 07:20:54 +0530 Subject: [PATCH 34/54] fix: use checkbox instead of Overlays --- Cargo.lock | 1741 +++++++++-------- .../tool/tool_messages/select_tool.rs | 1 - 2 files changed, 973 insertions(+), 769 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec2289225f..5487e27d28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "Inflector" @@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "ab_glyph" -version = "0.2.29" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +checksum = "1e0f4f6fbdc5ee39f2ede9f5f3ec79477271a6d6a2baff22310d51736bda6cea" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -20,9 +20,9 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169" [[package]] name = "addr2line" @@ -35,21 +35,21 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.3.3", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -63,9 +63,12 @@ dependencies = [ [[package]] name = "aligned-vec" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] [[package]] name = "alloc-no-stdlib" @@ -95,7 +98,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" dependencies = [ "android-properties", - "bitflags 2.9.0", + "bitflags 2.9.1", "cc", "cesu8", "jni", @@ -138,9 +141,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -153,44 +156,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -206,7 +209,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -233,7 +236,7 @@ version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading 0.8.6", + "libloading 0.8.8", ] [[package]] @@ -267,15 +270,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "av1-grain" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" dependencies = [ "anyhow", "arrayvec", @@ -287,18 +290,18 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" +checksum = "19135c0c7a60bfee564dbe44ab5ce0557c6bf3884e5291a50be76a15640c4fbd" dependencies = [ "arrayvec", ] [[package]] name = "axum" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ "axum-core", "bytes", @@ -309,7 +312,7 @@ dependencies = [ "http-body-util", "hyper", "hyper-util", - "itoa 1.0.15", + "itoa", "matchit", "memchr", "mime", @@ -330,12 +333,12 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" +checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "http-body-util", @@ -350,9 +353,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -434,9 +437,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -501,9 +504,9 @@ dependencies = [ [[package]] name = "brotli" -version = "7.0.0" +version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -512,9 +515,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -528,9 +531,9 @@ checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" @@ -543,13 +546,13 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.8.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -579,7 +582,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cairo-sys-rs", "glib", "libc", @@ -604,7 +607,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "log", "polling", "rustix 0.38.44", @@ -626,9 +629,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ "serde", ] @@ -674,9 +677,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "jobserver", "libc", @@ -712,9 +715,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -730,9 +733,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -772,9 +775,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.31" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -782,9 +785,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.31" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -794,21 +797,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "codespan-reporting" @@ -842,9 +845,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" @@ -931,9 +934,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -964,8 +967,8 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", + "bitflags 2.9.1", + "core-foundation 0.10.1", "core-graphics-types 0.2.0", "foreign-types 0.5.0", "libc", @@ -988,8 +991,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", + "bitflags 2.9.1", + "core-foundation 0.10.1", "libc", ] @@ -1058,9 +1061,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] @@ -1092,9 +1095,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" @@ -1108,15 +1111,15 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.27.2" +version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" dependencies = [ "cssparser-macros", "dtoa-short", - "itoa 0.4.8", + "itoa", "matches", - "phf 0.8.0", + "phf 0.10.1", "proc-macro2", "quote", "smallvec", @@ -1130,7 +1133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1140,14 +1143,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] name = "cursor-icon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "darling" @@ -1170,7 +1173,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1181,7 +1184,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1213,15 +1216,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.19" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1258,7 +1261,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1273,7 +1276,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", ] @@ -1285,7 +1288,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1294,7 +1297,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.6", + "libloading 0.8.8", ] [[package]] @@ -1311,13 +1314,13 @@ dependencies = [ [[package]] name = "dlopen2_derive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1337,9 +1340,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" dependencies = [ "serde", ] @@ -1381,7 +1384,7 @@ dependencies = [ "dyn-any", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1398,9 +1401,9 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embed-resource" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" +checksum = "0963f530273dc3022ab2bdc3fcd6d488e850256f2284a82b7413cb9481ee85dd" dependencies = [ "cc", "memchr", @@ -1437,17 +1440,37 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1466,12 +1489,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1556,9 +1579,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -1578,15 +1601,15 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "font-types" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd" +checksum = "1fa6a5e5a77b5f3f7f9e32879f484aa5b3632ddfbe568a16266c904a6f32cdaf" dependencies = [ "bytemuck", ] @@ -1612,9 +1635,9 @@ dependencies = [ [[package]] name = "fontconfig-parser" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" dependencies = [ "roxmltree", ] @@ -1683,7 +1706,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1784,7 +1807,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -1958,34 +1981,36 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] name = "gif" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" dependencies = [ "color_quant", "weezl", @@ -2042,9 +2067,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.29.2" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" +checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee" dependencies = [ "serde", ] @@ -2055,7 +2080,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "futures-channel", "futures-core", "futures-executor", @@ -2083,7 +2108,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -2140,7 +2165,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "gpu-alloc-types", ] @@ -2150,7 +2175,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -2167,11 +2192,11 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "gpu-descriptor-types", "hashbrown 0.15.4", ] @@ -2182,7 +2207,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -2281,7 +2306,7 @@ dependencies = [ "num-traits", "parley", "petgraph 0.7.1", - "rand 0.9.0", + "rand 0.9.1", "rand_chacha 0.9.0", "rustc-hash 2.1.1", "serde", @@ -2302,7 +2327,7 @@ dependencies = [ "log", "math-parser", "node-macro", - "rand 0.9.0", + "rand 0.9.1", ] [[package]] @@ -2334,7 +2359,7 @@ dependencies = [ "image", "ndarray", "node-macro", - "rand 0.9.0", + "rand 0.9.1", "rand_chacha 0.9.0", "serde", "specta", @@ -2363,7 +2388,7 @@ dependencies = [ "log", "ndarray", "node-macro", - "rand 0.9.0", + "rand 0.9.1", "rand_chacha 0.9.0", "reqwest", "tokio", @@ -2413,7 +2438,7 @@ name = "graphite-editor" version = "0.0.0" dependencies = [ "bezier-rs", - "bitflags 2.9.0", + "bitflags 2.9.1", "derivative", "dyn-any", "env_logger", @@ -2451,7 +2476,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -2521,7 +2546,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -2536,9 +2561,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" dependencies = [ "atomic-waker", "bytes", @@ -2546,7 +2571,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.7.1", + "indexmap 2.10.0", "slab", "tokio", "tokio-util", @@ -2555,9 +2580,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "bytemuck", "cfg-if", @@ -2596,15 +2621,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hermit-abi" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -2620,27 +2639,25 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "html5ever" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", + "match_token", ] [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", - "itoa 1.0.15", + "itoa", ] [[package]] @@ -2655,12 +2672,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "pin-project-lite", @@ -2678,12 +2695,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "1.6.0" @@ -2698,7 +2709,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.15", + "itoa", "pin-project-lite", "smallvec", "tokio", @@ -2707,11 +2718,10 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", "http", "hyper", "hyper-util", @@ -2741,21 +2751,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -2780,7 +2797,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -2794,16 +2811,17 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.61.2", ] [[package]] @@ -2838,54 +2856,47 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", - "litemap", - "tinystr", - "writeable", + "litemap 0.8.0", + "tinystr 0.8.1", + "writeable 0.6.1", "zerovec", ] [[package]] -name = "icu_locid_transform" +name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", + "litemap 0.7.5", + "tinystr 0.7.6", + "writeable 0.5.5", ] -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -2893,67 +2904,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", - "tinystr", - "writeable", + "tinystr 0.8.1", + "writeable 0.6.1", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.99", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -2973,9 +2971,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -2983,16 +2981,16 @@ dependencies = [ [[package]] name = "image" -version = "0.25.5" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", "byteorder-lite", "color_quant", "exr", "gif", - "image-webp 0.2.1", + "image-webp 0.2.3", "num-traits", "png", "qoi", @@ -3016,9 +3014,9 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b" dependencies = [ "byteorder-lite", "quick-error", @@ -3049,9 +3047,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown 0.15.4", @@ -3081,7 +3079,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -3108,6 +3106,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-docker" version = "0.2.0" @@ -3123,7 +3131,7 @@ version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.5.0", + "hermit-abi", "libc", "windows-sys 0.59.0", ] @@ -3162,12 +3170,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.15" @@ -3197,6 +3199,30 @@ dependencies = [ "system-deps", ] +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "jni" version = "0.21.1" @@ -3221,18 +3247,19 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] [[package]] name = "jpeg-decoder" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" [[package]] name = "js-sys" @@ -3272,7 +3299,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "serde", "unicode-segmentation", ] @@ -3284,7 +3311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.6", + "libloading 0.8.8", "pkg-config", ] @@ -3296,14 +3323,13 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kuchikiki" -version = "0.8.2" +version = "0.8.8-speedreader" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 1.9.3", - "matches", + "indexmap 2.10.0", "selectors", ] @@ -3356,9 +3382,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.170" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libfuzzer-sys" @@ -3382,29 +3408,29 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.2", ] [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.13", ] [[package]] @@ -3415,9 +3441,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -3425,6 +3451,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + [[package]] name = "litrs" version = "0.4.1" @@ -3433,9 +3465,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -3443,9 +3475,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "loop9" @@ -3456,6 +3488,12 @@ dependencies = [ "imgref", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac" version = "0.1.1" @@ -3473,18 +3511,29 @@ dependencies = [ [[package]] name = "markup5ever" -version = "0.11.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" dependencies = [ "log", - "phf 0.10.1", - "phf_codegen 0.10.0", + "phf 0.11.3", + "phf_codegen 0.11.3", "string_cache", "string_cache_codegen", "tendril", ] +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "matches" version = "0.1.10" @@ -3511,9 +3560,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" dependencies = [ "autocfg", "rawpointer", @@ -3531,9 +3580,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -3559,7 +3608,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block", "core-graphics-types 0.1.3", "foreign-types 0.5.0", @@ -3582,9 +3631,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -3592,20 +3641,20 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "muda" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492" +checksum = "58b89bf91c19bf036347f1ab85a81c560f08c0667c8601bece664d860a600988" dependencies = [ "crossbeam-channel", "dpi", @@ -3630,11 +3679,11 @@ checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg_aliases 0.1.1", "codespan-reporting", "hexf-parse", - "indexmap 2.7.1", + "indexmap 2.10.0", "log", "petgraph 0.6.5", "rustc-hash 1.1.0", @@ -3682,7 +3731,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys 0.5.0+25.2.9519653", @@ -3697,7 +3746,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys 0.6.0+11769913", @@ -3747,7 +3796,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -3805,7 +3854,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -3839,23 +3888,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -3905,11 +3955,11 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2 0.6.1", "libc", "objc2 0.6.1", @@ -3919,27 +3969,27 @@ dependencies = [ "objc2-core-graphics", "objc2-core-image", "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.0", + "objc2-quartz-core 0.3.1", ] [[package]] name = "objc2-cloud-kit" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c" +checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", "objc2-foundation 0.3.1", ] [[package]] name = "objc2-core-data" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4" +checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", "objc2-foundation 0.3.1", ] @@ -3950,18 +4000,19 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "dispatch2", "objc2 0.6.1", ] [[package]] name = "objc2-core-graphics" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" +checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", + "dispatch2", "objc2 0.6.1", "objc2-core-foundation", "objc2-io-surface", @@ -3969,17 +4020,10 @@ dependencies = [ [[package]] name = "objc2-core-image" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56" +checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" dependencies = [ -<<<<<<< HEAD - "objc2 0.6.1", - "objc2-foundation 0.3.1", -||||||| 71ddae90 - "objc2 0.6.0", - "objc2-foundation 0.3.0", -======= "objc2 0.6.1", "objc2-foundation 0.3.1", ] @@ -3990,9 +4034,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ba833d4a1cb1aac330f8c973fd92b6ff1858e4aef5cdd00a255eefb28022fb5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2-core-foundation", ->>>>>>> master ] [[package]] @@ -4022,7 +4065,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4034,7 +4077,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2 0.6.1", "libc", "objc2 0.6.1", @@ -4043,11 +4086,11 @@ dependencies = [ [[package]] name = "objc2-io-surface" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" +checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", "objc2-core-foundation", ] @@ -4058,7 +4101,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4070,7 +4113,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4079,22 +4122,22 @@ dependencies = [ [[package]] name = "objc2-quartz-core" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" +checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", "objc2-foundation 0.3.1", ] [[package]] name = "objc2-ui-kit" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1" +checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", "objc2-core-foundation", "objc2-foundation 0.3.1", @@ -4102,11 +4145,11 @@ dependencies = [ [[package]] name = "objc2-web-kit" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce" +checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2 0.6.1", "objc2 0.6.1", "objc2-app-kit", @@ -4125,9 +4168,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "oorandom" @@ -4149,11 +4198,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.72" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "foreign-types 0.3.2", "libc", @@ -4170,7 +4219,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -4181,9 +4230,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -4208,9 +4257,9 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224" dependencies = [ "libc", "windows-sys 0.59.0", @@ -4252,9 +4301,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -4262,13 +4311,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.13", "smallvec", "windows-targets 0.52.6", ] @@ -4341,9 +4390,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.15" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", "thiserror 2.0.12", @@ -4352,9 +4401,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.15" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" dependencies = [ "pest", "pest_generator", @@ -4362,24 +4411,23 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.15" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] name = "pest_meta" -version = "2.7.15" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" dependencies = [ - "once_cell", "pest", "sha2", ] @@ -4391,7 +4439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset 0.4.2", - "indexmap 2.7.1", + "indexmap 2.10.0", ] [[package]] @@ -4401,7 +4449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset 0.5.7", - "indexmap 2.7.1", + "indexmap 2.10.0", ] [[package]] @@ -4410,9 +4458,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ - "phf_macros 0.8.0", "phf_shared 0.8.0", - "proc-macro-hack", ] [[package]] @@ -4421,7 +4467,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ + "phf_macros 0.10.0", "phf_shared 0.10.0", + "proc-macro-hack", ] [[package]] @@ -4446,12 +4494,12 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -4486,12 +4534,12 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro-hack", "proc-macro2", "quote", @@ -4508,7 +4556,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -4564,13 +4612,13 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plist" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d" +checksum = "3d77244ce2d584cd84f6a15f86195b8c9b2a0dfbfd817c09e0464244091a58ed" dependencies = [ "base64 0.22.1", - "indexmap 2.7.1", - "quick-xml 0.32.0", + "indexmap 2.10.0", + "quick-xml", "serde", "time", ] @@ -4618,24 +4666,24 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.4" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.4.0", + "hermit-abi", "pin-project-lite", - "rustix 0.38.44", + "rustix 1.0.7", "tracing", "windows-sys 0.59.0", ] [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -4646,6 +4694,15 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -4654,11 +4711,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -4717,7 +4774,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "toml_edit 0.22.24", + "toml_edit 0.22.27", ] [[package]] @@ -4763,7 +4820,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -4774,30 +4831,30 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -4833,29 +4890,21 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.37.2" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", + "cfg_aliases 0.2.1", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -4865,17 +4914,19 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tracing", + "web-time 1.1.0", ] [[package]] name = "quinn-proto" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "getrandom 0.2.15", - "rand 0.8.5", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.1", "ring", "rustc-hash 2.1.1", "rustls", @@ -4889,9 +4940,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.10" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ "cfg_aliases 0.2.1", "libc", @@ -4903,13 +4954,19 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.7.3" @@ -4937,13 +4994,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.23", ] [[package]] @@ -4991,7 +5047,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -5000,7 +5056,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", ] [[package]] @@ -5064,9 +5120,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.11" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" dependencies = [ "avif-serialize", "imgref", @@ -5116,7 +5172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f9e8a4f503e5c8750e4cd3b32a4e090035c46374b305a15c70bad833dca05f" dependencies = [ "bytemuck", - "font-types 0.8.3", + "font-types 0.8.4", ] [[package]] @@ -5150,11 +5206,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -5163,11 +5219,31 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "regex" version = "1.11.1" @@ -5205,9 +5281,9 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.12" +version = "0.12.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" dependencies = [ "base64 0.22.1", "bytes", @@ -5225,28 +5301,25 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", "rustls", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", @@ -5254,7 +5327,6 @@ dependencies = [ "wasm-streams", "web-sys", "webpki-roots", - "windows-registry", ] [[package]] @@ -5285,13 +5357,13 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -5304,7 +5376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.9.0", + "bitflags 2.9.1", "serde", "serde_derive", ] @@ -5317,9 +5389,9 @@ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -5348,7 +5420,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -5357,22 +5429,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.1" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys 0.9.2", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.23" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "once_cell", "ring", @@ -5382,29 +5454,21 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time 1.1.0", + "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -5413,9 +5477,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "rustybuzz" @@ -5423,7 +5487,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "bytemuck", "core_maths", "log", @@ -5474,6 +5538,30 @@ dependencies = [ "uuid", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1375ba8ef45a6f15d83fa8748f1079428295d403d6ea991d09ab100155fbc06d" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "schemars_derive" version = "0.8.22" @@ -5483,7 +5571,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -5517,7 +5605,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5536,22 +5624,20 @@ dependencies = [ [[package]] name = "selectors" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" dependencies = [ "bitflags 1.3.2", "cssparser", "derive_more", "fxhash", "log", - "matches", "phf 0.8.0", "phf_codegen 0.8.0", "precomputed-hash", "servo_arc", "smallvec", - "thin-slice", ] [[package]] @@ -5602,7 +5688,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -5613,7 +5699,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -5622,7 +5708,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "itoa 1.0.15", + "itoa", "memchr", "ryu", "serde", @@ -5634,7 +5720,7 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ - "itoa 1.0.15", + "itoa", "serde", ] @@ -5646,14 +5732,14 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -5665,22 +5751,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.15", + "itoa", "ryu", "serde", ] [[package]] name = "serde_with" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.1", + "indexmap 2.10.0", + "schemars 0.9.0", + "schemars 1.0.3", "serde", "serde_derive", "serde_json", @@ -5690,14 +5778,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -5724,9 +5812,9 @@ dependencies = [ [[package]] name = "servo_arc" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" dependencies = [ "nodrop", "stable_deref_trait", @@ -5734,9 +5822,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -5745,12 +5833,13 @@ dependencies = [ [[package]] name = "shared_child" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" +checksum = "c2778001df1384cf20b6dc5a5a90f48da35539885edaaefd887f8d744e939c0b" dependencies = [ "libc", - "windows-sys 0.59.0", + "sigchld", + "windows-sys 0.60.2", ] [[package]] @@ -5759,6 +5848,36 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "sigchld" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1219ef50fc0fdb04fcc243e6aa27f855553434ffafe4fa26554efb78b5b4bf89" +dependencies = [ + "libc", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -5827,12 +5946,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "slotmap" @@ -5858,7 +5974,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "calloop", "calloop-wayland-source", "cursor-icon", @@ -5888,9 +6004,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5912,7 +6028,7 @@ dependencies = [ "objc2-foundation 0.2.2", "objc2-quartz-core 0.2.2", "raw-window-handle", - "redox_syscall 0.5.10", + "redox_syscall 0.5.13", "wasm-bindgen", "web-sys", "windows-sys 0.59.0", @@ -5964,7 +6080,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -5982,7 +6098,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -6051,9 +6167,9 @@ checksum = "94afda9cd163c04f6bee8b4bf2501c91548deae308373c436f36aeff3cf3c4a3" [[package]] name = "svg_fmt" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa" +checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" [[package]] name = "svgtypes" @@ -6100,9 +6216,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.99" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -6120,13 +6236,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -6135,7 +6251,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6165,12 +6281,12 @@ dependencies = [ [[package]] name = "tao" -version = "0.32.8" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c8b1020610b9138dd7b1e06cf259ae91aa05c30f3bd0d6b42a03997b92dec1" +checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", + "bitflags 2.9.1", + "core-foundation 0.10.1", "core-graphics 0.24.0", "crossbeam-channel", "dispatch", @@ -6196,8 +6312,8 @@ dependencies = [ "tao-macros", "unicode-segmentation", "url", - "windows 0.60.0", - "windows-core 0.60.1", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -6210,7 +6326,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -6221,17 +6337,16 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.4.1" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d08db1ff9e011e04014e737ec022610d756c0eae0b3b3a9037bccaf3003173a" +checksum = "124e129c9c0faa6bec792c5948c89e86c90094133b0b9044df0ce5f0a8efaa0d" dependencies = [ "anyhow", "bytes", "dirs", "dunce", "embed_plist", - "futures-util", - "getrandom 0.2.15", + "getrandom 0.3.3", "glob", "gtk", "heck 0.5.0", @@ -6244,6 +6359,7 @@ dependencies = [ "objc2 0.6.1", "objc2-app-kit", "objc2-foundation 0.3.1", + "objc2-ui-kit", "percent-encoding", "plist", "raw-window-handle", @@ -6266,14 +6382,14 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows 0.60.0", + "windows 0.61.3", ] [[package]] name = "tauri-build" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd20e4661c2cce65343319e6e8da256958f5af958cafc47c0d0af66a55dcd17" +checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83" dependencies = [ "anyhow", "cargo_toml", @@ -6281,7 +6397,7 @@ dependencies = [ "glob", "heck 0.5.0", "json-patch", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde_json", @@ -6293,9 +6409,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458258b19032450ccf975840116ecf013e539eadbb74420bd890e8c56ab2b1a4" +checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406" dependencies = [ "base64 0.22.1", "brotli", @@ -6309,7 +6425,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.99", + "syn 2.0.104", "tauri-utils", "thiserror 2.0.12", "time", @@ -6320,28 +6436,28 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.1.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d402813d3b9c773a0fa58697c457c771f10e735498fdcb7b343264d18e5a601f" +checksum = "f237fbea5866fa5f2a60a21bea807a2d6e0379db070d89c3a10ac0f2d4649bbc" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4190775d6ff73fe66d9af44c012739a2659720efd9c0e1e56a918678038699d" +checksum = "1d9a0bd00bf1930ad1a604d08b0eb6b2a9c1822686d65d7f4731a7723b8901d3" dependencies = [ "anyhow", "glob", "plist", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri-utils", @@ -6351,15 +6467,15 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88371e340ad2f07409a3b68294abe73f20bc9c1bc1b631a31dc37a3d0161f682" +checksum = "c341290d31991dbca38b31d412c73dfbdb070bb11536784f19dd2211d13b778f" dependencies = [ "anyhow", "dunce", "glob", "percent-encoding", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "serde_repr", @@ -6369,14 +6485,13 @@ dependencies = [ "thiserror 2.0.12", "toml", "url", - "uuid", ] [[package]] name = "tauri-plugin-http" -version = "2.4.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40dcd6c922a1885e1f0bcebc6768fec6e005bd4b9001c5d90a2f5d4cab297729" +checksum = "b0c1a38da944b357ffa23bafd563b1579f18e6fbd118fcd84769406d35dcc5c7" dependencies = [ "bytes", "cookie_store", @@ -6384,7 +6499,7 @@ dependencies = [ "http", "regex", "reqwest", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri", @@ -6398,16 +6513,16 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d5eb3368b959937ad2aeaf6ef9a8f5d11e01ffe03629d3530707bbcb27ff5d" +checksum = "2b9ffadec5c3523f11e8273465cacb3d86ea7652a28e6e2a2e9b5c182f791d25" dependencies = [ "encoding_rs", "log", "open", "os_pipe", "regex", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "shared_child", @@ -6419,29 +6534,31 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.5.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ada7ac2f9276f09b8c3afffd3215fd5d9bff23c22df8a7c70e7ef67cacd532" +checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4" dependencies = [ "cookie", "dpi", "gtk", "http", "jni", + "objc2 0.6.1", + "objc2-ui-kit", "raw-window-handle", "serde", "serde_json", "tauri-utils", "thiserror 2.0.12", "url", - "windows 0.60.0", + "windows 0.61.3", ] [[package]] name = "tauri-runtime-wry" -version = "2.5.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2e5842c57e154af43a20a49c7efee0ce2578c20b4c2bdf266852b422d2e421" +checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad" dependencies = [ "gtk", "http", @@ -6460,15 +6577,15 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows 0.60.0", + "windows 0.61.3", "wry", ] [[package]] name = "tauri-utils" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f037e66c7638cc0a2213f61566932b9a06882b8346486579c90e4b019bac447" +checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e" dependencies = [ "anyhow", "brotli", @@ -6487,7 +6604,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde-untagged", @@ -6504,25 +6621,25 @@ dependencies = [ [[package]] name = "tauri-winres" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0" +checksum = "e8d321dbc6f998d825ab3f0d62673e810c861aac2d0de2cc2c395328f1d113b4" dependencies = [ "embed-resource", + "indexmap 2.10.0", "toml", ] [[package]] name = "tempfile" -version = "3.18.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.3", "once_cell", - "rustix 1.0.1", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -6546,12 +6663,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - [[package]] name = "thiserror" version = "1.0.69" @@ -6578,7 +6689,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -6589,7 +6700,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -6610,7 +6721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", - "itoa 1.0.15", + "itoa", "num-conv", "powerfmt", "serde", @@ -6665,6 +6776,15 @@ name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -6697,9 +6817,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -6719,7 +6839,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -6744,9 +6864,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -6757,21 +6877,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.24", + "toml_edit 0.22.27", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] @@ -6782,7 +6902,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.10.0", "toml_datetime", "winnow 0.5.40", ] @@ -6793,24 +6913,31 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.10.0", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.10.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.3", + "toml_write", + "winnow 0.7.11", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tower" version = "0.5.2" @@ -6827,6 +6954,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -6852,18 +6997,18 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] [[package]] name = "tray-icon" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5" +checksum = "2da75ec677957aa21f6e0b361df0daab972f13a5bee3606de0638fd4ee1c666a" dependencies = [ "crossbeam-channel", "dirs", @@ -7084,12 +7229,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -7104,19 +7243,21 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] name = "v_frame" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" dependencies = [ "aligned-vec", "num-traits", @@ -7229,15 +7370,15 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -7264,7 +7405,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -7299,7 +7440,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7328,9 +7469,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" dependencies = [ "cc", "downcast-rs", @@ -7342,11 +7483,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "rustix 0.38.44", "wayland-backend", "wayland-scanner", @@ -7358,16 +7499,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182" dependencies = [ "rustix 0.38.44", "wayland-client", @@ -7380,7 +7521,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -7392,7 +7533,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7405,7 +7546,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7419,7 +7560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", - "quick-xml 0.37.2", + "quick-xml", "quote", ] @@ -7511,24 +7652,24 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.8" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" dependencies = [ "rustls-pki-types", ] [[package]] name = "webview2-com" -version = "0.36.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d606f600e5272b514dbb66539dd068211cc20155be8d3958201b4b5bd79ed3" +checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.60.0", - "windows-core 0.60.1", - "windows-implement 0.59.0", + "windows 0.61.3", + "windows-core 0.61.2", + "windows-implement 0.60.0", "windows-interface 0.59.1", ] @@ -7540,25 +7681,25 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] name = "webview2-com-sys" -version = "0.36.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac" +checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" dependencies = [ "thiserror 2.0.12", - "windows 0.60.0", - "windows-core 0.60.1", + "windows 0.61.3", + "windows-core 0.61.2", ] [[package]] name = "weezl" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" [[package]] name = "wgpu" @@ -7593,11 +7734,11 @@ checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a" dependencies = [ "arrayvec", "bit-vec", - "bitflags 2.9.0", + "bitflags 2.9.1", "bytemuck", "cfg_aliases 0.1.1", "document-features", - "indexmap 2.7.1", + "indexmap 2.10.0", "log", "naga", "once_cell", @@ -7639,7 +7780,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.9.0", + "bitflags 2.9.1", "block", "bytemuck", "cfg_aliases 0.1.1", @@ -7652,7 +7793,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.6", + "libloading 0.8.8", "log", "metal", "naga", @@ -7680,7 +7821,7 @@ version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "js-sys", "web-sys", ] @@ -7743,12 +7884,12 @@ dependencies = [ [[package]] name = "windows" -version = "0.60.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-future", "windows-link", "windows-numerics", @@ -7756,20 +7897,11 @@ dependencies = [ [[package]] name = "windows-collections" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" -dependencies = [ - "windows-core 0.60.1", -] - -[[package]] -name = "windows-core" -version = "0.52.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-targets 0.52.6", + "windows-core 0.61.2", ] [[package]] @@ -7787,25 +7919,26 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.60.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.59.0", + "windows-implement 0.60.0", "windows-interface 0.59.1", "windows-link", - "windows-result 0.3.1", - "windows-strings 0.3.1", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] name = "windows-future" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-link", + "windows-threading", ] [[package]] @@ -7816,18 +7949,18 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] name = "windows-implement" -version = "0.59.0" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -7838,7 +7971,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -7849,34 +7982,34 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-numerics" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-link", ] [[package]] name = "windows-registry" -version = "0.2.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-link", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -7890,9 +8023,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] @@ -7909,9 +8042,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -7952,6 +8085,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -7991,18 +8133,43 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-version" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bfbcc4996dd183ff1376a20ade1242da0d2dcaff83cc76710a588d24fd4c5db" +checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" dependencies = [ "windows-link", ] @@ -8025,6 +8192,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -8043,6 +8216,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -8061,12 +8240,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -8085,6 +8276,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -8103,6 +8300,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -8121,6 +8324,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -8139,6 +8348,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winit" version = "0.29.15" @@ -8148,7 +8363,7 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.9.0", + "bitflags 2.9.1", "bytemuck", "calloop", "cfg_aliases 0.1.1", @@ -8198,49 +8413,49 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.52.0" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] -name = "write16" -version = "1.0.0" +name = "writeable" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wry" -version = "0.50.5" +version = "0.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b78efae8b853c6c817e8752fc1dbf9cab8a8ffe9c30f399bd750ccf0f0730" +checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9" dependencies = [ "base64 0.22.1", "block2 0.6.1", @@ -8274,8 +8489,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.60.0", - "windows-core 0.60.1", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -8310,7 +8525,7 @@ dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading 0.8.6", + "libloading 0.8.8", "once_cell", "rustix 0.38.44", "x11rb-protocol", @@ -8324,9 +8539,9 @@ checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" [[package]] name = "xkbcommon-dl" @@ -8334,7 +8549,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "dlib", "log", "once_cell", @@ -8349,9 +8564,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" [[package]] name = "xmlwriter" @@ -8373,9 +8588,9 @@ checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -8385,13 +8600,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", "synstructure", ] @@ -8403,43 +8618,22 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" -dependencies = [ - "zerocopy-derive 0.8.23", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -8459,7 +8653,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", "synstructure", ] @@ -8469,11 +8663,22 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -8482,13 +8687,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.104", ] [[package]] @@ -8508,9 +8713,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +checksum = "7384255a918371b5af158218d131530f694de9ad3815ebdd0453a940485cb0fa" dependencies = [ "zune-core", ] diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index fdfa9346b3..5a6fdee0d5 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -228,7 +228,6 @@ impl SelectTool { vec![ CheckboxInput::new(self.tool_data.dot_state.enabled) - .icon("Overlays") .tooltip("Disable Transform Pivot Point") .on_update(|optional_input: &CheckboxInput| SelectToolMessage::SelectOptions(SelectOptionsUpdate::ToggleDotType(optional_input.checked)).into()) .widget_holder(), From 117b24f91d48697a7e868aa6b6a2470ce0079240 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 4 Jul 2025 13:05:55 +0530 Subject: [PATCH 35/54] refactor: add dot to path_tool --- .../tool/common_functionality/pivot.rs | 151 +++++++++++++++ .../messages/tool/tool_messages/path_tool.rs | 78 +++++++- .../tool/tool_messages/select_tool.rs | 173 +++--------------- .../transform_layer_message.rs | 2 +- .../transform_layer_message_handler.rs | 4 +- 5 files changed, 251 insertions(+), 157 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index aad0d3cd25..80cc12685e 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -2,9 +2,157 @@ use crate::consts::PIVOT_DIAMETER; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::tool_messages::select_tool::SelectOptionsUpdate; +use crate::messages::tool::tool_messages::path_tool::PathOptionsUpdate; +use crate::messages::tool::tool_messages::tool_prelude::*; use glam::{DAffine2, DVec2}; use graphene_std::transform::ReferencePoint; +use std::fmt; + +pub fn pin_pivot_widget(disabled: bool, source: Source) -> WidgetHolder { + IconButton::new(if disabled { "PinInactive" } else { "PinActive" }, 24) + .tooltip(if disabled { "Pin Transform Pivot" } else { "Unpin Transform Pivot" }) + .on_update(move |_| match source { + Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), + Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), + }) + .widget_holder() +} + +pub fn pivot_reference_point_widget(disabled: bool, reference_point: ReferencePoint, source: Source) -> WidgetHolder { + ReferencePointInput::new(reference_point) + .on_update(move |pivot_input: &ReferencePointInput| match source { + Source::Select => SelectToolMessage::SetPivot { position: pivot_input.value }.into(), + Source::Path => PathToolMessage::SetPivot { position: pivot_input.value }.into(), + }) + .disabled(disabled) + .widget_holder() +} + +pub fn dot_type_widget(state: DotState, source: Source) -> Vec { + let dot_type_entries = [DotType::Pivot, DotType::Average, DotType::Active] + .iter() + .map(|dot_type| { + MenuListEntry::new(format!("{dot_type:?}")).label(dot_type.to_string()).on_commit({ + let value = source.clone(); + move |_| match value { + Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::DotType(*dot_type)).into(), + Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::DotType(*dot_type)).into(), + } + }) + }) + .collect(); + + vec![ + CheckboxInput::new(state.enabled) + .tooltip("Disable Transform Pivot Point") + .on_update(move |optional_input: &CheckboxInput| match source { + Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::ToggleDotType(optional_input.checked)).into(), + Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::ToggleDotType(optional_input.checked)).into(), + }) + .widget_holder(), + Separator::new(SeparatorType::Related).widget_holder(), + DropdownInput::new(vec![dot_type_entries]) + .selected_index(Some(match state.dot { + DotType::Pivot => 0, + DotType::Average => 1, + DotType::Active => 2, + })) + .tooltip("Choose between type of Transform Pivot Point") + .disabled(!state.enabled) + .widget_holder(), + ] +} + +#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] +pub enum Source { + Path, + #[default] + Select, +} + +#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] +pub struct Dot { + pub pivot: Pivot, + pub state: DotState, + pub layer: Option, +} + +impl Dot { + pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 { + let network = &document.network_interface; + self.state + .enabled + .then_some({ + match self.state.dot { + DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), + DotType::Pivot => self.pivot.position(), + DotType::Active => self.layer.map(|layer| graph_modification_utils::get_viewport_origin(layer, network)), + } + }) + .flatten() + .unwrap_or_else(|| self.pivot.transform_from_normalized.transform_point2(DVec2::splat(0.5))) + } + + pub fn recalculate_transform(&mut self, document: &DocumentMessageHandler) -> DAffine2 { + self.pivot.recalculate_pivot(document); + self.pivot.transform_from_normalized + } + + pub fn pin_inactive(&self) -> bool { + !self.pivot.pinned || !self.state.is_pivot() + } + +} + +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum DotType { + // Pivot + #[default] + Pivot, + // Origin + // Indidual, + Average, + Active, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct DotState { + pub enabled: bool, + pub dot: DotType, +} + +impl Default for DotState { + fn default() -> Self { + Self { + enabled: true, + dot: DotType::default(), + } + } +} + +impl DotState { + pub fn is_pivot_type(&self) -> bool { + self.dot == DotType::Pivot || !self.enabled + } + + pub fn is_pivot(&self) -> bool { + self.dot == DotType::Pivot && self.enabled + } +} + +impl fmt::Display for DotType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DotType::Pivot => write!(f, "Draft Pivot"), + DotType::Average => write!(f, "Average of Origins"), + DotType::Active => write!(f, "Active Object Origin"), + } + } +} #[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct Pivot { @@ -20,6 +168,8 @@ pub struct Pivot { pub last_non_none_reference: ReferencePoint, /// Used to enable and disable the pivot active: bool, + /// Used to enable and disable the pivot + pub pinned: bool, } impl Default for Pivot { @@ -31,6 +181,7 @@ impl Default for Pivot { old_pivot_position: ReferencePoint::Center, last_non_none_reference: ReferencePoint::Center, active: true, + pinned: false, } } } diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index ff929ce9bd..eb3079e1e8 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -11,6 +11,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node use crate::messages::portfolio::document::utility_types::transformation::Axis; use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::pivot::{Dot, DotType, Source, dot_type_widget, pin_pivot_widget, pivot_reference_point_widget}; use crate::messages::tool::common_functionality::shape_editor::{ ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState, }; @@ -18,6 +19,7 @@ use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandi use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate}; use bezier_rs::{Bezier, TValue}; use graphene_std::renderer::Quad; +use graphene_std::transform::ReferencePoint; use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData}; use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType}; use std::vec; @@ -103,6 +105,9 @@ pub enum PathToolMessage { SelectedPointYChanged { new_y: f64, }, + SetPivot { + position: ReferencePoint, + }, SwapSelectedHandles, UpdateOptions(PathOptionsUpdate), UpdateSelectedPointsStatus { @@ -138,6 +143,9 @@ pub enum PathOptionsUpdate { OverlayModeType(PathOverlayMode), PointEditingMode { enabled: bool }, SegmentEditingMode { enabled: bool }, + DotType(DotType), + ToggleDotType(bool), + TogglePivotPinned(), } impl ToolMetadata for PathTool { @@ -252,6 +260,16 @@ impl LayoutHolder for PathTool { .selected_index(Some(self.options.path_overlay_mode as u32)) .widget_holder(); + let [checkbox, dropdown] = { + let dot_widget = dot_type_widget(self.tool_data.dot.state, Source::Path); + [dot_widget.get(0).unwrap().clone(), dot_widget.get(2).unwrap().clone()] + }; + + let has_somrthing = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty(); + let pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path); + + let pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Path); + Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: vec![ x_location, @@ -265,8 +283,16 @@ impl LayoutHolder for PathTool { point_editing_mode, related_seperator.clone(), segment_editing_mode, - unrelated_seperator, + unrelated_seperator.clone(), path_overlay_mode_widget, + unrelated_seperator.clone(), + checkbox.clone(), + related_seperator.clone(), + dropdown.clone(), + unrelated_seperator, + pivot_reference, + related_seperator.clone(), + pin_pivot, ], }])) } @@ -290,6 +316,29 @@ impl<'a> MessageHandler> for PathToo self.options.path_editing_mode.segment_editing_mode = enabled; responses.add(OverlaysMessage::Draw); } + PathOptionsUpdate::DotType(dot_type) => { + if self.tool_data.dot.state.enabled { + self.tool_data.dot.state.dot = dot_type; + responses.add(ToolMessage::UpdateHints); + let dot = self.tool_data.get_as_dot(); + responses.add(TransformLayerMessage::SetDot { dot }); + responses.add(NodeGraphMessage::RunDocumentGraph); + self.send_layout(responses, LayoutTarget::ToolOptions); + } + } + PathOptionsUpdate::ToggleDotType(state) => { + self.tool_data.dot.state.enabled = state; + responses.add(ToolMessage::UpdateHints); + responses.add(NodeGraphMessage::RunDocumentGraph); + self.send_layout(responses, LayoutTarget::ToolOptions); + } + + PathOptionsUpdate::TogglePivotPinned() => { + self.tool_data.dot.pivot.pinned = !self.tool_data.dot.pivot.pinned; + responses.add(ToolMessage::UpdateHints); + responses.add(NodeGraphMessage::RunDocumentGraph); + self.send_layout(responses, LayoutTarget::ToolOptions); + } }, ToolMessage::Path(PathToolMessage::ClosePath) => { responses.add(DocumentMessage::AddTransaction); @@ -447,6 +496,7 @@ struct PathToolData { last_click_time: u64, dragging_state: DraggingState, angle: f64, + dot: Dot, opposite_handle_position: Option, last_clicked_point_was_selected: bool, last_clicked_segment_was_selected: bool, @@ -1316,6 +1366,10 @@ impl PathToolData { } } } + + fn get_as_dot(&self) -> Dot { + self.dot.clone() + } } impl Fsm for PathToolFsmState { @@ -1719,14 +1773,8 @@ impl Fsm for PathToolFsmState { } (PathToolFsmState::Ready, PathToolMessage::PointerMove { delete_segment, .. }) => { tool_data.delete_segment_pressed = input.keyboard.get(delete_segment as usize); - - if !tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty() { - tool_data.saved_points_before_anchor_convert_smooth_sharp.clear(); - } - - if tool_data.adjacent_anchor_offset.is_some() { - tool_data.adjacent_anchor_offset = None; - } + tool_data.saved_points_before_anchor_convert_smooth_sharp.clear(); + tool_data.adjacent_anchor_offset = None; responses.add(OverlaysMessage::Draw); @@ -2163,6 +2211,18 @@ impl Fsm for PathToolFsmState { responses.add(DocumentMessage::EndTransaction); PathToolFsmState::Ready } + (_, PathToolMessage::SetPivot { position }) => { + responses.add(DocumentMessage::StartTransaction); + + tool_data.dot.pivot.last_non_none_reference = position; + let pos: Option = position.into(); + tool_data.dot.pivot.set_normalized_position(pos.unwrap()); + let dot = tool_data.get_as_dot(); + responses.add(TransformLayerMessage::SetDot { dot }); + responses.add(NodeGraphMessage::RunDocumentGraph); + + self + } (_, _) => PathToolFsmState::Ready, } } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 5a6fdee0d5..1d17b56446 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -15,7 +15,7 @@ use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRos use crate::messages::tool::common_functionality::graph_modification_utils; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; use crate::messages::tool::common_functionality::measure; -use crate::messages::tool::common_functionality::pivot::Pivot; +use crate::messages::tool::common_functionality::pivot::{Dot, DotType, Source, dot_type_widget, pin_pivot_widget, pivot_reference_point_widget}; use crate::messages::tool::common_functionality::shape_editor::SelectionShapeType; use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager}; use crate::messages::tool::common_functionality::transformation_cage::*; @@ -56,76 +56,6 @@ pub enum NestedSelectionBehavior { Deepest, } -#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] -pub struct Dot(Pivot, DotState, Option); - -impl Dot { - pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 { - let network = &document.network_interface; - self.1 - .enabled - .then_some({ - match self.1.dot { - DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), - DotType::Pivot => self.0.position(), - DotType::Active => self.2.map(|layer| graph_modification_utils::get_viewport_origin(layer, network)), - } - }) - .flatten() - .unwrap_or_else(|| self.0.transform_from_normalized.transform_point2(DVec2::splat(0.5))) - } - pub fn recalculate_transform(&mut self, document: &DocumentMessageHandler) -> DAffine2 { - self.0.recalculate_pivot(document); - self.0.transform_from_normalized - } -} - -#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] -pub enum DotType { - // Pivot - #[default] - Pivot, - // Origin - // Indidual, - Average, - Active, -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct DotState { - enabled: bool, - dot: DotType, -} - -impl Default for DotState { - fn default() -> Self { - Self { - enabled: true, - dot: DotType::default(), - } - } -} - -impl DotState { - pub fn is_pivot_type(&self) -> bool { - self.dot == DotType::Pivot || !self.enabled - } - - pub fn is_pivot(&self) -> bool { - self.dot == DotType::Pivot && self.enabled - } -} - -impl fmt::Display for DotType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DotType::Pivot => write!(f, "Draft Pivot"), - DotType::Average => write!(f, "Average of Origins"), - DotType::Active => write!(f, "Active Object Origin"), - } - } -} - impl fmt::Display for NestedSelectionBehavior { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -200,50 +130,6 @@ impl SelectTool { .widget_holder() } - fn pivot_reference_point_widget(&self, disabled: bool) -> WidgetHolder { - ReferencePointInput::new(self.tool_data.pivot.to_pivot_position()) - .on_update(|pivot_input: &ReferencePointInput| SelectToolMessage::SetPivot { position: pivot_input.value }.into()) - .disabled(disabled) - .widget_holder() - } - - fn pin_pivot_widget(&self) -> Vec { - vec![ - IconButton::new(if self.tool_data.pin_inactive() { "PinInactive" } else { "PinActive" }, 24) - .tooltip(if self.tool_data.pin_inactive() { "Unpin Transform Pivot" } else { "Pin Transform Pivot" }) - .on_update(|_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into()) - .widget_holder(), - ] - } - - fn dot_type_widget(&self) -> Vec { - let dot_type_entries = [DotType::Pivot, DotType::Average, DotType::Active] - .iter() - .map(|dot_type| { - MenuListEntry::new(format!("{dot_type:?}")) - .label(dot_type.to_string()) - .on_commit(move |_| SelectToolMessage::SelectOptions(SelectOptionsUpdate::DotType(*dot_type)).into()) - }) - .collect(); - - vec![ - CheckboxInput::new(self.tool_data.dot_state.enabled) - .tooltip("Disable Transform Pivot Point") - .on_update(|optional_input: &CheckboxInput| SelectToolMessage::SelectOptions(SelectOptionsUpdate::ToggleDotType(optional_input.checked)).into()) - .widget_holder(), - Separator::new(SeparatorType::Related).widget_holder(), - DropdownInput::new(vec![dot_type_entries]) - .selected_index(Some(match self.tool_data.dot_state.dot { - DotType::Pivot => 0, - DotType::Average => 1, - DotType::Active => 2, - })) - .tooltip("Choose between type of Transform Pivot Point") - .disabled(!self.tool_data.dot_state.enabled) - .widget_holder(), - ] - } - fn alignment_widgets(&self, disabled: bool) -> impl Iterator + use<> { [AlignAxis::X, AlignAxis::Y] .into_iter() @@ -316,14 +202,19 @@ impl LayoutHolder for SelectTool { // Dot Type (Pivot/Origin/Off) widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - widgets.extend(self.dot_type_widget()); + widgets.extend(dot_type_widget(self.tool_data.dot.state, Source::Select)); // Pivot widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - widgets.push(self.pivot_reference_point_widget(self.tool_data.selected_layers_count == 0 || !self.tool_data.dot_state.is_pivot())); + widgets.push(pivot_reference_point_widget( + self.tool_data.selected_layers_count == 0 || !self.tool_data.dot.state.is_pivot(), + self.tool_data.dot.pivot.to_pivot_position(), + Source::Select, + )); + // Pivot pin widgets.push(Separator::new(SeparatorType::Related).widget_holder()); - widgets.extend(self.pin_pivot_widget()); + widgets.push(pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Select)); // Align let disabled = self.tool_data.selected_layers_count < 2; @@ -370,8 +261,8 @@ impl<'a> MessageHandler> for SelectT responses.add(ToolMessage::UpdateHints); } SelectOptionsUpdate::DotType(dot_type) => { - if self.tool_data.dot_state.enabled { - self.tool_data.dot_state.dot = *dot_type; + if self.tool_data.dot.state.enabled { + self.tool_data.dot.state.dot = *dot_type; responses.add(ToolMessage::UpdateHints); let dot = self.tool_data.get_as_dot(); responses.add(TransformLayerMessage::SetDot { dot }); @@ -380,13 +271,14 @@ impl<'a> MessageHandler> for SelectT } } SelectOptionsUpdate::ToggleDotType(state) => { - self.tool_data.dot_state.enabled = *state; + self.tool_data.dot.state.enabled = *state; responses.add(ToolMessage::UpdateHints); responses.add(NodeGraphMessage::RunDocumentGraph); redraw_ref_pivot = true; } + SelectOptionsUpdate::TogglePivotPinned() => { - self.tool_data.pivot_pinned = !self.tool_data.pivot_pinned; + self.tool_data.dot.pivot.pinned = !self.tool_data.dot.pivot.pinned; responses.add(ToolMessage::UpdateHints); responses.add(NodeGraphMessage::RunDocumentGraph); redraw_ref_pivot = true; @@ -396,7 +288,7 @@ impl<'a> MessageHandler> for SelectT self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false); - if self.tool_data.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed || redraw_ref_pivot { + if self.tool_data.dot.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed || redraw_ref_pivot { // Send the layout containing the updated pivot position (a bit ugly to do it here not in the fsm but that doesn't have SelectTool) self.send_layout(responses, LayoutTarget::ToolOptions); self.tool_data.selected_layers_changed = false; @@ -470,7 +362,6 @@ struct SelectToolData { selection_mode: Option, layers_dragging: Vec, // Unordered, often used as temporary buffer orderer_layers: Vec, // Ordered list of layers - active_layer: Option, layer_selected_on_start: Option, select_single_layer: Option, axis_align: bool, @@ -478,9 +369,7 @@ struct SelectToolData { bounding_box_manager: Option, snap_manager: SnapManager, cursor: MouseCursorIcon, - pivot: Pivot, - pivot_pinned: bool, - dot_state: DotState, + dot: Dot, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -648,24 +537,20 @@ impl SelectToolData { } fn state_from_dot(&self, mouse: DVec2) -> Option { - match self.dot_state.dot { - DotType::Pivot if !self.pivot_pinned => self.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), + match self.dot.state.dot { + DotType::Pivot if !self.dot.pivot.pinned => self.dot.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), _ => None, } } fn get_as_dot(&self) -> Dot { - Dot(self.pivot.clone(), self.dot_state, self.active_layer.clone()) + self.dot.clone() } fn sync_history(&mut self) { self.orderer_layers.retain(|layer| self.layers_dragging.contains(layer)); self.orderer_layers.extend(self.layers_dragging.iter().find(|&layer| !self.orderer_layers.contains(layer))); - self.active_layer = self.orderer_layers.last().map(|x| *x) - } - - fn pin_inactive(&self) -> bool { - !self.pivot_pinned || !self.dot_state.is_pivot() + self.dot.layer = self.orderer_layers.last().map(|x| *x) } } @@ -881,10 +766,10 @@ impl Fsm for SelectToolFsmState { }); let mut active_origin = None; - if overlay_context.visibility_settings.origin() && !tool_data.dot_state.is_pivot_type() { + if overlay_context.visibility_settings.origin() && !tool_data.dot.state.is_pivot_type() { for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); - if Some(layer) == tool_data.active_layer { + if Some(layer) == tool_data.dot.layer { active_origin = Some(origin); continue; } @@ -895,8 +780,8 @@ impl Fsm for SelectToolFsmState { overlay_context.dowel_pin(origin, Some(COLOR_OVERLAY_ORANGE)); } - let draw_pivot = tool_data.dot_state.is_pivot() && overlay_context.visibility_settings.pivot(); - tool_data.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot); + let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot(); + tool_data.dot.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot); // Update compass rose if overlay_context.visibility_settings.compass_rose() { @@ -1124,7 +1009,7 @@ impl Fsm for SelectToolFsmState { let extend = input.keyboard.key(extend_selection); if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); - let position = tool_data.pivot.last_non_none_reference; + let position = tool_data.dot.pivot.last_non_none_reference; responses.add(SelectToolMessage::SetPivot { position }); tool_data.layers_dragging.clear(); } @@ -1283,7 +1168,7 @@ impl Fsm for SelectToolFsmState { (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => { let mouse_position = input.mouse.position; let snapped_mouse_position = mouse_position; - tool_data.pivot.set_viewport_position(snapped_mouse_position); + tool_data.dot.pivot.set_viewport_position(snapped_mouse_position); responses.add(NodeGraphMessage::RunDocumentGraph); // Auto-panning @@ -1329,7 +1214,7 @@ impl Fsm for SelectToolFsmState { .map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge))); // Dragging the pivot overrules the other operations - if tool_data.pivot.is_over(input.mouse.position) { + if tool_data.state_from_dot(input.mouse.position).is_some() { cursor = MouseCursorIcon::Move; } @@ -1621,9 +1506,9 @@ impl Fsm for SelectToolFsmState { (_, SelectToolMessage::SetPivot { position }) => { responses.add(DocumentMessage::StartTransaction); - tool_data.pivot.last_non_none_reference = position; + tool_data.dot.pivot.last_non_none_reference = position; let pos: Option = position.into(); - tool_data.pivot.set_normalized_position(pos.unwrap()); + tool_data.dot.pivot.set_normalized_position(pos.unwrap()); let dot = tool_data.get_as_dot(); responses.add(TransformLayerMessage::SetDot { dot }); responses.add(NodeGraphMessage::RunDocumentGraph); diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs index 3e56729050..e75a5f0503 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -2,7 +2,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::transformation::TransformType; use crate::messages::prelude::*; -use crate::messages::tool::tool_messages::select_tool::Dot; +use crate::messages::tool::common_functionality::pivot::Dot; use glam::DVec2; #[impl_message(Message, ToolMessage, TransformLayer)] diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 6e4fed4dae..980d873571 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -5,8 +5,8 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye use crate::messages::portfolio::document::utility_types::misc::PTZ; use crate::messages::portfolio::document::utility_types::transformation::{Axis, OriginalTransforms, Selected, TransformOperation, TransformType, Typing}; use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::pivot::Dot; use crate::messages::tool::common_functionality::shape_editor::ShapeState; -use crate::messages::tool::tool_messages::select_tool::Dot; use crate::messages::tool::tool_messages::tool_prelude::Key; use crate::messages::tool::utility_types::{ToolData, ToolType}; use glam::{DAffine2, DVec2}; @@ -192,9 +192,7 @@ impl MessageHandler> for TransformLayer *selected.original_transforms = OriginalTransforms::default(); let viewspace = document.metadata().transform_to_viewport(selected_layers[0]); - let selected_segments = shape_editor.selected_segments().collect::>(); - let mut affected_points = shape_editor.selected_points().copied().collect::>(); for (segment_id, _, start, end) in vector_data.segment_bezier_iter() { From 0c9bd2e8cec595b1aa534696648f7c3b4c6d4179 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 5 Jul 2025 14:25:54 +0530 Subject: [PATCH 36/54] add: active origins --- .../messages/tool/tool_messages/path_tool.rs | 6 +++ .../transform_layer_message_handler.rs | 37 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index eb3079e1e8..459baeab54 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -560,6 +560,7 @@ impl PathToolData { fn update_selection_status(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler) { let selection_status = get_selection_status(&document.network_interface, shape_editor); + // debug!("{:?}", selection_status); self.can_toggle_colinearity = match &selection_status { SelectionStatus::None => false, @@ -602,6 +603,8 @@ impl PathToolData { let old_selection = shape_editor.selected_points().cloned().collect::>(); + debug!("{old_selection:?}"); + // Check if the point is already selected; if not, select the first point within the threshold (in pixels) // Don't select the points which are not shown currently in PathOverlayMode if let Some((already_selected, mut selection_info)) = shape_editor.get_point_selection_state( @@ -1382,6 +1385,9 @@ impl Fsm for PathToolFsmState { update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options); let ToolMessage::Path(event) = event else { return self }; + if !matches!(event, PathToolMessage::Overlays(_) | PathToolMessage::UpdateSelectedPointsStatus { .. }) { + // debug!("{event:?}"); + } match (self, event) { (_, PathToolMessage::SelectionChanged) => { // Set the newly targeted layers to visible diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 980d873571..2e1c111b68 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -5,7 +5,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye use crate::messages::portfolio::document::utility_types::misc::PTZ; use crate::messages::portfolio::document::utility_types::transformation::{Axis, OriginalTransforms, Selected, TransformOperation, TransformType, Typing}; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::pivot::Dot; +use crate::messages::tool::common_functionality::pivot::{Dot, DotType}; use crate::messages::tool::common_functionality::shape_editor::ShapeState; use crate::messages::tool::tool_messages::tool_prelude::Key; use crate::messages::tool::utility_types::{ToolData, ToolType}; @@ -63,13 +63,31 @@ impl TransformLayerMessageHandler { } } -fn calculate_pivot(selected_points: &Vec<&ManipulatorPointId>, vector_data: &VectorData, viewspace: DAffine2, get_location: impl Fn(&ManipulatorPointId) -> Option) -> Option<(DVec2, DVec2)> { +fn calculate_pivot( + selected_points: &Vec<&ManipulatorPointId>, + vector_data: &VectorData, + viewspace: DAffine2, + get_location: impl Fn(&ManipulatorPointId) -> Option, + dot: &Dot, +) -> Option<(DVec2, DVec2)> { + let average_position = || { + let mut point_count = 0; + selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64 + }; + let position = || { + if !dot.state.enabled { + return average_position(); + } + match dot.state.dot { + DotType::Average => average_position(), + DotType::Active => selected_points.first().map(|p| get_location(p)).flatten().unwrap_or_else(average_position), + DotType::Pivot => average_position(), + } + }; let [point] = selected_points.as_slice() else { // Handle the case where there are multiple points - let mut point_count = 0; - let average_position = selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64; - - return Some((average_position, average_position)); + let position = position(); + return Some((position, position)); }; match point { @@ -81,9 +99,8 @@ fn calculate_pivot(selected_points: &Vec<&ManipulatorPointId>, vector_data: &Vec } _ => { // Calculate the average position of all selected points - let mut point_count = 0; - let average_position = selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64; - Some((average_position, average_position)) + let position = position(); + Some((position, position)) } } } @@ -205,7 +222,7 @@ impl MessageHandler> for TransformLayer let affected_point_refs = affected_points.iter().collect(); let get_location = |point: &&ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position)); - if let Some((new_pivot, grab_target)) = calculate_pivot(&affected_point_refs, &vector_data, viewspace, |point: &ManipulatorPointId| get_location(&point)) { + if let Some((new_pivot, grab_target)) = calculate_pivot(&affected_point_refs, &vector_data, viewspace, |point: &ManipulatorPointId| get_location(&point), &self.dot) { *selected.pivot = new_pivot; self.local_pivot = document_to_viewport.inverse().transform_point2(*selected.pivot); From 06e8e4e6e04a7cfcda2dfea7b0e9e2b9842bcb15 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 5 Jul 2025 22:16:28 -0700 Subject: [PATCH 37/54] UI tweaks --- editor/src/consts.rs | 2 +- .../portfolio/document/overlays/utility_types.rs | 7 ++++--- .../src/messages/tool/common_functionality/pivot.rs | 12 ++++++------ .../src/messages/tool/tool_messages/select_tool.rs | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/editor/src/consts.rs b/editor/src/consts.rs index 94299addd6..5ce971a2a3 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -61,7 +61,7 @@ pub const SELECTION_DRAG_ANGLE: f64 = 90.; pub const PIVOT_CROSSHAIR_THICKNESS: f64 = 1.; pub const PIVOT_CROSSHAIR_LENGTH: f64 = 9.; pub const PIVOT_DIAMETER: f64 = 5.; -pub const DOWEL_PIN_RADIUS: f64 = 5.; +pub const DOWEL_PIN_RADIUS: f64 = 4.; // COMPASS ROSE pub const COMPASS_ROSE_RING_INNER_DIAMETER: f64 = 13.; diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 916589744f..0aa3632c53 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,7 +1,8 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ - COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, - COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_ORANGE, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, + COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, + PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, }; use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; @@ -560,7 +561,7 @@ impl OverlayContext { pub fn dowel_pin(&mut self, position: DVec2, color: Option<&str>) { let (x, y) = (position.round() - DVec2::splat(0.5)).into(); - let color = color.unwrap_or(COLOR_OVERLAY_YELLOW); + let color = color.unwrap_or(COLOR_OVERLAY_ORANGE); self.start_dpi_aware_transform(); diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 80cc12685e..3f657bcb71 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -5,8 +5,8 @@ use crate::messages::portfolio::document::overlays::utility_types::OverlayContex use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::graph_modification_utils; -use crate::messages::tool::tool_messages::select_tool::SelectOptionsUpdate; use crate::messages::tool::tool_messages::path_tool::PathOptionsUpdate; +use crate::messages::tool::tool_messages::select_tool::SelectOptionsUpdate; use crate::messages::tool::tool_messages::tool_prelude::*; use glam::{DAffine2, DVec2}; use graphene_std::transform::ReferencePoint; @@ -105,7 +105,6 @@ impl Dot { pub fn pin_inactive(&self) -> bool { !self.pivot.pinned || !self.state.is_pivot() } - } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] @@ -114,9 +113,9 @@ pub enum DotType { #[default] Pivot, // Origin - // Indidual, Average, Active, + // TODO: Add "Individual" } #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] @@ -147,9 +146,10 @@ impl DotState { impl fmt::Display for DotType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - DotType::Pivot => write!(f, "Draft Pivot"), - DotType::Average => write!(f, "Average of Origins"), - DotType::Active => write!(f, "Active Object Origin"), + DotType::Pivot => write!(f, "Custom Pivot"), + DotType::Average => write!(f, "Origin (Average Point)"), + DotType::Active => write!(f, "Origin (Active Object)"), + // TODO: Add "Origin (Individual)" } } } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 1d17b56446..304296b7ea 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -200,12 +200,12 @@ impl LayoutHolder for SelectTool { // Select mode (Deep/Shallow) widgets.push(self.deep_selection_widget()); - // Dot Type (Pivot/Origin/Off) + // Dot Type (checkbox + dropdown for pivot/origin) widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); widgets.extend(dot_type_widget(self.tool_data.dot.state, Source::Select)); - // Pivot - widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); + // Reference point 9-box widget + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); widgets.push(pivot_reference_point_widget( self.tool_data.selected_layers_count == 0 || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), @@ -777,7 +777,7 @@ impl Fsm for SelectToolFsmState { } } if let Some(origin) = active_origin { - overlay_context.dowel_pin(origin, Some(COLOR_OVERLAY_ORANGE)); + overlay_context.dowel_pin(origin, Some(COLOR_OVERLAY_YELLOW)); } let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot(); From 7d46c7dcfdb219bf9700fa305baddcad2c4252fd Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 6 Jul 2025 10:29:21 +0530 Subject: [PATCH 38/54] add: add all of the stuff for path tool --- .../tool/common_functionality/pivot.rs | 20 +- .../messages/tool/tool_messages/path_tool.rs | 13 +- .../tool/tool_messages/select_tool.rs | 8 +- .../transform_layer_message_handler.rs | 264 ++++++++++-------- 4 files changed, 181 insertions(+), 124 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 3f657bcb71..14d24cf053 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -9,7 +9,7 @@ use crate::messages::tool::tool_messages::path_tool::PathOptionsUpdate; use crate::messages::tool::tool_messages::select_tool::SelectOptionsUpdate; use crate::messages::tool::tool_messages::tool_prelude::*; use glam::{DAffine2, DVec2}; -use graphene_std::transform::ReferencePoint; +use graphene_std::{transform::ReferencePoint, vector::ManipulatorPointId}; use std::fmt; pub fn pin_pivot_widget(disabled: bool, source: Source) -> WidgetHolder { @@ -79,6 +79,7 @@ pub struct Dot { pub pivot: Pivot, pub state: DotState, pub layer: Option, + pub point: Option, } impl Dot { @@ -223,6 +224,23 @@ impl Pivot { self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } + pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, bounds: Option<[DVec2; 2]>) { + if !self.active { + return; + } + + let selected = document.network_interface.selected_nodes(); + if !selected.has_selected_nodes() { + self.normalized_pivot = DVec2::splat(0.5); + self.pivot = None; + return; + }; + + let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]); + self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + } + pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>, draw: bool) { if !overlay_context.visibility_settings.pivot() { self.active = false; diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index a64b0eea4c..17996e8f38 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -500,6 +500,7 @@ struct PathToolData { dragging_state: DraggingState, angle: f64, dot: Dot, + ordered_points: Vec, opposite_handle_position: Option, last_clicked_point_was_selected: bool, last_clicked_segment_was_selected: bool, @@ -1377,6 +1378,12 @@ impl PathToolData { fn get_as_dot(&self) -> Dot { self.dot.clone() } + + fn sync_history(&mut self, points: &Vec) { + self.ordered_points.retain(|layer| points.contains(layer)); + self.ordered_points.extend(points.iter().find(|&layer| !self.ordered_points.contains(layer))); + self.dot.point = self.ordered_points.last().map(|x| *x) + } } impl Fsm for PathToolFsmState { @@ -1389,9 +1396,6 @@ impl Fsm for PathToolFsmState { update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options); let ToolMessage::Path(event) = event else { return self }; - if !matches!(event, PathToolMessage::Overlays(_) | PathToolMessage::UpdateSelectedPointsStatus { .. }) { - // debug!("{event:?}"); - } match (self, event) { (_, PathToolMessage::SelectionChanged) => { // Set the newly targeted layers to visible @@ -1408,6 +1412,9 @@ impl Fsm for PathToolFsmState { shape_editor.update_selected_anchors_status(display_anchors); shape_editor.update_selected_handles_status(display_handles); + let new_points = shape_editor.selected_points().copied().collect::>(); + tool_data.sync_history(&new_points); + self } (_, PathToolMessage::Overlays(mut overlay_context)) => { diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 304296b7ea..caf7b7c06a 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -361,7 +361,7 @@ struct SelectToolData { lasso_polygon: Vec, selection_mode: Option, layers_dragging: Vec, // Unordered, often used as temporary buffer - orderer_layers: Vec, // Ordered list of layers + ordered_layers: Vec, // Ordered list of layers layer_selected_on_start: Option, select_single_layer: Option, axis_align: bool, @@ -548,9 +548,9 @@ impl SelectToolData { } fn sync_history(&mut self) { - self.orderer_layers.retain(|layer| self.layers_dragging.contains(layer)); - self.orderer_layers.extend(self.layers_dragging.iter().find(|&layer| !self.orderer_layers.contains(layer))); - self.dot.layer = self.orderer_layers.last().map(|x| *x) + self.ordered_layers.retain(|layer| self.layers_dragging.contains(layer)); + self.ordered_layers.extend(self.layers_dragging.iter().find(|&layer| !self.ordered_layers.contains(layer))); + self.dot.layer = self.ordered_layers.last().map(|x| *x) } } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 1bb548d1fd..387fc1ca76 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -38,6 +38,8 @@ pub struct TransformLayerMessageHandler { dot: Dot, pivot: ViewportPosition, + path_bounds: Option<[DVec2; 2]>, + local_pivot: DocumentPosition, local_mouse_start: DocumentPosition, grab_target: DocumentPosition, @@ -64,43 +66,66 @@ impl TransformLayerMessageHandler { } fn calculate_pivot( + document: &DocumentMessageHandler, selected_points: &Vec<&ManipulatorPointId>, vector_data: &VectorData, viewspace: DAffine2, get_location: impl Fn(&ManipulatorPointId) -> Option, - dot: &Dot, -) -> Option<(DVec2, DVec2)> { + dot: &mut Dot, + layers: LayerNodeIdentifier, +) -> (Option<(DVec2, DVec2)>, Option<[DVec2; 2]>) { let average_position = || { let mut point_count = 0; selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64 }; - let position = || { - if !dot.state.enabled { - return average_position(); + let bounds = selected_points.iter().filter_map(|p| get_location(p)).fold(None, |acc: Option<[DVec2; 2]>, point| { + if let Some([mut min, mut max]) = acc { + min.x = min.x.min(point.x); + min.y = min.y.min(point.y); + max.x = max.x.max(point.x); + max.y = max.y.max(point.y); + Some([min, max]) + } else { + Some([point, point]) } - match dot.state.dot { - DotType::Average => average_position(), - DotType::Active => selected_points.first().map(|p| get_location(p)).flatten().unwrap_or_else(average_position), - DotType::Pivot => average_position(), + }); + dot.pivot.recalculate_pivot_for_layer(document, layers, bounds); + let position = || { + { + if dot.state.enabled { + match dot.state.dot { + DotType::Average => None, + DotType::Active => dot.point.and_then(|p| get_location(&p)), + DotType::Pivot => dot.pivot.position(), + } + } else { + None + } } + .unwrap_or_else(average_position) }; let [point] = selected_points.as_slice() else { // Handle the case where there are multiple points let position = position(); - return Some((position, position)); + return (Some((position, position)), bounds); }; match point { ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => { // Get the anchor position and transform it to the pivot - let pivot_pos = point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position))?; - let target = viewspace.transform_point2(point.get_position(vector_data)?); - Some((pivot_pos, target)) + let (Some(pivot_pos), Some(position)) = ( + point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position)), + point.get_position(vector_data), + ) else { + return (None, None); + }; + let target = viewspace.transform_point2(position); + (Some((pivot_pos, target)), None) } _ => { // Calculate the average position of all selected points let position = position(); - Some((position, position)) + (Some((position, position)), bounds) } } } @@ -222,8 +247,17 @@ impl MessageHandler> for TransformLayer let affected_point_refs = affected_points.iter().collect(); let get_location = |point: &&ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position)); - if let Some((new_pivot, grab_target)) = calculate_pivot(&affected_point_refs, &vector_data, viewspace, |point: &ManipulatorPointId| get_location(&point), &self.dot) { + if let (Some((new_pivot, grab_target)), bounds) = calculate_pivot( + document, + &affected_point_refs, + &vector_data, + viewspace, + |point: &ManipulatorPointId| get_location(&point), + &mut self.dot, + selected_layers[0], + ) { *selected.pivot = new_pivot; + self.path_bounds = bounds; self.local_pivot = document_to_viewport.inverse().transform_point2(*selected.pivot); self.grab_target = document_to_viewport.inverse().transform_point2(grab_target); @@ -249,118 +283,116 @@ impl MessageHandler> for TransformLayer return; } - for layer in document.metadata().all_layers() { - if !document.network_interface.is_artboard(&layer.to_node(), &[]) { - continue; - }; + let viewport_box = input.viewport_bounds.size(); + let axis_constraint = self.transform_operation.axis_constraint(); - let viewport_box = input.viewport_bounds.size(); - let axis_constraint = self.transform_operation.axis_constraint(); + let format_rounded = |value: f64, precision: usize| { + if self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() { + format!("{:.*}", precision, value).trim_end_matches('0').trim_end_matches('.').to_string() + } else { + self.typing.string.clone() + } + }; - let format_rounded = |value: f64, precision: usize| { - if self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() { - format!("{:.*}", precision, value).trim_end_matches('0').trim_end_matches('.').to_string() - } else { - self.typing.string.clone() + // TODO: Ensure removing this and adding this doesn't change the position of layers under PTZ ops + // responses.add(TransformLayerMessage::PointerMove { + // slow_key: SLOW_KEY, + // increments_key: INCREMENTS_KEY, + // }); + + match self.transform_operation { + TransformOperation::None => (), + TransformOperation::Grabbing(translation) => { + let translation = translation.to_dvec(self.initial_transform, self.increments); + let viewport_translate = document_to_viewport.transform_vector2(translation); + let pivot = document_to_viewport.transform_point2(self.grab_target); + let quad = Quad::from_box([pivot, pivot + viewport_translate]).0; + let e1 = (self.layer_bounding_box.0[1] - self.layer_bounding_box.0[0]).normalize_or(DVec2::X); + + if matches!(axis_constraint, Axis::Both | Axis::X) && translation.x != 0. { + let end = if self.local { (quad[1] - quad[0]).rotate(e1) + quad[0] } else { quad[1] }; + overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); + + let x_transform = DAffine2::from_translation((quad[0] + end) / 2.); + overlay_context.text(&format_rounded(translation.x, 3), COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]); } - }; - - // TODO: Ensure removing this and adding this doesn't change the position of layers under PTZ ops - // responses.add(TransformLayerMessage::PointerMove { - // slow_key: SLOW_KEY, - // increments_key: INCREMENTS_KEY, - // }); - - match self.transform_operation { - TransformOperation::None => (), - TransformOperation::Grabbing(translation) => { - let translation = translation.to_dvec(self.initial_transform, self.increments); - let viewport_translate = document_to_viewport.transform_vector2(translation); - let pivot = document_to_viewport.transform_point2(self.grab_target); - let quad = Quad::from_box([pivot, pivot + viewport_translate]).0; - let e1 = (self.layer_bounding_box.0[1] - self.layer_bounding_box.0[0]).normalize_or(DVec2::X); - - if matches!(axis_constraint, Axis::Both | Axis::X) && translation.x != 0. { - let end = if self.local { (quad[1] - quad[0]).rotate(e1) + quad[0] } else { quad[1] }; - overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); - - let x_transform = DAffine2::from_translation((quad[0] + end) / 2.); - overlay_context.text(&format_rounded(translation.x, 3), COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]); - } - - if matches!(axis_constraint, Axis::Both | Axis::Y) && translation.y != 0. { - let end = if self.local { (quad[3] - quad[0]).rotate(e1) + quad[0] } else { quad[3] }; - overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); - let x_parameter = viewport_translate.x.clamp(-1., 1.); - let y_transform = DAffine2::from_translation((quad[0] + end) / 2. + x_parameter * DVec2::X * 0.); - let pivot_selection = if x_parameter >= -1e-3 { Pivot::Start } else { Pivot::End }; - if axis_constraint != Axis::Both || self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() { - overlay_context.text(&format_rounded(translation.y, 2), COLOR_OVERLAY_BLUE, None, y_transform, 3., [pivot_selection, Pivot::Middle]); - } - } - if matches!(axis_constraint, Axis::Both) && translation.x != 0. && translation.y != 0. { - overlay_context.line(quad[1], quad[2], None, None); - overlay_context.line(quad[3], quad[2], None, None); + if matches!(axis_constraint, Axis::Both | Axis::Y) && translation.y != 0. { + let end = if self.local { (quad[3] - quad[0]).rotate(e1) + quad[0] } else { quad[3] }; + overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); + let x_parameter = viewport_translate.x.clamp(-1., 1.); + let y_transform = DAffine2::from_translation((quad[0] + end) / 2. + x_parameter * DVec2::X * 0.); + let pivot_selection = if x_parameter >= -1e-3 { Pivot::Start } else { Pivot::End }; + if axis_constraint != Axis::Both || self.typing.digits.is_empty() || !self.transform_operation.can_begin_typing() { + overlay_context.text(&format_rounded(translation.y, 2), COLOR_OVERLAY_BLUE, None, y_transform, 3., [pivot_selection, Pivot::Middle]); } } - TransformOperation::Scaling(scale) => { - let scale = scale.to_f64(self.increments); - let text = format!("{}x", format_rounded(scale, 3)); - let pivot = document_to_viewport.transform_point2(self.local_pivot); - let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start); - let local_edge = start_mouse - pivot; - let local_edge = project_edge_to_quad(local_edge, &self.layer_bounding_box, self.local, axis_constraint); - let boundary_point = pivot + local_edge * scale.min(1.); - let end_point = pivot + local_edge * scale.max(1.); - - if scale > 0. { - overlay_context.dashed_line(pivot, boundary_point, None, None, Some(2.), Some(2.), Some(0.5)); - } - overlay_context.line(boundary_point, end_point, None, None); - let transform = DAffine2::from_translation(boundary_point.midpoint(pivot) + local_edge.perp().normalize_or(DVec2::X) * local_edge.element_product().signum() * 24.); - overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]); + if matches!(axis_constraint, Axis::Both) && translation.x != 0. && translation.y != 0. { + overlay_context.line(quad[1], quad[2], None, None); + overlay_context.line(quad[3], quad[2], None, None); } - TransformOperation::Rotating(rotation) => { - let angle = rotation.to_f64(self.increments); - let pivot = document_to_viewport.transform_point2(self.local_pivot); - let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start); - let offset_angle = if self.grs_pen_handle { - self.handle - self.last_point - } else if using_path_tool { - start_mouse - pivot - } else { - self.layer_bounding_box.top_right() - self.layer_bounding_box.top_right() - }; - let tilt_offset = document.document_ptz.unmodified_tilt(); - let offset_angle = offset_angle.to_angle() + tilt_offset; - let width = viewport_box.max_element(); - let radius = start_mouse.distance(pivot); - let arc_radius = ANGLE_MEASURE_RADIUS_FACTOR * width; - let radius = radius.clamp(ARC_MEASURE_RADIUS_FACTOR_RANGE.0 * width, ARC_MEASURE_RADIUS_FACTOR_RANGE.1 * width); - let angle_in_degrees = angle.to_degrees(); - let display_angle = if angle_in_degrees.is_sign_positive() { - angle_in_degrees - (angle_in_degrees / 360.).floor() * 360. - } else if angle_in_degrees.is_sign_negative() { - angle_in_degrees - ((angle_in_degrees / 360.).floor() + 1.) * 360. - } else { - angle_in_degrees - }; - let text = format!("{}°", format_rounded(display_angle, 2)); - let text_texture_width = overlay_context.get_width(&text) / 2.; - let text_texture_height = 12.; - let text_angle_on_unit_circle = DVec2::from_angle((angle % TAU) / 2. + offset_angle); - let text_texture_position = DVec2::new( - (arc_radius + 4. + text_texture_width) * text_angle_on_unit_circle.x, - (arc_radius + text_texture_height) * text_angle_on_unit_circle.y, - ); - let transform = DAffine2::from_translation(text_texture_position + pivot); - overlay_context.draw_angle(pivot, radius, arc_radius, offset_angle, angle); - overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]); + } + TransformOperation::Scaling(scale) => { + let scale = scale.to_f64(self.increments); + let text = format!("{}x", format_rounded(scale, 3)); + let pivot = document_to_viewport.transform_point2(self.local_pivot); + let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start); + let local_edge = start_mouse - pivot; + let local_edge = project_edge_to_quad(local_edge, &self.layer_bounding_box, self.local, axis_constraint); + let boundary_point = pivot + local_edge * scale.min(1.); + let end_point = pivot + local_edge * scale.max(1.); + + if scale > 0. { + overlay_context.dashed_line(pivot, boundary_point, None, None, Some(2.), Some(2.), Some(0.5)); } + overlay_context.line(boundary_point, end_point, None, None); + + let transform = DAffine2::from_translation(boundary_point.midpoint(pivot) + local_edge.perp().normalize_or(DVec2::X) * local_edge.element_product().signum() * 24.); + overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]); + } + TransformOperation::Rotating(rotation) => { + let angle = rotation.to_f64(self.increments); + let pivot = document_to_viewport.transform_point2(self.local_pivot); + let start_mouse = document_to_viewport.transform_point2(self.local_mouse_start); + let offset_angle = if self.grs_pen_handle { + self.handle - self.last_point + } else if using_path_tool { + start_mouse - pivot + } else { + self.layer_bounding_box.top_right() - self.layer_bounding_box.top_right() + }; + let tilt_offset = document.document_ptz.unmodified_tilt(); + let offset_angle = offset_angle.to_angle() + tilt_offset; + let width = viewport_box.max_element(); + let radius = start_mouse.distance(pivot); + let arc_radius = ANGLE_MEASURE_RADIUS_FACTOR * width; + let radius = radius.clamp(ARC_MEASURE_RADIUS_FACTOR_RANGE.0 * width, ARC_MEASURE_RADIUS_FACTOR_RANGE.1 * width); + let angle_in_degrees = angle.to_degrees(); + let display_angle = if angle_in_degrees.is_sign_positive() { + angle_in_degrees - (angle_in_degrees / 360.).floor() * 360. + } else if angle_in_degrees.is_sign_negative() { + angle_in_degrees - ((angle_in_degrees / 360.).floor() + 1.) * 360. + } else { + angle_in_degrees + }; + let text = format!("{}°", format_rounded(display_angle, 2)); + let text_texture_width = overlay_context.get_width(&text) / 2.; + let text_texture_height = 12.; + let text_angle_on_unit_circle = DVec2::from_angle((angle % TAU) / 2. + offset_angle); + let text_texture_position = DVec2::new( + (arc_radius + 4. + text_texture_width) * text_angle_on_unit_circle.x, + (arc_radius + text_texture_height) * text_angle_on_unit_circle.y, + ); + let transform = DAffine2::from_translation(text_texture_position + pivot); + overlay_context.draw_angle(pivot, radius, arc_radius, offset_angle, angle); + overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]); } } + + if let Some(bounds) = self.path_bounds { + overlay_context.quad(Quad::from_box(bounds), None, None); + } } // Messages From a0115ff54e7d2095b02dbbde4e017a45f843e709 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 6 Jul 2025 10:31:52 +0530 Subject: [PATCH 39/54] remove: unused layer --- editor/src/messages/tool/common_functionality/pivot.rs | 2 +- .../tool/transform_layer/transform_layer_message_handler.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 14d24cf053..1f42d74e27 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -224,7 +224,7 @@ impl Pivot { self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } - pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, bounds: Option<[DVec2; 2]>) { + pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, bounds: Option<[DVec2; 2]>) { if !self.active { return; } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 387fc1ca76..cefcf422cb 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -72,7 +72,6 @@ fn calculate_pivot( viewspace: DAffine2, get_location: impl Fn(&ManipulatorPointId) -> Option, dot: &mut Dot, - layers: LayerNodeIdentifier, ) -> (Option<(DVec2, DVec2)>, Option<[DVec2; 2]>) { let average_position = || { let mut point_count = 0; @@ -89,7 +88,7 @@ fn calculate_pivot( Some([point, point]) } }); - dot.pivot.recalculate_pivot_for_layer(document, layers, bounds); + dot.pivot.recalculate_pivot_for_layer(document, bounds); let position = || { { if dot.state.enabled { @@ -254,7 +253,6 @@ impl MessageHandler> for TransformLayer viewspace, |point: &ManipulatorPointId| get_location(&point), &mut self.dot, - selected_layers[0], ) { *selected.pivot = new_pivot; self.path_bounds = bounds; From ba31408f87594e2d6ca20e20dd59e88056603c3c Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 6 Jul 2025 12:30:57 +0530 Subject: [PATCH 40/54] fix: pivot pinning and origin angle --- .../document/overlays/utility_types.rs | 13 +++--- .../tool/common_functionality/pivot.rs | 11 +++-- .../messages/tool/tool_messages/path_tool.rs | 29 ++++++------ .../tool/tool_messages/select_tool.rs | 45 ++++++++++++++++--- .../transform_layer_message_handler.rs | 4 +- 5 files changed, 70 insertions(+), 32 deletions(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 0aa3632c53..ea8f89f4b4 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,8 +1,7 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ - COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_ORANGE, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, - COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, - PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, + COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, }; use crate::messages::prelude::Message; use bezier_rs::{Bezier, Subpath}; @@ -559,9 +558,9 @@ impl OverlayContext { self.end_dpi_aware_transform(); } - pub fn dowel_pin(&mut self, position: DVec2, color: Option<&str>) { + pub fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) { let (x, y) = (position.round() - DVec2::splat(0.5)).into(); - let color = color.unwrap_or(COLOR_OVERLAY_ORANGE); + let color = color.unwrap_or(COLOR_OVERLAY_YELLOW); self.start_dpi_aware_transform(); @@ -577,11 +576,11 @@ impl OverlayContext { self.render_context.begin_path(); // Top-left sector self.render_context.move_to(x, y); - self.render_context.arc(x, y, DOWEL_PIN_RADIUS, FRAC_PI_2, PI).expect("Failed to draw arc"); + self.render_context.arc(x, y, DOWEL_PIN_RADIUS, FRAC_PI_2 + angle, PI + angle).expect("Failed to draw arc"); self.render_context.close_path(); // Bottom-right sector self.render_context.move_to(x, y); - self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2, TAU).expect("Failed to draw arc"); + self.render_context.arc(x, y, DOWEL_PIN_RADIUS, PI + FRAC_PI_2 + angle, TAU + angle).expect("Failed to draw arc"); self.render_context.close_path(); self.render_context.set_fill_style_str(color); self.render_context.fill(); diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 1f42d74e27..368e96980d 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -171,6 +171,8 @@ pub struct Pivot { active: bool, /// Used to enable and disable the pivot pub pinned: bool, + /// Had selected_visible_and_unlocked_layers + pub empty: bool, } impl Default for Pivot { @@ -183,6 +185,7 @@ impl Default for Pivot { last_non_none_reference: ReferencePoint::Center, active: true, pinned: false, + empty: true, } } } @@ -195,9 +198,9 @@ impl Pivot { } let selected = document.network_interface.selected_nodes(); + + self.empty = !selected.has_selected_nodes(); if !selected.has_selected_nodes() { - self.normalized_pivot = DVec2::splat(0.5); - self.pivot = None; return; }; @@ -221,7 +224,9 @@ impl Pivot { let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]); self.transform_from_normalized = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + if self.old_pivot_position != ReferencePoint::None { + self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); + } } pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, bounds: Option<[DVec2; 2]>) { diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 17996e8f38..2622ba989b 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -263,15 +263,15 @@ impl LayoutHolder for PathTool { .selected_index(Some(self.options.path_overlay_mode as u32)) .widget_holder(); - let [checkbox, dropdown] = { + let [_checkbox, _dropdown] = { let dot_widget = dot_type_widget(self.tool_data.dot.state, Source::Path); - [dot_widget.get(0).unwrap().clone(), dot_widget.get(2).unwrap().clone()] + [dot_widget[0].clone(), dot_widget[2].clone()] }; let has_somrthing = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty(); - let pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path); + let _pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path); - let pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Path); + let _pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Path); Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: vec![ @@ -289,13 +289,13 @@ impl LayoutHolder for PathTool { unrelated_seperator.clone(), path_overlay_mode_widget, unrelated_seperator.clone(), - checkbox.clone(), - related_seperator.clone(), - dropdown.clone(), - unrelated_seperator, - pivot_reference, - related_seperator.clone(), - pin_pivot, + // checkbox.clone(), + // related_seperator.clone(), + // dropdown.clone(), + // unrelated_seperator, + // pivot_reference, + // related_seperator.clone(), + // pin_pivot, ], }])) } @@ -566,7 +566,6 @@ impl PathToolData { fn update_selection_status(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler) { let selection_status = get_selection_status(&document.network_interface, shape_editor); - // debug!("{:?}", selection_status); self.can_toggle_colinearity = match &selection_status { SelectionStatus::None => false, @@ -610,8 +609,6 @@ impl PathToolData { let old_selection = shape_editor.selected_points().cloned().collect::>(); - debug!("{old_selection:?}"); - // Check if the point is already selected; if not, select the first point within the threshold (in pixels) // Don't select the points which are not shown currently in PathOverlayMode if let Some((already_selected, mut selection_info)) = shape_editor.get_point_selection_state( @@ -1396,6 +1393,10 @@ impl Fsm for PathToolFsmState { update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options); let ToolMessage::Path(event) = event else { return self }; + + // TODO(mTvare6): Remove it once dots are implemented for path_tool + tool_data.dot.state.enabled = false; + match (self, event) { (_, PathToolMessage::SelectionChanged) => { // Set the newly targeted layers to visible diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index caf7b7c06a..08999fe73b 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -538,7 +538,7 @@ impl SelectToolData { fn state_from_dot(&self, mouse: DVec2) -> Option { match self.dot.state.dot { - DotType::Pivot if !self.dot.pivot.pinned => self.dot.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), + DotType::Pivot => self.dot.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), _ => None, } } @@ -766,21 +766,52 @@ impl Fsm for SelectToolFsmState { }); let mut active_origin = None; + let mut origin_angle = 0.; if overlay_context.visibility_settings.origin() && !tool_data.dot.state.is_pivot_type() { + let get_angle = |layer: LayerNodeIdentifier| -> f64 { + let quad = Quad::from_box([DVec2::ZERO, DVec2::ONE]); + let bounds = document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface) * quad; + (bounds.top_left() - bounds.top_right()).to_angle() + }; + if tool_data.dot.state.dot == DotType::Average { + let mut count = 0; + + let sum: f64 = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .map(get_angle) + .inspect(|_| count += 1) + .sum(); + if count > 0 { + origin_angle = sum / count as f64; + } + } else if tool_data.dot.state.dot == DotType::Active { + origin_angle = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .find(|&layer| Some(layer) == tool_data.dot.layer) + .iter() + .map(|&layer| get_angle(layer)) + .sum(); + } + for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); if Some(layer) == tool_data.dot.layer { active_origin = Some(origin); continue; } - overlay_context.dowel_pin(origin, None); + overlay_context.dowel_pin(origin, origin_angle, None); } } if let Some(origin) = active_origin { - overlay_context.dowel_pin(origin, Some(COLOR_OVERLAY_YELLOW)); + overlay_context.dowel_pin(origin, origin_angle, Some(COLOR_OVERLAY_ORANGE)); } - let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot(); + let has_layers = document.network_interface.selected_nodes().has_selected_nodes(); + let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot() && has_layers; tool_data.dot.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot); // Update compass rose @@ -1009,8 +1040,10 @@ impl Fsm for SelectToolFsmState { let extend = input.keyboard.key(extend_selection); if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); - let position = tool_data.dot.pivot.last_non_none_reference; - responses.add(SelectToolMessage::SetPivot { position }); + if !tool_data.dot.pivot.pinned { + let position = tool_data.dot.pivot.last_non_none_reference; + responses.add(SelectToolMessage::SetPivot { position }); + } tool_data.layers_dragging.clear(); } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index cefcf422cb..061890816c 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -388,8 +388,8 @@ impl MessageHandler> for TransformLayer } } - if let Some(bounds) = self.path_bounds { - overlay_context.quad(Quad::from_box(bounds), None, None); + if let Some(_) = self.path_bounds { + // overlay_context.quad(Quad::from_box(bounds), None, None); } } From 74aa907ae4c782a72568c83e45c2649b3db4ddee Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 6 Jul 2025 14:32:11 +0530 Subject: [PATCH 41/54] fix: pin only if moved in first place --- editor/src/consts.rs | 1 - .../document/overlays/utility_types.rs | 18 +++++++----------- .../tool/common_functionality/pivot.rs | 11 ++++++----- .../messages/tool/tool_messages/path_tool.rs | 2 +- .../messages/tool/tool_messages/select_tool.rs | 6 ++++-- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/editor/src/consts.rs b/editor/src/consts.rs index 5ce971a2a3..ce079f830a 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -134,7 +134,6 @@ pub const SCALE_EFFECT: f64 = 0.5; // COLORS pub const COLOR_OVERLAY_BLUE: &str = "#00a8ff"; -pub const COLOR_OVERLAY_BLUE_50: &str = "rgba(0, 168, 255, 0.5)"; pub const COLOR_OVERLAY_YELLOW: &str = "#ffc848"; pub const COLOR_OVERLAY_GREEN: &str = "#63ce63"; pub const COLOR_OVERLAY_RED: &str = "#ef5454"; diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index ea8f89f4b4..dd2500c7f0 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,6 +1,6 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ - COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_ORANGE, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, }; use crate::messages::prelude::Message; @@ -431,10 +431,7 @@ impl OverlayContext { pub fn draw_scale(&mut self, start: DVec2, scale: f64, radius: f64, text: &str) { let sign = scale.signum(); - let mut fill_color = graphene_std::Color::from_rgb_str(crate::consts::COLOR_OVERLAY_WHITE.strip_prefix('#').unwrap()) - .unwrap() - .with_alpha(0.05) - .to_rgba_hex_srgb(); + let mut fill_color = Color::from_rgb_str(COLOR_OVERLAY_WHITE.strip_prefix('#').unwrap()).unwrap().with_alpha(0.05).to_rgba_hex_srgb(); fill_color.insert(0, '#'); let fill_color = Some(fill_color.as_str()); self.line(start + DVec2::X * radius * sign, start + DVec2::X * (radius * scale), None, None); @@ -471,10 +468,7 @@ impl OverlayContext { // Hover ring if show_hover_ring { - let mut fill_color = graphene_std::Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) - .unwrap() - .with_alpha(0.5) - .to_rgba_hex_srgb(); + let mut fill_color = Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()).unwrap().with_alpha(0.5).to_rgba_hex_srgb(); fill_color.insert(0, '#'); self.render_context.set_line_width(HOVER_RING_STROKE_WIDTH); @@ -560,7 +554,7 @@ impl OverlayContext { pub fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) { let (x, y) = (position.round() - DVec2::splat(0.5)).into(); - let color = color.unwrap_or(COLOR_OVERLAY_YELLOW); + let color = color.unwrap_or(COLOR_OVERLAY_ORANGE); self.start_dpi_aware_transform(); @@ -637,9 +631,11 @@ impl OverlayContext { pub fn outline_overlay_bezier(&mut self, bezier: Bezier, transform: DAffine2) { self.start_dpi_aware_transform(); + let color = Color::from_rgb_str(COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()).unwrap().with_alpha(0.05).to_rgba_hex_srgb(); + self.render_context.begin_path(); self.bezier_command(bezier, transform, true); - self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE_50); + self.render_context.set_stroke_style_str(&color); self.render_context.set_line_width(4.); self.render_context.stroke(); diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 368e96980d..f369104379 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -12,12 +12,13 @@ use glam::{DAffine2, DVec2}; use graphene_std::{transform::ReferencePoint, vector::ManipulatorPointId}; use std::fmt; -pub fn pin_pivot_widget(disabled: bool, source: Source) -> WidgetHolder { - IconButton::new(if disabled { "PinInactive" } else { "PinActive" }, 24) - .tooltip(if disabled { "Pin Transform Pivot" } else { "Unpin Transform Pivot" }) +pub fn pin_pivot_widget(inactive: bool, enabled: bool, source: Source) -> WidgetHolder { + IconButton::new(if inactive { "PinInactive" } else { "PinActive" }, 24) + .tooltip(if inactive { "Pin Transform Pivot" } else { "Unpin Transform Pivot" }) .on_update(move |_| match source { - Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), - Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), + Source::Select if enabled => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), + Source::Path if enabled => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), + _ => Message::NoOp }) .widget_holder() } diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index f777900ca9..ccba8649a4 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -271,7 +271,7 @@ impl LayoutHolder for PathTool { let has_somrthing = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty(); let _pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path); - let _pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Path); + let _pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), false, Source::Path); Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: vec![ diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 08999fe73b..46eb9d6a7e 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -214,7 +214,9 @@ impl LayoutHolder for SelectTool { // Pivot pin widgets.push(Separator::new(SeparatorType::Related).widget_holder()); - widgets.push(pin_pivot_widget(self.tool_data.dot.pin_inactive(), Source::Select)); + + let pin_enabled = self.tool_data.dot.pivot.old_pivot_position == ReferencePoint::None; + widgets.push(pin_pivot_widget(self.tool_data.dot.pin_inactive(), pin_enabled, Source::Select)); // Align let disabled = self.tool_data.selected_layers_count < 2; @@ -807,7 +809,7 @@ impl Fsm for SelectToolFsmState { } } if let Some(origin) = active_origin { - overlay_context.dowel_pin(origin, origin_angle, Some(COLOR_OVERLAY_ORANGE)); + overlay_context.dowel_pin(origin, origin_angle, Some(COLOR_OVERLAY_YELLOW)); } let has_layers = document.network_interface.selected_nodes().has_selected_nodes(); From 1ec29743c39a82ac7ce28a5e7023c5bd3ca69e76 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sun, 6 Jul 2025 15:38:57 +0530 Subject: [PATCH 42/54] cargo: fmt --- editor/src/messages/tool/common_functionality/pivot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index f369104379..bdc2cefe96 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -18,7 +18,7 @@ pub fn pin_pivot_widget(inactive: bool, enabled: bool, source: Source) -> Widget .on_update(move |_| match source { Source::Select if enabled => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), Source::Path if enabled => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), - _ => Message::NoOp + _ => Message::NoOp, }) .widget_holder() } From 9a05bbe46db8b05ff9eed0343afe9a9c73346a4a Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 7 Jul 2025 06:30:48 +0530 Subject: [PATCH 43/54] fix: pivot use disabled method --- editor/src/messages/tool/common_functionality/pivot.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index bdc2cefe96..ad9055001d 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -15,6 +15,7 @@ use std::fmt; pub fn pin_pivot_widget(inactive: bool, enabled: bool, source: Source) -> WidgetHolder { IconButton::new(if inactive { "PinInactive" } else { "PinActive" }, 24) .tooltip(if inactive { "Pin Transform Pivot" } else { "Unpin Transform Pivot" }) + .disabled(!enabled) .on_update(move |_| match source { Source::Select if enabled => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), Source::Path if enabled => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), From f392ba9e92db022449dccad107d6896c68ad1f9d Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 7 Jul 2025 06:36:19 +0530 Subject: [PATCH 44/54] fix: remove redudant NoOp --- editor/src/messages/tool/common_functionality/pivot.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index ad9055001d..cde351cd3f 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -17,9 +17,8 @@ pub fn pin_pivot_widget(inactive: bool, enabled: bool, source: Source) -> Widget .tooltip(if inactive { "Pin Transform Pivot" } else { "Unpin Transform Pivot" }) .disabled(!enabled) .on_update(move |_| match source { - Source::Select if enabled => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), - Source::Path if enabled => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), - _ => Message::NoOp, + Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), + Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), }) .widget_holder() } From 154ad8bd4b83fc52cc68b1eb2aa03531570043c4 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 7 Jul 2025 09:27:05 +0530 Subject: [PATCH 45/54] fix: 3 stuff --- .../tool/common_functionality/pivot.rs | 10 +++---- .../messages/tool/tool_messages/path_tool.rs | 2 +- .../tool/tool_messages/select_tool.rs | 26 +++++++++++-------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index cde351cd3f..54db651d3e 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -12,9 +12,9 @@ use glam::{DAffine2, DVec2}; use graphene_std::{transform::ReferencePoint, vector::ManipulatorPointId}; use std::fmt; -pub fn pin_pivot_widget(inactive: bool, enabled: bool, source: Source) -> WidgetHolder { - IconButton::new(if inactive { "PinInactive" } else { "PinActive" }, 24) - .tooltip(if inactive { "Pin Transform Pivot" } else { "Unpin Transform Pivot" }) +pub fn pin_pivot_widget(active: bool, enabled: bool, source: Source) -> WidgetHolder { + IconButton::new(if active { "PinActive" } else { "PinInactive" }, 24) + .tooltip(if active { "Unpin Transform Pivot" } else { "Pin Transform Pivot" }) .disabled(!enabled) .on_update(move |_| match source { Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), @@ -104,8 +104,8 @@ impl Dot { self.pivot.transform_from_normalized } - pub fn pin_inactive(&self) -> bool { - !self.pivot.pinned || !self.state.is_pivot() + pub fn pin_active(&self) -> bool { + self.pivot.pinned && self.state.is_pivot_type() } } diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 6b953c18b5..690b97ff31 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -271,7 +271,7 @@ impl LayoutHolder for PathTool { let has_somrthing = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty(); let _pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path); - let _pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_inactive(), false, Source::Path); + let _pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_active(), false, Source::Path); Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: vec![ diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 46eb9d6a7e..7bf8daf861 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -204,19 +204,22 @@ impl LayoutHolder for SelectTool { widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); widgets.extend(dot_type_widget(self.tool_data.dot.state, Source::Select)); - // Reference point 9-box widget - widgets.push(Separator::new(SeparatorType::Related).widget_holder()); - widgets.push(pivot_reference_point_widget( - self.tool_data.selected_layers_count == 0 || !self.tool_data.dot.state.is_pivot(), - self.tool_data.dot.pivot.to_pivot_position(), - Source::Select, - )); + if self.tool_data.dot.state.is_pivot_type() { + // Reference point 9-box widget + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + widgets.push(pivot_reference_point_widget( + self.tool_data.selected_layers_count == 0 || !self.tool_data.dot.state.is_pivot(), + self.tool_data.dot.pivot.to_pivot_position(), + Source::Select, + )); - // Pivot pin - widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + // Pivot pin + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); - let pin_enabled = self.tool_data.dot.pivot.old_pivot_position == ReferencePoint::None; - widgets.push(pin_pivot_widget(self.tool_data.dot.pin_inactive(), pin_enabled, Source::Select)); + let pin_enabled = self.tool_data.dot.pivot.old_pivot_position == ReferencePoint::None || !self.tool_data.dot.state.enabled; + + widgets.push(pin_pivot_widget(self.tool_data.dot.pin_active(), pin_enabled, Source::Select)); + } // Align let disabled = self.tool_data.selected_layers_count < 2; @@ -1542,6 +1545,7 @@ impl Fsm for SelectToolFsmState { responses.add(DocumentMessage::StartTransaction); tool_data.dot.pivot.last_non_none_reference = position; + tool_data.dot.pivot.pinned = false; let pos: Option = position.into(); tool_data.dot.pivot.set_normalized_position(pos.unwrap()); let dot = tool_data.get_as_dot(); From f976b2d573c438dd49f998eda2c869c31de432c7 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 7 Jul 2025 10:11:41 +0530 Subject: [PATCH 46/54] fix: select from elsewhere --- .../src/messages/tool/tool_message_handler.rs | 5 +++++ .../messages/tool/tool_messages/select_tool.rs | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index 9413495488..e20d0989b1 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -181,6 +181,11 @@ impl MessageHandler> for ToolMessageHandler { send: Box::new(TransformLayerMessage::SelectionChanged.into()), }); + responses.add(BroadcastMessage::SubscribeEvent { + on: BroadcastEvent::SelectionChanged, + send: Box::new(SelectToolMessage::SyncHistory.into()), + }); + self.tool_is_active = true; let tool_data = &mut self.tool_state.tool_data; diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 7bf8daf861..97d634f532 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -99,6 +99,7 @@ pub enum SelectToolMessage { SetPivot { position: ReferencePoint, }, + SyncHistory, } impl ToolMetadata for SelectTool { @@ -552,9 +553,10 @@ impl SelectToolData { self.dot.clone() } - fn sync_history(&mut self) { - self.ordered_layers.retain(|layer| self.layers_dragging.contains(layer)); - self.ordered_layers.extend(self.layers_dragging.iter().find(|&layer| !self.ordered_layers.contains(layer))); + fn sync_history(&mut self, document: &DocumentMessageHandler) { + let layers: Vec<_> = document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect(); + self.ordered_layers.retain(|layer| layers.contains(layer)); + self.ordered_layers.extend(layers.iter().find(|&layer| !self.ordered_layers.contains(layer))); self.dot.layer = self.ordered_layers.last().map(|x| *x) } } @@ -1457,7 +1459,6 @@ impl Fsm for SelectToolFsmState { NestedSelectionBehavior::Deepest => { let filtered_selections = filter_nested_selection(document.metadata(), &new_selected); tool_data.layers_dragging.extend(filtered_selections); - tool_data.sync_history(); } NestedSelectionBehavior::Shallowest => { // Find each new_selected's parent node @@ -1466,7 +1467,6 @@ impl Fsm for SelectToolFsmState { .map(|layer| layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(layer)) .collect(); tool_data.layers_dragging.extend(parent_selected.iter().copied()); - tool_data.sync_history(); } } } @@ -1554,6 +1554,11 @@ impl Fsm for SelectToolFsmState { self } + (_, SelectToolMessage::SyncHistory) => { + tool_data.sync_history(&document); + + self + } _ => self, } } @@ -1724,7 +1729,6 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec } } - tool_data.sync_history(); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: tool_data .layers_dragging @@ -1779,10 +1783,8 @@ fn drag_deepest_manipulation(responses: &mut VecDeque, selected: Vec Date: Mon, 7 Jul 2025 11:36:07 +0530 Subject: [PATCH 47/54] fix: compass rose wobbling around --- .../tool/common_functionality/compass_rose.rs | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/compass_rose.rs b/editor/src/messages/tool/common_functionality/compass_rose.rs index 8a7a2f6b2a..249a96b5d3 100644 --- a/editor/src/messages/tool/common_functionality/compass_rose.rs +++ b/editor/src/messages/tool/common_functionality/compass_rose.rs @@ -1,5 +1,4 @@ use crate::consts::{COMPASS_ROSE_ARROW_CLICK_TARGET_ANGLE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER}; -use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::DocumentMessageHandler; use glam::{DAffine2, DVec2}; use std::f64::consts::FRAC_PI_2; @@ -10,26 +9,34 @@ pub struct CompassRose { } impl CompassRose { - fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { - let [min, max] = document.metadata().nonzero_bounding_box(layer); - - let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); - let layer_transform = document.metadata().transform_to_viewport(layer); - layer_transform * bounds_transform - } pub fn refresh_position(&mut self, document: &DocumentMessageHandler) { - let selected_nodes = document.network_interface.selected_nodes(); - let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); + let selected = document.network_interface.selected_nodes(); - let Some(first) = layers.next() else { return }; - let count = layers.count() + 1; - let transform = if count == 1 { - Self::get_layer_pivot_transform(first, document) - } else { - let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); - DAffine2::from_translation(min) * DAffine2::from_scale(max - min) + if !selected.has_selected_nodes() { + return; }; + let transform = selected + .selected_visible_and_unlocked_layers(&document.network_interface) + .find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface)) + .unwrap_or_default(); + + let bounds = document + .network_interface + .selected_nodes() + .selected_visible_and_unlocked_layers(&document.network_interface) + .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) + .filter_map(|layer| { + document + .metadata() + .bounding_box_with_transform(layer, transform.inverse() * document.metadata().transform_to_viewport(layer)) + }) + .reduce(graphene_std::renderer::Quad::combine_bounds); + + let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]); + let transform = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + self.compass_center = transform.transform_point2(DVec2::splat(0.5)); } From af8508af5c663d699183b7568e265d4029282a9b Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 7 Jul 2025 15:14:39 +0530 Subject: [PATCH 48/54] add: move pivot on grab --- .../tool/common_functionality/pivot.rs | 56 ++----------------- .../tool/tool_messages/select_tool.rs | 23 +++++++- .../messages/tool/tool_messages/text_tool.rs | 3 - .../transform_layer_message_handler.rs | 2 +- 4 files changed, 29 insertions(+), 55 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 54db651d3e..266608dbfb 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -1,7 +1,6 @@ //! Handler for the pivot overlay visible on the selected layer(s) whilst using the Select tool which controls the center of rotation/scale. use crate::consts::PIVOT_DIAMETER; -use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::graph_modification_utils; @@ -91,7 +90,7 @@ impl Dot { .then_some({ match self.state.dot { DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), - DotType::Pivot => self.pivot.position(), + DotType::Pivot => self.pivot.pivot, DotType::Active => self.layer.map(|layer| graph_modification_utils::get_viewport_origin(layer, network)), } }) @@ -107,6 +106,10 @@ impl Dot { pub fn pin_active(&self) -> bool { self.pivot.pinned && self.state.is_pivot_type() } + + pub fn pivot_disconnected(&self) -> bool { + self.pivot.old_pivot_position == ReferencePoint::None + } } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] @@ -163,14 +166,12 @@ pub struct Pivot { /// Transform to get from normalized pivot to viewspace pub transform_from_normalized: DAffine2, /// The viewspace pivot position - pivot: Option, + pub pivot: Option, /// The old pivot position in the GUI, used to reduce refreshes of the document bar pub old_pivot_position: ReferencePoint, /// The last ReferencePoint which wasn't none pub last_non_none_reference: ReferencePoint, /// Used to enable and disable the pivot - active: bool, - /// Used to enable and disable the pivot pub pinned: bool, /// Had selected_visible_and_unlocked_layers pub empty: bool, @@ -184,7 +185,6 @@ impl Default for Pivot { pivot: Default::default(), old_pivot_position: ReferencePoint::Center, last_non_none_reference: ReferencePoint::Center, - active: true, pinned: false, empty: true, } @@ -194,12 +194,7 @@ impl Default for Pivot { impl Pivot { /// Recomputes the pivot position and transform. pub fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { - if !self.active { - return; - } - let selected = document.network_interface.selected_nodes(); - self.empty = !selected.has_selected_nodes(); if !selected.has_selected_nodes() { return; @@ -231,10 +226,6 @@ impl Pivot { } pub fn recalculate_pivot_for_layer(&mut self, document: &DocumentMessageHandler, bounds: Option<[DVec2; 2]>) { - if !self.active { - return; - } - let selected = document.network_interface.selected_nodes(); if !selected.has_selected_nodes() { self.normalized_pivot = DVec2::splat(0.5); @@ -247,29 +238,8 @@ impl Pivot { self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } - pub fn update(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>, draw: bool) { - if !overlay_context.visibility_settings.pivot() { - self.active = false; - return; - } else { - self.active = true; - } - - self.recalculate_pivot(document); - if !draw { - return; - }; - if let (Some(pivot), Some(data)) = (self.pivot, draw_data) { - overlay_context.pivot(pivot, data.0); - } - } - /// Answers if the pivot widget has changed (so we should refresh the tool bar at the top of the canvas). pub fn should_refresh_pivot_position(&mut self) -> bool { - if !self.active { - return false; - } - let new = self.to_pivot_position(); let should_refresh = new != self.old_pivot_position; self.old_pivot_position = new; @@ -280,16 +250,8 @@ impl Pivot { self.normalized_pivot.into() } - pub fn position(&self) -> Option { - self.pivot - } - /// Sets the viewport position of the pivot. pub fn set_viewport_position(&mut self, position: DVec2) { - if !self.active { - return; - } - if self.transform_from_normalized.matrix2.determinant().abs() <= f64::EPSILON { return; }; @@ -300,18 +262,12 @@ impl Pivot { /// Set the pivot using a normalized position. pub fn set_normalized_position(&mut self, position: DVec2) { - if !self.active { - return; - } self.normalized_pivot = position; self.pivot = Some(self.transform_from_normalized.transform_point2(position)); } /// Answers if the pointer is currently positioned over the pivot. pub fn is_over(&self, mouse: DVec2) -> bool { - if !self.active { - return false; - } self.pivot.filter(|&pivot| mouse.distance_squared(pivot) < (PIVOT_DIAMETER / 2.).powi(2)).is_some() } } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 97d634f532..a770b652c0 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -376,6 +376,7 @@ struct SelectToolData { snap_manager: SnapManager, cursor: MouseCursorIcon, dot: Dot, + dot_start: Option, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -569,6 +570,7 @@ impl Fsm for SelectToolFsmState { let ToolActionHandlerData { document, input, font_cache, .. } = tool_action_data; let ToolMessage::Select(event) = event else { return self }; + debug!("{:?}", event); match (self, event) { (_, SelectToolMessage::Overlays(mut overlay_context)) => { tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); @@ -817,9 +819,18 @@ impl Fsm for SelectToolFsmState { overlay_context.dowel_pin(origin, origin_angle, Some(COLOR_OVERLAY_YELLOW)); } + debug!("{:?}", tool_data.dot_start); let has_layers = document.network_interface.selected_nodes().has_selected_nodes(); let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot() && has_layers; - tool_data.dot.pivot.update(document, &mut overlay_context, Some((angle,)), draw_pivot); + tool_data.dot.pivot.recalculate_pivot(document); + let pivot = draw_pivot.then_some(tool_data.dot.pivot.pivot).flatten(); + if let Some(pivot) = pivot { + let offset = tool_data + .dot_start + .map(|offset| tool_data.dot.pivot_disconnected().then_some(tool_data.drag_current - offset).unwrap_or_default()) + .unwrap_or_default(); + overlay_context.pivot(pivot + offset, angle); + } // Update compass rose if overlay_context.visibility_settings.compass_rose() { @@ -1029,6 +1040,8 @@ impl Fsm for SelectToolFsmState { let axis_state = compass_rose_state.axis_type().filter(|_| can_grab_compass_rose); (axis_state.unwrap_or_default(), axis_state.is_some()) }; + + tool_data.dot_start = Some(tool_data.drag_current); SelectToolFsmState::Dragging { axis, using_compass, @@ -1065,6 +1078,8 @@ impl Fsm for SelectToolFsmState { tool_data.get_snap_candidates(document, input); responses.add(DocumentMessage::StartTransaction); + + tool_data.dot_start = Some(tool_data.drag_current); SelectToolFsmState::Dragging { axis: Axis::None, using_compass: false, @@ -1394,6 +1409,12 @@ impl Fsm for SelectToolFsmState { tool_data.snap_manager.cleanup(responses); tool_data.select_single_layer = None; + if let Some(start) = tool_data.dot_start { + let offset = tool_data.dot.pivot_disconnected().then_some(tool_data.drag_current - start).unwrap_or_default(); + tool_data.dot.pivot.pivot.as_mut().map(|v| *v += offset); + } + tool_data.dot_start = None; + let dot = tool_data.get_as_dot(); responses.add(TransformLayerMessage::SetDot { dot }); diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index a71a90d461..6be22719cb 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -9,7 +9,6 @@ use crate::messages::portfolio::document::utility_types::network_interface::Inpu use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name}; -use crate::messages::tool::common_functionality::pivot::Pivot; use crate::messages::tool::common_functionality::resize::Resize; use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData}; use crate::messages::tool::common_functionality::transformation_cage::*; @@ -283,7 +282,6 @@ struct TextToolData { // Since the overlays must be drawn without knowledge of the inputs cached_resize_bounds: [DVec2; 2], bounding_box_manager: Option, - pivot: Pivot, snap_candidates: Vec, // TODO: Handle multiple layers in the future layer_dragging: Option, @@ -526,7 +524,6 @@ impl Fsm for TextToolFsmState { } bounding_box_manager.render_overlays(&mut overlay_context, false); - tool_data.pivot.update(document, &mut overlay_context, None, true); } } else { tool_data.bounding_box_manager.take(); diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 061890816c..f334f3cab4 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -95,7 +95,7 @@ fn calculate_pivot( match dot.state.dot { DotType::Average => None, DotType::Active => dot.point.and_then(|p| get_location(&p)), - DotType::Pivot => dot.pivot.position(), + DotType::Pivot => dot.pivot.pivot, } } else { None From e4c9c0d713fc08f4537fbb1f1a9e98e795cc0179 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 7 Jul 2025 16:32:01 +0530 Subject: [PATCH 49/54] add: move pivot on nudge --- .../portfolio/document/document_message_handler.rs | 1 + .../portfolio/document/node_graph/utility_types.rs | 2 +- .../src/messages/tool/tool_messages/select_tool.rs | 12 ++++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index e35dded5e4..0fbf8ae64b 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -750,6 +750,7 @@ impl MessageHandler> for DocumentMessag // Nudge translation without resizing if !resize { let transform = DAffine2::from_translation(DVec2::from_angle(-self.document_ptz.tilt()).rotate(DVec2::new(delta_x, delta_y))); + responses.add(SelectToolMessage::ShiftSelectedNodes { offset: transform.translation }); for layer in self.network_interface.shallowest_unique_layers(&[]).filter(|layer| can_move(*layer)) { responses.add(GraphOperationMessage::TransformChange { diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index b743cb1fc6..1295ef2917 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -198,7 +198,7 @@ pub struct FrontendClickTargets { pub modify_import_export: Vec, } -#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum Direction { Up, Down, diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index a770b652c0..c174d49bf7 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -100,6 +100,9 @@ pub enum SelectToolMessage { position: ReferencePoint, }, SyncHistory, + ShiftSelectedNodes { + offset: DVec2, + }, } impl ToolMetadata for SelectTool { @@ -570,7 +573,6 @@ impl Fsm for SelectToolFsmState { let ToolActionHandlerData { document, input, font_cache, .. } = tool_action_data; let ToolMessage::Select(event) = event else { return self }; - debug!("{:?}", event); match (self, event) { (_, SelectToolMessage::Overlays(mut overlay_context)) => { tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); @@ -819,7 +821,6 @@ impl Fsm for SelectToolFsmState { overlay_context.dowel_pin(origin, origin_angle, Some(COLOR_OVERLAY_YELLOW)); } - debug!("{:?}", tool_data.dot_start); let has_layers = document.network_interface.selected_nodes().has_selected_nodes(); let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot() && has_layers; tool_data.dot.pivot.recalculate_pivot(document); @@ -1580,6 +1581,13 @@ impl Fsm for SelectToolFsmState { self } + (_, SelectToolMessage::ShiftSelectedNodes { offset }) => { + if tool_data.dot.pivot_disconnected() { + tool_data.dot.pivot.pivot.as_mut().map(|v| *v += offset); + } + + self + } _ => self, } } From c47c53d75eef34a803db496cb69385e23422c0dc Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Tue, 8 Jul 2025 12:56:43 +0530 Subject: [PATCH 50/54] add: move pivot on Grab --- .../tool/tool_messages/select_tool.rs | 20 ++++++++++++++++++- .../transform_layer_message_handler.rs | 9 +++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index c174d49bf7..30a22cb95f 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -103,6 +103,10 @@ pub enum SelectToolMessage { ShiftSelectedNodes { offset: DVec2, }, + PivotShift { + offset: Option, + flush: bool, + }, } impl ToolMetadata for SelectTool { @@ -380,6 +384,7 @@ struct SelectToolData { cursor: MouseCursorIcon, dot: Dot, dot_start: Option, + dot_shift: Option, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -830,7 +835,8 @@ impl Fsm for SelectToolFsmState { .dot_start .map(|offset| tool_data.dot.pivot_disconnected().then_some(tool_data.drag_current - offset).unwrap_or_default()) .unwrap_or_default(); - overlay_context.pivot(pivot + offset, angle); + let shift = tool_data.dot_shift.unwrap_or_default(); + overlay_context.pivot(pivot + offset + shift, angle); } // Update compass rose @@ -1582,12 +1588,24 @@ impl Fsm for SelectToolFsmState { self } (_, SelectToolMessage::ShiftSelectedNodes { offset }) => { + let offset = document.metadata().document_to_viewport.transform_vector2(offset); if tool_data.dot.pivot_disconnected() { tool_data.dot.pivot.pivot.as_mut().map(|v| *v += offset); } self } + (_, SelectToolMessage::PivotShift { offset, flush }) => { + if flush { + tool_data.dot.pivot.pivot.as_mut().map(|v| *v += tool_data.dot_shift.take().unwrap_or_default()); + return self; + } + if tool_data.dot.pivot_disconnected() { + tool_data.dot_shift = offset; + } + + self + } _ => self, } } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index f334f3cab4..b0b61c04f4 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -307,6 +307,12 @@ impl MessageHandler> for TransformLayer let quad = Quad::from_box([pivot, pivot + viewport_translate]).0; let e1 = (self.layer_bounding_box.0[1] - self.layer_bounding_box.0[0]).normalize_or(DVec2::X); + debug!("A"); + responses.add(SelectToolMessage::PivotShift { + offset: Some(viewport_translate), + flush: false, + }); + if matches!(axis_constraint, Axis::Both | Axis::X) && translation.x != 0. { let end = if self.local { (quad[1] - quad[0]).rotate(e1) + quad[0] } else { quad[1] }; overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); @@ -415,6 +421,8 @@ impl MessageHandler> for TransformLayer responses.add(NodeGraphMessage::RunDocumentGraph); } + responses.add(SelectToolMessage::PivotShift { offset: None, flush: true }); + if final_transform { responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER)); } @@ -538,6 +546,7 @@ impl MessageHandler> for TransformLayer responses.add(ToolMessage::UpdateHints); } + responses.add(SelectToolMessage::PivotShift { offset: None, flush: false }); responses.add(OverlaysMessage::RemoveProvider(TRANSFORM_GRS_OVERLAY_PROVIDER)); } TransformLayerMessage::ConstrainX => { From 9a14349a0110652b89ee23ab42ea97ba325da8c2 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Tue, 8 Jul 2025 00:43:24 -0700 Subject: [PATCH 51/54] Code review and tooltips --- editor/src/consts.rs | 2 +- .../utility_types/widgets/input_widgets.rs | 2 + .../document/overlays/utility_types.rs | 8 +- .../tool/common_functionality/compass_rose.rs | 2 +- .../graph_modification_utils.rs | 5 +- .../tool/common_functionality/pivot.rs | 123 ++++++------ .../common_functionality/utility_functions.rs | 6 +- .../messages/tool/tool_messages/path_tool.rs | 64 +++--- .../tool/tool_messages/select_tool.rs | 184 ++++++++++-------- .../transform_layer_message.rs | 4 +- .../transform_layer_message_handler.rs | 48 +++-- .../widgets/inputs/ReferencePointInput.svelte | 3 +- frontend/src/messages.ts | 3 + 13 files changed, 246 insertions(+), 208 deletions(-) diff --git a/editor/src/consts.rs b/editor/src/consts.rs index ce079f830a..58585e2dab 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -135,9 +135,9 @@ pub const SCALE_EFFECT: f64 = 0.5; // COLORS pub const COLOR_OVERLAY_BLUE: &str = "#00a8ff"; pub const COLOR_OVERLAY_YELLOW: &str = "#ffc848"; +pub const COLOR_OVERLAY_YELLOW_DULL: &str = "#d7ba8b"; pub const COLOR_OVERLAY_GREEN: &str = "#63ce63"; pub const COLOR_OVERLAY_RED: &str = "#ef5454"; -pub const COLOR_OVERLAY_ORANGE: &str = "#e27a44"; pub const COLOR_OVERLAY_GRAY: &str = "#cccccc"; pub const COLOR_OVERLAY_WHITE: &str = "#ffffff"; pub const COLOR_OVERLAY_LABEL_BACKGROUND: &str = "#000000cc"; diff --git a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs index b76f23a067..893b301cd8 100644 --- a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs @@ -471,6 +471,8 @@ pub struct ReferencePointInput { pub disabled: bool, + pub tooltip: String, + // Callbacks #[serde(skip)] #[derivative(Debug = "ignore", PartialEq = "ignore")] diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index dd2500c7f0..6b7d2bbd05 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -1,6 +1,6 @@ use super::utility_functions::overlay_canvas_context; use crate::consts::{ - COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_ORANGE, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, + COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COLOR_OVERLAY_YELLOW_DULL, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, DOWEL_PIN_RADIUS, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER, }; use crate::messages::prelude::Message; @@ -554,7 +554,7 @@ impl OverlayContext { pub fn dowel_pin(&mut self, position: DVec2, angle: f64, color: Option<&str>) { let (x, y) = (position.round() - DVec2::splat(0.5)).into(); - let color = color.unwrap_or(COLOR_OVERLAY_ORANGE); + let color = color.unwrap_or(COLOR_OVERLAY_YELLOW_DULL); self.start_dpi_aware_transform(); @@ -765,11 +765,11 @@ impl OverlayContext { // └──┴──┴──┴──┘ let pixels = [(0, 0), (2, 2)]; for &(x, y) in &pixels { - let index = (x + y * PATTERN_WIDTH as usize) * 4; + let index = (x + y * PATTERN_WIDTH) * 4; data[index..index + 4].copy_from_slice(&color.to_rgba8_srgb()); } - let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(wasm_bindgen::Clamped(&mut data), PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap(); + let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(wasm_bindgen::Clamped(&data), PATTERN_WIDTH as u32, PATTERN_HEIGHT as u32).unwrap(); pattern_context.put_image_data(&image_data, 0., 0.).unwrap(); let pattern = self.render_context.create_pattern_with_offscreen_canvas(&pattern_canvas, "repeat").unwrap().unwrap(); diff --git a/editor/src/messages/tool/common_functionality/compass_rose.rs b/editor/src/messages/tool/common_functionality/compass_rose.rs index 249a96b5d3..72d99b0a89 100644 --- a/editor/src/messages/tool/common_functionality/compass_rose.rs +++ b/editor/src/messages/tool/common_functionality/compass_rose.rs @@ -14,7 +14,7 @@ impl CompassRose { if !selected.has_selected_nodes() { return; - }; + } let transform = selected .selected_visible_and_unlocked_layers(&document.network_interface) diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index ea7beb879e..33c19d0c0d 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -245,8 +245,9 @@ pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerN /// Locate the origin of the transform node pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let origin_node_input_index = 1; - if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", origin_node_input_index)? { + use graphene_std::transform_nodes::transform::TranslateInput; + + if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", TranslateInput::INDEX)? { Some(*origin) } else { None diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 266608dbfb..d5ba0c2e9b 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -11,87 +11,100 @@ use glam::{DAffine2, DVec2}; use graphene_std::{transform::ReferencePoint, vector::ManipulatorPointId}; use std::fmt; -pub fn pin_pivot_widget(active: bool, enabled: bool, source: Source) -> WidgetHolder { +pub fn pin_pivot_widget(active: bool, enabled: bool, source: PivotToolSource) -> WidgetHolder { IconButton::new(if active { "PinActive" } else { "PinInactive" }, 24) - .tooltip(if active { "Unpin Transform Pivot" } else { "Pin Transform Pivot" }) + .tooltip(String::from(if active { "Unpin Custom Pivot" } else { "Pin Custom Pivot" }) + "\n\nUnless pinned, the pivot will return to its prior reference point when a new selection is made.") .disabled(!enabled) .on_update(move |_| match source { - Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned()).into(), - Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned()).into(), + PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotPinned).into(), + PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotPinned).into(), }) .widget_holder() } -pub fn pivot_reference_point_widget(disabled: bool, reference_point: ReferencePoint, source: Source) -> WidgetHolder { +pub fn pivot_reference_point_widget(disabled: bool, reference_point: ReferencePoint, source: PivotToolSource) -> WidgetHolder { ReferencePointInput::new(reference_point) + .tooltip("Custom Pivot Reference Point\n\nPlaces the pivot at a corner, edge, or center of the selection bounds, unless it is dragged elsewhere.") + .disabled(disabled) .on_update(move |pivot_input: &ReferencePointInput| match source { - Source::Select => SelectToolMessage::SetPivot { position: pivot_input.value }.into(), - Source::Path => PathToolMessage::SetPivot { position: pivot_input.value }.into(), + PivotToolSource::Select => SelectToolMessage::SetPivot { position: pivot_input.value }.into(), + PivotToolSource::Path => PathToolMessage::SetPivot { position: pivot_input.value }.into(), }) - .disabled(disabled) .widget_holder() } -pub fn dot_type_widget(state: DotState, source: Source) -> Vec { - let dot_type_entries = [DotType::Pivot, DotType::Average, DotType::Active] +pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource) -> Vec { + let gizmo_type_entries = [PivotGizmoType::Pivot, PivotGizmoType::Average, PivotGizmoType::Active] .iter() - .map(|dot_type| { - MenuListEntry::new(format!("{dot_type:?}")).label(dot_type.to_string()).on_commit({ + .map(|gizmo_type| { + MenuListEntry::new(format!("{gizmo_type:?}")).label(gizmo_type.to_string()).on_commit({ let value = source.clone(); move |_| match value { - Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::DotType(*dot_type)).into(), - Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::DotType(*dot_type)).into(), + PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::PivotGizmoType(*gizmo_type)).into(), + PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::PivotGizmoType(*gizmo_type)).into(), } }) }) .collect(); vec![ - CheckboxInput::new(state.enabled) - .tooltip("Disable Transform Pivot Point") + CheckboxInput::new(!state.disabled) + .tooltip( + "Pivot Gizmo\n\ + \n\ + Enabled: the chosen gizmo type is shown and used to control rotation and scaling.\n\ + Disabled: rotation and scaling occurs about the center of the selection bounds.", + ) .on_update(move |optional_input: &CheckboxInput| match source { - Source::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::ToggleDotType(optional_input.checked)).into(), - Source::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::ToggleDotType(optional_input.checked)).into(), + PivotToolSource::Select => SelectToolMessage::SelectOptions(SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(), + PivotToolSource::Path => PathToolMessage::UpdateOptions(PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked)).into(), }) .widget_holder(), Separator::new(SeparatorType::Related).widget_holder(), - DropdownInput::new(vec![dot_type_entries]) - .selected_index(Some(match state.dot { - DotType::Pivot => 0, - DotType::Average => 1, - DotType::Active => 2, + DropdownInput::new(vec![gizmo_type_entries]) + .selected_index(Some(match state.gizmo_type { + PivotGizmoType::Pivot => 0, + PivotGizmoType::Average => 1, + PivotGizmoType::Active => 2, })) - .tooltip("Choose between type of Transform Pivot Point") - .disabled(!state.enabled) + .tooltip( + "Pivot Gizmo Type\n\ + \n\ + Selects which gizmo type is shown and used as the center of rotation/scaling transformations.\n\ + \n\ + Custom Pivot: rotates and scales relative to the selection bounds, or elsewhere if dragged.\n\ + Origin (Average Point): rotates and scales about the average point of all selected layer origins.\n\ + Origin (Active Object): rotates and scales about the origin of the most recently selected layer.", + ) + .disabled(state.disabled) .widget_holder(), ] } #[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] -pub enum Source { +pub enum PivotToolSource { Path, #[default] Select, } #[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] -pub struct Dot { +pub struct PivotGizmo { pub pivot: Pivot, - pub state: DotState, + pub state: PivotGizmoState, pub layer: Option, pub point: Option, } -impl Dot { +impl PivotGizmo { pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 { let network = &document.network_interface; - self.state - .enabled + (!self.state.disabled) .then_some({ - match self.state.dot { - DotType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), - DotType::Pivot => self.pivot.pivot, - DotType::Active => self.layer.map(|layer| graph_modification_utils::get_viewport_origin(layer, network)), + match self.state.gizmo_type { + PivotGizmoType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)), + PivotGizmoType::Pivot => self.pivot.pivot, + PivotGizmoType::Active => self.layer.map(|layer| graph_modification_utils::get_viewport_origin(layer, network)), } }) .flatten() @@ -113,7 +126,7 @@ impl Dot { } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] -pub enum DotType { +pub enum PivotGizmoType { // Pivot #[default] Pivot, @@ -123,37 +136,28 @@ pub enum DotType { // TODO: Add "Individual" } -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct DotState { - pub enabled: bool, - pub dot: DotType, +#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct PivotGizmoState { + pub disabled: bool, + pub gizmo_type: PivotGizmoType, } -impl Default for DotState { - fn default() -> Self { - Self { - enabled: true, - dot: DotType::default(), - } - } -} - -impl DotState { +impl PivotGizmoState { pub fn is_pivot_type(&self) -> bool { - self.dot == DotType::Pivot || !self.enabled + self.gizmo_type == PivotGizmoType::Pivot || self.disabled } pub fn is_pivot(&self) -> bool { - self.dot == DotType::Pivot && self.enabled + self.gizmo_type == PivotGizmoType::Pivot && !self.disabled } } -impl fmt::Display for DotType { +impl fmt::Display for PivotGizmoType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - DotType::Pivot => write!(f, "Custom Pivot"), - DotType::Average => write!(f, "Origin (Average Point)"), - DotType::Active => write!(f, "Origin (Active Object)"), + PivotGizmoType::Pivot => write!(f, "Custom Pivot"), + PivotGizmoType::Average => write!(f, "Origin (Average Point)"), + PivotGizmoType::Active => write!(f, "Origin (Active Object)"), // TODO: Add "Origin (Individual)" } } @@ -170,7 +174,7 @@ pub struct Pivot { /// The old pivot position in the GUI, used to reduce refreshes of the document bar pub old_pivot_position: ReferencePoint, /// The last ReferencePoint which wasn't none - pub last_non_none_reference: ReferencePoint, + pub last_non_none_reference_point: ReferencePoint, /// Used to enable and disable the pivot pub pinned: bool, /// Had selected_visible_and_unlocked_layers @@ -184,7 +188,7 @@ impl Default for Pivot { transform_from_normalized: Default::default(), pivot: Default::default(), old_pivot_position: ReferencePoint::Center, - last_non_none_reference: ReferencePoint::Center, + last_non_none_reference_point: ReferencePoint::Center, pinned: false, empty: true, } @@ -198,7 +202,7 @@ impl Pivot { self.empty = !selected.has_selected_nodes(); if !selected.has_selected_nodes() { return; - }; + } let transform = selected .selected_visible_and_unlocked_layers(&document.network_interface) @@ -220,6 +224,7 @@ impl Pivot { let [min, max] = bounds.unwrap_or([DVec2::ZERO, DVec2::ONE]); self.transform_from_normalized = transform * DAffine2::from_translation(min) * DAffine2::from_scale(max - min); + if self.old_pivot_position != ReferencePoint::None { self.pivot = Some(self.transform_from_normalized.transform_point2(self.normalized_pivot)); } diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index 18909dd8fc..6ae3f130b5 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -393,7 +393,7 @@ pub fn transforming_transform_cage( input: &InputPreprocessorMessageHandler, responses: &mut VecDeque, layers_dragging: &mut Vec, - pos: Option, + center_of_transformation: Option, ) -> (bool, bool, bool) { let dragging_bounds = bounding_box_manager.as_mut().and_then(|bounding_box| { let edges = bounding_box.check_selected_edges(input.mouse.position); @@ -430,7 +430,7 @@ pub fn transforming_transform_cage( } }); - bounds.center_of_transformation = pos.unwrap_or_else(|| { + bounds.center_of_transformation = center_of_transformation.unwrap_or_else(|| { document .network_interface .selected_nodes() @@ -465,7 +465,7 @@ pub fn transforming_transform_cage( } }); - bounds.center_of_transformation = pos.unwrap_or_else(|| { + bounds.center_of_transformation = center_of_transformation.unwrap_or_else(|| { document .network_interface .selected_nodes() diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 52d46952d2..0642613cf0 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -11,7 +11,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node use crate::messages::portfolio::document::utility_types::transformation::Axis; use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; -use crate::messages::tool::common_functionality::pivot::{Dot, DotType, Source, dot_type_widget, pin_pivot_widget, pivot_reference_point_widget}; +use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType, PivotToolSource, pin_pivot_widget, pivot_gizmo_type_widget, pivot_reference_point_widget}; use crate::messages::tool::common_functionality::shape_editor::{ ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedLayerState, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState, }; @@ -146,9 +146,9 @@ pub enum PathOptionsUpdate { OverlayModeType(PathOverlayMode), PointEditingMode { enabled: bool }, SegmentEditingMode { enabled: bool }, - DotType(DotType), - ToggleDotType(bool), - TogglePivotPinned(), + PivotGizmoType(PivotGizmoType), + TogglePivotGizmoType(bool), + TogglePivotPinned, } impl ToolMetadata for PathTool { @@ -264,14 +264,18 @@ impl LayoutHolder for PathTool { .widget_holder(); let [_checkbox, _dropdown] = { - let dot_widget = dot_type_widget(self.tool_data.dot.state, Source::Path); - [dot_widget[0].clone(), dot_widget[2].clone()] + let pivot_gizmo_type_widget = pivot_gizmo_type_widget(self.tool_data.pivot_gizmo.state, PivotToolSource::Path); + [pivot_gizmo_type_widget[0].clone(), pivot_gizmo_type_widget[2].clone()] }; - let has_somrthing = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty(); - let _pivot_reference = pivot_reference_point_widget(has_somrthing || !self.tool_data.dot.state.is_pivot(), self.tool_data.dot.pivot.to_pivot_position(), Source::Path); + let has_something = !self.tool_data.saved_points_before_anchor_convert_smooth_sharp.is_empty(); + let _pivot_reference = pivot_reference_point_widget( + has_something || !self.tool_data.pivot_gizmo.state.is_pivot(), + self.tool_data.pivot_gizmo.pivot.to_pivot_position(), + PivotToolSource::Path, + ); - let _pin_pivot = pin_pivot_widget(self.tool_data.dot.pin_active(), false, Source::Path); + let _pin_pivot = pin_pivot_widget(self.tool_data.pivot_gizmo.pin_active(), false, PivotToolSource::Path); Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: vec![ @@ -319,25 +323,25 @@ impl<'a> MessageHandler> for PathToo self.options.path_editing_mode.segment_editing_mode = enabled; responses.add(OverlaysMessage::Draw); } - PathOptionsUpdate::DotType(dot_type) => { - if self.tool_data.dot.state.enabled { - self.tool_data.dot.state.dot = dot_type; + PathOptionsUpdate::PivotGizmoType(gizmo_type) => { + if !self.tool_data.pivot_gizmo.state.disabled { + self.tool_data.pivot_gizmo.state.gizmo_type = gizmo_type; responses.add(ToolMessage::UpdateHints); - let dot = self.tool_data.get_as_dot(); - responses.add(TransformLayerMessage::SetDot { dot }); + let pivot_gizmo = self.tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); responses.add(NodeGraphMessage::RunDocumentGraph); self.send_layout(responses, LayoutTarget::ToolOptions); } } - PathOptionsUpdate::ToggleDotType(state) => { - self.tool_data.dot.state.enabled = state; + PathOptionsUpdate::TogglePivotGizmoType(state) => { + self.tool_data.pivot_gizmo.state.disabled = !state; responses.add(ToolMessage::UpdateHints); responses.add(NodeGraphMessage::RunDocumentGraph); self.send_layout(responses, LayoutTarget::ToolOptions); } - PathOptionsUpdate::TogglePivotPinned() => { - self.tool_data.dot.pivot.pinned = !self.tool_data.dot.pivot.pinned; + PathOptionsUpdate::TogglePivotPinned => { + self.tool_data.pivot_gizmo.pivot.pinned = !self.tool_data.pivot_gizmo.pivot.pinned; responses.add(ToolMessage::UpdateHints); responses.add(NodeGraphMessage::RunDocumentGraph); self.send_layout(responses, LayoutTarget::ToolOptions); @@ -492,7 +496,7 @@ struct PathToolData { last_click_time: u64, dragging_state: DraggingState, angle: f64, - dot: Dot, + pivot_gizmo: PivotGizmo, ordered_points: Vec, opposite_handle_position: Option, last_clicked_point_was_selected: bool, @@ -1367,14 +1371,14 @@ impl PathToolData { } } - fn get_as_dot(&self) -> Dot { - self.dot.clone() + fn pivot_gizmo(&self) -> PivotGizmo { + self.pivot_gizmo.clone() } - fn sync_history(&mut self, points: &Vec) { + fn sync_history(&mut self, points: &[ManipulatorPointId]) { self.ordered_points.retain(|layer| points.contains(layer)); self.ordered_points.extend(points.iter().find(|&layer| !self.ordered_points.contains(layer))); - self.dot.point = self.ordered_points.last().map(|x| *x) + self.pivot_gizmo.point = self.ordered_points.last().copied() } } @@ -1389,8 +1393,8 @@ impl Fsm for PathToolFsmState { let ToolMessage::Path(event) = event else { return self }; - // TODO(mTvare6): Remove it once dots are implemented for path_tool - tool_data.dot.state.enabled = false; + // TODO(mTvare6): Remove once gizmos are implemented for path_tool + tool_data.pivot_gizmo.state.disabled = true; match (self, event) { (_, PathToolMessage::SelectionChanged) => { @@ -2273,11 +2277,11 @@ impl Fsm for PathToolFsmState { (_, PathToolMessage::SetPivot { position }) => { responses.add(DocumentMessage::StartTransaction); - tool_data.dot.pivot.last_non_none_reference = position; - let pos: Option = position.into(); - tool_data.dot.pivot.set_normalized_position(pos.unwrap()); - let dot = tool_data.get_as_dot(); - responses.add(TransformLayerMessage::SetDot { dot }); + tool_data.pivot_gizmo.pivot.last_non_none_reference_point = position; + let position: Option = position.into(); + tool_data.pivot_gizmo.pivot.set_normalized_position(position.unwrap()); + let pivot_gizmo = tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); responses.add(NodeGraphMessage::RunDocumentGraph); self diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 30a22cb95f..bac9725787 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -15,7 +15,7 @@ use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRos use crate::messages::tool::common_functionality::graph_modification_utils; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; use crate::messages::tool::common_functionality::measure; -use crate::messages::tool::common_functionality::pivot::{Dot, DotType, Source, dot_type_widget, pin_pivot_widget, pivot_reference_point_widget}; +use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType, PivotToolSource, pin_pivot_widget, pivot_gizmo_type_widget, pivot_reference_point_widget}; use crate::messages::tool::common_functionality::shape_editor::SelectionShapeType; use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager}; use crate::messages::tool::common_functionality::transformation_cage::*; @@ -44,9 +44,9 @@ pub struct SelectOptions { #[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SelectOptionsUpdate { NestedSelectionBehavior(NestedSelectionBehavior), - DotType(DotType), - ToggleDotType(bool), - TogglePivotPinned(), + PivotGizmoType(PivotGizmoType), + TogglePivotGizmoType(bool), + TogglePivotPinned, } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] @@ -134,7 +134,12 @@ impl SelectTool { DropdownInput::new(vec![layer_selection_behavior_entries]) .selected_index(Some((self.tool_data.nested_selection_behavior == NestedSelectionBehavior::Deepest) as u32)) - .tooltip("Choose if clicking nested layers directly selects the deepest, or selects the shallowest and deepens by double clicking") + .tooltip( + "Selection Mode\n\ + \n\ + Shallow Select: clicks initially select the least-nested layers and double clicks drill deeper into the folder hierarchy.\n\ + Deep Select: clicks directly select the most-nested layers in the folder hierarchy.", + ) .widget_holder() } @@ -183,7 +188,7 @@ impl SelectTool { fn boolean_widgets(&self, selected_count: usize) -> impl Iterator + use<> { let list = ::list(); - list.into_iter().map(|i| i.into_iter()).flatten().map(move |(operation, info)| { + list.iter().flat_map(|i| i.iter()).map(move |(operation, info)| { let mut tooltip = info.label.to_string(); if let Some(doc) = info.docstring.as_deref() { tooltip.push_str("\n\n"); @@ -208,25 +213,28 @@ impl LayoutHolder for SelectTool { // Select mode (Deep/Shallow) widgets.push(self.deep_selection_widget()); - // Dot Type (checkbox + dropdown for pivot/origin) + // Pivot gizmo type (checkbox + dropdown for pivot/origin) widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - widgets.extend(dot_type_widget(self.tool_data.dot.state, Source::Select)); + widgets.extend(pivot_gizmo_type_widget(self.tool_data.pivot_gizmo.state, PivotToolSource::Select)); - if self.tool_data.dot.state.is_pivot_type() { - // Reference point 9-box widget + if self.tool_data.pivot_gizmo.state.is_pivot_type() { + // Nine-position reference point widget widgets.push(Separator::new(SeparatorType::Related).widget_holder()); widgets.push(pivot_reference_point_widget( - self.tool_data.selected_layers_count == 0 || !self.tool_data.dot.state.is_pivot(), - self.tool_data.dot.pivot.to_pivot_position(), - Source::Select, + self.tool_data.selected_layers_count == 0 || !self.tool_data.pivot_gizmo.state.is_pivot(), + self.tool_data.pivot_gizmo.pivot.to_pivot_position(), + PivotToolSource::Select, )); - // Pivot pin + // Pivot pin button widgets.push(Separator::new(SeparatorType::Related).widget_holder()); - let pin_enabled = self.tool_data.dot.pivot.old_pivot_position == ReferencePoint::None || !self.tool_data.dot.state.enabled; + let pin_active = self.tool_data.pivot_gizmo.pin_active(); + let pin_enabled = self.tool_data.pivot_gizmo.pivot.old_pivot_position == ReferencePoint::None && !self.tool_data.pivot_gizmo.state.disabled; - widgets.push(pin_pivot_widget(self.tool_data.dot.pin_active(), pin_enabled, Source::Select)); + if pin_active || pin_enabled { + widgets.push(pin_pivot_widget(pin_active, pin_enabled, PivotToolSource::Select)); + } } // Align @@ -266,42 +274,43 @@ impl LayoutHolder for SelectTool { impl<'a> MessageHandler> for SelectTool { fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { - let mut redraw_ref_pivot = false; + let mut redraw_reference_pivot = false; + if let ToolMessage::Select(SelectToolMessage::SelectOptions(ref option_update)) = message { match option_update { SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior) => { self.tool_data.nested_selection_behavior = *nested_selection_behavior; responses.add(ToolMessage::UpdateHints); } - SelectOptionsUpdate::DotType(dot_type) => { - if self.tool_data.dot.state.enabled { - self.tool_data.dot.state.dot = *dot_type; + SelectOptionsUpdate::PivotGizmoType(gizmo_type) => { + if !self.tool_data.pivot_gizmo.state.disabled { + self.tool_data.pivot_gizmo.state.gizmo_type = *gizmo_type; responses.add(ToolMessage::UpdateHints); - let dot = self.tool_data.get_as_dot(); - responses.add(TransformLayerMessage::SetDot { dot }); + let pivot_gizmo = self.tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); responses.add(NodeGraphMessage::RunDocumentGraph); - redraw_ref_pivot = true; + redraw_reference_pivot = true; } } - SelectOptionsUpdate::ToggleDotType(state) => { - self.tool_data.dot.state.enabled = *state; + SelectOptionsUpdate::TogglePivotGizmoType(state) => { + self.tool_data.pivot_gizmo.state.disabled = !state; responses.add(ToolMessage::UpdateHints); responses.add(NodeGraphMessage::RunDocumentGraph); - redraw_ref_pivot = true; + redraw_reference_pivot = true; } - SelectOptionsUpdate::TogglePivotPinned() => { - self.tool_data.dot.pivot.pinned = !self.tool_data.dot.pivot.pinned; + SelectOptionsUpdate::TogglePivotPinned => { + self.tool_data.pivot_gizmo.pivot.pinned = !self.tool_data.pivot_gizmo.pivot.pinned; responses.add(ToolMessage::UpdateHints); responses.add(NodeGraphMessage::RunDocumentGraph); - redraw_ref_pivot = true; + redraw_reference_pivot = true; } } } self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false); - if self.tool_data.dot.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed || redraw_ref_pivot { + if self.tool_data.pivot_gizmo.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed || redraw_reference_pivot { // Send the layout containing the updated pivot position (a bit ugly to do it here not in the fsm but that doesn't have SelectTool) self.send_layout(responses, LayoutTarget::ToolOptions); self.tool_data.selected_layers_changed = false; @@ -382,9 +391,9 @@ struct SelectToolData { bounding_box_manager: Option, snap_manager: SnapManager, cursor: MouseCursorIcon, - dot: Dot, - dot_start: Option, - dot_shift: Option, + pivot_gizmo: PivotGizmo, + pivot_gizmo_start: Option, + pivot_gizmo_shift: Option, compass_rose: CompassRose, line_center: DVec2, skew_edge: EdgeBool, @@ -551,22 +560,22 @@ impl SelectToolData { self.layers_dragging = original; } - fn state_from_dot(&self, mouse: DVec2) -> Option { - match self.dot.state.dot { - DotType::Pivot => self.dot.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), + fn state_from_pivot_gizmo(&self, mouse: DVec2) -> Option { + match self.pivot_gizmo.state.gizmo_type { + PivotGizmoType::Pivot => self.pivot_gizmo.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), _ => None, } } - fn get_as_dot(&self) -> Dot { - self.dot.clone() + fn pivot_gizmo(&self) -> PivotGizmo { + self.pivot_gizmo.clone() } fn sync_history(&mut self, document: &DocumentMessageHandler) { let layers: Vec<_> = document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface).collect(); self.ordered_layers.retain(|layer| layers.contains(layer)); self.ordered_layers.extend(layers.iter().find(|&layer| !self.ordered_layers.contains(layer))); - self.dot.layer = self.ordered_layers.last().map(|x| *x) + self.pivot_gizmo.layer = self.ordered_layers.last().copied() } } @@ -783,14 +792,14 @@ impl Fsm for SelectToolFsmState { let mut active_origin = None; let mut origin_angle = 0.; - if overlay_context.visibility_settings.origin() && !tool_data.dot.state.is_pivot_type() { + if overlay_context.visibility_settings.origin() && !tool_data.pivot_gizmo.state.is_pivot_type() { let get_angle = |layer: LayerNodeIdentifier| -> f64 { let quad = Quad::from_box([DVec2::ZERO, DVec2::ONE]); let bounds = document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface) * quad; (bounds.top_left() - bounds.top_right()).to_angle() }; - if tool_data.dot.state.dot == DotType::Average { - let mut count = 0; + if tool_data.pivot_gizmo.state.gizmo_type == PivotGizmoType::Average { + let mut count = 0_usize; let sum: f64 = document .network_interface @@ -802,12 +811,12 @@ impl Fsm for SelectToolFsmState { if count > 0 { origin_angle = sum / count as f64; } - } else if tool_data.dot.state.dot == DotType::Active { + } else if tool_data.pivot_gizmo.state.gizmo_type == PivotGizmoType::Active { origin_angle = document .network_interface .selected_nodes() .selected_visible_and_unlocked_layers(&document.network_interface) - .find(|&layer| Some(layer) == tool_data.dot.layer) + .find(|&layer| Some(layer) == tool_data.pivot_gizmo.layer) .iter() .map(|&layer| get_angle(layer)) .sum(); @@ -815,7 +824,7 @@ impl Fsm for SelectToolFsmState { for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) { let origin = graph_modification_utils::get_viewport_origin(layer, &document.network_interface); - if Some(layer) == tool_data.dot.layer { + if Some(layer) == tool_data.pivot_gizmo.layer { active_origin = Some(origin); continue; } @@ -827,15 +836,15 @@ impl Fsm for SelectToolFsmState { } let has_layers = document.network_interface.selected_nodes().has_selected_nodes(); - let draw_pivot = tool_data.dot.state.is_pivot() && overlay_context.visibility_settings.pivot() && has_layers; - tool_data.dot.pivot.recalculate_pivot(document); - let pivot = draw_pivot.then_some(tool_data.dot.pivot.pivot).flatten(); + let draw_pivot = tool_data.pivot_gizmo.state.is_pivot() && overlay_context.visibility_settings.pivot() && has_layers; + tool_data.pivot_gizmo.pivot.recalculate_pivot(document); + let pivot = draw_pivot.then_some(tool_data.pivot_gizmo.pivot.pivot).flatten(); if let Some(pivot) = pivot { let offset = tool_data - .dot_start - .map(|offset| tool_data.dot.pivot_disconnected().then_some(tool_data.drag_current - offset).unwrap_or_default()) + .pivot_gizmo_start + .map(|offset| tool_data.pivot_gizmo.pivot_disconnected().then_some(tool_data.drag_current - offset).unwrap_or_default()) .unwrap_or_default(); - let shift = tool_data.dot_shift.unwrap_or_default(); + let shift = tool_data.pivot_gizmo_shift.unwrap_or_default(); overlay_context.pivot(pivot + offset + shift, angle); } @@ -995,8 +1004,8 @@ impl Fsm for SelectToolFsmState { let intersection_list = document.click_list(input).collect::>(); let intersection = document.find_deepest(&intersection_list); - let pos = tool_data.get_as_dot().position(document); - let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, Some(pos)); + let position = tool_data.pivot_gizmo().position(document); + let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, Some(position)); // If the user is dragging the bounding box bounds, go into ResizingBounds mode. // If the user is dragging the rotate trigger, go into RotatingBounds mode. @@ -1015,7 +1024,7 @@ impl Fsm for SelectToolFsmState { let show_compass = bounds.is_some_and(|quad| quad.all_sides_at_least_width(COMPASS_ROSE_HOVER_RING_DIAMETER) && quad.contains(mouse_position)); let can_grab_compass_rose = compass_rose_state.can_grab() && (show_compass || bounds.is_none()); - let state = if let Some(state) = tool_data.state_from_dot(input.mouse.position) { + let state = if let Some(state) = tool_data.state_from_pivot_gizmo(input.mouse.position) { responses.add(DocumentMessage::StartTransaction); // tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true); @@ -1048,7 +1057,8 @@ impl Fsm for SelectToolFsmState { (axis_state.unwrap_or_default(), axis_state.is_some()) }; - tool_data.dot_start = Some(tool_data.drag_current); + tool_data.pivot_gizmo_start = Some(tool_data.drag_current); + SelectToolFsmState::Dragging { axis, using_compass, @@ -1067,10 +1077,12 @@ impl Fsm for SelectToolFsmState { let extend = input.keyboard.key(extend_selection); if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); - if !tool_data.dot.pivot.pinned { - let position = tool_data.dot.pivot.last_non_none_reference; + + if !tool_data.pivot_gizmo.pivot.pinned { + let position = tool_data.pivot_gizmo.pivot.last_non_none_reference_point; responses.add(SelectToolMessage::SetPivot { position }); } + tool_data.layers_dragging.clear(); } @@ -1086,7 +1098,8 @@ impl Fsm for SelectToolFsmState { responses.add(DocumentMessage::StartTransaction); - tool_data.dot_start = Some(tool_data.drag_current); + tool_data.pivot_gizmo_start = Some(tool_data.drag_current); + SelectToolFsmState::Dragging { axis: Axis::None, using_compass: false, @@ -1230,7 +1243,9 @@ impl Fsm for SelectToolFsmState { (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => { let mouse_position = input.mouse.position; let snapped_mouse_position = mouse_position; - tool_data.dot.pivot.set_viewport_position(snapped_mouse_position); + + tool_data.pivot_gizmo.pivot.set_viewport_position(snapped_mouse_position); + responses.add(NodeGraphMessage::RunDocumentGraph); // Auto-panning @@ -1276,7 +1291,7 @@ impl Fsm for SelectToolFsmState { .map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge))); // Dragging the pivot overrules the other operations - if tool_data.state_from_dot(input.mouse.position).is_some() { + if tool_data.state_from_pivot_gizmo(input.mouse.position).is_some() { cursor = MouseCursorIcon::Move; } @@ -1416,14 +1431,16 @@ impl Fsm for SelectToolFsmState { tool_data.snap_manager.cleanup(responses); tool_data.select_single_layer = None; - if let Some(start) = tool_data.dot_start { - let offset = tool_data.dot.pivot_disconnected().then_some(tool_data.drag_current - start).unwrap_or_default(); - tool_data.dot.pivot.pivot.as_mut().map(|v| *v += offset); + if let Some(start) = tool_data.pivot_gizmo_start { + let offset = tool_data.pivot_gizmo.pivot_disconnected().then_some(tool_data.drag_current - start).unwrap_or_default(); + if let Some(v) = tool_data.pivot_gizmo.pivot.pivot.as_mut() { + *v += offset; + } } - tool_data.dot_start = None; + tool_data.pivot_gizmo_start = None; - let dot = tool_data.get_as_dot(); - responses.add(TransformLayerMessage::SetDot { dot }); + let pivot_gizmo = tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } @@ -1434,9 +1451,12 @@ impl Fsm for SelectToolFsmState { ) => { let drag_too_small = input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON; let response = if drag_too_small { DocumentMessage::AbortTransaction } else { DocumentMessage::EndTransaction }; - let dot = tool_data.get_as_dot(); - responses.add(TransformLayerMessage::SetDot { dot }); + + let pivot_gizmo = tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); + responses.add(response); + tool_data.axis_align = false; tool_data.snap_manager.cleanup(responses); @@ -1572,36 +1592,42 @@ impl Fsm for SelectToolFsmState { (_, SelectToolMessage::SetPivot { position }) => { responses.add(DocumentMessage::StartTransaction); - tool_data.dot.pivot.last_non_none_reference = position; - tool_data.dot.pivot.pinned = false; + tool_data.pivot_gizmo.pivot.last_non_none_reference_point = position; + tool_data.pivot_gizmo.pivot.pinned = false; + let pos: Option = position.into(); - tool_data.dot.pivot.set_normalized_position(pos.unwrap()); - let dot = tool_data.get_as_dot(); - responses.add(TransformLayerMessage::SetDot { dot }); + + tool_data.pivot_gizmo.pivot.set_normalized_position(pos.unwrap()); + + let pivot_gizmo = tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); + responses.add(NodeGraphMessage::RunDocumentGraph); self } (_, SelectToolMessage::SyncHistory) => { - tool_data.sync_history(&document); + tool_data.sync_history(document); self } (_, SelectToolMessage::ShiftSelectedNodes { offset }) => { let offset = document.metadata().document_to_viewport.transform_vector2(offset); - if tool_data.dot.pivot_disconnected() { - tool_data.dot.pivot.pivot.as_mut().map(|v| *v += offset); + if tool_data.pivot_gizmo.pivot_disconnected() { + if let Some(v) = tool_data.pivot_gizmo.pivot.pivot.as_mut() { + *v += offset; + } } self } (_, SelectToolMessage::PivotShift { offset, flush }) => { if flush { - tool_data.dot.pivot.pivot.as_mut().map(|v| *v += tool_data.dot_shift.take().unwrap_or_default()); + tool_data.pivot_gizmo.pivot.pivot.as_mut().map(|v| *v += tool_data.pivot_gizmo_shift.take().unwrap_or_default()); return self; } - if tool_data.dot.pivot_disconnected() { - tool_data.dot_shift = offset; + if tool_data.pivot_gizmo.pivot_disconnected() { + tool_data.pivot_gizmo_shift = offset; } self diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs index 1006b6dfe0..c819260e58 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -2,7 +2,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::transformation::TransformType; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::pivot::Dot; +use crate::messages::tool::common_functionality::pivot::PivotGizmo; use glam::DVec2; #[impl_message(Message, ToolMessage, TransformLayer)] @@ -17,7 +17,6 @@ pub enum TransformLayerMessage { BeginGrab, BeginRotate, BeginScale, - SetDot { dot: Dot }, BeginGRS { operation: TransformType }, BeginGrabPen { last_point: DVec2, handle: DVec2 }, BeginRotatePen { last_point: DVec2, handle: DVec2 }, @@ -31,4 +30,5 @@ pub enum TransformLayerMessage { TypeDecimalPoint, TypeDigit { digit: u8 }, TypeNegate, + SetPivotGizmo { pivot_gizmo: PivotGizmo }, } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index b0b61c04f4..a3d108efe9 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -5,7 +5,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye use crate::messages::portfolio::document::utility_types::misc::PTZ; use crate::messages::portfolio::document::utility_types::transformation::{Axis, OriginalTransforms, Selected, TransformOperation, TransformType, Typing}; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::pivot::{Dot, DotType}; +use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType}; use crate::messages::tool::common_functionality::shape_editor::ShapeState; use crate::messages::tool::tool_messages::tool_prelude::Key; use crate::messages::tool::utility_types::{ToolData, ToolType}; @@ -35,7 +35,7 @@ pub struct TransformLayerMessageHandler { start_mouse: ViewportPosition, original_transforms: OriginalTransforms, - dot: Dot, + pivot_gizmo: PivotGizmo, pivot: ViewportPosition, path_bounds: Option<[DVec2; 2]>, @@ -71,10 +71,10 @@ fn calculate_pivot( vector_data: &VectorData, viewspace: DAffine2, get_location: impl Fn(&ManipulatorPointId) -> Option, - dot: &mut Dot, + gizmo: &mut PivotGizmo, ) -> (Option<(DVec2, DVec2)>, Option<[DVec2; 2]>) { let average_position = || { - let mut point_count = 0; + let mut point_count = 0_usize; selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::() / point_count as f64 }; let bounds = selected_points.iter().filter_map(|p| get_location(p)).fold(None, |acc: Option<[DVec2; 2]>, point| { @@ -88,19 +88,17 @@ fn calculate_pivot( Some([point, point]) } }); - dot.pivot.recalculate_pivot_for_layer(document, bounds); + gizmo.pivot.recalculate_pivot_for_layer(document, bounds); let position = || { - { - if dot.state.enabled { - match dot.state.dot { - DotType::Average => None, - DotType::Active => dot.point.and_then(|p| get_location(&p)), - DotType::Pivot => dot.pivot.pivot, - } - } else { - None + (if !gizmo.state.disabled { + match gizmo.state.gizmo_type { + PivotGizmoType::Average => None, + PivotGizmoType::Active => gizmo.point.and_then(|p| get_location(&p)), + PivotGizmoType::Pivot => gizmo.pivot.pivot, } - } + } else { + None + }) .unwrap_or_else(average_position) }; let [point] = selected_points.as_slice() else { @@ -112,14 +110,14 @@ fn calculate_pivot( match point { ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => { // Get the anchor position and transform it to the pivot - let (Some(pivot_pos), Some(position)) = ( + let (Some(pivot_position), Some(position)) = ( point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position)), point.get_position(vector_data), ) else { return (None, None); }; let target = viewspace.transform_point2(position); - (Some((pivot_pos, target)), None) + (Some((pivot_position, target)), None) } _ => { // Calculate the average position of all selected points @@ -220,11 +218,11 @@ impl MessageHandler> for TransformLayer } if !using_path_tool { - self.dot.recalculate_transform(document); + self.pivot_gizmo.recalculate_transform(document); let network_interface = &document.network_interface; let mean_center_bbox = network_interface.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network_interface); - let dot_position = self.dot.position(document); - *selected.pivot = dot_position; + let gizmo_position = self.pivot_gizmo.position(document); + *selected.pivot = gizmo_position; self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(mean_center_bbox); } @@ -252,7 +250,7 @@ impl MessageHandler> for TransformLayer &vector_data, viewspace, |point: &ManipulatorPointId| get_location(&point), - &mut self.dot, + &mut self.pivot_gizmo, ) { *selected.pivot = new_pivot; self.path_bounds = bounds; @@ -393,10 +391,6 @@ impl MessageHandler> for TransformLayer overlay_context.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]); } } - - if let Some(_) = self.path_bounds { - // overlay_context.quad(Quad::from_box(bounds), None, None); - } } // Messages @@ -754,7 +748,9 @@ impl MessageHandler> for TransformLayer self.initial_transform, ) } - TransformLayerMessage::SetDot { dot } => self.dot = dot, + TransformLayerMessage::SetPivotGizmo { pivot_gizmo } => { + self.pivot_gizmo = pivot_gizmo; + } } } diff --git a/frontend/src/components/widgets/inputs/ReferencePointInput.svelte b/frontend/src/components/widgets/inputs/ReferencePointInput.svelte index 14531e489b..fe1839d072 100644 --- a/frontend/src/components/widgets/inputs/ReferencePointInput.svelte +++ b/frontend/src/components/widgets/inputs/ReferencePointInput.svelte @@ -7,13 +7,14 @@ export let value: string; export let disabled = false; + export let tooltip: string | undefined = undefined; function setValue(newValue: ReferencePoint) { dispatch("value", newValue); } -
+
diff --git a/frontend/src/messages.ts b/frontend/src/messages.ts index 53cd2a26e5..28b777f806 100644 --- a/frontend/src/messages.ts +++ b/frontend/src/messages.ts @@ -1340,6 +1340,9 @@ export class ReferencePointInput extends WidgetProps { value!: ReferencePoint; disabled!: boolean; + + @Transform(({ value }: { value: string }) => value || undefined) + tooltip!: string | undefined; } // WIDGET From 0dceed70474c4f716dd801f5bd2edb4190af60ab Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Tue, 8 Jul 2025 13:28:21 +0530 Subject: [PATCH 52/54] fixes --- editor/src/messages/tool/tool_messages/select_tool.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index bac9725787..9ae3459a7d 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -562,7 +562,7 @@ impl SelectToolData { fn state_from_pivot_gizmo(&self, mouse: DVec2) -> Option { match self.pivot_gizmo.state.gizmo_type { - PivotGizmoType::Pivot => self.pivot_gizmo.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), + PivotGizmoType::Pivot if self.pivot_gizmo.state.is_pivot() => self.pivot_gizmo.pivot.is_over(mouse).then_some(SelectToolFsmState::DraggingPivot), _ => None, } } @@ -1617,6 +1617,9 @@ impl Fsm for SelectToolFsmState { if let Some(v) = tool_data.pivot_gizmo.pivot.pivot.as_mut() { *v += offset; } + + let pivot_gizmo = tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); } self @@ -1624,6 +1627,8 @@ impl Fsm for SelectToolFsmState { (_, SelectToolMessage::PivotShift { offset, flush }) => { if flush { tool_data.pivot_gizmo.pivot.pivot.as_mut().map(|v| *v += tool_data.pivot_gizmo_shift.take().unwrap_or_default()); + let pivot_gizmo = tool_data.pivot_gizmo(); + responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo }); return self; } if tool_data.pivot_gizmo.pivot_disconnected() { From 42d0dd5eef2019b0a62bb092a8433b98c34e2d9f Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Tue, 8 Jul 2025 13:41:27 +0530 Subject: [PATCH 53/54] fixes --- .../tool/transform_layer/transform_layer_message_handler.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index a3d108efe9..c03d173198 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -301,11 +301,10 @@ impl MessageHandler> for TransformLayer TransformOperation::Grabbing(translation) => { let translation = translation.to_dvec(self.initial_transform, self.increments); let viewport_translate = document_to_viewport.transform_vector2(translation); - let pivot = document_to_viewport.transform_point2(self.grab_target); + let pivot = document_to_viewport.transform_point2(self.local_pivot); let quad = Quad::from_box([pivot, pivot + viewport_translate]).0; let e1 = (self.layer_bounding_box.0[1] - self.layer_bounding_box.0[0]).normalize_or(DVec2::X); - debug!("A"); responses.add(SelectToolMessage::PivotShift { offset: Some(viewport_translate), flush: false, From f953014044d546379a872766f71853d6e35c7847 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Tue, 8 Jul 2025 13:52:51 +0530 Subject: [PATCH 54/54] fixes --- .../transform_layer/transform_layer_message_handler.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index c03d173198..7258163772 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -219,12 +219,9 @@ impl MessageHandler> for TransformLayer if !using_path_tool { self.pivot_gizmo.recalculate_transform(document); - let network_interface = &document.network_interface; - let mean_center_bbox = network_interface.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network_interface); - let gizmo_position = self.pivot_gizmo.position(document); - *selected.pivot = gizmo_position; + *selected.pivot = self.pivot_gizmo.position(document); self.local_pivot = document.metadata().document_to_viewport.inverse().transform_point2(*selected.pivot); - self.grab_target = document.metadata().document_to_viewport.inverse().transform_point2(mean_center_bbox); + self.grab_target = self.local_pivot; } // Here vector data from all layers is not considered which can be a problem in pivot calculation else if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { @@ -301,7 +298,7 @@ impl MessageHandler> for TransformLayer TransformOperation::Grabbing(translation) => { let translation = translation.to_dvec(self.initial_transform, self.increments); let viewport_translate = document_to_viewport.transform_vector2(translation); - let pivot = document_to_viewport.transform_point2(self.local_pivot); + let pivot = document_to_viewport.transform_point2(self.grab_target); let quad = Quad::from_box([pivot, pivot + viewport_translate]).0; let e1 = (self.layer_bounding_box.0[1] - self.layer_bounding_box.0[0]).normalize_or(DVec2::X);