From 4ad72eac622fb908996efd174cf4a6aea4dbd78d Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Sun, 1 Dec 2024 10:08:36 +0530 Subject: [PATCH 01/19] implemented left selection logic --- .../tool/tool_messages/select_tool.rs | 28 ++++++++++++++++++- 1 file changed, 27 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 937b7c847a..d28087f568 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -4,6 +4,7 @@ use super::tool_prelude::*; use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE}; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::utility_types::Direction; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; @@ -19,6 +20,7 @@ use graph_craft::document::NodeId; use graphene_core::renderer::Quad; use graphene_std::renderer::Rect; use graphene_std::vector::misc::BooleanOperation; +// use web_sys::console; use std::fmt; @@ -39,6 +41,12 @@ pub enum SelectOptionsUpdate { NestedSelectionBehavior(NestedSelectionBehavior), } +enum SelectionDirection { + LeftWards, + Rightwards, + None, +} + #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum NestedSelectionBehavior { #[default] @@ -301,6 +309,17 @@ impl SelectToolData { Quad::from_box(bbox) } + fn calculate_direction(&self) -> SelectionDirection { + let bbox: [DVec2; 2] = self.selection_box(); + if bbox[1].x > bbox[0].x { + SelectionDirection::Rightwards + } else if bbox[1].x < bbox[0].x { + SelectionDirection::LeftWards + } else { + SelectionDirection::None + } + } + fn selection_box(&self) -> [DVec2; 2] { if self.drag_current == self.drag_start { let tolerance = DVec2::splat(SELECTION_TOLERANCE); @@ -913,6 +932,7 @@ impl Fsm for SelectToolFsmState { if !tool_data.has_dragged && input.keyboard.key(remove_from_selection) && tool_data.layer_selected_on_start.is_none() { let quad = tool_data.selection_quad(); + let intersection = document.intersect_quad_no_artboards(quad, input); if let Some(path) = intersection.last() { @@ -1006,7 +1026,13 @@ impl Fsm for SelectToolFsmState { } (SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { let quad = tool_data.selection_quad(); - let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); + let direction = tool_data.calculate_direction(); + // let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); + let new_selected: HashSet<_> = match direction { + SelectionDirection::Rightwards => HashSet::new(), + SelectionDirection::LeftWards => document.intersect_quad_no_artboards(quad, input).collect(), + SelectionDirection::None => HashSet::new(), + }; let current_selected: HashSet<_> = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect(); if new_selected != current_selected { tool_data.layers_dragging = new_selected.into_iter().collect(); From e10db918bdf7769c0eed72b8684f5619ca506db5 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Mon, 23 Dec 2024 18:01:00 +0530 Subject: [PATCH 02/19] added logic for right ward selection --- .../document/document_message_handler.rs | 36 +++++++++++++++++++ .../tool/tool_messages/select_tool.rs | 4 +-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 303ff572f6..63a2e5a663 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1389,6 +1389,42 @@ impl DocumentMessageHandler { self.intersect_quad(viewport_quad, ipp).filter(|layer| !self.network_interface.is_artboard(&layer.to_node(), &[])) } + pub fn is_layer_fully_inside(&self, layer: &LayerNodeIdentifier, quad: graphene_core::renderer::Quad) -> bool { + // Get the bounding box of the layer in document space + if let Some(bounding_box) = self.metadata().bounding_box_viewport(*layer) { + // Check if the bounding box is fully within the selection quad + let [top_left, bottom_right] = bounding_box; + + // info!("bounding box = {:?}", bounding_box); + + // info!("Quad input: {:?}", quad); + let quad_bbox = quad.bounding_box(); + // info!("quad box = {:?}", quad_bbox); + + let quad_left = quad_bbox[0].x; + let quad_right = quad_bbox[1].x; + let quad_top = quad_bbox[0].y.max(quad_bbox[1].y); // Correct top + let quad_bottom = quad_bbox[0].y.min(quad_bbox[1].y); // Correct bottom + + // Extract layer's bounding box coordinates + let layer_left = top_left.x; + let layer_right = bottom_right.x; + let layer_top = bottom_right.y; + let layer_bottom = top_left.y; + + let is_fully_contained = layer_left >= quad_left && layer_right <= quad_right && layer_top <= quad_top && layer_bottom >= quad_bottom; + + // // Debug logging + // log::info!("Layer Bounds: left = {}, right = {}, top = {}, bottom = {}", layer_left, layer_right, layer_top, layer_bottom); + // log::info!("Quad Bounds: left = {}, right = {}, top = {}, bottom = {}", quad_left, quad_right, quad_top, quad_bottom); + // log::info!("Layer is fully contained: {}", is_fully_contained); + + is_fully_contained + } else { + false + } + } + /// Find all of the layers that were clicked on from a viewport space location pub fn click_xray(&self, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + '_ { let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index d28087f568..eea54dba29 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -6,7 +6,7 @@ use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::node_graph::utility_types::Direction; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; -use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::document_metadata::{self, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::transformation::Selected; @@ -1029,7 +1029,7 @@ impl Fsm for SelectToolFsmState { let direction = tool_data.calculate_direction(); // let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); let new_selected: HashSet<_> = match direction { - SelectionDirection::Rightwards => HashSet::new(), + SelectionDirection::Rightwards => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), SelectionDirection::LeftWards => document.intersect_quad_no_artboards(quad, input).collect(), SelectionDirection::None => HashSet::new(), }; From b2450fb5a667f8a87850d6c6a1a87147e4c4ca1f Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Mon, 23 Dec 2024 18:06:33 +0530 Subject: [PATCH 03/19] removed the logs code --- .../portfolio/document/document_message_handler.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 63a2e5a663..c010e7a89b 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1395,11 +1395,7 @@ impl DocumentMessageHandler { // Check if the bounding box is fully within the selection quad let [top_left, bottom_right] = bounding_box; - // info!("bounding box = {:?}", bounding_box); - - // info!("Quad input: {:?}", quad); let quad_bbox = quad.bounding_box(); - // info!("quad box = {:?}", quad_bbox); let quad_left = quad_bbox[0].x; let quad_right = quad_bbox[1].x; @@ -1414,11 +1410,6 @@ impl DocumentMessageHandler { let is_fully_contained = layer_left >= quad_left && layer_right <= quad_right && layer_top <= quad_top && layer_bottom >= quad_bottom; - // // Debug logging - // log::info!("Layer Bounds: left = {}, right = {}, top = {}, bottom = {}", layer_left, layer_right, layer_top, layer_bottom); - // log::info!("Quad Bounds: left = {}, right = {}, top = {}, bottom = {}", quad_left, quad_right, quad_top, quad_bottom); - // log::info!("Layer is fully contained: {}", is_fully_contained); - is_fully_contained } else { false From cc2ec2ee6207fede135613ada58911fd0885e67d Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Tue, 24 Dec 2024 12:09:26 +0530 Subject: [PATCH 04/19] corrected capitalization error --- editor/src/messages/tool/tool_messages/select_tool.rs | 2 +- 1 file changed, 1 insertion(+), 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 eea54dba29..27786981e2 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -42,7 +42,7 @@ pub enum SelectOptionsUpdate { } enum SelectionDirection { - LeftWards, + Leftwards, Rightwards, None, } From 99ed23a4dbb17dc4e9993c520445f181301d633b Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Tue, 24 Dec 2024 12:10:42 +0530 Subject: [PATCH 05/19] corrected capitalization error --- editor/src/messages/tool/tool_messages/select_tool.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 27786981e2..0f8a078fea 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -314,7 +314,7 @@ impl SelectToolData { if bbox[1].x > bbox[0].x { SelectionDirection::Rightwards } else if bbox[1].x < bbox[0].x { - SelectionDirection::LeftWards + SelectionDirection::Leftwards } else { SelectionDirection::None } @@ -1030,7 +1030,7 @@ impl Fsm for SelectToolFsmState { // let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); let new_selected: HashSet<_> = match direction { SelectionDirection::Rightwards => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), - SelectionDirection::LeftWards => document.intersect_quad_no_artboards(quad, input).collect(), + SelectionDirection::Leftwards => document.intersect_quad_no_artboards(quad, input).collect(), SelectionDirection::None => HashSet::new(), }; let current_selected: HashSet<_> = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect(); From 199630e97e73a7b0f726967b8daa64d716622509 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Tue, 24 Dec 2024 17:26:01 +0530 Subject: [PATCH 06/19] added radio buttons for selection_mode --- .../preferences_dialog_message_handler.rs | 41 +++++++++++++++++++ editor/src/messages/preferences/mod.rs | 3 ++ .../messages/preferences/preference_type.rs | 18 ++++++++ .../preferences/preferences_message.rs | 4 +- .../preferences_message_handler.rs | 4 ++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 editor/src/messages/preferences/preference_type.rs diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index b084df83f8..642e282d14 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -1,4 +1,5 @@ use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; pub struct PreferencesDialogMessageData<'a> { @@ -62,6 +63,42 @@ impl PreferencesDialogMessageHandler { .widget_holder(), ]; + let selection_mode_tooltip = "Choose the selection mode for objects in the editor"; + let selection_mode_checkboxes = vec![ + CheckboxInput::new(matches!(preferences.selection_mode, SelectionMode::Touched)) + .tooltip("Select objects that are touched by the selection area") + .on_update(|_| { + PreferencesMessage::SelectionMode { + selection_mode: SelectionMode::Touched, + } + .into() + }) + .widget_holder(), + TextLabel::new("Touched").table_align(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(matches!(preferences.selection_mode, SelectionMode::Contained)) + .tooltip("Select objects that are fully contained within the selection area") + .on_update(|_| { + PreferencesMessage::SelectionMode { + selection_mode: SelectionMode::Contained, + } + .into() + }) + .widget_holder(), + TextLabel::new("Contained").table_align(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + CheckboxInput::new(matches!(preferences.selection_mode, SelectionMode::ByDragDirection)) + .tooltip("Select objects based on the drag direction of the selection area") + .on_update(|_| { + PreferencesMessage::SelectionMode { + selection_mode: SelectionMode::ByDragDirection, + } + .into() + }) + .widget_holder(), + TextLabel::new("By Drag Direction").table_align(true).widget_holder(), + ]; + // TODO: Reenable when Imaginate is restored // let imaginate_server_hostname = vec![ // TextLabel::new("Imaginate").min_width(60).italic(true).widget_holder(), @@ -90,6 +127,10 @@ impl PreferencesDialogMessageHandler { LayoutGroup::Row { widgets: zoom_with_scroll }, LayoutGroup::Row { widgets: renderer_section }, LayoutGroup::Row { widgets: use_vello }, + LayoutGroup::Row { + widgets: vec![TextLabel::new("Selection Mode").italic(true).widget_holder()], + }, + LayoutGroup::Row { widgets: selection_mode_checkboxes }, // LayoutGroup::Row { widgets: imaginate_server_hostname }, // LayoutGroup::Row { widgets: imaginate_refresh_frequency }, ])) diff --git a/editor/src/messages/preferences/mod.rs b/editor/src/messages/preferences/mod.rs index f61ee402ce..872ca43677 100644 --- a/editor/src/messages/preferences/mod.rs +++ b/editor/src/messages/preferences/mod.rs @@ -1,6 +1,9 @@ +mod preference_type; mod preferences_message; mod preferences_message_handler; +#[doc(inline)] +pub use preference_type::SelectionMode; #[doc(inline)] pub use preferences_message::{PreferencesMessage, PreferencesMessageDiscriminant}; #[doc(inline)] diff --git a/editor/src/messages/preferences/preference_type.rs b/editor/src/messages/preferences/preference_type.rs new file mode 100644 index 0000000000..3215ada685 --- /dev/null +++ b/editor/src/messages/preferences/preference_type.rs @@ -0,0 +1,18 @@ +use std::fmt; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum SelectionMode { + Touched, + Contained, + ByDragDirection, +} + +impl fmt::Display for SelectionMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SelectionMode::Touched => write!(f, "Touched"), + SelectionMode::Contained => write!(f, "Contained"), + SelectionMode::ByDragDirection => write!(f, "By Drag Direction"), + } + } +} diff --git a/editor/src/messages/preferences/preferences_message.rs b/editor/src/messages/preferences/preferences_message.rs index 44f1c68613..68e57aeacb 100644 --- a/editor/src/messages/preferences/preferences_message.rs +++ b/editor/src/messages/preferences/preferences_message.rs @@ -1,13 +1,13 @@ +use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; - #[impl_message(Message, Preferences)] #[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum PreferencesMessage { Load { preferences: String }, ResetToDefaults, - ImaginateRefreshFrequency { seconds: f64 }, UseVello { use_vello: bool }, + SelectionMode { selection_mode: SelectionMode }, ImaginateServerHostname { hostname: String }, ModifyLayout { zoom_with_scroll: bool }, } diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index 940c8aed3a..a694932b4e 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -1,4 +1,5 @@ use crate::messages::input_mapper::key_mapping::MappingVariant; +use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; use graph_craft::wasm_application_io::EditorPreferences; @@ -8,6 +9,7 @@ pub struct PreferencesMessageHandler { pub imaginate_refresh_frequency: f64, pub zoom_with_scroll: bool, pub use_vello: bool, + pub selection_mode: SelectionMode, } impl PreferencesMessageHandler { @@ -34,6 +36,7 @@ impl Default for PreferencesMessageHandler { imaginate_refresh_frequency: 1., zoom_with_scroll: matches!(MappingVariant::default(), MappingVariant::ZoomWithScroll), use_vello, + selection_mode: SelectionMode::Touched, } } } @@ -98,6 +101,7 @@ impl MessageHandler for PreferencesMessageHandler { responses.add(KeyMappingMessage::ModifyMapping(variant)); responses.add(FrontendMessage::UpdateZoomWithScroll { zoom_with_scroll }); } + PreferencesMessage::SelectionMode { selection_mode } => todo!(), } responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); From c3b7d87752ffd074f094101301ebb387b6e97b81 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Tue, 24 Dec 2024 18:15:34 +0530 Subject: [PATCH 07/19] fixed multiple selection of checkboxes --- .../preferences_dialog/preferences_dialog_message_handler.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index 642e282d14..bc423a73b1 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -64,6 +64,7 @@ impl PreferencesDialogMessageHandler { ]; let selection_mode_tooltip = "Choose the selection mode for objects in the editor"; + let selection_mode_checkboxes = vec![ CheckboxInput::new(matches!(preferences.selection_mode, SelectionMode::Touched)) .tooltip("Select objects that are touched by the selection area") From d91da7ff4d9eb59a969a99cd6008c9a584efae81 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Tue, 24 Dec 2024 19:16:35 +0530 Subject: [PATCH 08/19] adapted to the RadioEntryData --- .../preferences_dialog_message_handler.rs | 50 +++++++++---------- .../preferences_message_handler.rs | 6 ++- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index bc423a73b1..58ba5ea310 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -1,4 +1,6 @@ -use crate::messages::layout::utility_types::widget_prelude::*; +use std::sync::Arc; + +use crate::messages::layout::utility_types::{layout_widget, widget_prelude::*}; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; @@ -63,42 +65,40 @@ impl PreferencesDialogMessageHandler { .widget_holder(), ]; - let selection_mode_tooltip = "Choose the selection mode for objects in the editor"; - - let selection_mode_checkboxes = vec![ - CheckboxInput::new(matches!(preferences.selection_mode, SelectionMode::Touched)) + let selection_section = vec![TextLabel::new("Selection Mode").italic(true).widget_holder()]; + let selection_mode = RadioInput::new(vec![ + RadioEntryData::new("touched") + .label("Touched") .tooltip("Select objects that are touched by the selection area") - .on_update(|_| { + .on_update(move |_| { PreferencesMessage::SelectionMode { selection_mode: SelectionMode::Touched, } .into() - }) - .widget_holder(), - TextLabel::new("Touched").table_align(true).widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), - CheckboxInput::new(matches!(preferences.selection_mode, SelectionMode::Contained)) + }), + RadioEntryData::new("contained") + .label("Contained") .tooltip("Select objects that are fully contained within the selection area") - .on_update(|_| { + .on_update(move |_| { PreferencesMessage::SelectionMode { selection_mode: SelectionMode::Contained, } .into() - }) - .widget_holder(), - TextLabel::new("Contained").table_align(true).widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), - CheckboxInput::new(matches!(preferences.selection_mode, SelectionMode::ByDragDirection)) + }), + RadioEntryData::new("by_drag_direction") + .label("By Drag Direction") .tooltip("Select objects based on the drag direction of the selection area") - .on_update(|_| { + .on_update(move |_| { PreferencesMessage::SelectionMode { selection_mode: SelectionMode::ByDragDirection, } .into() - }) - .widget_holder(), - TextLabel::new("By Drag Direction").table_align(true).widget_holder(), - ]; + }), + ]) + .selected_index(Some( + (preferences.selection_mode == SelectionMode::ByDragDirection) as u32, // Accessing selection_mode correctly + )) + .widget_holder(); // TODO: Reenable when Imaginate is restored // let imaginate_server_hostname = vec![ @@ -128,10 +128,8 @@ impl PreferencesDialogMessageHandler { LayoutGroup::Row { widgets: zoom_with_scroll }, LayoutGroup::Row { widgets: renderer_section }, LayoutGroup::Row { widgets: use_vello }, - LayoutGroup::Row { - widgets: vec![TextLabel::new("Selection Mode").italic(true).widget_holder()], - }, - LayoutGroup::Row { widgets: selection_mode_checkboxes }, + LayoutGroup::Row { widgets: selection_section }, + LayoutGroup::Row { widgets: vec![selection_mode] }, // LayoutGroup::Row { widgets: imaginate_server_hostname }, // LayoutGroup::Row { widgets: imaginate_refresh_frequency }, ])) diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index a694932b4e..884c407c80 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -101,9 +101,11 @@ impl MessageHandler for PreferencesMessageHandler { responses.add(KeyMappingMessage::ModifyMapping(variant)); responses.add(FrontendMessage::UpdateZoomWithScroll { zoom_with_scroll }); } - PreferencesMessage::SelectionMode { selection_mode } => todo!(), + PreferencesMessage::SelectionMode { selection_mode } => { + log::info!("Setting selection mode: {:?}", selection_mode); + self.selection_mode = selection_mode; + } } - responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); } From f98b9cec6cb08a40063f835bf399062545169e6f Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Wed, 25 Dec 2024 22:08:02 +0530 Subject: [PATCH 09/19] State management bug --- .../preferences_dialog_message_handler.rs | 8 +++-- .../messages/preferences/preference_type.rs | 6 ++++ .../preferences_message_handler.rs | 6 +++- .../tool/tool_messages/select_tool.rs | 29 ++++++++++++++----- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index 58ba5ea310..8e77f3441c 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -95,9 +95,11 @@ impl PreferencesDialogMessageHandler { .into() }), ]) - .selected_index(Some( - (preferences.selection_mode == SelectionMode::ByDragDirection) as u32, // Accessing selection_mode correctly - )) + .selected_index(Some(match preferences.selection_mode { + SelectionMode::Touched => 0, + SelectionMode::Contained => 1, + SelectionMode::ByDragDirection => 2, + })) .widget_holder(); // TODO: Reenable when Imaginate is restored diff --git a/editor/src/messages/preferences/preference_type.rs b/editor/src/messages/preferences/preference_type.rs index 3215ada685..84966bf89e 100644 --- a/editor/src/messages/preferences/preference_type.rs +++ b/editor/src/messages/preferences/preference_type.rs @@ -16,3 +16,9 @@ impl fmt::Display for SelectionMode { } } } + +impl Default for SelectionMode { + fn default() -> Self { + SelectionMode::Touched + } +} diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index 884c407c80..71aa791d00 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -1,6 +1,10 @@ use crate::messages::input_mapper::key_mapping::MappingVariant; +use crate::messages::portfolio::document::DocumentMessageHandler; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; +use crate::messages::tool::tool_messages::select_tool::SelectTool; +use crate::messages::tool::ToolMessageData; +use graph_craft::document; use graph_craft::wasm_application_io::EditorPreferences; #[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type)] @@ -102,7 +106,7 @@ impl MessageHandler for PreferencesMessageHandler { responses.add(FrontendMessage::UpdateZoomWithScroll { zoom_with_scroll }); } PreferencesMessage::SelectionMode { selection_mode } => { - log::info!("Setting selection mode: {:?}", selection_mode); + info!("Setting selection mode to: {:?}", selection_mode); self.selection_mode = selection_mode; } } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 0f8a078fea..a7715af77e 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -10,6 +10,8 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{sel use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::transformation::Selected; +use crate::messages::preferences::PreferencesMessageHandler; +use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; use crate::messages::tool::common_functionality::pivot::Pivot; use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager}; @@ -77,7 +79,6 @@ pub enum SelectToolMessage { // Standard messages Abort, Overlays(OverlayContext), - // Tool-specific messages DragStart { extend_selection: Key, select_deepest: Key }, DragStop { remove_from_selection: Key }, @@ -87,6 +88,7 @@ pub enum SelectToolMessage { PointerOutsideViewport(SelectToolPointerKeys), SelectOptions(SelectOptionsUpdate), SetPivot { position: PivotPosition }, + UpdateSelectionMode { selection_mode: SelectionMode }, } impl ToolMetadata for SelectTool { @@ -263,6 +265,7 @@ enum SelectToolFsmState { RotatingBounds, DraggingPivot, } + impl Default for SelectToolFsmState { fn default() -> Self { let selection = NestedSelectionBehavior::Deepest; @@ -288,6 +291,7 @@ struct SelectToolData { selected_layers_changed: bool, snap_candidates: Vec, auto_panning: AutoPanning, + selection_mode: SelectionMode, } impl SelectToolData { @@ -304,12 +308,12 @@ impl SelectToolData { } } - fn selection_quad(&self) -> Quad { + pub fn selection_quad(&self) -> Quad { let bbox = self.selection_box(); Quad::from_box(bbox) } - fn calculate_direction(&self) -> SelectionDirection { + pub fn calculate_direction(&self) -> SelectionDirection { let bbox: [DVec2; 2] = self.selection_box(); if bbox[1].x > bbox[0].x { SelectionDirection::Rightwards @@ -320,7 +324,7 @@ impl SelectToolData { } } - fn selection_box(&self) -> [DVec2; 2] { + pub fn selection_box(&self) -> [DVec2; 2] { if self.drag_current == self.drag_start { let tolerance = DVec2::splat(SELECTION_TOLERANCE); [self.drag_start - tolerance, self.drag_start + tolerance] @@ -1025,14 +1029,23 @@ impl Fsm for SelectToolFsmState { SelectToolFsmState::Ready { selection } } (SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { + let mut preferences_handler = PreferencesMessageHandler::default(); + tool_data.selection_mode = preferences_handler.selection_mode.clone(); + info!("Setting selection mode to: {:?}", tool_data.selection_mode); let quad = tool_data.selection_quad(); let direction = tool_data.calculate_direction(); + info!("Using SelectionMode: {:?}", tool_data.selection_mode); // let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); - let new_selected: HashSet<_> = match direction { - SelectionDirection::Rightwards => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), - SelectionDirection::Leftwards => document.intersect_quad_no_artboards(quad, input).collect(), - SelectionDirection::None => HashSet::new(), + let new_selected: HashSet<_> = match tool_data.selection_mode { + SelectionMode::Touched => document.intersect_quad_no_artboards(quad, input).collect(), + SelectionMode::Contained => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), + SelectionMode::ByDragDirection => match direction { + SelectionDirection::Rightwards => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), + SelectionDirection::Leftwards => document.intersect_quad_no_artboards(quad, input).collect(), + SelectionDirection::None => HashSet::new(), + }, }; + let current_selected: HashSet<_> = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect(); if new_selected != current_selected { tool_data.layers_dragging = new_selected.into_iter().collect(); From 7271d82bb6a9e71cca16b89208d2460212175242 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Thu, 26 Dec 2024 19:28:06 +0530 Subject: [PATCH 10/19] integrated message system to selection_mode --- .../src/messages/frontend/frontend_message.rs | 5 +++++ .../messages/portfolio/portfolio_message.rs | 4 ++++ .../portfolio/portfolio_message_handler.rs | 8 ++++++++ editor/src/messages/portfolio/utility_types.rs | 2 ++ .../preferences/preferences_message_handler.rs | 2 +- editor/src/messages/tool/tool_message.rs | 5 ++++- .../messages/tool/tool_messages/select_tool.rs | 18 ++++++++++-------- editor/src/messages/tool/utility_types.rs | 1 + 8 files changed, 35 insertions(+), 10 deletions(-) diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index f5482cdeb1..6cb80b92cc 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -4,6 +4,7 @@ use crate::messages::portfolio::document::node_graph::utility_types::{ BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, FrontendNodeWire, Transform, WirePath, }; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; +use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; use crate::messages::tool::utility_types::HintData; @@ -294,4 +295,8 @@ pub enum FrontendMessage { #[serde(rename = "zoomWithScroll")] zoom_with_scroll: bool, }, + UpdateSelectionMode { + #[serde(rename = "selectionMode")] + selection_mode: SelectionMode, + }, } diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index 2674ec2f13..b25ad47e8a 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -2,6 +2,7 @@ use super::document::utility_types::document_metadata::LayerNodeIdentifier; use super::utility_types::PanelType; use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; +use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; use graphene_core::raster::Image; @@ -121,4 +122,7 @@ pub enum PortfolioMessage { UpdateDocumentWidgets, UpdateOpenDocumentsList, UpdateVelloPreference, + UpdateSelectionMode { + selection_mode: SelectionMode, + }, } diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index c658fb1de4..694fc63833 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -9,6 +9,7 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT}; use crate::messages::portfolio::document::DocumentMessageData; +use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType}; use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor}; @@ -38,6 +39,7 @@ pub struct PortfolioMessageHandler { copy_buffer: [Vec; INTERNAL_CLIPBOARD_COUNT as usize], pub persistent_data: PersistentData, pub executor: NodeGraphExecutor, + pub selection_mode: SelectionMode, } impl MessageHandler> for PortfolioMessageHandler { @@ -865,6 +867,12 @@ impl MessageHandler> for PortfolioMes responses.add(NodeGraphMessage::RunDocumentGraph); self.persistent_data.use_vello = preferences.use_vello; } + + PortfolioMessage::UpdateSelectionMode { selection_mode } => { + self.selection_mode = selection_mode; + info!("Selection mode updated to: {:?}", selection_mode); + responses.add(Message::Frontend(FrontendMessage::UpdateSelectionMode { selection_mode })); + } } } diff --git a/editor/src/messages/portfolio/utility_types.rs b/editor/src/messages/portfolio/utility_types.rs index a44e47838d..0c82676664 100644 --- a/editor/src/messages/portfolio/utility_types.rs +++ b/editor/src/messages/portfolio/utility_types.rs @@ -1,5 +1,7 @@ use graphene_std::{imaginate::ImaginatePersistentData, text::FontCache}; +use crate::messages::preferences::SelectionMode; + #[derive(Debug, Default)] pub struct PersistentData { pub font_cache: FontCache, diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index 71aa791d00..a361d40a19 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -97,7 +97,6 @@ impl MessageHandler for PreferencesMessageHandler { } PreferencesMessage::ModifyLayout { zoom_with_scroll } => { self.zoom_with_scroll = zoom_with_scroll; - let variant = match zoom_with_scroll { false => MappingVariant::Default, true => MappingVariant::ZoomWithScroll, @@ -108,6 +107,7 @@ impl MessageHandler for PreferencesMessageHandler { PreferencesMessage::SelectionMode { selection_mode } => { info!("Setting selection mode to: {:?}", selection_mode); self.selection_mode = selection_mode; + responses.add(PortfolioMessage::UpdateSelectionMode { selection_mode }); } } responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); diff --git a/editor/src/messages/tool/tool_message.rs b/editor/src/messages/tool/tool_message.rs index ed9e8c23f7..a5c138242d 100644 --- a/editor/src/messages/tool/tool_message.rs +++ b/editor/src/messages/tool/tool_message.rs @@ -1,6 +1,6 @@ use super::utility_types::ToolType; +use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; - use graphene_core::raster::color::Color; #[impl_message(Message, Tool)] @@ -98,4 +98,7 @@ pub enum ToolMessage { Undo, UpdateCursor, UpdateHints, + UpdateSelectionMode { + selection_mode: SelectionMode, + }, } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index a7715af77e..e700cab8d7 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -3,13 +3,15 @@ use super::tool_prelude::*; use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE}; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; -use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::graph_operation::utility_types::{self, TransformIn}; use crate::messages::portfolio::document::node_graph::utility_types::Direction; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::{self, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::transformation::Selected; +use crate::messages::portfolio::utility_types::PersistentData; +use crate::messages::portfolio::PortfolioMessageData; use crate::messages::preferences::PreferencesMessageHandler; use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; @@ -88,7 +90,6 @@ pub enum SelectToolMessage { PointerOutsideViewport(SelectToolPointerKeys), SelectOptions(SelectOptionsUpdate), SetPivot { position: PivotPosition }, - UpdateSelectionMode { selection_mode: SelectionMode }, } impl ToolMetadata for SelectTool { @@ -219,6 +220,10 @@ impl<'a> MessageHandler> for SelectT self.tool_data.nested_selection_behavior = nested_selection_behavior; responses.add(ToolMessage::UpdateHints); } + if let ToolMessage::UpdateSelectionMode { selection_mode } = message { + self.tool_data.selection_mode = selection_mode; + info!("Selection mode updated in SelectTool: {:?}", selection_mode); + } self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false); @@ -426,14 +431,13 @@ 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, .. } = tool_action_data; - + info!("Current selection mode during transition: {:?}", tool_data.selection_mode); let ToolMessage::Select(event) = event else { return self; }; match (self, event) { (_, SelectToolMessage::Overlays(mut overlay_context)) => { tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); - let selected_layers_count = document.network_interface.selected_nodes(&[]).unwrap().selected_unlocked_layers(&document.network_interface).count(); tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count; tool_data.selected_layers_count = selected_layers_count; @@ -1028,13 +1032,11 @@ impl Fsm for SelectToolFsmState { let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } } + (SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { - let mut preferences_handler = PreferencesMessageHandler::default(); - tool_data.selection_mode = preferences_handler.selection_mode.clone(); - info!("Setting selection mode to: {:?}", tool_data.selection_mode); let quad = tool_data.selection_quad(); let direction = tool_data.calculate_direction(); - info!("Using SelectionMode: {:?}", tool_data.selection_mode); + info!("mode under select is {:?}", tool_data.selection_mode); // let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); let new_selected: HashSet<_> = match tool_data.selection_mode { SelectionMode::Touched => document.intersect_quad_no_artboards(quad, input).collect(), diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs index 561c38dbe9..5282a2aff4 100644 --- a/editor/src/messages/tool/utility_types.rs +++ b/editor/src/messages/tool/utility_types.rs @@ -9,6 +9,7 @@ use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::input_mapper::utility_types::misc::ActionKeys; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::overlays::utility_types::OverlayProvider; +use crate::messages::preferences::PreferencesMessageHandler; use crate::messages::prelude::*; use crate::node_graph_executor::NodeGraphExecutor; From 36577950478dd1614e6c66e03fa10498bc2073c6 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Sun, 29 Dec 2024 11:09:18 +0530 Subject: [PATCH 11/19] updated --- .../utility_types/document_metadata.rs | 2 +- .../transformation_cage.rs | 10 +-- .../tool/tool_messages/artboard_tool.rs | 71 +++++++++++++++---- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index 1ef32ba91b..3fbef8220f 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -460,7 +460,7 @@ impl<'a> DoubleEndedIterator for DescendantsIter<'a> { #[derive(Debug, Clone, Copy, Default)] pub struct NodeRelations { - parent: Option, + pub parent: Option, previous_sibling: Option, next_sibling: Option, first_child: Option, diff --git a/editor/src/messages/tool/common_functionality/transformation_cage.rs b/editor/src/messages/tool/common_functionality/transformation_cage.rs index 647799c552..13fda76974 100644 --- a/editor/src/messages/tool/common_functionality/transformation_cage.rs +++ b/editor/src/messages/tool/common_functionality/transformation_cage.rs @@ -20,11 +20,11 @@ pub struct SizeSnapData<'a> { /// Contains the edges that are being dragged along with the original bounds. #[derive(Clone, Debug, Default)] pub struct SelectedEdges { - bounds: [DVec2; 2], - top: bool, - bottom: bool, - left: bool, - right: bool, + pub bounds: [DVec2; 2], + pub top: bool, + pub bottom: bool, + pub left: bool, + pub right: bool, // Aspect ratio in the form of width/height, so x:1 = width:height aspect_ratio: f64, } diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index 8536aac065..278cdc6169 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -1,4 +1,5 @@ use super::tool_prelude::*; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; @@ -110,12 +111,12 @@ struct ArtboardToolData { drag_current: DVec2, auto_panning: AutoPanning, snap_candidates: Vec, + // child_layers: Vec, } impl ArtboardToolData { fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, _input: &InputPreprocessorMessageHandler) { self.snap_candidates.clear(); - let Some(layer) = self.selected_artboard else { return }; if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) { @@ -123,6 +124,25 @@ impl ArtboardToolData { } } + pub fn get_child_layers_of_selected_artboard(&self, document: &DocumentMessageHandler) -> Vec { + let Some(artboard_id) = self.selected_artboard else { + return Vec::new(); + }; + let structure = document.metadata().structure.clone(); + let child_layers = structure + .iter() + .filter_map(|(layer_id, node_relations)| { + if let Some(parent_id) = node_relations.parent { + if parent_id == artboard_id { + return Some(*layer_id); + } + } + None + }) + .collect::>(); + child_layers + } + fn check_dragging_bounds(&mut self, cursor: DVec2) -> Option<(bool, bool, bool, bool)> { let bounding_box = self.bounding_box_manager.as_mut()?; let edges = bounding_box.check_selected_edges(cursor)?; @@ -195,19 +215,44 @@ impl ArtboardToolData { location: position.round().as_ivec2(), dimensions: size.round().as_ivec2(), }); + let artboard_bounds_viewport = document.metadata().bounding_box_viewport(self.selected_artboard.unwrap()); - // TODO: Resize artboard children when resizing left/top edges so that they stay in the same viewport space - // let old_top_left = bounds.bounds[0].round().as_ivec2(); - // let new_top_left = position.round().as_ivec2(); - // let top_left_delta = new_top_left - old_top_left; - // if top_left_delta != IVec2::ZERO { - // responses.add(GraphOperationMessage::TransformChange { - // layer: self.selected_artboard.unwrap(), - // transform: DAffine2::from_translation((-top_left_delta).into()), - // transform_in: TransformIn::Local, - // skip_rerender: false, - // }); - // } + let top_edge_resized = bounds.selected_edges.as_ref().map_or(false, |edges| edges.top); + let left_edge_resized = bounds.selected_edges.as_ref().map_or(false, |edges| edges.left); + let original_left_edge_x = bounds.bounds[0].x; + let original_top_edge_y = bounds.bounds[0].y; + + let translation_x = if left_edge_resized { + let delta_x = min.x.round() - original_left_edge_x.round(); + info!("mix.x :{},original_left_edge_x:{}", min.x.round(), original_left_edge_x); + delta_x + } else { + 0.0 + }; + + let translation_y = if top_edge_resized { + let deltay_y = min.y.round() - original_top_edge_y.round(); + deltay_y + } else { + 0.0 + }; + + let translation = DVec2::new(translation_x, translation_y); + let reverse_translation = DVec2::new( + if left_edge_resized { -translation.x } else { translation.x }, + if top_edge_resized { -translation.y } else { translation.y }, + ); + info!("Translation: {:?}, Reverse Translation: {:?}", translation, reverse_translation); + + let child_layers = self.get_child_layers_of_selected_artboard(document); + for layer in child_layers { + responses.add(GraphOperationMessage::TransformChange { + layer, + transform: DAffine2::from_translation((reverse_translation).into()), + transform_in: TransformIn::Local, + skip_rerender: false, + }); + } } } From c144289f1cfbd9842e9fed61deef8976824aca38 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Mon, 6 Jan 2025 18:25:25 +0530 Subject: [PATCH 12/19] updated --- .../messages/tool/tool_messages/artboard_tool.rs | 1 + .../messages/tool/tool_messages/select_tool.rs | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index 3bbff0a74e..cf90ade73c 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -112,6 +112,7 @@ struct ArtboardToolData { drag_current: DVec2, auto_panning: AutoPanning, snap_candidates: Vec, + dragging_current_artboard_location: IVec2, } impl ArtboardToolData { diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 1ff63a0a46..da3f137cea 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -14,7 +14,7 @@ use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::portfolio::PortfolioMessageData; use crate::messages::preferences::PreferencesMessageHandler; use crate::messages::preferences::SelectionMode; -use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; +use crate::messages::tool::common_functionality::graph_modification_utils::{get_text, is_layer_fed_by_node_of_name}; use crate::messages::tool::common_functionality::pivot::Pivot; use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager}; use crate::messages::tool::common_functionality::transformation_cage::*; @@ -431,7 +431,7 @@ impl Fsm for SelectToolFsmState { type ToolOptions = (); 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, .. } = tool_action_data; + let ToolActionHandlerData { document, input, font_cache, .. } = tool_action_data; info!("Current selection mode during transition: {:?}", tool_data.selection_mode); let ToolMessage::Select(event) = event else { return self; @@ -1043,8 +1043,13 @@ impl Fsm for SelectToolFsmState { SelectToolFsmState::Ready { selection } } - (SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { - + ( + SelectToolFsmState::DrawingBox { .. }, + SelectToolMessage::DragStop { + remove_from_selection, + negative_box_selection, + }, + ) => { let quad = tool_data.selection_quad(); let direction = tool_data.calculate_direction(); info!("mode under select is {:?}", tool_data.selection_mode); @@ -1063,7 +1068,7 @@ impl Fsm for SelectToolFsmState { if new_selected != current_selected { // Negative selection when both Shift and Ctrl are pressed if input.keyboard.key(remove_from_selection) && input.keyboard.key(negative_box_selection) { - let updated_selection = current_selected + let updated_selection: Vec = current_selected .into_iter() .filter(|layer| !new_selected.iter().any(|selected| layer.starts_with(*selected, document.metadata()))) .collect(); From a5360f2ef69a5975d9bc41932238fff0849d4c0f Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Wed, 8 Jan 2025 12:18:07 +0530 Subject: [PATCH 13/19] added selection mode to transition arms --- .../messages/preferences/preference_type.rs | 2 +- .../tool/tool_messages/select_tool.rs | 51 ++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/editor/src/messages/preferences/preference_type.rs b/editor/src/messages/preferences/preference_type.rs index 84966bf89e..c6ce4a967c 100644 --- a/editor/src/messages/preferences/preference_type.rs +++ b/editor/src/messages/preferences/preference_type.rs @@ -1,6 +1,6 @@ use std::fmt; -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type, Hash)] pub enum SelectionMode { Touched, Contained, diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index da3f137cea..f8a4d44ecd 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -219,6 +219,7 @@ impl<'a> MessageHandler> for SelectT 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; + // info!("nested mode updated : {:?}", nested_selection_behavior); responses.add(ToolMessage::UpdateHints); } if let ToolMessage::UpdateSelectionMode { selection_mode } = message { @@ -264,8 +265,8 @@ impl ToolTransition for SelectTool { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum SelectToolFsmState { - Ready { selection: NestedSelectionBehavior }, - DrawingBox { selection: NestedSelectionBehavior }, + Ready { selection: NestedSelectionBehavior, selection_mode: SelectionMode }, + DrawingBox { selection: NestedSelectionBehavior, selection_mode: SelectionMode }, Dragging, ResizingBounds, RotatingBounds, @@ -275,7 +276,8 @@ enum SelectToolFsmState { impl Default for SelectToolFsmState { fn default() -> Self { let selection = NestedSelectionBehavior::Deepest; - SelectToolFsmState::Ready { selection } + let selection_mode = SelectionMode::Touched; + SelectToolFsmState::Ready { selection, selection_mode } } } @@ -433,6 +435,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; info!("Current selection mode during transition: {:?}", tool_data.selection_mode); + // info!("Current nested mode during transition: {:?}", tool_data.nested_selection_behavior); let ToolMessage::Select(event) = event else { return self; }; @@ -707,7 +710,8 @@ impl Fsm for SelectToolFsmState { } else { // Make a box selection, preserving previously selected layers let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::DrawingBox { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::DrawingBox { selection,selection_mode } } }; tool_data.non_duplicated_layers = None; @@ -718,7 +722,8 @@ impl Fsm for SelectToolFsmState { responses.add(DocumentMessage::AbortTransaction); let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::Dragging, SelectToolMessage::PointerMove(modifier_keys)) => { tool_data.has_dragged = true; @@ -866,7 +871,8 @@ impl Fsm for SelectToolFsmState { tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::DrawingBox { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::DrawingBox { selection, selection_mode } } (SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove(_)) => { let mut cursor = tool_data.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true)); @@ -885,7 +891,8 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::Dragging, SelectToolMessage::PointerOutsideViewport(_)) => { // AutoPanning @@ -940,7 +947,8 @@ impl Fsm for SelectToolFsmState { responses.add_front(response); let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::Dragging, SelectToolMessage::DragStop { remove_from_selection, .. }) => { // Deselect layer if not snap dragging @@ -998,7 +1006,8 @@ impl Fsm for SelectToolFsmState { tool_data.select_single_layer = None; let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::ResizingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON { @@ -1014,7 +1023,8 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::RotatingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON { @@ -1028,7 +1038,8 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::DraggingPivot, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON { @@ -1040,7 +1051,8 @@ impl Fsm for SelectToolFsmState { tool_data.snap_manager.cleanup(responses); let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } ( @@ -1052,7 +1064,6 @@ impl Fsm for SelectToolFsmState { ) => { let quad = tool_data.selection_quad(); let direction = tool_data.calculate_direction(); - info!("mode under select is {:?}", tool_data.selection_mode); // let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); let new_selected: HashSet<_> = match tool_data.selection_mode { SelectionMode::Touched => document.intersect_quad_no_artboards(quad, input).collect(), @@ -1101,7 +1112,8 @@ impl Fsm for SelectToolFsmState { responses.add(OverlaysMessage::Draw); let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::Ready { .. }, SelectToolMessage::Enter) => { let selected_nodes = document.network_interface.selected_nodes(&[]).unwrap(); @@ -1116,7 +1128,8 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (SelectToolFsmState::Dragging, SelectToolMessage::Abort) => { responses.add(DocumentMessage::AbortTransaction); @@ -1124,7 +1137,8 @@ impl Fsm for SelectToolFsmState { responses.add(OverlaysMessage::Draw); let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (_, SelectToolMessage::Abort) => { tool_data.layers_dragging.retain(|layer| { @@ -1140,7 +1154,8 @@ impl Fsm for SelectToolFsmState { responses.add(OverlaysMessage::Draw); let selection = tool_data.nested_selection_behavior; - SelectToolFsmState::Ready { selection } + let selection_mode = tool_data.selection_mode; + SelectToolFsmState::Ready { selection, selection_mode } } (_, SelectToolMessage::SetPivot { position }) => { responses.add(DocumentMessage::StartTransaction); @@ -1171,7 +1186,7 @@ impl Fsm for SelectToolFsmState { fn update_hints(&self, responses: &mut VecDeque) { match self { - SelectToolFsmState::Ready { selection } => { + SelectToolFsmState::Ready { selection, selection_mode } => { let hint_data = HintData(vec![ HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]), HintGroup({ From b1cdfc07771f322648d61415e95fc01a561a40eb Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Thu, 9 Jan 2025 12:27:51 +0530 Subject: [PATCH 14/19] removed from portfolio message and added preference in ToolMessageData --- editor/src/dispatcher.rs | 2 ++ editor/src/messages/portfolio/portfolio_message.rs | 3 --- .../messages/portfolio/portfolio_message_handler.rs | 6 ------ .../preferences/preferences_message_handler.rs | 10 +++++----- editor/src/messages/tool/tool_message_handler.rs | 5 +++++ editor/src/messages/tool/tool_messages/select_tool.rs | 10 +--------- editor/src/messages/tool/utility_types.rs | 5 ++++- frontend/src/state-providers/node-graph.ts | 8 ++++++++ frontend/src/wasm-communication/messages.ts | 4 ++++ 9 files changed, 29 insertions(+), 24 deletions(-) diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs index 1c902513d6..a2698a2c0f 100644 --- a/editor/src/dispatcher.rs +++ b/editor/src/dispatcher.rs @@ -217,9 +217,11 @@ impl Dispatcher { self.message_handlers.preferences_message_handler.process_message(message, &mut queue, ()); } Message::Tool(message) => { + let preferences = &self.message_handlers.preferences_message_handler; let document_id = self.message_handlers.portfolio_message_handler.active_document_id().unwrap(); if let Some(document) = self.message_handlers.portfolio_message_handler.documents.get_mut(&document_id) { let data = ToolMessageData { + preferences, document_id, document, input: &self.message_handlers.input_preprocessor_message_handler, diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index b25ad47e8a..02b5673e86 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -122,7 +122,4 @@ pub enum PortfolioMessage { UpdateDocumentWidgets, UpdateOpenDocumentsList, UpdateVelloPreference, - UpdateSelectionMode { - selection_mode: SelectionMode, - }, } diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index dcd73622db..785523c567 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -889,12 +889,6 @@ impl MessageHandler> for PortfolioMes responses.add(NodeGraphMessage::RunDocumentGraph); self.persistent_data.use_vello = preferences.use_vello; } - - PortfolioMessage::UpdateSelectionMode { selection_mode } => { - self.selection_mode = selection_mode; - info!("Selection mode updated to: {:?}", selection_mode); - responses.add(Message::Frontend(FrontendMessage::UpdateSelectionMode { selection_mode })); - } } } diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index a361d40a19..b421e76551 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -1,10 +1,6 @@ use crate::messages::input_mapper::key_mapping::MappingVariant; -use crate::messages::portfolio::document::DocumentMessageHandler; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; -use crate::messages::tool::tool_messages::select_tool::SelectTool; -use crate::messages::tool::ToolMessageData; -use graph_craft::document; use graph_craft::wasm_application_io::EditorPreferences; #[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type)] @@ -17,6 +13,10 @@ pub struct PreferencesMessageHandler { } impl PreferencesMessageHandler { + pub fn get_selection_mode(&self) -> SelectionMode { + self.selection_mode + } + pub fn editor_preferences(&self) -> EditorPreferences { EditorPreferences { imaginate_hostname: self.imaginate_server_hostname.clone(), @@ -107,7 +107,7 @@ impl MessageHandler for PreferencesMessageHandler { PreferencesMessage::SelectionMode { selection_mode } => { info!("Setting selection mode to: {:?}", selection_mode); self.selection_mode = selection_mode; - responses.add(PortfolioMessage::UpdateSelectionMode { selection_mode }); + responses.add(FrontendMessage::UpdateSelectionMode { selection_mode }); } } responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index ca855b90d7..a5eaa67309 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -18,6 +18,7 @@ pub struct ToolMessageData<'a> { pub input: &'a InputPreprocessorMessageHandler, pub persistent_data: &'a PersistentData, pub node_graph: &'a NodeGraphExecutor, + pub preferences: &'a PreferencesMessageHandler, } #[derive(Debug, Default)] @@ -35,6 +36,7 @@ impl MessageHandler> for ToolMessageHandler { document, input, persistent_data, + preferences, node_graph, } = data; let font_cache = &persistent_data.font_cache; @@ -86,6 +88,7 @@ impl MessageHandler> for ToolMessageHandler { font_cache, shape_editor: &mut self.shape_editor, node_graph, + preferences, }; if let Some(tool_abort_message) = tool.event_to_message_map().tool_abort { @@ -174,6 +177,7 @@ impl MessageHandler> for ToolMessageHandler { input, font_cache, shape_editor: &mut self.shape_editor, + preferences, node_graph, }; @@ -257,6 +261,7 @@ impl MessageHandler> for ToolMessageHandler { if let Some(tool) = tool_data.tools.get_mut(&tool_type) { if tool_type == tool_data.active_tool_type { let mut data = ToolActionHandlerData { + preferences, document, document_id, global_tool_data: &self.tool_state.document_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 f8a4d44ecd..d145627393 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -4,15 +4,11 @@ use super::tool_prelude::*; use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE}; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; use crate::messages::portfolio::document::graph_operation::utility_types::{self, TransformIn}; -use crate::messages::portfolio::document::node_graph::utility_types::Direction; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::{self, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::transformation::Selected; -use crate::messages::portfolio::utility_types::PersistentData; -use crate::messages::portfolio::PortfolioMessageData; -use crate::messages::preferences::PreferencesMessageHandler; use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::graph_modification_utils::{get_text, is_layer_fed_by_node_of_name}; use crate::messages::tool::common_functionality::pivot::Pivot; @@ -222,10 +218,6 @@ impl<'a> MessageHandler> for SelectT // info!("nested mode updated : {:?}", nested_selection_behavior); responses.add(ToolMessage::UpdateHints); } - if let ToolMessage::UpdateSelectionMode { selection_mode } = message { - self.tool_data.selection_mode = selection_mode; - info!("Selection mode updated in SelectTool: {:?}", selection_mode); - } self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false); @@ -434,8 +426,8 @@ 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.selection_mode = tool_action_data.preferences.get_selection_mode(); info!("Current selection mode during transition: {:?}", tool_data.selection_mode); - // info!("Current nested mode during transition: {:?}", tool_data.nested_selection_behavior); let ToolMessage::Select(event) = event else { return self; }; diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs index 584ae8a16e..fbc1e5544f 100644 --- a/editor/src/messages/tool/utility_types.rs +++ b/editor/src/messages/tool/utility_types.rs @@ -9,7 +9,7 @@ use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::input_mapper::utility_types::misc::ActionKeys; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::overlays::utility_types::OverlayProvider; -use crate::messages::preferences::PreferencesMessageHandler; +use crate::messages::preferences::{self, PreferencesMessageHandler}; use crate::messages::prelude::*; use crate::node_graph_executor::NodeGraphExecutor; @@ -26,6 +26,7 @@ pub struct ToolActionHandlerData<'a> { pub font_cache: &'a FontCache, pub shape_editor: &'a mut ShapeState, pub node_graph: &'a NodeGraphExecutor, + pub preferences: &'a PreferencesMessageHandler, } impl<'a> ToolActionHandlerData<'a> { pub fn new( @@ -36,6 +37,7 @@ impl<'a> ToolActionHandlerData<'a> { font_cache: &'a FontCache, shape_editor: &'a mut ShapeState, node_graph: &'a NodeGraphExecutor, + preferences: &'a PreferencesMessageHandler, ) -> Self { Self { document, @@ -45,6 +47,7 @@ impl<'a> ToolActionHandlerData<'a> { font_cache, shape_editor, node_graph, + preferences, } } } diff --git a/frontend/src/state-providers/node-graph.ts b/frontend/src/state-providers/node-graph.ts index faafc31662..ad1dece0a2 100644 --- a/frontend/src/state-providers/node-graph.ts +++ b/frontend/src/state-providers/node-graph.ts @@ -23,6 +23,7 @@ import { UpdateNodeThumbnail, UpdateWirePathInProgress, UpdateZoomWithScroll, + UpdateSelectionMode, } from "@graphite/wasm-communication/messages"; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type @@ -45,6 +46,7 @@ export function createNodeGraphState(editor: Editor) { nodeDescriptions: new Map(), nodeTypes: [] as FrontendNodeType[], zoomWithScroll: false as boolean, + selectionMode: UpdateSelectionMode.name, thumbnails: new Map(), selected: [] as bigint[], transform: { scale: 1, x: 0, y: 0 }, @@ -142,6 +144,12 @@ export function createNodeGraphState(editor: Editor) { return state; }); }); + editor.subscriptions.subscribeJsMessage(UpdateSelectionMode, (updateSelectionMode) => { + update((state) => { + state.selectionMode = updateSelectionMode.selectionMode; + return state; + }); + }); return { subscribe, diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index 52aab6895b..bdb9e7218f 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -133,6 +133,9 @@ export class UpdateWirePathInProgress extends JsMessage { export class UpdateZoomWithScroll extends JsMessage { readonly zoomWithScroll!: boolean; } +export class UpdateSelectionMode extends JsMessage { + readonly selectionMode!: SelectionMode; +} // Allows the auto save system to use a string for the id rather than a BigInt. // IndexedDb does not allow for BigInts as primary keys. @@ -1629,5 +1632,6 @@ export const messageMakers: Record = { UpdateWirePathInProgress, UpdateWorkingColorsLayout, UpdateZoomWithScroll, + UpdateSelectionMode, } as const; export type JsMessageType = keyof typeof messageMakers; From c1f170a091ee7663382defd90b46f44e1b4dac31 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Thu, 9 Jan 2025 12:40:55 +0530 Subject: [PATCH 15/19] removed dead code of selection_mode from frontend logic --- .../messages/preferences/preferences_message_handler.rs | 1 - frontend/src/state-providers/node-graph.ts | 9 --------- frontend/src/wasm-communication/messages.ts | 5 +---- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index b421e76551..a622dbc7b2 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -107,7 +107,6 @@ impl MessageHandler for PreferencesMessageHandler { PreferencesMessage::SelectionMode { selection_mode } => { info!("Setting selection mode to: {:?}", selection_mode); self.selection_mode = selection_mode; - responses.add(FrontendMessage::UpdateSelectionMode { selection_mode }); } } responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); diff --git a/frontend/src/state-providers/node-graph.ts b/frontend/src/state-providers/node-graph.ts index ad1dece0a2..0df6d00781 100644 --- a/frontend/src/state-providers/node-graph.ts +++ b/frontend/src/state-providers/node-graph.ts @@ -23,7 +23,6 @@ import { UpdateNodeThumbnail, UpdateWirePathInProgress, UpdateZoomWithScroll, - UpdateSelectionMode, } from "@graphite/wasm-communication/messages"; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type @@ -46,7 +45,6 @@ export function createNodeGraphState(editor: Editor) { nodeDescriptions: new Map(), nodeTypes: [] as FrontendNodeType[], zoomWithScroll: false as boolean, - selectionMode: UpdateSelectionMode.name, thumbnails: new Map(), selected: [] as bigint[], transform: { scale: 1, x: 0, y: 0 }, @@ -144,13 +142,6 @@ export function createNodeGraphState(editor: Editor) { return state; }); }); - editor.subscriptions.subscribeJsMessage(UpdateSelectionMode, (updateSelectionMode) => { - update((state) => { - state.selectionMode = updateSelectionMode.selectionMode; - return state; - }); - }); - return { subscribe, }; diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index bdb9e7218f..924705e76c 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -133,9 +133,7 @@ export class UpdateWirePathInProgress extends JsMessage { export class UpdateZoomWithScroll extends JsMessage { readonly zoomWithScroll!: boolean; } -export class UpdateSelectionMode extends JsMessage { - readonly selectionMode!: SelectionMode; -} + // Allows the auto save system to use a string for the id rather than a BigInt. // IndexedDb does not allow for BigInts as primary keys. @@ -1632,6 +1630,5 @@ export const messageMakers: Record = { UpdateWirePathInProgress, UpdateWorkingColorsLayout, UpdateZoomWithScroll, - UpdateSelectionMode, } as const; export type JsMessageType = keyof typeof messageMakers; From 7c7ba7db099d7125546d72bd60f75497b7d34625 Mon Sep 17 00:00:00 2001 From: Pratik Agrawal Date: Thu, 9 Jan 2025 12:58:25 +0530 Subject: [PATCH 16/19] removed dead code for zoomWithScroll --- editor/src/messages/frontend/frontend_message.rs | 8 -------- .../messages/preferences/preferences_message_handler.rs | 1 - frontend/src/state-providers/node-graph.ts | 8 -------- frontend/src/wasm-communication/messages.ts | 6 ------ 4 files changed, 23 deletions(-) diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index c0c1344b09..e873064407 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -295,12 +295,4 @@ pub enum FrontendMessage { layout_target: LayoutTarget, diff: Vec, }, - UpdateZoomWithScroll { - #[serde(rename = "zoomWithScroll")] - zoom_with_scroll: bool, - }, - UpdateSelectionMode { - #[serde(rename = "selectionMode")] - selection_mode: SelectionMode, - }, } diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index a622dbc7b2..7467ca24fb 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -102,7 +102,6 @@ impl MessageHandler for PreferencesMessageHandler { true => MappingVariant::ZoomWithScroll, }; responses.add(KeyMappingMessage::ModifyMapping(variant)); - responses.add(FrontendMessage::UpdateZoomWithScroll { zoom_with_scroll }); } PreferencesMessage::SelectionMode { selection_mode } => { info!("Setting selection mode to: {:?}", selection_mode); diff --git a/frontend/src/state-providers/node-graph.ts b/frontend/src/state-providers/node-graph.ts index 0df6d00781..b95831f367 100644 --- a/frontend/src/state-providers/node-graph.ts +++ b/frontend/src/state-providers/node-graph.ts @@ -22,7 +22,6 @@ import { UpdateNodeGraphTransform, UpdateNodeThumbnail, UpdateWirePathInProgress, - UpdateZoomWithScroll, } from "@graphite/wasm-communication/messages"; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type @@ -44,7 +43,6 @@ export function createNodeGraphState(editor: Editor) { inputTypeDescriptions: new Map(), nodeDescriptions: new Map(), nodeTypes: [] as FrontendNodeType[], - zoomWithScroll: false as boolean, thumbnails: new Map(), selected: [] as bigint[], transform: { scale: 1, x: 0, y: 0 }, @@ -136,12 +134,6 @@ export function createNodeGraphState(editor: Editor) { return state; }); }); - editor.subscriptions.subscribeJsMessage(UpdateZoomWithScroll, (updateZoomWithScroll) => { - update((state) => { - state.zoomWithScroll = updateZoomWithScroll.zoomWithScroll; - return state; - }); - }); return { subscribe, }; diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index 924705e76c..2b5b2fb6ad 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -130,11 +130,6 @@ export class UpdateWirePathInProgress extends JsMessage { readonly wirePath!: WirePath | undefined; } -export class UpdateZoomWithScroll extends JsMessage { - readonly zoomWithScroll!: boolean; -} - - // Allows the auto save system to use a string for the id rather than a BigInt. // IndexedDb does not allow for BigInts as primary keys. // TypeScript does not allow subclasses to change the type of class variables in subclasses. @@ -1629,6 +1624,5 @@ export const messageMakers: Record = { UpdateToolShelfLayout, UpdateWirePathInProgress, UpdateWorkingColorsLayout, - UpdateZoomWithScroll, } as const; export type JsMessageType = keyof typeof messageMakers; From 0a717999b8cea5eb0d9ac6c459185ef2a07548e6 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 25 Jan 2025 18:24:29 -0800 Subject: [PATCH 17/19] Cleanup --- .../preferences_dialog_message_handler.rs | 71 ++++++++------- .../src/messages/frontend/frontend_message.rs | 1 - .../document/document_message_handler.rs | 32 +++---- .../messages/portfolio/portfolio_message.rs | 3 +- .../portfolio/portfolio_message_handler.rs | 6 +- .../src/messages/portfolio/utility_types.rs | 5 +- .../messages/preferences/preference_type.rs | 15 +--- .../preferences/preferences_message.rs | 6 +- .../preferences_message_handler.rs | 33 +++---- editor/src/messages/tool/tool_message.rs | 1 + .../tool/tool_messages/artboard_tool.rs | 21 +---- .../tool/tool_messages/select_tool.rs | 90 ++++++++----------- editor/src/messages/tool/utility_types.rs | 2 +- 13 files changed, 120 insertions(+), 166 deletions(-) diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index 8e77f3441c..02b4c69a90 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -1,6 +1,4 @@ -use std::sync::Arc; - -use crate::messages::layout::utility_types::{layout_widget, widget_prelude::*}; +use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; @@ -34,37 +32,6 @@ impl PreferencesDialogMessageHandler { const TITLE: &'static str = "Editor Preferences"; fn layout(&self, preferences: &PreferencesMessageHandler) -> Layout { - let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)"; - let input_section = vec![TextLabel::new("Input").italic(true).widget_holder()]; - let zoom_with_scroll = vec![ - CheckboxInput::new(preferences.zoom_with_scroll) - .tooltip(zoom_with_scroll_tooltip) - .on_update(|checkbox_input: &CheckboxInput| { - PreferencesMessage::ModifyLayout { - zoom_with_scroll: checkbox_input.checked, - } - .into() - }) - .widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), - TextLabel::new("Zoom with Scroll").table_align(true).tooltip(zoom_with_scroll_tooltip).widget_holder(), - ]; - let vello_tooltip = "Use the experimental Vello renderer (your browser must support WebGPU)"; - let renderer_section = vec![TextLabel::new("Renderer").italic(true).widget_holder()]; - let use_vello = vec![ - CheckboxInput::new(preferences.use_vello && preferences.supports_wgpu()) - .tooltip(vello_tooltip) - .disabled(!preferences.supports_wgpu()) - .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::UseVello { use_vello: checkbox_input.checked }.into()) - .widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), - TextLabel::new("Vello (Experimental)") - .table_align(true) - .tooltip(vello_tooltip) - .disabled(!preferences.supports_wgpu()) - .widget_holder(), - ]; - let selection_section = vec![TextLabel::new("Selection Mode").italic(true).widget_holder()]; let selection_mode = RadioInput::new(vec![ RadioEntryData::new("touched") @@ -102,6 +69,38 @@ impl PreferencesDialogMessageHandler { })) .widget_holder(); + let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)"; + let input_section = vec![TextLabel::new("Input").italic(true).widget_holder()]; + let zoom_with_scroll = vec![ + CheckboxInput::new(preferences.zoom_with_scroll) + .tooltip(zoom_with_scroll_tooltip) + .on_update(|checkbox_input: &CheckboxInput| { + PreferencesMessage::ModifyLayout { + zoom_with_scroll: checkbox_input.checked, + } + .into() + }) + .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextLabel::new("Zoom with Scroll").table_align(true).tooltip(zoom_with_scroll_tooltip).widget_holder(), + ]; + + let vello_tooltip = "Use the experimental Vello renderer (your browser must support WebGPU)"; + let renderer_section = vec![TextLabel::new("Renderer").italic(true).widget_holder()]; + let use_vello = vec![ + CheckboxInput::new(preferences.use_vello && preferences.supports_wgpu()) + .tooltip(vello_tooltip) + .disabled(!preferences.supports_wgpu()) + .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::UseVello { use_vello: checkbox_input.checked }.into()) + .widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextLabel::new("Vello (Experimental)") + .table_align(true) + .tooltip(vello_tooltip) + .disabled(!preferences.supports_wgpu()) + .widget_holder(), + ]; + // TODO: Reenable when Imaginate is restored // let imaginate_server_hostname = vec![ // TextLabel::new("Imaginate").min_width(60).italic(true).widget_holder(), @@ -126,12 +125,12 @@ impl PreferencesDialogMessageHandler { // ]; Layout::WidgetLayout(WidgetLayout::new(vec![ + LayoutGroup::Row { widgets: selection_section }, + LayoutGroup::Row { widgets: vec![selection_mode] }, LayoutGroup::Row { widgets: input_section }, LayoutGroup::Row { widgets: zoom_with_scroll }, LayoutGroup::Row { widgets: renderer_section }, LayoutGroup::Row { widgets: use_vello }, - LayoutGroup::Row { widgets: selection_section }, - LayoutGroup::Row { widgets: vec![selection_mode] }, // LayoutGroup::Row { widgets: imaginate_server_hostname }, // LayoutGroup::Row { widgets: imaginate_refresh_frequency }, ])) diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index e873064407..65555a21f2 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -4,7 +4,6 @@ use crate::messages::portfolio::document::node_graph::utility_types::{ BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, FrontendNodeWire, Transform, WirePath, }; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; -use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; use crate::messages::tool::utility_types::HintData; diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 375fbe8b14..92dbfaef75 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1391,29 +1391,25 @@ impl DocumentMessageHandler { pub fn is_layer_fully_inside(&self, layer: &LayerNodeIdentifier, quad: graphene_core::renderer::Quad) -> bool { // Get the bounding box of the layer in document space - if let Some(bounding_box) = self.metadata().bounding_box_viewport(*layer) { - // Check if the bounding box is fully within the selection quad - let [top_left, bottom_right] = bounding_box; + let Some(bounding_box) = self.metadata().bounding_box_viewport(*layer) else { return false }; - let quad_bbox = quad.bounding_box(); + // Check if the bounding box is fully within the selection quad + let [top_left, bottom_right] = bounding_box; - let quad_left = quad_bbox[0].x; - let quad_right = quad_bbox[1].x; - let quad_top = quad_bbox[0].y.max(quad_bbox[1].y); // Correct top - let quad_bottom = quad_bbox[0].y.min(quad_bbox[1].y); // Correct bottom + let quad_bbox = quad.bounding_box(); - // Extract layer's bounding box coordinates - let layer_left = top_left.x; - let layer_right = bottom_right.x; - let layer_top = bottom_right.y; - let layer_bottom = top_left.y; + let quad_left = quad_bbox[0].x; + let quad_right = quad_bbox[1].x; + let quad_top = quad_bbox[0].y.max(quad_bbox[1].y); // Correct top + let quad_bottom = quad_bbox[0].y.min(quad_bbox[1].y); // Correct bottom - let is_fully_contained = layer_left >= quad_left && layer_right <= quad_right && layer_top <= quad_top && layer_bottom >= quad_bottom; + // Extract layer's bounding box coordinates + let layer_left = top_left.x; + let layer_right = bottom_right.x; + let layer_top = bottom_right.y; + let layer_bottom = top_left.y; - is_fully_contained - } else { - false - } + layer_left >= quad_left && layer_right <= quad_right && layer_top <= quad_top && layer_bottom >= quad_bottom } /// Find all of the layers that were clicked on from a viewport space location diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index 02b5673e86..ea1c3aa25e 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -2,7 +2,6 @@ use super::document::utility_types::document_metadata::LayerNodeIdentifier; use super::utility_types::PanelType; use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; -use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; use graphene_core::raster::Image; @@ -56,7 +55,7 @@ pub enum PortfolioMessage { ImaginateCheckServerStatus, ImaginatePollServerStatus, EditorPreferences, - ImaginateServerHostname, + // ImaginateServerHostname, Import, LoadDocumentResources { document_id: DocumentId, diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 785523c567..6f9ec7601a 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -323,9 +323,9 @@ impl MessageHandler> for PortfolioMes responses.add(PropertiesPanelMessage::Refresh); } PortfolioMessage::EditorPreferences => self.executor.update_editor_preferences(preferences.editor_preferences()), - PortfolioMessage::ImaginateServerHostname => { - self.persistent_data.imaginate.set_host_name(&preferences.imaginate_server_hostname); - } + // PortfolioMessage::ImaginateServerHostname => { + // self.persistent_data.imaginate.set_host_name(&preferences.imaginate_server_hostname); + // } PortfolioMessage::Import => { // This portfolio message wraps the frontend message so it can be listed as an action, which isn't possible for frontend messages responses.add(FrontendMessage::TriggerImport); diff --git a/editor/src/messages/portfolio/utility_types.rs b/editor/src/messages/portfolio/utility_types.rs index 0c82676664..73203dbaca 100644 --- a/editor/src/messages/portfolio/utility_types.rs +++ b/editor/src/messages/portfolio/utility_types.rs @@ -1,6 +1,5 @@ -use graphene_std::{imaginate::ImaginatePersistentData, text::FontCache}; - -use crate::messages::preferences::SelectionMode; +use graphene_std::imaginate::ImaginatePersistentData; +use graphene_std::text::FontCache; #[derive(Debug, Default)] pub struct PersistentData { diff --git a/editor/src/messages/preferences/preference_type.rs b/editor/src/messages/preferences/preference_type.rs index c6ce4a967c..9a6271fb03 100644 --- a/editor/src/messages/preferences/preference_type.rs +++ b/editor/src/messages/preferences/preference_type.rs @@ -1,14 +1,13 @@ -use std::fmt; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type, Hash)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type, Hash)] pub enum SelectionMode { + #[default] Touched, Contained, ByDragDirection, } -impl fmt::Display for SelectionMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl std::fmt::Display for SelectionMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { SelectionMode::Touched => write!(f, "Touched"), SelectionMode::Contained => write!(f, "Contained"), @@ -16,9 +15,3 @@ impl fmt::Display for SelectionMode { } } } - -impl Default for SelectionMode { - fn default() -> Self { - SelectionMode::Touched - } -} diff --git a/editor/src/messages/preferences/preferences_message.rs b/editor/src/messages/preferences/preferences_message.rs index 68e57aeacb..1115e471c5 100644 --- a/editor/src/messages/preferences/preferences_message.rs +++ b/editor/src/messages/preferences/preferences_message.rs @@ -1,13 +1,17 @@ use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; + #[impl_message(Message, Preferences)] #[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum PreferencesMessage { + // Management messages Load { preferences: String }, ResetToDefaults, + + // Per-preference messages ImaginateRefreshFrequency { seconds: f64 }, UseVello { use_vello: bool }, SelectionMode { selection_mode: SelectionMode }, - ImaginateServerHostname { hostname: String }, + // ImaginateServerHostname { hostname: String }, ModifyLayout { zoom_with_scroll: bool }, } diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index 7467ca24fb..c31542655f 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -48,6 +48,7 @@ impl Default for PreferencesMessageHandler { impl MessageHandler for PreferencesMessageHandler { fn process_message(&mut self, message: PreferencesMessage, responses: &mut VecDeque, _data: ()) { match message { + // Management messages PreferencesMessage::Load { preferences } => { if let Ok(deserialized_preferences) = serde_json::from_str::(&preferences) { *self = deserialized_preferences; @@ -70,6 +71,7 @@ impl MessageHandler for PreferencesMessageHandler { *self = Self::default() } + // Per-preference messages PreferencesMessage::ImaginateRefreshFrequency { seconds } => { self.imaginate_refresh_frequency = seconds; responses.add(PortfolioMessage::ImaginateCheckServerStatus); @@ -80,23 +82,24 @@ impl MessageHandler for PreferencesMessageHandler { responses.add(PortfolioMessage::UpdateVelloPreference); responses.add(PortfolioMessage::EditorPreferences); } - PreferencesMessage::ImaginateServerHostname { hostname } => { - let initial = hostname.clone(); - let has_protocol = hostname.starts_with("http://") || hostname.starts_with("https://"); - let hostname = if has_protocol { hostname } else { "http://".to_string() + &hostname }; - let hostname = if hostname.ends_with('/') { hostname } else { hostname + "/" }; - - if hostname != initial { - refresh_dialog(responses); - } + // PreferencesMessage::ImaginateServerHostname { hostname } => { + // let initial = hostname.clone(); + // let has_protocol = hostname.starts_with("http://") || hostname.starts_with("https://"); + // let hostname = if has_protocol { hostname } else { "http://".to_string() + &hostname }; + // let hostname = if hostname.ends_with('/') { hostname } else { hostname + "/" }; - self.imaginate_server_hostname = hostname; - responses.add(PortfolioMessage::ImaginateServerHostname); - responses.add(PortfolioMessage::ImaginateCheckServerStatus); - responses.add(PortfolioMessage::EditorPreferences); - } + // if hostname != initial { + // refresh_dialog(responses); + // } + + // self.imaginate_server_hostname = hostname; + // responses.add(PortfolioMessage::ImaginateServerHostname); + // responses.add(PortfolioMessage::ImaginateCheckServerStatus); + // responses.add(PortfolioMessage::EditorPreferences); + // } PreferencesMessage::ModifyLayout { zoom_with_scroll } => { self.zoom_with_scroll = zoom_with_scroll; + let variant = match zoom_with_scroll { false => MappingVariant::Default, true => MappingVariant::ZoomWithScroll, @@ -104,10 +107,10 @@ impl MessageHandler for PreferencesMessageHandler { responses.add(KeyMappingMessage::ModifyMapping(variant)); } PreferencesMessage::SelectionMode { selection_mode } => { - info!("Setting selection mode to: {:?}", selection_mode); self.selection_mode = selection_mode; } } + responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); } diff --git a/editor/src/messages/tool/tool_message.rs b/editor/src/messages/tool/tool_message.rs index a5c138242d..f812f63a22 100644 --- a/editor/src/messages/tool/tool_message.rs +++ b/editor/src/messages/tool/tool_message.rs @@ -1,6 +1,7 @@ use super::utility_types::ToolType; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; + use graphene_core::raster::color::Color; #[impl_message(Message, Tool)] diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index cf90ade73c..dbedeae347 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -118,6 +118,7 @@ struct ArtboardToolData { impl ArtboardToolData { fn get_snap_candidates(&mut self, document: &DocumentMessageHandler, _input: &InputPreprocessorMessageHandler) { self.snap_candidates.clear(); + let Some(layer) = self.selected_artboard else { return }; if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) { @@ -125,25 +126,6 @@ impl ArtboardToolData { } } - pub fn get_child_layers_of_selected_artboard(&self, document: &DocumentMessageHandler) -> Vec { - let Some(artboard_id) = self.selected_artboard else { - return Vec::new(); - }; - let structure = document.metadata().structure.clone(); - let child_layers = structure - .iter() - .filter_map(|(layer_id, node_relations)| { - if let Some(parent_id) = node_relations.parent { - if parent_id == artboard_id { - return Some(*layer_id); - } - } - None - }) - .collect::>(); - child_layers - } - fn check_dragging_bounds(&mut self, cursor: DVec2) -> Option<(bool, bool, bool, bool)> { let bounding_box = self.bounding_box_manager.as_mut()?; let edges = bounding_box.check_selected_edges(cursor)?; @@ -217,7 +199,6 @@ impl ArtboardToolData { location: position.round().as_ivec2(), dimensions: size.round().as_ivec2(), }); - let artboard_bounds_viewport = document.metadata().bounding_box_viewport(self.selected_artboard.unwrap()); let translation = position.round().as_ivec2() - self.dragging_current_artboard_location; self.dragging_current_artboard_location = position.round().as_ivec2(); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index d145627393..b028bd8d43 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -3,9 +3,9 @@ use super::tool_prelude::*; use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE}; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; -use crate::messages::portfolio::document::graph_operation::utility_types::{self, TransformIn}; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; -use crate::messages::portfolio::document::utility_types::document_metadata::{self, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::transformation::Selected; @@ -21,7 +21,6 @@ use graphene_core::renderer::Quad; use graphene_core::text::load_face; use graphene_std::renderer::Rect; use graphene_std::vector::misc::BooleanOperation; -// use web_sys::console; use std::fmt; @@ -78,6 +77,7 @@ pub enum SelectToolMessage { // Standard messages Abort, Overlays(OverlayContext), + // Tool-specific messages DragStart { extend_selection: Key, select_deepest: Key }, DragStop { remove_from_selection: Key, negative_box_selection: Key }, @@ -215,7 +215,6 @@ impl<'a> MessageHandler> for SelectT 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; - // info!("nested mode updated : {:?}", nested_selection_behavior); responses.add(ToolMessage::UpdateHints); } @@ -257,8 +256,8 @@ impl ToolTransition for SelectTool { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum SelectToolFsmState { - Ready { selection: NestedSelectionBehavior, selection_mode: SelectionMode }, - DrawingBox { selection: NestedSelectionBehavior, selection_mode: SelectionMode }, + Ready { selection: NestedSelectionBehavior }, + DrawingBox, Dragging, ResizingBounds, RotatingBounds, @@ -267,9 +266,9 @@ enum SelectToolFsmState { impl Default for SelectToolFsmState { fn default() -> Self { - let selection = NestedSelectionBehavior::Deepest; - let selection_mode = SelectionMode::Touched; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { + selection: NestedSelectionBehavior::Deepest, + } } } @@ -426,15 +425,15 @@ 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; + + // TODO: Should this be moved down a line? tool_data.selection_mode = tool_action_data.preferences.get_selection_mode(); - info!("Current selection mode during transition: {:?}", tool_data.selection_mode); - let ToolMessage::Select(event) = event else { - return self; - }; + let ToolMessage::Select(event) = event else { return self }; match (self, event) { (_, SelectToolMessage::Overlays(mut overlay_context)) => { tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context); + let selected_layers_count = document.network_interface.selected_nodes(&[]).unwrap().selected_unlocked_layers(&document.network_interface).count(); tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count; tool_data.selected_layers_count = selected_layers_count; @@ -500,7 +499,7 @@ impl Fsm for SelectToolFsmState { tool_data.pivot.update_pivot(document, &mut overlay_context); // Check if the tool is in box selection mode - if matches!(self, Self::DrawingBox { .. }) { + if matches!(self, Self::DrawingBox) { // Get the updated selection box bounds let quad = Quad::from_box([tool_data.drag_start, tool_data.drag_current]); @@ -700,10 +699,7 @@ impl Fsm for SelectToolFsmState { responses.add(DocumentMessage::StartTransaction); SelectToolFsmState::Dragging } else { - // Make a box selection, preserving previously selected layers - let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::DrawingBox { selection,selection_mode } + SelectToolFsmState::DrawingBox } }; tool_data.non_duplicated_layers = None; @@ -714,8 +710,7 @@ impl Fsm for SelectToolFsmState { responses.add(DocumentMessage::AbortTransaction); let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::Dragging, SelectToolMessage::PointerMove(modifier_keys)) => { tool_data.has_dragged = true; @@ -851,7 +846,7 @@ impl Fsm for SelectToolFsmState { SelectToolFsmState::DraggingPivot } - (SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::PointerMove(modifier_keys)) => { + (SelectToolFsmState::DrawingBox, SelectToolMessage::PointerMove(modifier_keys)) => { tool_data.drag_current = input.mouse.position; responses.add(OverlaysMessage::Draw); @@ -862,9 +857,7 @@ impl Fsm for SelectToolFsmState { ]; tool_data.auto_panning.setup_by_mouse_position(input, &messages, responses); - let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::DrawingBox { selection, selection_mode } + SelectToolFsmState::DrawingBox } (SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove(_)) => { let mut cursor = tool_data.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true)); @@ -883,8 +876,7 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::Dragging, SelectToolMessage::PointerOutsideViewport(_)) => { // AutoPanning @@ -912,7 +904,7 @@ impl Fsm for SelectToolFsmState { self } - (SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::PointerOutsideViewport(_)) => { + (SelectToolFsmState::DrawingBox, SelectToolMessage::PointerOutsideViewport(_)) => { // AutoPanning if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { tool_data.drag_start += shift; @@ -939,8 +931,7 @@ impl Fsm for SelectToolFsmState { responses.add_front(response); let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::Dragging, SelectToolMessage::DragStop { remove_from_selection, .. }) => { // Deselect layer if not snap dragging @@ -949,7 +940,6 @@ impl Fsm for SelectToolFsmState { if !tool_data.has_dragged && input.keyboard.key(remove_from_selection) && tool_data.layer_selected_on_start.is_none() { // When you click on the layer with remove from selection key (shift) pressed, we deselect all nodes that are children. let quad = tool_data.selection_quad(); - let intersection = document.intersect_quad_no_artboards(quad, input); if let Some(path) = intersection.last() { @@ -998,8 +988,7 @@ impl Fsm for SelectToolFsmState { tool_data.select_single_layer = None; let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::ResizingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON { @@ -1015,8 +1004,7 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::RotatingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON { @@ -1030,8 +1018,7 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::DraggingPivot, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON { @@ -1043,24 +1030,21 @@ impl Fsm for SelectToolFsmState { tool_data.snap_manager.cleanup(responses); let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } - ( - SelectToolFsmState::DrawingBox { .. }, + SelectToolFsmState::DrawingBox, SelectToolMessage::DragStop { remove_from_selection, negative_box_selection, }, ) => { let quad = tool_data.selection_quad(); - let direction = tool_data.calculate_direction(); - // let new_selected: HashSet<_> = document.intersect_quad_no_artboards(quad, input).collect(); - let new_selected: HashSet<_> = match tool_data.selection_mode { + + let new_selected = match tool_data.selection_mode { SelectionMode::Touched => document.intersect_quad_no_artboards(quad, input).collect(), SelectionMode::Contained => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), - SelectionMode::ByDragDirection => match direction { + SelectionMode::ByDragDirection => match tool_data.calculate_direction() { SelectionDirection::Rightwards => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), SelectionDirection::Leftwards => document.intersect_quad_no_artboards(quad, input).collect(), SelectionDirection::None => HashSet::new(), @@ -1071,7 +1055,7 @@ impl Fsm for SelectToolFsmState { if new_selected != current_selected { // Negative selection when both Shift and Ctrl are pressed if input.keyboard.key(remove_from_selection) && input.keyboard.key(negative_box_selection) { - let updated_selection: Vec = current_selected + let updated_selection = current_selected .into_iter() .filter(|layer| !new_selected.iter().any(|selected| layer.starts_with(*selected, document.metadata()))) .collect(); @@ -1104,8 +1088,7 @@ impl Fsm for SelectToolFsmState { responses.add(OverlaysMessage::Draw); let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::Ready { .. }, SelectToolMessage::Enter) => { let selected_nodes = document.network_interface.selected_nodes(&[]).unwrap(); @@ -1120,8 +1103,7 @@ impl Fsm for SelectToolFsmState { } let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (SelectToolFsmState::Dragging, SelectToolMessage::Abort) => { responses.add(DocumentMessage::AbortTransaction); @@ -1129,8 +1111,7 @@ impl Fsm for SelectToolFsmState { responses.add(OverlaysMessage::Draw); let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (_, SelectToolMessage::Abort) => { tool_data.layers_dragging.retain(|layer| { @@ -1146,8 +1127,7 @@ impl Fsm for SelectToolFsmState { responses.add(OverlaysMessage::Draw); let selection = tool_data.nested_selection_behavior; - let selection_mode = tool_data.selection_mode; - SelectToolFsmState::Ready { selection, selection_mode } + SelectToolFsmState::Ready { selection } } (_, SelectToolMessage::SetPivot { position }) => { responses.add(DocumentMessage::StartTransaction); @@ -1178,7 +1158,7 @@ impl Fsm for SelectToolFsmState { fn update_hints(&self, responses: &mut VecDeque) { match self { - SelectToolFsmState::Ready { selection, selection_mode } => { + SelectToolFsmState::Ready { selection } => { let hint_data = HintData(vec![ HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")]), HintGroup({ @@ -1217,7 +1197,7 @@ impl Fsm for SelectToolFsmState { ]); responses.add(FrontendMessage::UpdateInputHints { hint_data }); } - SelectToolFsmState::DrawingBox { .. } => { + SelectToolFsmState::DrawingBox => { let hint_data = HintData(vec![ HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), HintGroup(vec![HintInfo::keys([Key::Control, Key::Shift], "Remove from Selection").add_mac_keys([Key::Command, Key::Shift])]), diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs index fbc1e5544f..b61340118c 100644 --- a/editor/src/messages/tool/utility_types.rs +++ b/editor/src/messages/tool/utility_types.rs @@ -9,7 +9,7 @@ use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::input_mapper::utility_types::misc::ActionKeys; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::overlays::utility_types::OverlayProvider; -use crate::messages::preferences::{self, PreferencesMessageHandler}; +use crate::messages::preferences::PreferencesMessageHandler; use crate::messages::prelude::*; use crate::node_graph_executor::NodeGraphExecutor; From 5830d04c52bbae59495f952df89d7a377816ccc5 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 25 Jan 2025 20:46:09 -0800 Subject: [PATCH 18/19] Rename, simplify, use dashed box, and highlight only outlines of layers that'll get selected --- .../preferences_dialog_message_handler.rs | 30 ++++----- editor/src/messages/preferences/mod.rs | 2 +- .../messages/preferences/preference_type.rs | 20 ++++-- .../tool/tool_messages/select_tool.rs | 62 ++++++++++++------- 4 files changed, 69 insertions(+), 45 deletions(-) diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index 533be78f38..b59bf505ac 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -32,41 +32,37 @@ impl PreferencesDialogMessageHandler { const TITLE: &'static str = "Editor Preferences"; fn layout(&self, preferences: &PreferencesMessageHandler) -> Layout { - let selection_section = vec![TextLabel::new("Selection Mode").italic(true).widget_holder()]; + let selection_section = vec![TextLabel::new("Selection").italic(true).widget_holder()]; let selection_mode = RadioInput::new(vec![ - RadioEntryData::new("touched") - .label("Touched") - .tooltip("Select objects that are touched by the selection area") + RadioEntryData::new(SelectionMode::Touched.to_string()) + .label(SelectionMode::Touched.to_string()) + .tooltip(SelectionMode::Touched.tooltip_description()) .on_update(move |_| { PreferencesMessage::SelectionMode { selection_mode: SelectionMode::Touched, } .into() }), - RadioEntryData::new("contained") - .label("Contained") - .tooltip("Select objects that are fully contained within the selection area") + RadioEntryData::new(SelectionMode::Enclosed.to_string()) + .label(SelectionMode::Enclosed.to_string()) + .tooltip(SelectionMode::Enclosed.tooltip_description()) .on_update(move |_| { PreferencesMessage::SelectionMode { - selection_mode: SelectionMode::Contained, + selection_mode: SelectionMode::Enclosed, } .into() }), - RadioEntryData::new("by_drag_direction") - .label("By Drag Direction") - .tooltip("Select objects based on the drag direction of the selection area") + RadioEntryData::new(SelectionMode::Directional.to_string()) + .label(SelectionMode::Directional.to_string()) + .tooltip(SelectionMode::Directional.tooltip_description()) .on_update(move |_| { PreferencesMessage::SelectionMode { - selection_mode: SelectionMode::ByDragDirection, + selection_mode: SelectionMode::Directional, } .into() }), ]) - .selected_index(Some(match preferences.selection_mode { - SelectionMode::Touched => 0, - SelectionMode::Contained => 1, - SelectionMode::ByDragDirection => 2, - })) + .selected_index(Some(preferences.selection_mode as u32)) .widget_holder(); let zoom_with_scroll_tooltip = "Use the scroll wheel for zooming instead of vertically panning (not recommended for trackpads)"; diff --git a/editor/src/messages/preferences/mod.rs b/editor/src/messages/preferences/mod.rs index 872ca43677..5ab399f981 100644 --- a/editor/src/messages/preferences/mod.rs +++ b/editor/src/messages/preferences/mod.rs @@ -1,4 +1,4 @@ -mod preference_type; +pub mod preference_type; mod preferences_message; mod preferences_message_handler; diff --git a/editor/src/messages/preferences/preference_type.rs b/editor/src/messages/preferences/preference_type.rs index 9a6271fb03..a2ee5dece1 100644 --- a/editor/src/messages/preferences/preference_type.rs +++ b/editor/src/messages/preferences/preference_type.rs @@ -1,17 +1,27 @@ #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type, Hash)] pub enum SelectionMode { #[default] - Touched, - Contained, - ByDragDirection, + Touched = 0, + Enclosed = 1, + Directional = 2, } impl std::fmt::Display for SelectionMode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { SelectionMode::Touched => write!(f, "Touched"), - SelectionMode::Contained => write!(f, "Contained"), - SelectionMode::ByDragDirection => write!(f, "By Drag Direction"), + SelectionMode::Enclosed => write!(f, "Enclosed"), + SelectionMode::Directional => write!(f, "Directional"), + } + } +} + +impl SelectionMode { + pub fn tooltip_description(&self) -> &'static str { + match self { + SelectionMode::Touched => "Select all layers at least partially covered by the dragged selection area", + SelectionMode::Enclosed => "Select only layers fully enclosed by the dragged selection area", + SelectionMode::Directional => r#""Touched" for leftward drags, "Enclosed" for rightward drags"#, } } } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index da077256e9..c9358e9e68 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -41,12 +41,6 @@ pub enum SelectOptionsUpdate { NestedSelectionBehavior(NestedSelectionBehavior), } -enum SelectionDirection { - Leftwards, - Rightwards, - None, -} - #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum NestedSelectionBehavior { #[default] @@ -312,14 +306,16 @@ impl SelectToolData { Quad::from_box(bbox) } - pub fn calculate_direction(&self) -> SelectionDirection { + pub fn calculate_direction(&self) -> SelectionMode { let bbox: [DVec2; 2] = self.selection_box(); if bbox[1].x > bbox[0].x { - SelectionDirection::Rightwards + SelectionMode::Enclosed } else if bbox[1].x < bbox[0].x { - SelectionDirection::Leftwards + SelectionMode::Touched } else { - SelectionDirection::None + // If the x coordinates are equal, the area is zero, so we use rightwards which corresponds to the "Enclosed" + // selection mode to ensure the selection ends up empty, as nothing will be enclosed by an empty area. + SelectionMode::Enclosed } } @@ -503,17 +499,37 @@ impl Fsm for SelectToolFsmState { // Get the updated selection box bounds let quad = Quad::from_box([tool_data.drag_start, tool_data.drag_current]); + let mut selection_direction = tool_data.selection_mode; + if selection_direction == SelectionMode::Directional { + selection_direction = tool_data.calculate_direction(); + } + // Draw outline visualizations on the layers to be selected - for layer in document.intersect_quad_no_artboards(quad, input) { - overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer)); + let mut draw_layer_outline = |layer| overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer)); + let intersection = document.intersect_quad_no_artboards(quad, input); + if selection_direction == SelectionMode::Enclosed { + for layer in intersection.filter(|layer| document.is_layer_fully_inside(layer, quad)) { + draw_layer_outline(layer); + } + } else { + for layer in intersection { + draw_layer_outline(layer); + } } // Update the selection box - let fill_color = graphene_std::Color::from_rgb_str(crate::consts::COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) + let mut fill_color = graphene_std::Color::from_rgb_str(crate::consts::COLOR_OVERLAY_BLUE.strip_prefix('#').unwrap()) .unwrap() .with_alpha(0.05) .rgba_hex(); - overlay_context.quad(quad, Some(&("#".to_string() + &fill_color))); + fill_color.insert(0, '#'); + let fill_color = Some(fill_color.as_str()); + + if selection_direction == SelectionMode::Enclosed { + overlay_context.dashed_quad(quad, fill_color, Some(4.), Some(4.), Some(0.5)); + } else { + overlay_context.quad(quad, fill_color); + } } // Only highlight layers if the viewport is not being panned (middle mouse button is pressed) // TODO: Don't use `Key::Mmb` directly, instead take it as a variable from the input mappings list like in all other places @@ -1041,14 +1057,16 @@ impl Fsm for SelectToolFsmState { ) => { let quad = tool_data.selection_quad(); - let new_selected = match tool_data.selection_mode { - SelectionMode::Touched => document.intersect_quad_no_artboards(quad, input).collect(), - SelectionMode::Contained => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), - SelectionMode::ByDragDirection => match tool_data.calculate_direction() { - SelectionDirection::Rightwards => document.intersect_quad_no_artboards(quad, input).filter(|layer| document.is_layer_fully_inside(layer, quad)).collect(), - SelectionDirection::Leftwards => document.intersect_quad_no_artboards(quad, input).collect(), - SelectionDirection::None => HashSet::new(), - }, + let mut selection_direction = tool_data.selection_mode; + if selection_direction == SelectionMode::Directional { + selection_direction = tool_data.calculate_direction(); + } + + let intersection = document.intersect_quad_no_artboards(quad, input); + let new_selected: HashSet<_> = if selection_direction == SelectionMode::Enclosed { + intersection.filter(|layer| document.is_layer_fully_inside(layer, quad)).collect() + } else { + intersection.collect() }; let current_selected: HashSet<_> = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect(); From 189d33a5eacae03718f098ca8792b0a77f6344c9 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 25 Jan 2025 22:25:22 -0800 Subject: [PATCH 19/19] More code review --- .../preferences_dialog_message_handler.rs | 23 ++++----- .../messages/portfolio/portfolio_message.rs | 6 +-- .../portfolio/portfolio_message_handler.rs | 50 +++++++++---------- editor/src/messages/preferences/mod.rs | 6 +-- .../preferences/preferences_message.rs | 4 +- .../preferences_message_handler.rs | 42 ++++++++-------- .../{preference_type.rs => utility_types.rs} | 0 .../tool/tool_messages/select_tool.rs | 20 +++----- frontend/src/editor.ts | 8 +-- frontend/wasm/src/editor_api.rs | 8 +-- 10 files changed, 78 insertions(+), 89 deletions(-) rename editor/src/messages/preferences/{preference_type.rs => utility_types.rs} (100%) diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index b59bf505ac..a4b13e70fb 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -77,7 +77,6 @@ impl PreferencesDialogMessageHandler { .into() }) .widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), TextLabel::new("Zoom with Scroll").table_align(true).tooltip(zoom_with_scroll_tooltip).widget_holder(), ]; @@ -89,7 +88,6 @@ impl PreferencesDialogMessageHandler { .disabled(!preferences.supports_wgpu()) .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::UseVello { use_vello: checkbox_input.checked }.into()) .widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), TextLabel::new("Vello Renderer") .table_align(true) .tooltip(vello_tooltip) @@ -97,11 +95,19 @@ impl PreferencesDialogMessageHandler { .widget_holder(), ]; + let vector_mesh_tooltip = "Allow tools to produce vector meshes, where more than two segments can connect to an anchor point.\n\nCurrently this does not properly handle line joins and fills."; + let vector_meshes = vec![ + CheckboxInput::new(preferences.vector_meshes) + .tooltip(vector_mesh_tooltip) + .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::VectorMeshes { enabled: checkbox_input.checked }.into()) + .widget_holder(), + TextLabel::new("Vector Meshes").table_align(true).tooltip(vector_mesh_tooltip).widget_holder(), + ]; + // TODO: Reenable when Imaginate is restored // let imaginate_server_hostname = vec![ // TextLabel::new("Imaginate").min_width(60).italic(true).widget_holder(), // TextLabel::new("Server Hostname").table_align(true).widget_holder(), - // Separator::new(SeparatorType::Unrelated).widget_holder(), // TextInput::new(&preferences.imaginate_server_hostname) // .min_width(200) // .on_update(|text_input: &TextInput| PreferencesMessage::ImaginateServerHostname { hostname: text_input.value.clone() }.into()) @@ -110,7 +116,6 @@ impl PreferencesDialogMessageHandler { // let imaginate_refresh_frequency = vec![ // TextLabel::new("").min_width(60).widget_holder(), // TextLabel::new("Refresh Frequency").table_align(true).widget_holder(), - // Separator::new(SeparatorType::Unrelated).widget_holder(), // NumberInput::new(Some(preferences.imaginate_refresh_frequency)) // .unit(" seconds") // .min(0.) @@ -120,16 +125,6 @@ impl PreferencesDialogMessageHandler { // .widget_holder(), // ]; - let vector_mesh_tooltip = "Allow tools to produce vector meshes, where more than two segments can connect to an anchor point.\n\nCurrently this does not properly handle line joins and fills."; - let vector_meshes = vec![ - CheckboxInput::new(preferences.vector_meshes) - .tooltip(vector_mesh_tooltip) - .on_update(|checkbox_input: &CheckboxInput| PreferencesMessage::VectorMeshes { enabled: checkbox_input.checked }.into()) - .widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), - TextLabel::new("Vector Meshes").table_align(true).tooltip(vector_mesh_tooltip).widget_holder(), - ]; - Layout::WidgetLayout(WidgetLayout::new(vec![ LayoutGroup::Row { widgets: selection_section }, LayoutGroup::Row { widgets: vec![selection_mode] }, diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index 699ebe3eb1..f60f98d7c1 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -46,15 +46,15 @@ pub enum PortfolioMessage { document_id: DocumentId, }, DestroyAllDocuments, + EditorPreferences, FontLoaded { font_family: String, font_style: String, preview_url: String, data: Vec, }, - ImaginateCheckServerStatus, - ImaginatePollServerStatus, - EditorPreferences, + // ImaginateCheckServerStatus, + // ImaginatePollServerStatus, // ImaginateServerHostname, Import, LoadDocumentResources { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 49265fe749..9500656577 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -297,31 +297,31 @@ impl MessageHandler> for PortfolioMes responses.add(NodeGraphMessage::RunDocumentGraph); } } - PortfolioMessage::ImaginateCheckServerStatus => { - let server_status = self.persistent_data.imaginate.server_status().clone(); - self.persistent_data.imaginate.poll_server_check(); - #[cfg(target_arch = "wasm32")] - if let Some(fut) = self.persistent_data.imaginate.initiate_server_check() { - wasm_bindgen_futures::spawn_local(async move { - let () = fut.await; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen(module = "/../frontend/src/editor.ts")] - extern "C" { - #[wasm_bindgen(js_name = injectImaginatePollServerStatus)] - fn inject(); - } - inject(); - }) - } - if &server_status != self.persistent_data.imaginate.server_status() { - responses.add(PropertiesPanelMessage::Refresh); - } - } - PortfolioMessage::ImaginatePollServerStatus => { - self.persistent_data.imaginate.poll_server_check(); - responses.add(PropertiesPanelMessage::Refresh); - } + // PortfolioMessage::ImaginateCheckServerStatus => { + // let server_status = self.persistent_data.imaginate.server_status().clone(); + // self.persistent_data.imaginate.poll_server_check(); + // #[cfg(target_arch = "wasm32")] + // if let Some(fut) = self.persistent_data.imaginate.initiate_server_check() { + // wasm_bindgen_futures::spawn_local(async move { + // let () = fut.await; + // use wasm_bindgen::prelude::*; + + // #[wasm_bindgen(module = "/../frontend/src/editor.ts")] + // extern "C" { + // #[wasm_bindgen(js_name = injectImaginatePollServerStatus)] + // fn inject(); + // } + // inject(); + // }) + // } + // if &server_status != self.persistent_data.imaginate.server_status() { + // responses.add(PropertiesPanelMessage::Refresh); + // } + // } + // PortfolioMessage::ImaginatePollServerStatus => { + // self.persistent_data.imaginate.poll_server_check(); + // responses.add(PropertiesPanelMessage::Refresh); + // } PortfolioMessage::EditorPreferences => self.executor.update_editor_preferences(preferences.editor_preferences()), // PortfolioMessage::ImaginateServerHostname => { // self.persistent_data.imaginate.set_host_name(&preferences.imaginate_server_hostname); diff --git a/editor/src/messages/preferences/mod.rs b/editor/src/messages/preferences/mod.rs index 5ab399f981..916c384f8a 100644 --- a/editor/src/messages/preferences/mod.rs +++ b/editor/src/messages/preferences/mod.rs @@ -1,10 +1,10 @@ -pub mod preference_type; mod preferences_message; mod preferences_message_handler; +pub mod utility_types; -#[doc(inline)] -pub use preference_type::SelectionMode; #[doc(inline)] pub use preferences_message::{PreferencesMessage, PreferencesMessageDiscriminant}; #[doc(inline)] pub use preferences_message_handler::PreferencesMessageHandler; +#[doc(inline)] +pub use utility_types::SelectionMode; diff --git a/editor/src/messages/preferences/preferences_message.rs b/editor/src/messages/preferences/preferences_message.rs index 54522ef4ed..d060267a70 100644 --- a/editor/src/messages/preferences/preferences_message.rs +++ b/editor/src/messages/preferences/preferences_message.rs @@ -9,10 +9,10 @@ pub enum PreferencesMessage { ResetToDefaults, // Per-preference messages - // ImaginateRefreshFrequency { seconds: f64 }, - // ImaginateServerHostname { hostname: String }, UseVello { use_vello: bool }, SelectionMode { selection_mode: SelectionMode }, VectorMeshes { enabled: bool }, ModifyLayout { zoom_with_scroll: bool }, + // ImaginateRefreshFrequency { seconds: f64 }, + // ImaginateServerHostname { hostname: String }, } diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index 672c3b7430..f52b109b9a 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -1,6 +1,7 @@ use crate::messages::input_mapper::key_mapping::MappingVariant; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; + use graph_craft::wasm_application_io::EditorPreferences; #[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type)] @@ -74,26 +75,6 @@ impl MessageHandler for PreferencesMessageHandler { } // Per-preference messages - // PreferencesMessage::ImaginateRefreshFrequency { seconds } => { - // self.imaginate_refresh_frequency = seconds; - // responses.add(PortfolioMessage::ImaginateCheckServerStatus); - // responses.add(PortfolioMessage::EditorPreferences); - // } - // PreferencesMessage::ImaginateServerHostname { hostname } => { - // let initial = hostname.clone(); - // let has_protocol = hostname.starts_with("http://") || hostname.starts_with("https://"); - // let hostname = if has_protocol { hostname } else { "http://".to_string() + &hostname }; - // let hostname = if hostname.ends_with('/') { hostname } else { hostname + "/" }; - - // if hostname != initial { - // refresh_dialog(responses); - // } - - // self.imaginate_server_hostname = hostname; - // responses.add(PortfolioMessage::ImaginateServerHostname); - // responses.add(PortfolioMessage::ImaginateCheckServerStatus); - // responses.add(PortfolioMessage::EditorPreferences); - //} PreferencesMessage::UseVello { use_vello } => { self.use_vello = use_vello; responses.add(PortfolioMessage::UpdateVelloPreference); @@ -115,6 +96,27 @@ impl MessageHandler for PreferencesMessageHandler { self.selection_mode = selection_mode; } } + // TODO: Reenable when Imaginate is restored (and move back up one line since the auto-formatter doesn't like it in that block) + // PreferencesMessage::ImaginateRefreshFrequency { seconds } => { + // self.imaginate_refresh_frequency = seconds; + // responses.add(PortfolioMessage::ImaginateCheckServerStatus); + // responses.add(PortfolioMessage::EditorPreferences); + // } + // PreferencesMessage::ImaginateServerHostname { hostname } => { + // let initial = hostname.clone(); + // let has_protocol = hostname.starts_with("http://") || hostname.starts_with("https://"); + // let hostname = if has_protocol { hostname } else { "http://".to_string() + &hostname }; + // let hostname = if hostname.ends_with('/') { hostname } else { hostname + "/" }; + + // if hostname != initial { + // refresh_dialog(responses); + // } + + // self.imaginate_server_hostname = hostname; + // responses.add(PortfolioMessage::ImaginateServerHostname); + // responses.add(PortfolioMessage::ImaginateCheckServerStatus); + // responses.add(PortfolioMessage::EditorPreferences); + //} responses.add(FrontendMessage::TriggerSavePreferences { preferences: self.clone() }); } diff --git a/editor/src/messages/preferences/preference_type.rs b/editor/src/messages/preferences/utility_types.rs similarity index 100% rename from editor/src/messages/preferences/preference_type.rs rename to editor/src/messages/preferences/utility_types.rs diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index c9358e9e68..91e877e9e6 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -260,9 +260,8 @@ enum SelectToolFsmState { impl Default for SelectToolFsmState { fn default() -> Self { - SelectToolFsmState::Ready { - selection: NestedSelectionBehavior::Deepest, - } + let selection = NestedSelectionBehavior::Deepest; + SelectToolFsmState::Ready { selection } } } @@ -284,7 +283,6 @@ struct SelectToolData { selected_layers_changed: bool, snap_candidates: Vec, auto_panning: AutoPanning, - selection_mode: SelectionMode, } impl SelectToolData { @@ -308,13 +306,10 @@ impl SelectToolData { pub fn calculate_direction(&self) -> SelectionMode { let bbox: [DVec2; 2] = self.selection_box(); - if bbox[1].x > bbox[0].x { - SelectionMode::Enclosed - } else if bbox[1].x < bbox[0].x { + if bbox[1].x < bbox[0].x { SelectionMode::Touched } else { - // If the x coordinates are equal, the area is zero, so we use rightwards which corresponds to the "Enclosed" - // selection mode to ensure the selection ends up empty, as nothing will be enclosed by an empty area. + // This also covers the case where they're equal: the area is zero, so we use `Enclosed` to ensure the selection ends up empty, as nothing will be enclosed by an empty area SelectionMode::Enclosed } } @@ -422,9 +417,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; - // TODO: Should this be moved down a line? - tool_data.selection_mode = tool_action_data.preferences.get_selection_mode(); - let ToolMessage::Select(event) = event else { return self }; match (self, event) { (_, SelectToolMessage::Overlays(mut overlay_context)) => { @@ -499,7 +491,7 @@ impl Fsm for SelectToolFsmState { // Get the updated selection box bounds let quad = Quad::from_box([tool_data.drag_start, tool_data.drag_current]); - let mut selection_direction = tool_data.selection_mode; + let mut selection_direction = tool_action_data.preferences.get_selection_mode(); if selection_direction == SelectionMode::Directional { selection_direction = tool_data.calculate_direction(); } @@ -1057,7 +1049,7 @@ impl Fsm for SelectToolFsmState { ) => { let quad = tool_data.selection_quad(); - let mut selection_direction = tool_data.selection_mode; + let mut selection_direction = tool_action_data.preferences.get_selection_mode(); if selection_direction == SelectionMode::Directional { selection_direction = tool_data.calculate_direction(); } diff --git a/frontend/src/editor.ts b/frontend/src/editor.ts index de7035ccb6..cb3bf494fd 100644 --- a/frontend/src/editor.ts +++ b/frontend/src/editor.ts @@ -81,7 +81,7 @@ export function createEditor(): Editor { // TODO: Then, delete the `(window as any).editorHandle = handle;` line above. // This function is called by an FFI binding within the Rust code directly, rather than using the FrontendMessage system. // Then, this directly calls the `injectImaginatePollServerStatus` function on the `EditorHandle` object which is a JS binding generated by wasm-bindgen, going straight back into the Rust code. -export function injectImaginatePollServerStatus() { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (window as any).editorHandle?.injectImaginatePollServerStatus(); -} +// export function injectImaginatePollServerStatus() { +// // eslint-disable-next-line @typescript-eslint/no-explicit-any +// (window as any).editorHandle?.injectImaginatePollServerStatus(); +// } diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 19b7550863..5b14669b8e 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -725,10 +725,10 @@ impl EditorHandle { self.dispatch(message); } - #[wasm_bindgen(js_name = injectImaginatePollServerStatus)] - pub fn inject_imaginate_poll_server_status(&self) { - self.dispatch(PortfolioMessage::ImaginatePollServerStatus); - } + // #[wasm_bindgen(js_name = injectImaginatePollServerStatus)] + // pub fn inject_imaginate_poll_server_status(&self) { + // self.dispatch(PortfolioMessage::ImaginatePollServerStatus); + // } // TODO: Eventually remove this document upgrade code #[wasm_bindgen(js_name = triggerUpgradeDocumentToVectorManipulationFormat)]