mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
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 <keavon@keavon.com>
This commit is contained in:
parent
6c1ccfb5bb
commit
9236bfcec0
2 changed files with 117 additions and 1 deletions
|
@ -90,6 +90,9 @@ pub enum PortfolioMessage {
|
|||
PasteSerializedData {
|
||||
data: String,
|
||||
},
|
||||
CenterPastedLayers {
|
||||
layers: Vec<LayerNodeIdentifier>,
|
||||
},
|
||||
PasteImage {
|
||||
name: Option<String>,
|
||||
image: Image<Color>,
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::messages::dialog::simple_dialogs;
|
|||
use crate::messages::frontend::utility_types::FrontendDocumentDetails;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::DocumentMessageData;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
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::utility_types::nodes::SelectedNodes;
|
||||
|
@ -18,9 +19,10 @@ use crate::messages::prelude::*;
|
|||
use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType};
|
||||
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
||||
use bezier_rs::Subpath;
|
||||
use glam::IVec2;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graphene_core::renderer::Quad;
|
||||
use graphene_core::text::{Font, TypesettingConfig};
|
||||
use graphene_std::vector::style::{Fill, FillType, Gradient};
|
||||
use graphene_std::vector::{VectorData, VectorDataTable};
|
||||
|
@ -1003,6 +1005,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
|||
if let Some(document) = self.active_document() {
|
||||
if let Ok(data) = serde_json::from_str::<Vec<CopyBufferEntry>>(&data) {
|
||||
let parent = document.new_layer_parent(false);
|
||||
let mut layers = Vec::new();
|
||||
|
||||
let mut added_nodes = false;
|
||||
|
||||
|
@ -1012,16 +1015,126 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
|||
responses.add(DocumentMessage::AddTransaction);
|
||||
added_nodes = true;
|
||||
}
|
||||
|
||||
document.load_layer_resources(responses);
|
||||
let new_ids: HashMap<_, _> = entry.nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect();
|
||||
let layer = LayerNodeIdentifier::new_unchecked(new_ids[&NodeId(0)]);
|
||||
responses.add(NodeGraphMessage::AddNodes { nodes: entry.nodes, new_ids });
|
||||
responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index: 0 });
|
||||
layers.push(layer);
|
||||
}
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(Message::StartBuffer);
|
||||
responses.add(PortfolioMessage::CenterPastedLayers { layers });
|
||||
}
|
||||
}
|
||||
}
|
||||
PortfolioMessage::CenterPastedLayers { layers } => {
|
||||
if let Some(document) = self.active_document_mut() {
|
||||
let viewport_bounds_quad_pixels = Quad::from_box([DVec2::ZERO, ipp.viewport_bounds.size()]);
|
||||
let viewport_center_pixels = viewport_bounds_quad_pixels.center(); // In viewport pixel coordinates
|
||||
|
||||
let doc_to_viewport_transform = document.metadata().document_to_viewport;
|
||||
let viewport_to_doc_transform = doc_to_viewport_transform.inverse();
|
||||
|
||||
let viewport_quad_doc_space = viewport_to_doc_transform * viewport_bounds_quad_pixels;
|
||||
|
||||
let mut top_level_items_to_center: Vec<LayerNodeIdentifier> = Vec::new();
|
||||
let mut artboards_in_selection: Vec<LayerNodeIdentifier> = Vec::new();
|
||||
|
||||
for &layer_id in &layers {
|
||||
if document.network_interface.is_artboard(&layer_id.to_node(), &document.node_graph_handler.network) {
|
||||
artboards_in_selection.push(layer_id);
|
||||
}
|
||||
}
|
||||
|
||||
for &layer_id in &layers {
|
||||
let is_child_of_selected_artboard = artboards_in_selection.iter().any(|&artboard_id| {
|
||||
if layer_id == artboard_id {
|
||||
return false;
|
||||
}
|
||||
layer_id.ancestors(document.metadata()).any(|ancestor| ancestor == artboard_id)
|
||||
});
|
||||
|
||||
if !is_child_of_selected_artboard {
|
||||
top_level_items_to_center.push(layer_id);
|
||||
}
|
||||
}
|
||||
|
||||
if top_level_items_to_center.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut combined_min_doc = DVec2::MAX;
|
||||
let mut combined_max_doc = DVec2::MIN;
|
||||
let mut has_any_bounds = false;
|
||||
|
||||
for &item_id in &top_level_items_to_center {
|
||||
if let Some(bounds_doc) = document.metadata().bounding_box_document(item_id) {
|
||||
combined_min_doc = combined_min_doc.min(bounds_doc[0]);
|
||||
combined_max_doc = combined_max_doc.max(bounds_doc[1]);
|
||||
has_any_bounds = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !has_any_bounds {
|
||||
return;
|
||||
}
|
||||
|
||||
let combined_bounds_doc_quad = Quad::from_box([combined_min_doc, combined_max_doc]);
|
||||
|
||||
if combined_bounds_doc_quad.intersects(viewport_quad_doc_space) {
|
||||
return;
|
||||
}
|
||||
|
||||
let combined_center_doc = combined_bounds_doc_quad.center();
|
||||
let combined_center_viewport_pixels = doc_to_viewport_transform.transform_point2(combined_center_doc);
|
||||
let translation_viewport_pixels_rounded = (viewport_center_pixels - combined_center_viewport_pixels).round();
|
||||
|
||||
let final_translation_offset_doc = viewport_to_doc_transform.transform_vector2(translation_viewport_pixels_rounded);
|
||||
|
||||
if final_translation_offset_doc.abs_diff_eq(glam::DVec2::ZERO, 1e-9) {
|
||||
return;
|
||||
}
|
||||
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
|
||||
for &item_id in &top_level_items_to_center {
|
||||
if document.network_interface.is_artboard(&item_id.to_node(), &document.node_graph_handler.network) {
|
||||
if let Some(bounds_doc) = document.metadata().bounding_box_document(item_id) {
|
||||
let current_artboard_origin_doc = bounds_doc[0];
|
||||
let dimensions_doc = bounds_doc[1] - bounds_doc[0];
|
||||
let new_artboard_origin_doc = current_artboard_origin_doc + final_translation_offset_doc;
|
||||
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
layer: item_id,
|
||||
location: new_artboard_origin_doc.round().as_ivec2(),
|
||||
dimensions: dimensions_doc.round().as_ivec2(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let current_abs_doc_transform = document.metadata().transform_to_document(item_id);
|
||||
|
||||
let new_abs_doc_transform = DAffine2 {
|
||||
matrix2: current_abs_doc_transform.matrix2,
|
||||
translation: current_abs_doc_transform.translation + final_translation_offset_doc,
|
||||
};
|
||||
|
||||
let transform = doc_to_viewport_transform * new_abs_doc_transform;
|
||||
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer: item_id,
|
||||
transform,
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
}
|
||||
PortfolioMessage::PasteImage {
|
||||
name,
|
||||
image,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue