Skip to content

Commit 1ea9e5f

Browse files
committed
Show source-geometry outlines and aggregate all rows for layer click targets
1 parent 34496cc commit 1ea9e5f

6 files changed

Lines changed: 176 additions & 80 deletions

File tree

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ pub enum DocumentMessage {
215215
UpdateClickTargets {
216216
click_targets: HashMap<NodeId, Vec<Arc<ClickTarget>>>,
217217
},
218+
UpdateOutlines {
219+
outlines: HashMap<NodeId, Vec<Arc<ClickTarget>>>,
220+
},
218221
UpdateClipTargets {
219222
clip_targets: HashSet<NodeId>,
220223
},

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,19 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
12701270
.collect();
12711271
self.network_interface.update_click_targets(layer_click_targets);
12721272
}
1273+
DocumentMessage::UpdateOutlines { outlines } => {
1274+
let layer_outlines = outlines
1275+
.into_iter()
1276+
.filter(|(node_id, _)| self.network_interface.document_network().nodes.contains_key(node_id))
1277+
.filter_map(|(node_id, outlines)| {
1278+
self.network_interface.is_layer(&node_id, &[]).then(|| {
1279+
let layer = LayerNodeIdentifier::new(node_id, &self.network_interface);
1280+
(layer, outlines)
1281+
})
1282+
})
1283+
.collect();
1284+
self.network_interface.update_outlines(layer_outlines);
1285+
}
12731286
DocumentMessage::UpdateClipTargets { clip_targets } => {
12741287
self.network_interface.update_clip_targets(clip_targets);
12751288
}

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub struct DocumentMetadata {
2828
pub first_element_source_ids: HashMap<NodeId, Option<NodeId>>,
2929
pub structure: HashMap<LayerNodeIdentifier, NodeRelations>,
3030
pub click_targets: HashMap<LayerNodeIdentifier, Vec<Arc<ClickTarget>>>,
31+
/// Source-geometry outlines for hover/selection overlays, separate from `click_targets` so
32+
/// nodes with an `editor:click_target` override still outline the precise geometry.
33+
pub outlines: HashMap<LayerNodeIdentifier, Vec<Arc<ClickTarget>>>,
3134
pub clip_targets: HashSet<NodeId>,
3235
pub vector_modify: HashMap<NodeId, Vector>,
3336
/// Vector data keyed by layer ID, used as fallback when no Path node exists.
@@ -154,17 +157,23 @@ impl DocumentMetadata {
154157
// ===============================
155158

156159
impl DocumentMetadata {
160+
/// Outline targets if present, otherwise click targets. Used for bounding boxes and outline
161+
/// drawing so layers with an `editor:click_target` override report precise geometry bounds.
162+
fn visual_targets(&self, layer: LayerNodeIdentifier) -> Option<&[Arc<ClickTarget>]> {
163+
self.outlines.get(&layer).or_else(|| self.click_targets.get(&layer)).map(|v| v.as_slice())
164+
}
165+
157166
/// Get the bounding box of the click target of the specified layer in the specified transform space
158167
pub fn bounding_box_with_transform(&self, layer: LayerNodeIdentifier, transform: DAffine2) -> Option<[DVec2; 2]> {
159-
self.click_targets(layer)?
168+
self.visual_targets(layer)?
160169
.iter()
161170
.filter_map(|click_target| click_target.bounding_box_with_transform(transform))
162171
.reduce(Quad::combine_bounds)
163172
}
164173

165174
/// Get the loose bounding box of the click target of the specified layer in the specified transform space
166175
pub fn loose_bounding_box_with_transform(&self, layer: LayerNodeIdentifier, transform: DAffine2) -> Option<[DVec2; 2]> {
167-
self.click_targets(layer)?
176+
self.visual_targets(layer)?
168177
.iter()
169178
.filter_map(|click_target| match click_target.target_type() {
170179
ClickTargetType::Subpath(subpath) => subpath.loose_bounding_box_with_transform(transform),
@@ -210,18 +219,14 @@ impl DocumentMetadata {
210219
}
211220

212221
pub fn layer_outline(&self, layer: LayerNodeIdentifier) -> impl Iterator<Item = &subpath::Subpath<PointId>> {
213-
static EMPTY: Vec<Arc<ClickTarget>> = Vec::new();
214-
let click_targets = self.click_targets.get(&layer).unwrap_or(&EMPTY);
215-
click_targets.iter().filter_map(|target| match target.target_type() {
222+
self.visual_targets(layer).unwrap_or(&[]).iter().filter_map(|target| match target.target_type() {
216223
ClickTargetType::Subpath(subpath) => Some(subpath),
217224
_ => None,
218225
})
219226
}
220227

221228
pub fn layer_with_free_points_outline(&self, layer: LayerNodeIdentifier) -> impl Iterator<Item = &ClickTargetType> {
222-
static EMPTY: Vec<Arc<ClickTarget>> = Vec::new();
223-
let click_targets = self.click_targets.get(&layer).unwrap_or(&EMPTY);
224-
click_targets.iter().map(|target| target.target_type())
229+
self.visual_targets(layer).unwrap_or(&[]).iter().map(|target| target.target_type())
225230
}
226231

227232
pub fn is_clip(&self, node: NodeId) -> bool {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3276,6 +3276,7 @@ impl NodeNetworkInterface {
32763276
self.document_metadata.local_transforms.retain(|node, _| nodes.contains(node));
32773277
self.document_metadata.vector_modify.retain(|node, _| nodes.contains(node));
32783278
self.document_metadata.click_targets.retain(|layer, _| self.document_metadata.structure.contains_key(layer));
3279+
self.document_metadata.outlines.retain(|layer, _| self.document_metadata.structure.contains_key(layer));
32793280
}
32803281

32813282
/// Update the cached transforms of the layers
@@ -3294,6 +3295,11 @@ impl NodeNetworkInterface {
32943295
self.document_metadata.click_targets = new_click_targets;
32953296
}
32963297

3298+
/// Update the cached source-geometry outline targets of the layers
3299+
pub fn update_outlines(&mut self, new_outlines: HashMap<LayerNodeIdentifier, Vec<Arc<ClickTarget>>>) {
3300+
self.document_metadata.outlines = new_outlines;
3301+
}
3302+
32973303
/// Update the cached clip targets of the layers
32983304
pub fn update_clip_targets(&mut self, new_clip_targets: HashSet<NodeId>) {
32993305
self.document_metadata.clip_targets = new_clip_targets;

editor/src/node_graph_executor.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ impl NodeGraphExecutor {
309309
Err(e) => {
310310
// Clear the click targets while the graph is in an un-renderable state
311311
document.network_interface.update_click_targets(HashMap::new());
312+
document.network_interface.update_outlines(HashMap::new());
312313
document.network_interface.update_vector_modify(HashMap::new());
313314
return Err(format!("Node graph evaluation failed:\n{e}"));
314315
}
@@ -355,6 +356,7 @@ impl NodeGraphExecutor {
355356
// Clear the click targets while the graph is in an un-renderable state
356357

357358
document.network_interface.update_click_targets(HashMap::new());
359+
document.network_interface.update_outlines(HashMap::new());
358360
document.network_interface.update_vector_modify(HashMap::new());
359361

360362
log::trace!("{e}");
@@ -415,6 +417,7 @@ impl NodeGraphExecutor {
415417
local_transforms,
416418
first_element_source_id,
417419
click_targets,
420+
outlines,
418421
clip_targets,
419422
vector_data,
420423
backgrounds: _,
@@ -427,6 +430,7 @@ impl NodeGraphExecutor {
427430
first_element_source_id,
428431
});
429432
responses.add(DocumentMessage::UpdateClickTargets { click_targets });
433+
responses.add(DocumentMessage::UpdateOutlines { outlines });
430434
responses.add(DocumentMessage::UpdateClipTargets { clip_targets });
431435
responses.add(DocumentMessage::UpdateVectorData { vector_data });
432436
responses.add(DocumentMessage::RenderScrollbars);

0 commit comments

Comments
 (0)