Migrate the Select tool to the document graph (#1433)

* function for accessing document metadata

* Better select tool

* Fix render

* Fix transforms

* Fix loading saved documents

* Populate graph UI when loading autosave

* Multiple transform nodes

* Fix deep select

* Graph tooltips

* Fix flip axis icon

* Show disabled widgets

* Stop select tool from selecting artboards

* Disable (not hide) the pivot widget; remove Deep/Shallow select for now

* Code review changes

* Fix pivot position with select tool

* Fix incorrectly selected layers when shift clicking

---------

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2023-10-17 18:59:30 +01:00
committed by Keavon Chambers
parent e1cdb2242d
commit 5827e989dc
46 changed files with 1041 additions and 1215 deletions

View File

@@ -1,5 +1,5 @@
use crate::messages::frontend::utility_types::FrontendImageData;
use crate::messages::portfolio::document::node_graph::wrap_network_in_scope;
use crate::messages::portfolio::document::node_graph::{transform_utils, wrap_network_in_scope};
use crate::messages::portfolio::document::utility_types::misc::{LayerMetadata, LayerPanelEntry};
use crate::messages::prelude::*;
@@ -56,6 +56,7 @@ pub struct NodeRuntime {
pub(crate) thumbnails: HashMap<NodeId, SvgSegmentList>,
pub(crate) click_targets: HashMap<NodeId, Vec<ClickTarget>>,
pub(crate) transforms: HashMap<NodeId, DAffine2>,
pub(crate) upstream_transforms: HashMap<NodeId, DAffine2>,
canvas_cache: HashMap<Vec<LayerId>, SurfaceId>,
}
@@ -80,6 +81,7 @@ pub(crate) struct GenerationResponse {
new_thumbnails: HashMap<NodeId, SvgSegmentList>,
new_click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
new_transforms: HashMap<LayerNodeIdentifier, DAffine2>,
new_upstream_transforms: HashMap<NodeId, DAffine2>,
}
enum NodeGraphUpdate {
@@ -119,6 +121,7 @@ impl NodeRuntime {
canvas_cache: HashMap::new(),
click_targets: HashMap::new(),
transforms: HashMap::new(),
upstream_transforms: HashMap::new(),
}
}
pub async fn run(&mut self) {
@@ -147,13 +150,14 @@ impl NodeRuntime {
let monitor_nodes = network
.recursive_nodes()
.filter(|node| node.implementation == DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode<_>"))
.map(|node| node.path.clone().unwrap_or_default())
.collect();
.filter(|(_, node)| node.implementation == DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode<_>"))
.map(|(_, node)| node.path.clone().unwrap_or_default())
.collect::<Vec<_>>();
let result = self.execute_network(&path, network, transform, viewport_resolution).await;
let mut responses = VecDeque::new();
self.update_thumbnails(&path, monitor_nodes, &mut responses);
self.update_thumbnails(&path, &monitor_nodes, &mut responses);
self.update_upstream_transforms(&path, &monitor_nodes, &mut responses);
let response = GenerationResponse {
generation_id,
result,
@@ -161,6 +165,7 @@ impl NodeRuntime {
new_thumbnails: self.thumbnails.clone(),
new_click_targets: self.click_targets.clone().into_iter().map(|(id, targets)| (LayerNodeIdentifier::new_unchecked(id), targets)).collect(),
new_transforms: self.transforms.clone().into_iter().map(|(id, transform)| (LayerNodeIdentifier::new_unchecked(id), transform)).collect(),
new_upstream_transforms: self.upstream_transforms.clone(),
};
self.sender.send_generation_response(response);
}
@@ -184,7 +189,10 @@ impl NodeRuntime {
resolution: viewport_resolution,
..Default::default()
},
#[cfg(any(feature = "resvg", feature = "vello"))]
export_format: graphene_core::application_io::ExportFormat::Canvas,
#[cfg(not(any(feature = "resvg", feature = "vello")))]
export_format: graphene_core::application_io::ExportFormat::Svg,
},
image_frame: None,
};
@@ -223,14 +231,14 @@ impl NodeRuntime {
}
/// Recomputes the thumbnails for the layers in the graph, modifying the state and updating the UI.
pub fn update_thumbnails(&mut self, layer_path: &[LayerId], monitor_nodes: Vec<Vec<u64>>, responses: &mut VecDeque<Message>) {
pub fn update_thumbnails(&mut self, layer_path: &[LayerId], monitor_nodes: &[Vec<u64>], responses: &mut VecDeque<Message>) {
let mut image_data: Vec<_> = Vec::new();
for node_path in monitor_nodes {
let Some(node_id) = node_path.get(node_path.len() - 2).copied() else {
warn!("Monitor node has invalid node id");
continue;
};
let Some(value) = self.executor.introspect(&node_path).flatten() else {
let Some(value) = self.executor.introspect(node_path).flatten() else {
warn!("Failed to introspect monitor node for thumbnail");
continue;
};
@@ -280,6 +288,24 @@ impl NodeRuntime {
responses.add(FrontendMessage::UpdateImageData { document_id: 0, image_data });
}
}
pub fn update_upstream_transforms(&mut self, layer_path: &[LayerId], monitor_nodes: &[Vec<u64>], responses: &mut VecDeque<Message>) {
for node_path in monitor_nodes {
let Some(node_id) = node_path.get(node_path.len() - 2).copied() else {
warn!("Monitor node has invalid node id");
continue;
};
let Some(value) = self.executor.introspect(node_path).flatten() else {
warn!("Failed to introspect monitor node for upstream transforms");
continue;
};
let Some(graphic_element_data) = value.downcast_ref::<graphene_core::vector::VectorData>() else {
warn!("Failed to downcast transform input to vector data");
continue;
};
self.upstream_transforms.insert(node_id, graphic_element_data.transform());
}
}
}
pub fn introspect_node(path: &[NodeId]) -> Option<Arc<dyn std::any::Any>> {
NODE_RUNTIME
@@ -470,9 +496,10 @@ impl NodeGraphExecutor {
new_thumbnails,
new_click_targets,
new_transforms,
new_upstream_transforms,
}) => {
self.thumbnails = new_thumbnails;
document.metadata.update_transforms(new_transforms);
document.metadata.update_transforms(new_transforms, new_upstream_transforms);
document.metadata.update_click_targets(new_click_targets);
let node_graph_output = result.map_err(|e| format!("Node graph evaluation failed: {:?}", e))?;
let execution_context = self.futures.remove(&generation_id).ok_or_else(|| "Invalid generation ID".to_string())?;