Migrate the Text tool to the document graph (#1435)

* Update text tool to document graph

* Fix selection issue

* Log graph reruns and text node evals

* Hash to set node

* Fix let node crash

* Fix loading document with fonts

* Allow pressing enter to edit

* Cleanup

* Code review nits

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2023-10-24 12:55:13 -07:00
committed by GitHub
co-authored by Keavon Chambers
parent 3d4e3a74e5
commit b8906f344e
17 changed files with 283 additions and 238 deletions
@@ -1430,37 +1430,18 @@ impl DocumentMessageHandler {
/// Loads layer resources such as creating the blob URLs for the images and loading all of the fonts in the document
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>, root: &LayerDataType, mut path: Vec<LayerId>, _document_id: u64) {
fn walk_layers(data: &LayerDataType, path: &mut Vec<LayerId>, responses: &mut VecDeque<Message>, fonts: &mut HashSet<Font>) {
match data {
LayerDataType::Folder(folder) => {
for (id, layer) in folder.layer_ids.iter().zip(folder.layers().iter()) {
path.push(*id);
walk_layers(&layer.data, path, responses, fonts);
path.pop();
}
let mut fonts = HashSet::new();
for (_node_id, node) in self.document_legacy.document_network.recursive_nodes() {
for input in &node.inputs {
if let NodeInput::Value {
tagged_value: TaggedValue::Font(font),
..
} = input
{
fonts.insert(font.clone());
}
LayerDataType::Layer(layer) => {
if layer.cached_output_data == CachedOutputData::None {
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: path.clone() });
}
for node in layer.network.nodes.values() {
for input in &node.inputs {
if let NodeInput::Value {
tagged_value: TaggedValue::Font(font),
..
} = input
{
fonts.insert(font.clone());
}
}
}
}
_ => {}
}
}
let mut fonts = HashSet::new();
walk_layers(root, &mut path, responses, &mut fonts);
for font in fonts {
responses.add_front(FrontendMessage::TriggerFontLoad { font, is_default: false });
}
@@ -3,6 +3,7 @@ use crate::messages::prelude::*;
use bezier_rs::Subpath;
use graph_craft::document::NodeId;
use graphene_core::raster::ImageFrame;
use graphene_core::text::Font;
use graphene_core::uuid::ManipulatorGroupId;
use graphene_core::vector::brush_stroke::BrushStroke;
use graphene_core::vector::style::{Fill, Stroke};
@@ -68,6 +69,12 @@ pub enum GraphOperationMessage {
id: NodeId,
subpaths: Vec<Subpath<ManipulatorGroupId>>,
},
NewTextLayer {
id: NodeId,
text: String,
font: Font,
size: f64,
},
ResizeArtboard {
id: NodeId,
location: IVec2,
@@ -8,6 +8,7 @@ use document_legacy::{LayerId, Operation};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{generate_uuid, DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
use graphene_core::raster::ImageFrame;
use graphene_core::text::Font;
use graphene_core::uuid::ManipulatorGroupId;
use graphene_core::vector::brush_stroke::BrushStroke;
use graphene_core::vector::style::{Fill, FillType, Stroke};
@@ -178,6 +179,34 @@ impl<'a> ModifyInputsContext<'a> {
self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
fn insert_text(&mut self, text: String, font: Font, size: f64, layer: NodeId) {
let text = resolve_document_node_type("Text").expect("Text node does not exist").to_document_node(
[
NodeInput::Network(graph_craft::concrete!(graphene_std::wasm_application_io::WasmEditorApi)),
NodeInput::value(TaggedValue::String(text), false),
NodeInput::value(TaggedValue::Font(font), false),
NodeInput::value(TaggedValue::F64(size), false),
],
Default::default(),
);
let cull = resolve_document_node_type("Cull").expect("Cull node does not exist").default_document_node();
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_document_node();
let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_document_node();
let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_document_node();
let stroke_id = generate_uuid();
self.insert_node_before(stroke_id, layer, 0, stroke, IVec2::new(-8, 0));
let fill_id = generate_uuid();
self.insert_node_before(fill_id, stroke_id, 0, fill, IVec2::new(-8, 0));
let transform_id = generate_uuid();
self.insert_node_before(transform_id, fill_id, 0, transform, IVec2::new(-8, 0));
let cull_id = generate_uuid();
self.insert_node_before(cull_id, transform_id, 0, cull, IVec2::new(-8, 0));
let text_id = generate_uuid();
self.insert_node_before(text_id, cull_id, 0, text, IVec2::new(-8, 0));
self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
fn insert_image_data(&mut self, image_frame: ImageFrame<Color>, layer: NodeId) {
let image = {
let node_type = resolve_document_node_type("Image").expect("Image node does not exist");
@@ -560,6 +589,12 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut NodeGraphMessage
modify_inputs.insert_vector_data(subpaths, layer);
}
}
GraphOperationMessage::NewTextLayer { id, text, font, size } => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.network.outputs[0].node_id, 0) {
modify_inputs.insert_text(text, font, size, layer);
}
}
GraphOperationMessage::ResizeArtboard { id, location, dimensions } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_layer(&[id], document, node_graph, responses) {
modify_inputs.resize_artboard(location, dimensions);
@@ -86,14 +86,17 @@ pub enum NodeGraphMessage {
input_index: usize,
value: TaggedValue,
},
SetSelectNodes {
SetSelectedNodes {
nodes: Vec<NodeId>,
},
ShiftNode {
node_id: NodeId,
},
ToggleHidden,
ToggleHiddenImpl,
SetHidden {
node_id: NodeId,
hidden: bool,
},
TogglePreview {
node_id: NodeId,
},
@@ -746,7 +746,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
let nodes = new_ids.values().copied().collect();
responses.add(NodeGraphMessage::SetSelectNodes { nodes });
responses.add(NodeGraphMessage::SetSelectedNodes { nodes });
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
}
@@ -817,7 +817,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
}
NodeGraphMessage::SetSelectNodes { nodes } => {
NodeGraphMessage::SetSelectedNodes { nodes } => {
responses.add(document.metadata.set_selected_nodes(nodes));
responses.add(PropertiesPanelMessage::ResendActiveProperties);
}
@@ -870,31 +870,27 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
}
NodeGraphMessage::ToggleHidden => {
responses.add(DocumentMessage::StartTransaction);
responses.add(NodeGraphMessage::ToggleHiddenImpl);
if let Some(network) = document.document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction);
let new_hidden = !document.metadata.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in document.metadata.selected_nodes() {
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
}
}
}
NodeGraphMessage::ToggleHiddenImpl => {
NodeGraphMessage::SetHidden { node_id, hidden } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
// Check if any of the selected nodes are hidden
if document.metadata.selected_nodes().any(|id| network.disabled.contains(id)) {
// Remove all selected nodes from the disabled list
network.disabled.retain(|id| !document.metadata.selected_nodes_ref().contains(id));
} else {
let original_outputs = network.original_outputs().iter().map(|output| output.node_id).collect::<Vec<_>>();
// Add all selected nodes to the disabled list (excluding input or output nodes)
network
.disabled
.extend(document.metadata.selected_nodes().filter(|&id| !network.inputs.contains(id) && !original_outputs.contains(id)));
if !hidden {
network.disabled.retain(|&id| node_id != id);
} else if !network.inputs.contains(&node_id) && !network.original_outputs().iter().any(|output| output.node_id == node_id) {
network.disabled.push(node_id);
}
Self::send_graph(network, &self.layer_path, responses);
// Only generate node graph if one of the selected nodes is connected to the output
if document.metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
if let Some(layer_path) = self.layer_path.clone() {
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
} else {
responses.add(NodeGraphMessage::RunDocumentGraph);
}
if network.connected_to_output(node_id) {
responses.add(NodeGraphMessage::RunDocumentGraph);
}
}
self.update_selection_action_buttons(document, responses);
@@ -2483,7 +2483,7 @@ impl DocumentNodeType {
}
}
pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
pub fn wrap_network_in_scope(mut network: NodeNetwork, hash: u64) -> NodeNetwork {
network.generate_node_paths(&[]);
let node_ids = network.nodes.keys().copied().collect::<Vec<_>>();
@@ -2520,11 +2520,18 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
..Default::default()
};
let mut begin_scope = resolve_document_node_type("Begin Scope")
.expect("Begin Scope node type not found")
.to_document_node(vec![input_type.unwrap()], DocumentNodeMetadata::default());
if let DocumentNodeImplementation::Network(g) = &mut begin_scope.implementation {
if let Some(node) = g.nodes.get_mut(&0) {
node.hash = hash;
}
}
// wrap the inner network in a scope
let nodes = vec![
resolve_document_node_type("Begin Scope")
.expect("Begin Scope node type not found")
.to_document_node(vec![input_type.unwrap()], DocumentNodeMetadata::default()),
begin_scope,
inner_network,
resolve_document_node_type("End Scope")
.expect("End Scope node type not found")