Skip to content

Commit 9236bfc

Browse files
mTvare6Keavon
andauthored
Transfer pasted layers to the viewport center when outside the current view area (#2306)
* Transfer pasted layers to viewport center when not in viewport Fixes #2301 * Move a layer as a whole and use change * Make a bbox and move content according to that * partial fix * Only move if none within viewport * Fix import error * Fix artboard * tmp, skip ones being added to ab * fix stuff * fix formatting * Code review --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 6c1ccfb commit 9236bfc

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed

editor/src/messages/portfolio/portfolio_message.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ pub enum PortfolioMessage {
9090
PasteSerializedData {
9191
data: String,
9292
},
93+
CenterPastedLayers {
94+
layers: Vec<LayerNodeIdentifier>,
95+
},
9396
PasteImage {
9497
name: Option<String>,
9598
image: Image<Color>,

editor/src/messages/portfolio/portfolio_message_handler.rs

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::messages::dialog::simple_dialogs;
1010
use crate::messages::frontend::utility_types::FrontendDocumentDetails;
1111
use crate::messages::layout::utility_types::widget_prelude::*;
1212
use crate::messages::portfolio::document::DocumentMessageData;
13+
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
1314
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
1415
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
1516
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
@@ -18,9 +19,10 @@ use crate::messages::prelude::*;
1819
use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType};
1920
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
2021
use bezier_rs::Subpath;
21-
use glam::IVec2;
22+
use glam::{DAffine2, DVec2, IVec2};
2223
use graph_craft::document::value::TaggedValue;
2324
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
25+
use graphene_core::renderer::Quad;
2426
use graphene_core::text::{Font, TypesettingConfig};
2527
use graphene_std::vector::style::{Fill, FillType, Gradient};
2628
use graphene_std::vector::{VectorData, VectorDataTable};
@@ -1003,6 +1005,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
10031005
if let Some(document) = self.active_document() {
10041006
if let Ok(data) = serde_json::from_str::<Vec<CopyBufferEntry>>(&data) {
10051007
let parent = document.new_layer_parent(false);
1008+
let mut layers = Vec::new();
10061009

10071010
let mut added_nodes = false;
10081011

@@ -1012,16 +1015,126 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
10121015
responses.add(DocumentMessage::AddTransaction);
10131016
added_nodes = true;
10141017
}
1018+
10151019
document.load_layer_resources(responses);
10161020
let new_ids: HashMap<_, _> = entry.nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect();
10171021
let layer = LayerNodeIdentifier::new_unchecked(new_ids[&NodeId(0)]);
10181022
responses.add(NodeGraphMessage::AddNodes { nodes: entry.nodes, new_ids });
10191023
responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index: 0 });
1024+
layers.push(layer);
10201025
}
1026+
10211027
responses.add(NodeGraphMessage::RunDocumentGraph);
1028+
responses.add(Message::StartBuffer);
1029+
responses.add(PortfolioMessage::CenterPastedLayers { layers });
10221030
}
10231031
}
10241032
}
1033+
PortfolioMessage::CenterPastedLayers { layers } => {
1034+
if let Some(document) = self.active_document_mut() {
1035+
let viewport_bounds_quad_pixels = Quad::from_box([DVec2::ZERO, ipp.viewport_bounds.size()]);
1036+
let viewport_center_pixels = viewport_bounds_quad_pixels.center(); // In viewport pixel coordinates
1037+
1038+
let doc_to_viewport_transform = document.metadata().document_to_viewport;
1039+
let viewport_to_doc_transform = doc_to_viewport_transform.inverse();
1040+
1041+
let viewport_quad_doc_space = viewport_to_doc_transform * viewport_bounds_quad_pixels;
1042+
1043+
let mut top_level_items_to_center: Vec<LayerNodeIdentifier> = Vec::new();
1044+
let mut artboards_in_selection: Vec<LayerNodeIdentifier> = Vec::new();
1045+
1046+
for &layer_id in &layers {
1047+
if document.network_interface.is_artboard(&layer_id.to_node(), &document.node_graph_handler.network) {
1048+
artboards_in_selection.push(layer_id);
1049+
}
1050+
}
1051+
1052+
for &layer_id in &layers {
1053+
let is_child_of_selected_artboard = artboards_in_selection.iter().any(|&artboard_id| {
1054+
if layer_id == artboard_id {
1055+
return false;
1056+
}
1057+
layer_id.ancestors(document.metadata()).any(|ancestor| ancestor == artboard_id)
1058+
});
1059+
1060+
if !is_child_of_selected_artboard {
1061+
top_level_items_to_center.push(layer_id);
1062+
}
1063+
}
1064+
1065+
if top_level_items_to_center.is_empty() {
1066+
return;
1067+
}
1068+
1069+
let mut combined_min_doc = DVec2::MAX;
1070+
let mut combined_max_doc = DVec2::MIN;
1071+
let mut has_any_bounds = false;
1072+
1073+
for &item_id in &top_level_items_to_center {
1074+
if let Some(bounds_doc) = document.metadata().bounding_box_document(item_id) {
1075+
combined_min_doc = combined_min_doc.min(bounds_doc[0]);
1076+
combined_max_doc = combined_max_doc.max(bounds_doc[1]);
1077+
has_any_bounds = true;
1078+
}
1079+
}
1080+
1081+
if !has_any_bounds {
1082+
return;
1083+
}
1084+
1085+
let combined_bounds_doc_quad = Quad::from_box([combined_min_doc, combined_max_doc]);
1086+
1087+
if combined_bounds_doc_quad.intersects(viewport_quad_doc_space) {
1088+
return;
1089+
}
1090+
1091+
let combined_center_doc = combined_bounds_doc_quad.center();
1092+
let combined_center_viewport_pixels = doc_to_viewport_transform.transform_point2(combined_center_doc);
1093+
let translation_viewport_pixels_rounded = (viewport_center_pixels - combined_center_viewport_pixels).round();
1094+
1095+
let final_translation_offset_doc = viewport_to_doc_transform.transform_vector2(translation_viewport_pixels_rounded);
1096+
1097+
if final_translation_offset_doc.abs_diff_eq(glam::DVec2::ZERO, 1e-9) {
1098+
return;
1099+
}
1100+
1101+
responses.add(DocumentMessage::AddTransaction);
1102+
1103+
for &item_id in &top_level_items_to_center {
1104+
if document.network_interface.is_artboard(&item_id.to_node(), &document.node_graph_handler.network) {
1105+
if let Some(bounds_doc) = document.metadata().bounding_box_document(item_id) {
1106+
let current_artboard_origin_doc = bounds_doc[0];
1107+
let dimensions_doc = bounds_doc[1] - bounds_doc[0];
1108+
let new_artboard_origin_doc = current_artboard_origin_doc + final_translation_offset_doc;
1109+
1110+
responses.add(GraphOperationMessage::ResizeArtboard {
1111+
layer: item_id,
1112+
location: new_artboard_origin_doc.round().as_ivec2(),
1113+
dimensions: dimensions_doc.round().as_ivec2(),
1114+
});
1115+
}
1116+
} else {
1117+
let current_abs_doc_transform = document.metadata().transform_to_document(item_id);
1118+
1119+
let new_abs_doc_transform = DAffine2 {
1120+
matrix2: current_abs_doc_transform.matrix2,
1121+
translation: current_abs_doc_transform.translation + final_translation_offset_doc,
1122+
};
1123+
1124+
let transform = doc_to_viewport_transform * new_abs_doc_transform;
1125+
1126+
responses.add(GraphOperationMessage::TransformSet {
1127+
layer: item_id,
1128+
transform,
1129+
transform_in: TransformIn::Viewport,
1130+
skip_rerender: false,
1131+
});
1132+
}
1133+
}
1134+
1135+
responses.add(NodeGraphMessage::RunDocumentGraph);
1136+
}
1137+
}
10251138
PortfolioMessage::PasteImage {
10261139
name,
10271140
image,

0 commit comments

Comments
 (0)