Skip to content

Add viewing/editing layer names, add Blend Mode node, and clean up Layer node #1489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,8 @@
// VS Code config
"html.format.wrapLineLength": 200,
"files.eol": "\n",
"files.insertFinalNewline": true
"files.insertFinalNewline": true,
"files.associations": {
"*.graphite": "json"
}
}
54 changes: 0 additions & 54 deletions demo-artwork/_upgrade-to-document-nodes.py_archive
Original file line number Diff line number Diff line change
Expand Up @@ -267,60 +267,6 @@ def update_layer(layer, indent, layer_node_id, next_id, opacity):
"lambda": False
}
},
{
"Network": {
"Concrete": {
"name": "alloc::string::String",
"size": 12,
"align": 4
}
}
},
{
"Network": {
"Concrete": {
"name": "graphene_core::raster::adjustments::BlendMode",
"size": 4,
"align": 4
}
}
},
{
"Network": {
"Concrete": {
"name": "f32",
"size": 4,
"align": 4
}
}
},
{
"Network": {
"Concrete": {
"name": "bool",
"size": 1,
"align": 1
}
}
},
{
"Network": {
"Concrete": {
"name": "bool",
"size": 1,
"align": 1
}
}
},
{
"Network": {
"Concrete": {
"name": "bool",
"size": 1,
"align": 1
}
}
},
{
"Network": {
"Fn": [
Expand Down
2 changes: 1 addition & 1 deletion demo-artwork/just-a-potted-cactus-v2.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/valley-of-spires-v2.graphite

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions document-legacy/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,13 +1031,6 @@ impl Document {
layer.visible = visible;
Some([vec![DocumentChanged], update_thumbnails_upstream(&path)].concat())
}
Operation::SetLayerName { path, name } => {
self.mark_as_dirty(&path)?;
let layer = self.layer_mut(&path)?;
layer.name = if name.as_str() == "" { None } else { Some(name) };

Some(vec![LayerChanged { path }])
}
Operation::SetLayerBlendMode { path, blend_mode } => {
self.mark_as_dirty(&path)?;
self.layer_mut(&path)?.blend_mode = blend_mode;
Expand Down
10 changes: 6 additions & 4 deletions document-legacy/src/document_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,12 @@ impl DocumentMetadata {
}

fn first_child_layer<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
graph.primary_flow_from_node(Some(node.inputs[0].as_node()?)).find(|(node, _)| node.name == "Layer")
graph.primary_flow_from_node(Some(node.inputs[0].as_node()?)).find(|(node, _)| node.is_layer())
}

fn sibling_below<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
node.inputs[7].as_node().and_then(|id| graph.nodes.get(&id).filter(|node| node.name == "Layer").map(|node| (node, id)))
let construct_layer_node = &node.inputs[1];
construct_layer_node.as_node().and_then(|id| graph.nodes.get(&id).filter(|node| node.is_layer()).map(|node| (node, id)))
}

// transforms
Expand Down Expand Up @@ -265,7 +267,7 @@ pub fn is_folder(layer: LayerNodeIdentifier, network: &NodeNetwork) -> bool {
|| network
.primary_flow_from_node(Some(layer.to_node()))
.skip(1)
.any(|(node, _)| node.name == "Artboard" || node.name == "Layer")
.any(|(node, _)| node.name == "Artboard" || node.is_layer())
}

// click targets
Expand Down Expand Up @@ -640,7 +642,7 @@ pub struct NodeRelations {
}

fn is_layer_node(node: NodeId, network: &NodeNetwork) -> bool {
node == LayerNodeIdentifier::ROOT.to_node() || network.nodes.get(&node).is_some_and(|node| node.name == "Layer")
node == LayerNodeIdentifier::ROOT.to_node() || network.nodes.get(&node).is_some_and(|node| node.is_layer())
}

#[test]
Expand Down
4 changes: 0 additions & 4 deletions document-legacy/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,6 @@ pub enum Operation {
path: Vec<LayerId>,
visible: bool,
},
SetLayerName {
path: Vec<LayerId>,
name: String,
},
SetLayerPreserveAspect {
layer_path: Vec<LayerId>,
preserve_aspect: bool,
Expand Down
4 changes: 0 additions & 4 deletions editor/src/messages/portfolio/document/document_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,6 @@ pub enum DocumentMessage {
layer_path: Vec<LayerId>,
set_expanded: bool,
},
SetLayerName {
layer_path: Vec<LayerId>,
name: String,
},
SetOpacityForSelectedLayers {
opacity: f64,
},
Expand Down
107 changes: 46 additions & 61 deletions editor/src/messages/portfolio/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl Default for DocumentMessageHandler {
document_legacy: DocumentLegacy::default(),
saved_document_identifier: 0,
auto_saved_document_identifier: 0,
name: String::from("Untitled Document"),
name: DEFAULT_DOCUMENT_NAME.to_string(),
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
commit_hash: crate::application::GRAPHITE_GIT_COMMIT_HASH.to_string(),

Expand Down Expand Up @@ -211,7 +211,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
// Messages
AbortTransaction => {
if !self.undo_in_progress {
self.undo(responses).unwrap_or_else(|e| warn!("{e}"));
self.undo(responses);
responses.extend([RenderDocument.into(), DocumentStructureChanged.into()]);
}
}
Expand Down Expand Up @@ -329,8 +329,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add_front(DocumentMessage::DirtyRenderDocument);
}
}
DocumentHistoryBackward => self.undo(responses).unwrap_or_else(|e| warn!("{e}")),
DocumentHistoryForward => self.redo(responses).unwrap_or_else(|e| warn!("{e}")),
DocumentHistoryBackward => self.undo(responses),
DocumentHistoryForward => self.redo(responses),
DocumentStructureChanged => {
let data_buffer: RawBuffer = self.serialize_root().as_slice().into();
responses.add(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer })
Expand Down Expand Up @@ -577,7 +577,11 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand

responses.add(DocumentMessage::StartTransaction);

let image_frame = ImageFrame { image, transform: DAffine2::IDENTITY };
let image_frame = ImageFrame {
image,
transform: DAffine2::IDENTITY,
blend_mode: BlendMode::Normal,
};

use crate::messages::tool::common_functionality::graph_modification_utils;
let layer = graph_modification_utils::new_image_layer(image_frame, generate_uuid(), self.new_layer_parent(), responses);
Expand Down Expand Up @@ -649,7 +653,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
});
}
RollbackTransaction => {
self.rollback(responses).unwrap_or_else(|e| warn!("{e}"));
self.rollback(responses);
responses.extend([RenderDocument.into(), DocumentStructureChanged.into()]);
}
SaveDocument => {
Expand Down Expand Up @@ -771,15 +775,6 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add(DocumentStructureChanged);
responses.add(LayerChanged { affected_layer_path: layer_path })
}
SetLayerName { layer_path, name } => {
if let Some(layer) = self.layer_panel_entry_from_path(&layer_path, &render_data) {
// Only save the history state if the name actually changed to something different
if layer.name != name {
self.backup(responses);
responses.add(DocumentOperation::SetLayerName { path: layer_path, name });
}
}
}
SetOpacityForSelectedLayers { opacity } => {
self.backup(responses);
let opacity = opacity.clamp(0., 1.);
Expand Down Expand Up @@ -1238,9 +1233,9 @@ impl DocumentMessageHandler {
});
}

pub fn rollback(&mut self, responses: &mut VecDeque<Message>) -> Result<(), EditorError> {
pub fn rollback(&mut self, responses: &mut VecDeque<Message>) {
self.backup(responses);
self.undo(responses)
self.undo(responses);
// TODO: Consider if we should check if the document is saved
}

Expand All @@ -1257,72 +1252,62 @@ impl DocumentMessageHandler {
DocumentSave { document, layer_metadata }
}

pub fn undo(&mut self, responses: &mut VecDeque<Message>) -> Result<(), EditorError> {
pub fn undo(&mut self, responses: &mut VecDeque<Message>) {
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
responses.add(PortfolioMessage::UpdateOpenDocumentsList);

let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();

match self.document_undo_history.pop_back() {
Some(DocumentSave { document, layer_metadata }) => {
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
// Also appropriately update the Properties panel if an undo action results in a layer being deleted
let prev_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();

if prev_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
if let Some(DocumentSave { document, layer_metadata }) = self.document_undo_history.pop_back() {
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
// Also appropriately update the Properties panel if an undo action results in a layer being deleted
let prev_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();

let document_save = self.replace_document(DocumentSave { document, layer_metadata });

self.document_redo_history.push_back(document_save);
if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_redo_history.pop_front();
}
if prev_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}

for layer in self.layer_metadata.keys() {
responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() })
}
let document_save = self.replace_document(DocumentSave { document, layer_metadata });

responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
self.document_redo_history.push_back(document_save);
if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_redo_history.pop_front();
}

Ok(())
for layer in self.layer_metadata.keys() {
responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() })
}
None => Err(EditorError::NoTransactionInProgress),

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

pub fn redo(&mut self, responses: &mut VecDeque<Message>) -> Result<(), EditorError> {
pub fn redo(&mut self, responses: &mut VecDeque<Message>) {
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
responses.add(PortfolioMessage::UpdateOpenDocumentsList);

let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();

match self.document_redo_history.pop_back() {
Some(DocumentSave { document, layer_metadata }) => {
// Update currently displayed layer on property panel if selection changes after redo action
// Also appropriately update property panel if redo action results in a layer being added
let next_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();

if next_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}

let document_save = self.replace_document(DocumentSave { document, layer_metadata });
self.document_undo_history.push_back(document_save);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
if let Some(DocumentSave { document, layer_metadata }) = self.document_redo_history.pop_back() {
// Update currently displayed layer on property panel if selection changes after redo action
// Also appropriately update property panel if redo action results in a layer being added
let next_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();

for layer in self.layer_metadata.keys() {
responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() })
}
if next_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}

responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
let document_save = self.replace_document(DocumentSave { document, layer_metadata });
self.document_undo_history.push_back(document_save);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}

Ok(())
for layer in self.layer_metadata.keys() {
responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() })
}
None => Err(EditorError::NoTransactionInProgress),

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl<'a> ModifyInputsContext<'a> {
error!("Tried to modify root layer");
return None;
};
while document.network.nodes.get(&id)?.name != "Layer" {
while !document.network.nodes.get(&id)?.is_layer() {
id = document.outwards_links.get(&id)?.first().copied()?;
}
document.layer_node = Some(id);
Expand Down Expand Up @@ -112,7 +112,7 @@ impl<'a> ModifyInputsContext<'a> {
// Locate the node output of the first sibling layer to the new layer
if let Some((node_id, output_index)) = self.skip_artboards(&mut output) {
let sibling_node = self.network.nodes.get(&node_id)?;
if sibling_node.name == "Layer" {
if sibling_node.is_layer() {
// There is already a layer node
sibling_layer = Some(NodeOutput::new(node_id, 0));
} else {
Expand All @@ -125,8 +125,8 @@ impl<'a> ModifyInputsContext<'a> {
// Skip some layer nodes
for _ in 0..skip_layer_nodes {
if let Some(old_sibling) = &sibling_layer {
output = NodeOutput::new(old_sibling.node_id, 7);
sibling_layer = self.network.nodes.get(&old_sibling.node_id)?.inputs[7].as_node().map(|node| NodeOutput::new(node, 0));
output = NodeOutput::new(old_sibling.node_id, 1);
sibling_layer = self.network.nodes.get(&old_sibling.node_id)?.inputs[1].as_node().map(|node| NodeOutput::new(node, 0));
shift = IVec2::new(0, 3);
}
}
Expand All @@ -139,14 +139,14 @@ impl<'a> ModifyInputsContext<'a> {
// Create node
let layer_node = resolve_document_node_type("Layer").expect("Layer node").default_document_node();
let new_id = if let Some(sibling_layer) = sibling_layer {
self.insert_between(new_id, sibling_layer, output, layer_node, 7, 0, shift)
self.insert_between(new_id, sibling_layer, output, layer_node, 1, 0, shift)
} else {
self.insert_node_before(new_id, output.node_id, output.node_output_index, layer_node, shift)
};

// Update the document metadata structure
if let Some(new_id) = new_id {
let parent = if self.network.nodes.get(&output_node_id).is_some_and(|node| node.name == "Layer") {
let parent = if self.network.nodes.get(&output_node_id).is_some_and(|node| node.is_layer()) {
LayerNodeIdentifier::new(output_node_id, self.network)
} else {
LayerNodeIdentifier::ROOT
Expand Down Expand Up @@ -498,7 +498,7 @@ impl<'a> ModifyInputsContext<'a> {

LayerNodeIdentifier::new(id, self.network).delete(self.document_metadata);

let new_input = node.inputs[7].clone();
let new_input = node.inputs[1].clone();
let deleted_position = node.metadata.position;

for post_node in self.outwards_links.get(&id).unwrap_or(&Vec::new()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ pub enum NodeGraphMessage {
node_id: NodeId,
hidden: bool,
},
SetName {
node_id: NodeId,
name: String,
},
SetNameImpl {
node_id: NodeId,
name: String,
},
TogglePreview {
node_id: NodeId,
},
Expand Down
Loading