mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-26 05:28:12 +08:00
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:
co-authored by
Keavon Chambers
parent
3d4e3a74e5
commit
b8906f344e
@@ -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);
|
||||
|
||||
+11
-4
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user