Skip to content

Commit ca0d102

Browse files
adamgerhantTrueDoctorKeavon
authored
Fix click targets (in, e.g., the boolean node) by resolving footprints from render output (#1946)
* add NodeId (u64) and Footprint to Graphic Group * Render Output footprints * Small bug fixes * Commented out render output click targets/footprints * Run graph when deleting * Switch to node path * Add upstream clicktargets for boolean operation * Fix boolean operations * Fix grouped layers * Add click targets to vello render * Add cache to artwork * Fix demo artwork * Improve recursion * Code review --------- Co-authored-by: Dennis Kobert <[email protected]> Co-authored-by: Keavon Chambers <[email protected]>
1 parent ef00773 commit ca0d102

File tree

28 files changed

+996
-663
lines changed

28 files changed

+996
-663
lines changed

Cargo.lock

Lines changed: 491 additions & 406 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo-artwork/isometric-fountain.graphite

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo-artwork/painted-dreams.graphite

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

editor/src/messages/portfolio/document/document_message.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ use graphene_core::raster::BlendMode;
1111
use graphene_core::raster::Image;
1212
use graphene_core::vector::style::ViewMode;
1313
use graphene_core::Color;
14+
use graphene_std::renderer::ClickTarget;
15+
use graphene_std::transform::Footprint;
16+
use graphene_std::vector::VectorData;
1417

1518
use glam::DAffine2;
1619

@@ -155,6 +158,15 @@ pub enum DocumentMessage {
155158
ToggleGridVisibility,
156159
ToggleOverlaysVisibility,
157160
ToggleSnapping,
161+
UpdateUpstreamTransforms {
162+
upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
163+
},
164+
UpdateClickTargets {
165+
click_targets: HashMap<NodeId, Vec<ClickTarget>>,
166+
},
167+
UpdateVectorModify {
168+
vector_modify: HashMap<NodeId, VectorData>,
169+
},
158170
Undo,
159171
UngroupSelectedLayers,
160172
UngroupLayer {

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,8 +1022,9 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
10221022
if self.network_interface.transaction_status() == TransactionStatus::Finished {
10231023
return;
10241024
}
1025+
1026+
self.document_undo_history.pop_back();
10251027
self.network_interface.finish_transaction();
1026-
self.undo(ipp, responses);
10271028
responses.add(OverlaysMessage::Draw);
10281029
}
10291030
DocumentMessage::AddTransaction => {
@@ -1054,6 +1055,25 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
10541055
self.snapping_state.snapping_enabled = !self.snapping_state.snapping_enabled;
10551056
responses.add(PortfolioMessage::UpdateDocumentWidgets);
10561057
}
1058+
DocumentMessage::UpdateUpstreamTransforms { upstream_transforms } => {
1059+
self.network_interface.update_transforms(upstream_transforms);
1060+
}
1061+
DocumentMessage::UpdateClickTargets { click_targets } => {
1062+
// TODO: Allow non layer nodes to have click targets
1063+
let layer_click_targets = click_targets
1064+
.into_iter()
1065+
.filter_map(|(node_id, click_targets)| {
1066+
self.network_interface.is_layer(&node_id, &[]).then(|| {
1067+
let layer = LayerNodeIdentifier::new(node_id, &self.network_interface, &[]);
1068+
(layer, click_targets)
1069+
})
1070+
})
1071+
.collect();
1072+
self.network_interface.update_click_targets(layer_click_targets);
1073+
}
1074+
DocumentMessage::UpdateVectorModify { vector_modify } => {
1075+
self.network_interface.update_vector_modify(vector_modify);
1076+
}
10571077
DocumentMessage::Undo => {
10581078
if self.network_interface.transaction_status() != TransactionStatus::Finished {
10591079
return;
@@ -1107,6 +1127,9 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
11071127
node_ids: vec![layer.to_node()],
11081128
delete_children: true,
11091129
});
1130+
responses.add(NodeGraphMessage::RunDocumentGraph);
1131+
responses.add(NodeGraphMessage::SelectedNodesUpdated);
1132+
responses.add(NodeGraphMessage::SendGraph);
11101133
}
11111134
DocumentMessage::PTZUpdate => {
11121135
if !self.graph_view_overlay_open {
@@ -1239,7 +1262,7 @@ impl DocumentMessageHandler {
12391262
.filter(|&layer| self.network_interface.selected_nodes(&[]).unwrap().layer_visible(layer, &self.network_interface))
12401263
.filter(|&layer| !self.network_interface.selected_nodes(&[]).unwrap().layer_locked(layer, &self.network_interface))
12411264
.filter(|&layer| !self.network_interface.is_artboard(&layer.to_node(), &[]))
1242-
.filter_map(|layer| self.metadata().click_target(layer).map(|targets| (layer, targets)))
1265+
.filter_map(|layer| self.metadata().click_targets(layer).map(|targets| (layer, targets)))
12431266
.filter(move |(layer, target)| {
12441267
target
12451268
.iter()
@@ -1256,7 +1279,7 @@ impl DocumentMessageHandler {
12561279
.all_layers()
12571280
.filter(|&layer| self.network_interface.selected_nodes(&[]).unwrap().layer_visible(layer, &self.network_interface))
12581281
.filter(|&layer| !self.network_interface.selected_nodes(&[]).unwrap().layer_locked(layer, &self.network_interface))
1259-
.filter_map(|layer| self.metadata().click_target(layer).map(|targets| (layer, targets)))
1282+
.filter_map(|layer| self.metadata().click_targets(layer).map(|targets| (layer, targets)))
12601283
.filter(move |(layer, target)| target.iter().any(|target| target.intersect_point(point, self.metadata().transform_to_document(*layer))))
12611284
.map(|(layer, _)| layer)
12621285
}

editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageData<'_>> for Gr
206206
});
207207
}
208208
// TODO: Replace deleted artboards with merge nodes
209+
responses.add(NodeGraphMessage::RunDocumentGraph);
210+
responses.add(NodeGraphMessage::SelectedNodesUpdated);
211+
responses.add(NodeGraphMessage::SendGraph);
209212
}
210213
GraphOperationMessage::NewSvg {
211214
id,

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,12 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
253253
},
254254
DocumentNode {
255255
manual_composition: Some(concrete!(Footprint)),
256-
inputs: vec![NodeInput::node(NodeId(1), 0), NodeInput::node(NodeId(2), 0)],
257-
implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _>"),
256+
inputs: vec![
257+
NodeInput::node(NodeId(1), 0),
258+
NodeInput::node(NodeId(2), 0),
259+
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
260+
],
261+
implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _, _>"),
258262
..Default::default()
259263
},
260264
]
@@ -359,8 +363,9 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
359363
inputs: vec![
360364
NodeInput::network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(concrete!(ArtboardGroup))), 0),
361365
NodeInput::node(NodeId(1), 0),
366+
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
362367
],
363-
implementation: DocumentNodeImplementation::proto("graphene_core::AddArtboardNode<_, _>"),
368+
implementation: DocumentNodeImplementation::proto("graphene_core::AddArtboardNode<_, _, _>"),
364369
..Default::default()
365370
},
366371
]
@@ -3800,14 +3805,62 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
38003805
category: "Vector",
38013806
node_template: NodeTemplate {
38023807
document_node: DocumentNode {
3808+
implementation: DocumentNodeImplementation::Network(NodeNetwork {
3809+
exports: vec![NodeInput::node(NodeId(1), 0)],
3810+
nodes: vec![
3811+
DocumentNode {
3812+
inputs: vec![NodeInput::network(concrete!(VectorData), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
3813+
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::vector::BooleanOperationNode<_>")),
3814+
..Default::default()
3815+
},
3816+
DocumentNode {
3817+
inputs: vec![NodeInput::node(NodeId(0), 0)],
3818+
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")),
3819+
manual_composition: Some(concrete!(Footprint)),
3820+
..Default::default()
3821+
},
3822+
]
3823+
.into_iter()
3824+
.enumerate()
3825+
.map(|(id, node)| (NodeId(id as u64), node))
3826+
.collect(),
3827+
..Default::default()
3828+
}),
38033829
inputs: vec![
38043830
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::EMPTY), true),
38053831
NodeInput::value(TaggedValue::BooleanOperation(vector::misc::BooleanOperation::Union), false),
38063832
],
3807-
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::vector::BooleanOperationNode<_>")),
38083833
..Default::default()
38093834
},
38103835
persistent_node_metadata: DocumentNodePersistentMetadata {
3836+
network_metadata: Some(NodeNetworkMetadata {
3837+
persistent_metadata: NodeNetworkPersistentMetadata {
3838+
node_metadata: [
3839+
DocumentNodeMetadata {
3840+
persistent_metadata: DocumentNodePersistentMetadata {
3841+
display_name: "Boolean Operation".to_string(),
3842+
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, 0)),
3843+
..Default::default()
3844+
},
3845+
..Default::default()
3846+
},
3847+
DocumentNodeMetadata {
3848+
persistent_metadata: DocumentNodePersistentMetadata {
3849+
display_name: "Cache".to_string(),
3850+
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
3851+
..Default::default()
3852+
},
3853+
..Default::default()
3854+
},
3855+
]
3856+
.into_iter()
3857+
.enumerate()
3858+
.map(|(id, node)| (NodeId(id as u64), node))
3859+
.collect(),
3860+
..Default::default()
3861+
},
3862+
..Default::default()
3863+
}),
38113864
input_names: vec!["Group of Paths".to_string(), "Operation".to_string()],
38123865
output_names: vec!["Vector".to_string()],
38133866
..Default::default()

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
114114
responses.add(NodeGraphMessage::SendSelectedNodes);
115115
responses.add(ArtboardToolMessage::UpdateSelectedArtboard);
116116
responses.add(DocumentMessage::DocumentStructureChanged);
117-
responses.add(NodeGraphMessage::RunDocumentGraph);
117+
responses.add(OverlaysMessage::Draw);
118+
responses.add(NodeGraphMessage::SendGraph);
118119
}
119120
NodeGraphMessage::CreateWire { output_connector, input_connector } => {
120121
// TODO: Add support for flattening NodeInput::Network exports in flatten_with_fns https://github.com/GraphiteEditor/Graphite/issues/1762
@@ -203,8 +204,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
203204
}
204205
NodeGraphMessage::DeleteNodes { node_ids, delete_children } => {
205206
network_interface.delete_nodes(node_ids, delete_children, selection_network_path);
206-
responses.add(NodeGraphMessage::SelectedNodesUpdated);
207-
responses.add(NodeGraphMessage::SendGraph);
208207
}
209208
// Deletes selected_nodes. If `reconnect` is true, then all children nodes (secondary input) of the selected nodes are deleted and the siblings (primary input/output) are reconnected.
210209
// If `reconnect` is false, then only the selected nodes are deleted and not reconnected.
@@ -217,7 +216,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
217216
responses.add(NodeGraphMessage::DeleteNodes {
218217
node_ids: selected_nodes.selected_nodes().cloned().collect::<Vec<_>>(),
219218
delete_children,
220-
})
219+
});
220+
responses.add(NodeGraphMessage::RunDocumentGraph);
221+
responses.add(NodeGraphMessage::SelectedNodesUpdated);
222+
responses.add(NodeGraphMessage::SendGraph);
221223
}
222224
NodeGraphMessage::DisconnectInput { input_connector } => {
223225
network_interface.disconnect_input(&input_connector, selection_network_path);

editor/src/messages/portfolio/document/utility_types/document_metadata.rs

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ pub struct DocumentMetadata {
2222
pub structure: HashMap<LayerNodeIdentifier, NodeRelations>,
2323
pub click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
2424
pub vector_modify: HashMap<NodeId, VectorData>,
25-
// TODO: Remove and derive from document_ptz in document message handler
2625
/// Transform from document space to viewport space.
2726
pub document_to_viewport: DAffine2,
2827
}
@@ -52,7 +51,7 @@ impl DocumentMetadata {
5251
self.structure.contains_key(&layer)
5352
}
5453

55-
pub fn click_target(&self, layer: LayerNodeIdentifier) -> Option<&Vec<ClickTarget>> {
54+
pub fn click_targets(&self, layer: LayerNodeIdentifier) -> Option<&Vec<ClickTarget>> {
5655
self.click_targets.get(&layer)
5756
}
5857

@@ -71,29 +70,15 @@ impl DocumentMetadata {
7170
// ============================
7271

7372
impl DocumentMetadata {
74-
/// Update the cached transforms of the layers
75-
pub fn update_transforms(&mut self, new_upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>) {
76-
self.upstream_transforms = new_upstream_transforms;
77-
}
78-
7973
/// Access the cached transformation to document space from layer space
8074
pub fn transform_to_document(&self, layer: LayerNodeIdentifier) -> DAffine2 {
8175
self.document_to_viewport.inverse() * self.transform_to_viewport(layer)
8276
}
8377

8478
pub fn transform_to_viewport(&self, layer: LayerNodeIdentifier) -> DAffine2 {
85-
layer
86-
.ancestors(self)
87-
.filter_map(|ancestor_layer| {
88-
if ancestor_layer != LayerNodeIdentifier::ROOT_PARENT {
89-
self.upstream_transforms.get(&ancestor_layer.to_node())
90-
} else {
91-
None
92-
}
93-
})
94-
.copied()
95-
.map(|(footprint, transform)| footprint.transform * transform)
96-
.next()
79+
self.upstream_transforms
80+
.get(&layer.to_node())
81+
.map(|(footprint, transform)| footprint.transform * *transform)
9782
.unwrap_or(self.document_to_viewport)
9883
}
9984

@@ -119,16 +104,9 @@ impl DocumentMetadata {
119104
// ===============================
120105

121106
impl DocumentMetadata {
122-
/// Update the cached click targets and vector modify values of the layers
123-
pub fn update_from_monitor(&mut self, new_click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>, new_vector_modify: HashMap<NodeId, VectorData>) {
124-
self.click_targets = new_click_targets;
125-
self.vector_modify = new_vector_modify;
126-
}
127-
128107
/// Get the bounding box of the click target of the specified layer in the specified transform space
129108
pub fn bounding_box_with_transform(&self, layer: LayerNodeIdentifier, transform: DAffine2) -> Option<[DVec2; 2]> {
130-
self.click_targets
131-
.get(&layer)?
109+
self.click_targets(layer)?
132110
.iter()
133111
.filter_map(|click_target| click_target.subpath().bounding_box_with_transform(transform))
134112
.reduce(Quad::combine_bounds)

editor/src/messages/portfolio/document/utility_types/network_interface.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use bezier_rs::Subpath;
1111
use graph_craft::document::{value::TaggedValue, DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork};
1212
use graph_craft::{concrete, Type};
1313
use graphene_std::renderer::{ClickTarget, Quad};
14+
use graphene_std::transform::Footprint;
1415
use graphene_std::vector::{PointId, VectorData, VectorModificationType};
1516
use interpreted_executor::{dynamic_executor::ResolvedDocumentNodeTypes, node_registry::NODE_REGISTRY};
1617

@@ -2327,7 +2328,7 @@ impl NodeNetworkInterface {
23272328
log::error!("Could not get nested node_metadata in position_from_downstream_node");
23282329
return None;
23292330
};
2330-
match &node_metadata.persistent_metadata.node_type_metadata.clone() {
2331+
match &node_metadata.persistent_metadata.node_type_metadata {
23312332
NodeTypePersistentMetadata::Layer(layer_metadata) => {
23322333
match layer_metadata.position {
23332334
LayerPosition::Absolute(position) => Some(position),
@@ -2550,8 +2551,7 @@ impl NodeNetworkInterface {
25502551
}
25512552

25522553
pub fn set_document_to_viewport_transform(&mut self, transform: DAffine2) {
2553-
let document_metadata = self.document_metadata_mut();
2554-
document_metadata.document_to_viewport = transform;
2554+
self.document_metadata.document_to_viewport = transform;
25552555
}
25562556

25572557
pub fn is_eligible_to_be_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
@@ -2882,7 +2882,7 @@ impl NodeNetworkInterface {
28822882
}
28832883

28842884
for (parent, child) in children {
2885-
parent.push_child(self.document_metadata_mut(), child);
2885+
parent.push_child(&mut self.document_metadata, child);
28862886
}
28872887

28882888
while let Some((primary_root_node_id, parent_layer_node)) = awaiting_primary_flow.pop() {
@@ -2902,7 +2902,7 @@ impl NodeNetworkInterface {
29022902
}
29032903
}
29042904
for child in children {
2905-
parent_layer_node.push_child(self.document_metadata_mut(), child);
2905+
parent_layer_node.push_child(&mut self.document_metadata, child);
29062906
}
29072907
}
29082908
}
@@ -2914,8 +2914,19 @@ impl NodeNetworkInterface {
29142914
self.document_metadata.click_targets.retain(|layer, _| self.document_metadata.structure.contains_key(layer));
29152915
}
29162916

2917-
pub fn document_metadata_mut(&mut self) -> &mut DocumentMetadata {
2918-
&mut self.document_metadata
2917+
/// Update the cached transforms of the layers
2918+
pub fn update_transforms(&mut self, new_upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>) {
2919+
self.document_metadata.upstream_transforms = new_upstream_transforms;
2920+
}
2921+
2922+
/// Update the cached click targets of the layers
2923+
pub fn update_click_targets(&mut self, new_click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>) {
2924+
self.document_metadata.click_targets = new_click_targets;
2925+
}
2926+
2927+
/// Update the vector modify of the layers
2928+
pub fn update_vector_modify(&mut self, new_vector_modify: HashMap<NodeId, VectorData>) {
2929+
self.document_metadata.vector_modify = new_vector_modify;
29192930
}
29202931
}
29212932

@@ -3083,7 +3094,7 @@ impl NodeNetworkInterface {
30833094
}
30843095

30853096
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts
3086-
pub fn set_implementation(&mut self, node_id: &NodeId, network_path: &[NodeId], implementation: DocumentNodeImplementation) {
3097+
pub fn replace_implementation(&mut self, node_id: &NodeId, network_path: &[NodeId], implementation: DocumentNodeImplementation) {
30873098
let Some(network) = self.network_mut(network_path) else {
30883099
log::error!("Could not get nested network in set_implementation");
30893100
return;
@@ -3095,6 +3106,20 @@ impl NodeNetworkInterface {
30953106
node.implementation = implementation;
30963107
}
30973108

3109+
// TODO: Eventually remove this (probably starting late 2024)
3110+
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts
3111+
pub fn replace_implementation_metadata(&mut self, node_id: &NodeId, network_path: &[NodeId], metadata: DocumentNodePersistentMetadata) {
3112+
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
3113+
log::error!("Could not get network metdata in set implementation");
3114+
return;
3115+
};
3116+
let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get_mut(node_id) else {
3117+
log::error!("Could not get persistent node metadata for node {node_id} in set implementation");
3118+
return;
3119+
};
3120+
node_metadata.persistent_metadata.network_metadata = metadata.network_metadata;
3121+
}
3122+
30983123
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts
30993124
pub fn replace_inputs(&mut self, node_id: &NodeId, inputs: Vec<NodeInput>, network_path: &[NodeId]) -> Vec<NodeInput> {
31003125
let Some(network) = self.network_mut(network_path) else {

0 commit comments

Comments
 (0)