Skip to content

Commit 88c4713

Browse files
0HyperCubeKeavon
andauthored
Thumbnails for the layer node (#1210)
* Thumbnails for the layer node * Raster node graph frames * Downscale to a random resolution * Cleanup and bug fixes * Generate paths before duplicating outputs * Fix stable id test * Code review changes * Code review pass with minor changes --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent d76bd36 commit 88c4713

File tree

24 files changed

+609
-131
lines changed

24 files changed

+609
-131
lines changed

document-legacy/src/layers/layer_layer.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ impl LayerData for LayerLayer {
5454
match &self.cached_output_data {
5555
CachedOutputData::VectorPath(vector_data) => {
5656
let layer_bounds = vector_data.bounding_box().unwrap_or_default();
57-
let transfomed_bounds = vector_data.bounding_box_with_transform(transform).unwrap_or_default();
57+
let transformed_bounds = vector_data.bounding_box_with_transform(transform).unwrap_or_default();
5858

5959
let _ = write!(svg, "<path d=\"");
6060
for subpath in &vector_data.subpaths {
6161
let _ = subpath.subpath_to_svg(svg, transform);
6262
}
6363
svg.push('"');
6464

65-
svg.push_str(&vector_data.style.render(render_data.view_mode, svg_defs, transform, layer_bounds, transfomed_bounds));
65+
svg.push_str(&vector_data.style.render(render_data.view_mode, svg_defs, transform, layer_bounds, transformed_bounds));
6666
let _ = write!(svg, "/>");
6767
}
6868
CachedOutputData::BlobURL(blob_url) => {

editor/src/messages/frontend/utility_types.rs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ pub struct FrontendImageData {
1818
#[serde(skip)]
1919
pub image_data: std::sync::Arc<Vec<u8>>,
2020
pub transform: Option<[f64; 6]>,
21+
#[serde(rename = "nodeId")]
22+
pub node_id: Option<graph_craft::document::NodeId>,
2123
}
2224

2325
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize, specta::Type)]

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
187187
}
188188
#[remain::unsorted]
189189
NodeGraph(message) => {
190-
let selected_layers = &mut self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice()));
191-
self.node_graph_handler.process_message(message, responses, (&mut self.document_legacy, selected_layers));
190+
self.node_graph_handler.process_message(message, responses, (&mut self.document_legacy, executor));
192191
}
193192
#[remain::unsorted]
194193
GraphOperation(message) => GraphOperationMessageHandler.process_message(message, responses, (&mut self.document_legacy, &mut self.node_graph_handler)),

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

+53-36
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::messages::input_mapper::utility_types::macros::action_keys;
33
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
44
use crate::messages::layout::utility_types::widgets::button_widgets::TextButton;
55
use crate::messages::prelude::*;
6+
use crate::node_graph_executor::NodeGraphExecutor;
67

78
use document_legacy::document::Document;
89
use document_legacy::layers::layer_layer::LayerLayer;
@@ -84,6 +85,8 @@ pub struct FrontendNode {
8485
pub position: (i32, i32),
8586
pub disabled: bool,
8687
pub previewed: bool,
88+
#[serde(rename = "thumbnailSvg")]
89+
pub thumbnail_svg: Option<String>,
8790
}
8891

8992
// (link_start, link_end, link_end_input_index)
@@ -254,9 +257,11 @@ impl NodeGraphMessageHandler {
254257
}
255258
}
256259

257-
fn send_graph(network: &NodeNetwork, responses: &mut VecDeque<Message>) {
260+
fn send_graph(network: &NodeNetwork, executor: &NodeGraphExecutor, layer_path: &Option<Vec<LayerId>>, responses: &mut VecDeque<Message>) {
258261
responses.add(PropertiesPanelMessage::ResendActiveProperties);
259262

263+
let layer_id = layer_path.as_ref().and_then(|path| path.last().copied());
264+
260265
// List of links in format (link_start, link_end, link_end_input_index)
261266
let links = network
262267
.nodes
@@ -288,37 +293,49 @@ impl NodeGraphMessageHandler {
288293
warn!("Node '{}' does not exist in library", node.name);
289294
continue;
290295
};
296+
297+
let primary_input = node
298+
.inputs
299+
.first()
300+
.filter(|input| input.is_exposed())
301+
.and_then(|_| node_type.inputs.get(0))
302+
.map(|input_type| input_type.data_type);
303+
let exposed_inputs = node
304+
.inputs
305+
.iter()
306+
.zip(node_type.inputs.iter())
307+
.skip(1)
308+
.filter(|(input, _)| input.is_exposed())
309+
.map(|(_, input_type)| NodeGraphInput {
310+
data_type: input_type.data_type,
311+
name: input_type.name.to_string(),
312+
})
313+
.collect();
314+
315+
let outputs = node_type
316+
.outputs
317+
.iter()
318+
.map(|output_type| NodeGraphOutput {
319+
data_type: output_type.data_type,
320+
name: output_type.name.to_string(),
321+
})
322+
.collect();
323+
324+
let thumbnail_svg = layer_id
325+
.and_then(|layer_id| executor.thumbnails.get(&layer_id))
326+
.and_then(|layer| layer.get(id))
327+
.map(|svg| svg.to_string());
328+
291329
nodes.push(FrontendNode {
292330
id: *id,
293331
display_name: node.name.clone(),
294-
primary_input: node
295-
.inputs
296-
.first()
297-
.filter(|input| input.is_exposed())
298-
.and_then(|_| node_type.inputs.get(0))
299-
.map(|input_type| input_type.data_type),
300-
exposed_inputs: node
301-
.inputs
302-
.iter()
303-
.zip(node_type.inputs.iter())
304-
.skip(1)
305-
.filter(|(input, _)| input.is_exposed())
306-
.map(|(_, input_type)| NodeGraphInput {
307-
data_type: input_type.data_type,
308-
name: input_type.name.to_string(),
309-
})
310-
.collect(),
311-
outputs: node_type
312-
.outputs
313-
.iter()
314-
.map(|output_type| NodeGraphOutput {
315-
data_type: output_type.data_type,
316-
name: output_type.name.to_string(),
317-
})
318-
.collect(),
332+
primary_input,
333+
exposed_inputs,
334+
outputs,
319335
position: node.metadata.position.into(),
320336
previewed: network.outputs_contain(*id),
321337
disabled: network.disabled.contains(id),
338+
thumbnail_svg,
322339
})
323340
}
324341
responses.add(FrontendMessage::UpdateNodeGraph { nodes, links });
@@ -405,9 +422,9 @@ impl NodeGraphMessageHandler {
405422
}
406423
}
407424

408-
impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &[LayerId]>)> for NodeGraphMessageHandler {
425+
impl MessageHandler<NodeGraphMessage, (&mut Document, &NodeGraphExecutor)> for NodeGraphMessageHandler {
409426
#[remain::check]
410-
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, (document, _selected): (&mut Document, &mut dyn Iterator<Item = &[LayerId]>)) {
427+
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, (document, executor): (&mut Document, &NodeGraphExecutor)) {
411428
#[remain::sorted]
412429
match message {
413430
NodeGraphMessage::CloseNodeGraph => {
@@ -536,7 +553,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &
536553
}
537554
}
538555
if let Some(network) = self.get_active_network(document) {
539-
Self::send_graph(network, responses);
556+
Self::send_graph(network, executor, &self.layer_path, responses);
540557
}
541558
self.collect_nested_addresses(document, responses);
542559
self.update_selected(document, responses);
@@ -561,7 +578,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &
561578
responses.add(NodeGraphMessage::InsertNode { node_id, document_node });
562579
}
563580

564-
Self::send_graph(network, responses);
581+
Self::send_graph(network, executor, &self.layer_path, responses);
565582
self.update_selected(document, responses);
566583
}
567584
}
@@ -571,7 +588,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &
571588
self.nested_path.pop();
572589
}
573590
if let Some(network) = self.get_active_network(document) {
574-
Self::send_graph(network, responses);
591+
Self::send_graph(network, executor, &self.layer_path, responses);
575592
}
576593
self.collect_nested_addresses(document, responses);
577594
self.update_selected(document, responses);
@@ -622,15 +639,15 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &
622639
node.metadata.position += IVec2::new(displacement_x, displacement_y)
623640
}
624641
}
625-
Self::send_graph(network, responses);
642+
Self::send_graph(network, executor, &self.layer_path, responses);
626643
}
627644
NodeGraphMessage::OpenNodeGraph { layer_path } => {
628645
self.layer_path = Some(layer_path);
629646

630647
if let Some(network) = self.get_active_network(document) {
631648
self.selected_nodes.clear();
632649

633-
Self::send_graph(network, responses);
650+
Self::send_graph(network, executor, &self.layer_path, responses);
634651

635652
let node_types = document_node_types::collect_node_types();
636653
responses.add(FrontendMessage::UpdateNodeTypes { node_types });
@@ -689,7 +706,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &
689706
}
690707
NodeGraphMessage::SendGraph { should_rerender } => {
691708
if let Some(network) = self.get_active_network(document) {
692-
Self::send_graph(network, responses);
709+
Self::send_graph(network, executor, &self.layer_path, responses);
693710
if should_rerender {
694711
if let Some(layer_path) = self.layer_path.clone() {
695712
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
@@ -816,7 +833,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &
816833
.disabled
817834
.extend(self.selected_nodes.iter().filter(|&id| !network.inputs.contains(id) && !original_outputs.contains(id)));
818835
}
819-
Self::send_graph(network, responses);
836+
Self::send_graph(network, executor, &self.layer_path, responses);
820837

821838
// Only generate node graph if one of the selected nodes is connected to the output
822839
if self.selected_nodes.iter().any(|&node_id| network.connected_to_output(node_id, true)) {
@@ -842,7 +859,7 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &
842859
} else {
843860
return;
844861
}
845-
Self::send_graph(network, responses);
862+
Self::send_graph(network, executor, &self.layer_path, responses);
846863
}
847864
self.update_selection_action_buttons(document, responses);
848865
if let Some(layer_path) = self.layer_path.clone() {

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

+36-4
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,40 @@ fn static_nodes() -> Vec<DocumentNodeType> {
121121
DocumentNodeType {
122122
name: "Layer",
123123
category: "General",
124-
identifier: NodeImplementation::proto("graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>"),
124+
identifier: NodeImplementation::DocumentNode(NodeNetwork {
125+
inputs: vec![0; 8],
126+
outputs: vec![NodeOutput::new(1, 0)],
127+
nodes: [
128+
(
129+
0,
130+
DocumentNode {
131+
inputs: vec![
132+
NodeInput::Network(concrete!(graphene_core::vector::VectorData)),
133+
NodeInput::Network(concrete!(String)),
134+
NodeInput::Network(concrete!(BlendMode)),
135+
NodeInput::Network(concrete!(f32)),
136+
NodeInput::Network(concrete!(bool)),
137+
NodeInput::Network(concrete!(bool)),
138+
NodeInput::Network(concrete!(bool)),
139+
NodeInput::Network(concrete!(graphene_core::GraphicGroup)),
140+
],
141+
implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>"),
142+
..Default::default()
143+
},
144+
),
145+
// The monitor node is used to display a thumbnail in the UI.
146+
(
147+
1,
148+
DocumentNode {
149+
inputs: vec![NodeInput::node(0, 0)],
150+
implementation: DocumentNodeImplementation::proto("graphene_std::memo::MonitorNode<_>"),
151+
..Default::default()
152+
},
153+
),
154+
]
155+
.into(),
156+
..Default::default()
157+
}),
125158
inputs: vec![
126159
DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
127160
DocumentInputType::value("Name", TaggedValue::String(String::new()), false),
@@ -528,7 +561,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
528561
identifier: NodeImplementation::DocumentNode(NodeNetwork {
529562
inputs: vec![0],
530563
outputs: vec![NodeOutput::new(1, 0)],
531-
nodes: vec![
564+
nodes: [
532565
(
533566
0,
534567
DocumentNode {
@@ -548,8 +581,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
548581
},
549582
),
550583
]
551-
.into_iter()
552-
.collect(),
584+
.into(),
553585
..Default::default()
554586
}),
555587
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -727,12 +727,12 @@ pub fn adjust_selective_color_properties(document_node: &DocumentNode, node_id:
727727
} = &document_node.inputs[colors_index]
728728
{
729729
use SelectiveColorChoice::*;
730-
let entries = [vec![Reds, Yellows, Greens, Cyans, Blues, Magentas], vec![Whites, Neutrals, Blacks]]
730+
let entries = [[Reds, Yellows, Greens, Cyans, Blues, Magentas].as_slice(), [Whites, Neutrals, Blacks].as_slice()]
731731
.into_iter()
732732
.map(|section| {
733733
section
734734
.into_iter()
735-
.map(|choice| DropdownEntryData::new(choice.to_string()).on_update(update_value(move |_| TaggedValue::SelectiveColorChoice(choice), node_id, colors_index)))
735+
.map(|choice| DropdownEntryData::new(choice.to_string()).on_update(update_value(move |_| TaggedValue::SelectiveColorChoice(*choice), node_id, colors_index)))
736736
.collect()
737737
})
738738
.collect();

editor/src/messages/portfolio/portfolio_message.rs

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ pub enum PortfolioMessage {
128128
SetImageBlobUrl {
129129
document_id: u64,
130130
layer_path: Vec<LayerId>,
131+
node_id: Option<NodeId>,
131132
blob_url: String,
132133
resolution: (f64, f64),
133134
},

editor/src/messages/portfolio/portfolio_message_handler.rs

+6
Original file line numberDiff line numberDiff line change
@@ -503,9 +503,15 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
503503
PortfolioMessage::SetImageBlobUrl {
504504
document_id,
505505
layer_path,
506+
node_id,
506507
blob_url,
507508
resolution,
508509
} => {
510+
if let (Some(layer_id), Some(node_id)) = (layer_path.last().copied(), node_id) {
511+
self.executor.insert_thumbnail_blob_url(blob_url, layer_id, node_id, responses);
512+
return;
513+
}
514+
509515
let message = DocumentMessage::SetImageBlobUrl {
510516
layer_path,
511517
blob_url,

0 commit comments

Comments
 (0)