mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Storing display name as a node input
This commit is contained in:
@@ -74,12 +74,8 @@ impl MessageHandler<DialogMessage, DialogMessageData<'_>> for DialogMessageHandl
|
||||
.all_layers()
|
||||
.filter(|&layer| document.network_interface.is_artboard(&layer.to_node(), &[]))
|
||||
.map(|layer| {
|
||||
let name = document
|
||||
.network_interface
|
||||
.node_metadata(&layer.to_node(), &[])
|
||||
.map(|node| node.persistent_metadata.display_name.clone())
|
||||
.and_then(|name| if name.is_empty() { None } else { Some(name) })
|
||||
.unwrap_or_else(|| "Artboard".to_string());
|
||||
let display_name = document.network_interface.display_name(&layer.to_node(), &[]);
|
||||
let name = if display_name.is_empty() { "Artboard".to_string() } else { display_name };
|
||||
(layer, name)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -23,6 +23,7 @@ pub struct NodeNetworkInterface {
|
||||
/// The node graph that generates this document's artwork. It recursively stores its sub-graphs, so this root graph is the whole snapshot of the document content.
|
||||
/// A public mutable reference should never be created. It should only be mutated through custom setters which perform the necessary side effects to keep network_metadata in sync
|
||||
network: NodeNetwork,
|
||||
// TODO: Remove and store in node network with IDs based on Self::metadata_node_id
|
||||
/// Stores all editor information for a NodeNetwork. Should automatically kept in sync by the setter methods when changes to the document network are made.
|
||||
network_metadata: NodeNetworkMetadata,
|
||||
// TODO: Wrap in TransientMetadata Option
|
||||
@@ -37,6 +38,36 @@ pub struct NodeNetworkInterface {
|
||||
transaction_status: TransactionStatus,
|
||||
}
|
||||
|
||||
#[derive(Hash)]
|
||||
pub enum Metadata {
|
||||
// Network persistent metadata
|
||||
NodeMetadata,
|
||||
Previewing,
|
||||
NavigationMetadata,
|
||||
SelectionUndoHistory,
|
||||
SelectionRedoHistory,
|
||||
// Network transient metadata
|
||||
SelectedNodes,
|
||||
StackDependents,
|
||||
AllNodesBoundingBox,
|
||||
OutwardWires,
|
||||
ImportExportPorts,
|
||||
// Node persistent metadata
|
||||
Reference,
|
||||
DisplayName,
|
||||
InputNames,
|
||||
OutputNames,
|
||||
HasPrimaryOutput,
|
||||
Locked,
|
||||
NodeTypeMetadata,
|
||||
// Node transient metadata
|
||||
ClickTargets,
|
||||
NodeTypeClickTargets,
|
||||
// Derived metadata
|
||||
Position,
|
||||
IsLayer,
|
||||
}
|
||||
|
||||
impl Clone for NodeNetworkInterface {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
@@ -453,6 +484,24 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
fn metadata_node_id(path: &[NodeId], metadata: Metadata) -> NodeId {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
path.hash(&mut hasher);
|
||||
metadata.hash(&mut hasher);
|
||||
NodeId(hasher.finish())
|
||||
}
|
||||
|
||||
fn metadata_value(&self, path: &[NodeId], metadata: Metadata) -> Option<&TaggedValue> {
|
||||
let node_id = Self::metadata_node_id(path, metadata);
|
||||
|
||||
let network = self.network(&[]).unwrap();
|
||||
let Some(node) = network.nodes.get(&node_id) else {
|
||||
log::error!("Could not get node {node_id} in value_from_node_id");
|
||||
return None;
|
||||
};
|
||||
node.inputs.first().expect("Metadata node should always have primary input to store data").as_value()
|
||||
}
|
||||
|
||||
/// Get the [`Type`] for any InputConnector
|
||||
pub fn input_type(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Type {
|
||||
// TODO: If the input_connector is a NodeInput::Value, return the type of the tagged value
|
||||
@@ -988,11 +1037,17 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
|
||||
pub fn display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
|
||||
let Some(node_metadata) = self.node_metadata(node_id, network_path) else {
|
||||
log::error!("Could not get node_metadata in display_name");
|
||||
let mut node_id_path = network_path.to_vec();
|
||||
node_id_path.push(*node_id);
|
||||
let Some(tagged_value, ..) = self.metadata_value(&node_id_path, Metadata::DisplayName) else {
|
||||
log::error!("Could not get tagged value in display_name");
|
||||
return "".to_string();
|
||||
};
|
||||
node_metadata.persistent_metadata.display_name.clone()
|
||||
let TaggedValue::String(display_name) = tagged_value else {
|
||||
log::error!("Tagged value should be String in display_name");
|
||||
return "".to_string();
|
||||
};
|
||||
display_name.clone()
|
||||
}
|
||||
|
||||
pub fn frontend_display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
|
||||
@@ -2212,7 +2267,7 @@ impl NodeNetworkInterface {
|
||||
DocumentNodeClickTargets {
|
||||
node_click_target,
|
||||
port_click_targets,
|
||||
node_type_metadata: NodeTypeClickTargets::Node,
|
||||
node_type_click_targets: NodeTypeClickTargets::Node,
|
||||
}
|
||||
} else {
|
||||
// Layer inputs
|
||||
@@ -2251,7 +2306,7 @@ impl NodeNetworkInterface {
|
||||
DocumentNodeClickTargets {
|
||||
node_click_target,
|
||||
port_click_targets,
|
||||
node_type_metadata: NodeTypeClickTargets::Layer(LayerClickTargets {
|
||||
node_type_click_targets: NodeTypeClickTargets::Layer(LayerClickTargets {
|
||||
visibility_click_target,
|
||||
grip_click_target,
|
||||
}),
|
||||
@@ -2450,7 +2505,7 @@ impl NodeNetworkInterface {
|
||||
let _ = port.subpath().subpath_to_svg(&mut port_path, DAffine2::IDENTITY);
|
||||
port_click_targets.push(port_path);
|
||||
}
|
||||
if let NodeTypeClickTargets::Layer(layer_metadata) = &node_click_targets.node_type_metadata {
|
||||
if let NodeTypeClickTargets::Layer(layer_metadata) = &node_click_targets.node_type_click_targets {
|
||||
let mut port_path = String::new();
|
||||
let _ = layer_metadata.visibility_click_target.subpath().subpath_to_svg(&mut port_path, DAffine2::IDENTITY);
|
||||
icon_click_targets.push(port_path);
|
||||
@@ -2601,7 +2656,7 @@ impl NodeNetworkInterface {
|
||||
.iter()
|
||||
.filter_map(|node_id| {
|
||||
self.node_click_targets(node_id, network_path).and_then(|transient_node_metadata| {
|
||||
if let NodeTypeClickTargets::Layer(layer) = &transient_node_metadata.node_type_metadata {
|
||||
if let NodeTypeClickTargets::Layer(layer) = &transient_node_metadata.node_type_click_targets {
|
||||
match click_target_type {
|
||||
LayerClickTargetTypes::Visibility => layer.visibility_click_target.intersect_point_no_stroke(point).then_some(*node_id),
|
||||
LayerClickTargetTypes::Grip => layer.grip_click_target.intersect_point_no_stroke(point).then_some(*node_id),
|
||||
@@ -3390,6 +3445,8 @@ impl NodeNetworkInterface {
|
||||
};
|
||||
|
||||
network.nodes.insert(node_id, node_template.document_node);
|
||||
// TODO: Remove this clone once the later usage is removed
|
||||
self.insert_all_node_metadata(node_id, network_path, node_template.persistent_node_metadata.clone());
|
||||
self.transaction_modified();
|
||||
|
||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||
@@ -3406,6 +3463,26 @@ impl NodeNetworkInterface {
|
||||
self.unload_node_click_targets(&node_id, network_path)
|
||||
}
|
||||
|
||||
fn insert_all_node_metadata(&mut self, node_id: NodeId, network_path: &[NodeId], persistent_metadata: DocumentNodePersistentMetadata) {
|
||||
let mut node_path = network_path.to_vec();
|
||||
node_path.push(node_id);
|
||||
let display_name_node_id = Self::metadata_node_id(&node_path, Metadata::DisplayName);
|
||||
self.insert_node_metadata(display_name_node_id, TaggedValue::String(persistent_metadata.display_name));
|
||||
}
|
||||
|
||||
fn insert_node_metadata(&mut self, metadata_node_id: NodeId, tagged_value: TaggedValue) {
|
||||
let network = self.network_mut(&[]).unwrap();
|
||||
log::debug!("Inserting metadata node with id {metadata_node_id}");
|
||||
network.nodes.insert(
|
||||
metadata_node_id,
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()),
|
||||
inputs: vec![NodeInput::value(tagged_value, true)],
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all nodes in `node_ids` and any sole dependents in the horizontal chain if the node to delete is a layer node.
|
||||
pub fn delete_nodes(&mut self, nodes_to_delete: Vec<NodeId>, delete_children: bool, network_path: &[NodeId]) {
|
||||
let Some(outward_wires) = self.outward_wires(network_path).cloned() else {
|
||||
@@ -3632,38 +3709,55 @@ impl NodeNetworkInterface {
|
||||
// }
|
||||
|
||||
pub fn set_display_name(&mut self, node_id: &NodeId, display_name: String, network_path: &[NodeId]) {
|
||||
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||
log::error!("Could not get node {node_id} in set_visibility");
|
||||
let network = self.network_mut(network_path).unwrap();
|
||||
|
||||
let mut node_path = network_path.to_vec();
|
||||
node_path.push(*node_id);
|
||||
let display_name_node_id = Self::metadata_node_id(&node_path, Metadata::DisplayName);
|
||||
|
||||
let Some(display_name_node) = network.nodes.get_mut(&display_name_node_id) else {
|
||||
log::error!("Could not get display name node with id {display_name_node_id} in set_display_name");
|
||||
return;
|
||||
};
|
||||
|
||||
if node_metadata.persistent_metadata.display_name == display_name {
|
||||
let Some(display_name_input) = display_name_node.inputs.get_mut(0) else {
|
||||
log::error!("Could not get display name input in set_display_name");
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(TaggedValue::String(current_display_name)) = display_name_input.as_value() else {
|
||||
log::error!("Could not get current display name in set_display_name");
|
||||
return;
|
||||
};
|
||||
|
||||
if *current_display_name == display_name {
|
||||
return;
|
||||
}
|
||||
|
||||
node_metadata.persistent_metadata.display_name.clone_from(&display_name);
|
||||
*display_name_input = NodeInput::value(TaggedValue::String(display_name), false);
|
||||
|
||||
// Keep the alias in sync with the `ToArtboard` name input
|
||||
if node_metadata.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Artboard") {
|
||||
let Some(nested_network) = self.network_mut(network_path) else {
|
||||
return;
|
||||
};
|
||||
let Some(artboard_node) = nested_network.nodes.get_mut(node_id) else {
|
||||
return;
|
||||
};
|
||||
let DocumentNodeImplementation::Network(network) = &mut artboard_node.implementation else {
|
||||
return;
|
||||
};
|
||||
// Keep this in sync with the definition
|
||||
let Some(to_artboard) = network.nodes.get_mut(&NodeId(0)) else {
|
||||
return;
|
||||
};
|
||||
// TODO: Connect to the display name node. Commenting this out breaks https://github.com/GraphiteEditor/Graphite/issues/1706
|
||||
// Keep the display in sync with the `ToArtboard` name input
|
||||
// if node_metadata.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Artboard") {
|
||||
// let Some(nested_network) = self.network_mut(network_path) else {
|
||||
// return;
|
||||
// };
|
||||
// let Some(artboard_node) = nested_network.nodes.get_mut(node_id) else {
|
||||
// return;
|
||||
// };
|
||||
// let DocumentNodeImplementation::Network(network) = &mut artboard_node.implementation else {
|
||||
// return;
|
||||
// };
|
||||
// // Keep this in sync with the definition
|
||||
// let Some(to_artboard) = network.nodes.get_mut(&NodeId(0)) else {
|
||||
// return;
|
||||
// };
|
||||
|
||||
let label_index = 1;
|
||||
let label = if !display_name.is_empty() { display_name } else { "Artboard".to_string() };
|
||||
let label_input = NodeInput::value(TaggedValue::String(label), false);
|
||||
to_artboard.inputs[label_index] = label_input;
|
||||
}
|
||||
// let label_index = 1;
|
||||
// let label = if !display_name.is_empty() { display_name } else { "Artboard".to_string() };
|
||||
// let label_input = NodeInput::value(TaggedValue::String(label), false);
|
||||
// to_artboard.inputs[label_index] = label_input;
|
||||
// }
|
||||
|
||||
self.transaction_modified();
|
||||
self.try_unload_layer_width(node_id, network_path);
|
||||
@@ -5309,7 +5403,7 @@ pub struct DocumentNodeClickTargets {
|
||||
/// Stores all port click targets in node graph space.
|
||||
pub port_click_targets: Ports,
|
||||
// Click targets that are specific to either nodes or layers, which are chosen states for displaying as a left-to-right node or bottom-to-top layer.
|
||||
pub node_type_metadata: NodeTypeClickTargets,
|
||||
pub node_type_click_targets: NodeTypeClickTargets,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
|
||||
Reference in New Issue
Block a user