Skip to content

Commit

Permalink
Replace the image layer type with an Image node (GraphiteEditor#948)
Browse files Browse the repository at this point in the history
* Use builder pattern for widgets

* Arguments to new function

* Add node graph when dragging in image

* Fix duplicate import

* Skip processing under node graph frame if unused

* Reduce node graph rerenders

* DUPLICATE ALL frontend changes into other frontend

* DUPLICATE more changes to another frontend

* Code review

* Allow importing SVG files as bitmaps

Co-authored-by: Keavon Chambers <[email protected]>
  • Loading branch information
0HyperCube and Keavon committed Jan 27, 2023
1 parent 66e8325 commit 64e6269
Show file tree
Hide file tree
Showing 32 changed files with 444 additions and 261 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion document-legacy/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ impl Document {
match &mut layer.data {
LayerDataType::Shape(s) => s.style = style,
LayerDataType::Text(text) => text.path_style = style,
_ => return Err(DocumentError::NotAShape),
_ => return Err(DocumentError::NotShape),
}
self.mark_as_dirty(&path)?;
Some([vec![DocumentChanged, LayerChanged { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
Expand Down
5 changes: 2 additions & 3 deletions document-legacy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ pub enum DocumentError {
IndexOutOfBounds,
NotAFolder,
NonReorderableSelection,
NotAShape,
NotShape,
NotText,
NotAnImage,
NotAnImaginate,
NotNodeGraph,
InvalidFile(String),
BooleanOperationError(BooleanOperationError),
}
Expand Down
24 changes: 12 additions & 12 deletions document-legacy/src/layers/layer_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,37 +488,37 @@ impl Layer {
}
}

/// Get a mutable reference to the Image element wrapped by the layer.
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Image`.
pub fn as_image_mut(&mut self) -> Result<&mut ImageLayer, DocumentError> {
/// Get a mutable reference to the NodeNetwork
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::NodeGraphFrame`.
pub fn as_node_graph_mut(&mut self) -> Result<&mut graph_craft::document::NodeNetwork, DocumentError> {
match &mut self.data {
LayerDataType::Image(img) => Ok(img),
_ => Err(DocumentError::NotAnImage),
LayerDataType::NodeGraphFrame(frame) => Ok(&mut frame.network),
_ => Err(DocumentError::NotNodeGraph),
}
}

/// Get a reference to the Image element wrapped by the layer.
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Image`.
pub fn as_image(&self) -> Result<&ImageLayer, DocumentError> {
/// Get a reference to the NodeNetwork
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::NodeGraphFrame`.
pub fn as_node_graph(&self) -> Result<&graph_craft::document::NodeNetwork, DocumentError> {
match &self.data {
LayerDataType::Image(img) => Ok(img),
_ => Err(DocumentError::NotAnImage),
LayerDataType::NodeGraphFrame(frame) => Ok(&frame.network),
_ => Err(DocumentError::NotNodeGraph),
}
}

pub fn style(&self) -> Result<&PathStyle, DocumentError> {
match &self.data {
LayerDataType::Shape(s) => Ok(&s.style),
LayerDataType::Text(t) => Ok(&t.path_style),
_ => Err(DocumentError::NotAShape),
_ => Err(DocumentError::NotShape),
}
}

pub fn style_mut(&mut self) -> Result<&mut PathStyle, DocumentError> {
match &mut self.data {
LayerDataType::Shape(s) => Ok(&mut s.style),
LayerDataType::Text(t) => Ok(&mut t.path_style),
_ => Err(DocumentError::NotAShape),
_ => Err(DocumentError::NotShape),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions editor/src/messages/portfolio/document/document_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use document_legacy::layers::style::ViewMode;
use document_legacy::LayerId;
use document_legacy::Operation as DocumentOperation;
use graph_craft::document::NodeId;
use graphene_core::raster::Image;
use serde::{Deserialize, Serialize};

#[remain::sorted]
Expand Down Expand Up @@ -115,8 +116,7 @@ pub enum DocumentMessage {
delta_y: f64,
},
PasteImage {
mime: String,
image_data: Vec<u8>,
image: Image,
mouse: Option<(f64, f64)>,
},
Redo,
Expand Down
77 changes: 59 additions & 18 deletions editor/src/messages/portfolio/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,25 +546,36 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
}
responses.push_back(BroadcastEvent::DocumentIsDirty.into());
}
PasteImage { mime, image_data, mouse } => {
PasteImage { image, mouse } => {
let image_size = DVec2::new(image.width as f64, image.height as f64);

responses.push_back(DocumentMessage::StartTransaction.into());

let path = vec![generate_uuid()];
let image_node_id = 2;
let mut network = graph_craft::document::NodeNetwork::new_network(32, image_node_id);

let Some(image_node_type) = crate::messages::portfolio::document::node_graph::resolve_document_node_type("Image") else {
warn!("Image node should be in registry");
return;
};

network.nodes.insert(
image_node_id,
graph_craft::document::DocumentNode {
name: image_node_type.name.to_string(),
inputs: vec![graph_craft::document::NodeInput::value(graph_craft::document::value::TaggedValue::Image(image), false)],
implementation: image_node_type.generate_implementation(),
metadata: graph_craft::document::DocumentNodeMetadata { position: (20, 4).into() },
},
);

responses.push_back(
DocumentOperation::AddImage {
DocumentOperation::AddNodeGraphFrame {
path: path.clone(),
transform: DAffine2::ZERO.to_cols_array(),
insert_index: -1,
image_data: image_data.clone(),
mime: mime.clone(),
}
.into(),
);
let image_data = std::sync::Arc::new(image_data);
responses.push_back(
FrontendMessage::UpdateImageData {
document_id,
image_data: vec![FrontendImageData { path: path.clone(), image_data, mime }],
transform: DAffine2::ZERO.to_cols_array(),
network,
}
.into(),
);
Expand All @@ -575,9 +586,21 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
.into(),
);

let mouse = mouse.map_or(ipp.viewport_bounds.center(), |pos| pos.into());
let transform = DAffine2::from_translation(mouse - ipp.viewport_bounds.top_left).to_cols_array();
responses.push_back(DocumentOperation::SetLayerTransformInViewport { path, transform }.into());
// Transform of parent folder
let to_parent_folder = self.document_legacy.generate_transform_across_scope(&path[..path.len() - 1], None).unwrap_or_default();

// Align the layer with the mouse or center of viewport
let viewport_location = mouse.map_or(ipp.viewport_bounds.center(), |pos| pos.into());
let center_in_viewport = DAffine2::from_translation(viewport_location - ipp.viewport_bounds.top_left);
let center_in_viewport_layerspace = to_parent_folder.inverse() * center_in_viewport;

// Make layer the size of the image
let fit_image_size = DAffine2::from_scale_angle_translation(image_size, 0., image_size / -2.);

let transform = (center_in_viewport_layerspace * fit_image_size).to_cols_array();
responses.push_back(DocumentOperation::SetLayerTransform { path, transform }.into());

responses.push_back(DocumentMessage::NodeGraphFrameGenerate.into());
}
Redo => {
responses.push_back(SelectToolMessage::Abort.into());
Expand Down Expand Up @@ -949,6 +972,24 @@ impl DocumentMessageHandler {

// Prepare the node graph input image

let Some(node_network) = self.document_legacy.layer(&layer_path).ok().and_then(|layer|layer.as_node_graph().ok()) else {
return None;
};

// Skip processing under node graph frame input if not connected
if !node_network.connected_to_output(node_network.inputs[0]) {
return Some(
PortfolioMessage::ProcessNodeGraphFrame {
document_id,
layer_path,
image_data: Default::default(),
size: (0, 0),
imaginate_node,
}
.into(),
);
}

// Calculate the size of the region to be exported

let old_transforms = self.remove_document_transform();
Expand Down Expand Up @@ -1366,7 +1407,7 @@ impl DocumentMessageHandler {
responses.push_back(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }.into())
}

responses.push_back(NodeGraphMessage::SendGraph.into());
responses.push_back(NodeGraphMessage::SendGraph { should_rerender: true }.into());

Ok(())
}
Expand Down Expand Up @@ -1400,7 +1441,7 @@ impl DocumentMessageHandler {
responses.push_back(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }.into())
}

responses.push_back(NodeGraphMessage::SendGraph.into());
responses.push_back(NodeGraphMessage::SendGraph { should_rerender: true }.into());

Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ pub enum NodeGraphMessage {
SelectNodes {
nodes: Vec<NodeId>,
},
SendGraph,
SendGraph {
should_rerender: bool,
},
SetDrawing {
new_drawing: bool,
},
Expand Down
Loading

0 comments on commit 64e6269

Please sign in to comment.