Skip to content

Commit

Permalink
Migrate text layers to nodes (#1155)
Browse files Browse the repository at this point in the history
* Initial work towards text to node

* Add the text generate node

* Implement live edit

* Fix merge error

* Cleanup text tool

* Implement text

* Fix transforms

* Fix broken image frame

* Double click to edit text

* Fix rendering text on load

* Moving whilst editing

* Better text properties

* Prevent changing vector when there is a Text node

* Push node api

* Use node fn macro

* Stable ids

* Image module as a seperate file

* Explain check for "Input Frame" node

* Code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
  • Loading branch information
0HyperCube and Keavon committed Apr 27, 2023
1 parent 04cdfb3 commit d6481b9
Show file tree
Hide file tree
Showing 44 changed files with 1,082 additions and 1,143 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

89 changes: 3 additions & 86 deletions document-legacy/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::layers::layer_info::{Layer, LayerData, LayerDataType, LayerDataTypeDi
use crate::layers::nodegraph_layer::{CachedOutputData, NodeGraphFrameLayer};
use crate::layers::shape_layer::ShapeLayer;
use crate::layers::style::RenderData;
use crate::layers::text_layer::{Font, TextLayer};
use crate::{DocumentError, DocumentResponse, Operation};

use glam::{DAffine2, DVec2};
Expand Down Expand Up @@ -430,30 +429,6 @@ impl Document {
Ok(())
}

/// Marks all decendants of the specified [Layer] of a specific [LayerDataType] as dirty
fn mark_layers_of_type_as_dirty(root: &mut Layer, data_type: LayerDataTypeDiscriminant) -> bool {
if let LayerDataType::Folder(folder) = &mut root.data {
let mut dirty = false;
for layer in folder.layers_mut() {
dirty = Self::mark_layers_of_type_as_dirty(layer, data_type) || dirty;
}
root.cache_dirty = dirty;
}
if LayerDataTypeDiscriminant::from(&root.data) == data_type {
root.cache_dirty = true;
if let LayerDataType::Text(text) = &mut root.data {
text.cached_path = None;
}
}

root.cache_dirty
}

/// Marks all layers in the [Document] of a specific [LayerDataType] as dirty
pub fn mark_all_layers_of_type_as_dirty(&mut self, data_type: LayerDataTypeDiscriminant) -> bool {
Self::mark_layers_of_type_as_dirty(&mut self.root, data_type)
}

pub fn transforms(&self, path: &[LayerId]) -> Result<Vec<DAffine2>, DocumentError> {
let mut root = &self.root;
let mut transforms = vec![self.root.transform];
Expand Down Expand Up @@ -539,25 +514,6 @@ impl Document {

Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
}
Operation::AddText {
path,
insert_index,
transform,
text,
style,
size,
font_name,
font_style,
} => {
let font = Font::new(font_name, font_style);
let layer_text = TextLayer::new(text, style, size, font, render_data);
let layer_data = LayerDataType::Text(layer_text);
let layer = Layer::new(layer_data, transform);

self.set_layer(&path, layer, insert_index)?;

Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
}
Operation::AddNodeGraphFrame {
path,
insert_index,
Expand All @@ -576,30 +532,6 @@ impl Document {
}
Some(vec![LayerChanged { path: layer_path.clone() }])
}
Operation::SetTextEditability { path, editable } => {
self.layer_mut(&path)?.as_text_mut()?.editable = editable;
self.mark_as_dirty(&path)?;
Some(vec![DocumentChanged])
}
Operation::SetTextContent { path, new_text } => {
// Not using Document::layer_mut is necessary because we also need to borrow the font cache
let mut current_folder = &mut self.root;

let (layer_path, id) = split_path(&path)?;
for id in layer_path {
current_folder = current_folder.as_folder_mut()?.layer_mut(*id).ok_or_else(|| DocumentError::LayerNotFound(layer_path.into()))?;
}
current_folder
.as_folder_mut()?
.layer_mut(id)
.ok_or_else(|| DocumentError::LayerNotFound(path.clone()))?
.as_text_mut()?
.update_text(new_text, render_data);

self.mark_as_dirty(&path)?;

Some([vec![DocumentChanged], update_thumbnails_upstream(&path)].concat())
}
Operation::AddNgon {
path,
insert_index,
Expand Down Expand Up @@ -736,22 +668,6 @@ impl Document {
return Err(DocumentError::IndexOutOfBounds);
}
}
Operation::ModifyFont { path, font_family, font_style, size } => {
// Not using Document::layer_mut is necessary because we also need to borrow the font cache
let mut current_folder = &mut self.root;
let (folder_path, id) = split_path(&path)?;
for id in folder_path {
current_folder = current_folder.as_folder_mut()?.layer_mut(*id).ok_or_else(|| DocumentError::LayerNotFound(folder_path.into()))?;
}
let layer_mut = current_folder.as_folder_mut()?.layer_mut(id).ok_or_else(|| DocumentError::LayerNotFound(folder_path.into()))?;
let text = layer_mut.as_text_mut()?;

text.font = Font::new(font_family, font_style);
text.size = size;
text.cached_path = Some(text.generate_path(text.load_face(render_data)));
self.mark_as_dirty(&path)?;
Some([vec![DocumentChanged, LayerChanged { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
}
Operation::RenameLayer { layer_path: path, new_name: name } => {
self.layer_mut(&path)?.name = Some(name);
Some(vec![LayerChanged { path }])
Expand Down Expand Up @@ -791,7 +707,9 @@ impl Document {
let layer = self.layer_mut(&path).expect("Clearing node graph image for invalid layer");
match &mut layer.data {
LayerDataType::NodeGraphFrame(node_graph) => {
node_graph.cached_output_data = CachedOutputData::None;
if matches!(node_graph.cached_output_data, CachedOutputData::BlobURL(_)) {
node_graph.cached_output_data = CachedOutputData::None;
}
}
e => panic!("Incorrectly trying to clear the blob URL for layer of type {}", LayerDataTypeDiscriminant::from(&*e)),
}
Expand Down Expand Up @@ -984,7 +902,6 @@ impl Document {
let layer = self.layer_mut(&path)?;
match &mut layer.data {
LayerDataType::Shape(s) => s.style = style,
LayerDataType::Text(text) => text.path_style = style,
_ => return Err(DocumentError::NotShape),
}
self.mark_as_dirty(&path)?;
Expand Down
32 changes: 0 additions & 32 deletions document-legacy/src/layers/layer_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use super::folder_layer::FolderLayer;
use super::nodegraph_layer::NodeGraphFrameLayer;
use super::shape_layer::ShapeLayer;
use super::style::{PathStyle, RenderData};
use super::text_layer::TextLayer;
use crate::intersection::Quad;
use crate::DocumentError;
use crate::LayerId;
Expand All @@ -23,8 +22,6 @@ pub enum LayerDataType {
Folder(FolderLayer),
/// A layer that wraps a [ShapeLayer] struct.
Shape(ShapeLayer),
/// A layer that wraps a [TextLayer] struct.
Text(TextLayer),
/// A layer that wraps an [NodeGraphFrameLayer] struct.
NodeGraphFrame(NodeGraphFrameLayer),
}
Expand All @@ -34,7 +31,6 @@ impl LayerDataType {
match self {
LayerDataType::Shape(s) => s,
LayerDataType::Folder(f) => f,
LayerDataType::Text(t) => t,
LayerDataType::NodeGraphFrame(n) => n,
}
}
Expand All @@ -43,7 +39,6 @@ impl LayerDataType {
match self {
LayerDataType::Shape(s) => s,
LayerDataType::Folder(f) => f,
LayerDataType::Text(t) => t,
LayerDataType::NodeGraphFrame(n) => n,
}
}
Expand Down Expand Up @@ -75,7 +70,6 @@ impl From<&LayerDataType> for LayerDataTypeDiscriminant {
match data {
Folder(_) => LayerDataTypeDiscriminant::Folder,
Shape(_) => LayerDataTypeDiscriminant::Shape,
Text(_) => LayerDataTypeDiscriminant::Text,
NodeGraphFrame(_) => LayerDataTypeDiscriminant::NodeGraphFrame,
}
}
Expand Down Expand Up @@ -459,24 +453,6 @@ impl Layer {
}
}

/// Get a mutable reference to the Text element wrapped by the layer.
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Text`.
pub fn as_text_mut(&mut self) -> Result<&mut TextLayer, DocumentError> {
match &mut self.data {
LayerDataType::Text(t) => Ok(t),
_ => Err(DocumentError::NotText),
}
}

/// Get a reference to the Text element wrapped by the layer.
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Text`.
pub fn as_text(&self) -> Result<&TextLayer, DocumentError> {
match &self.data {
LayerDataType::Text(t) => Ok(t),
_ => Err(DocumentError::NotText),
}
}

/// 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> {
Expand Down Expand Up @@ -505,7 +481,6 @@ impl Layer {
pub fn style(&self) -> Result<&PathStyle, DocumentError> {
match &self.data {
LayerDataType::Shape(s) => Ok(&s.style),
LayerDataType::Text(t) => Ok(&t.path_style),
LayerDataType::NodeGraphFrame(t) => t.as_vector_data().map(|vector| &vector.style).ok_or(DocumentError::NotShape),
_ => Err(DocumentError::NotShape),
}
Expand All @@ -514,7 +489,6 @@ impl Layer {
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::NotShape),
}
}
Expand Down Expand Up @@ -551,12 +525,6 @@ impl From<ShapeLayer> for Layer {
}
}

impl From<TextLayer> for Layer {
fn from(from: TextLayer) -> Layer {
Layer::new(LayerDataType::Text(from), DAffine2::IDENTITY.to_cols_array())
}
}

impl<'a> IntoIterator for &'a Layer {
type Item = &'a Layer;
type IntoIter = LayerIter<'a>;
Expand Down
4 changes: 1 addition & 3 deletions document-legacy/src/layers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//! There are currently these different types of layers:
//! * [Folder layers](folder_layer::FolderLayer), which encapsulate sub-layers
//! * [Shape layers](shape_layer::ShapeLayer), which contain generic SVG [`<path>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path)s
//! * [Text layers](text_layer::TextLayer), which contain a description of laid out text
//! * [Node Graph layers](nodegraph_layer::NodegraphLayer), which contain a node graph frame
//!
//! Refer to the module-level documentation for detailed information on each layer.
Expand All @@ -23,10 +22,9 @@ pub mod folder_layer;
pub mod layer_info;
/// Contains the [NodegraphLayer](nodegraph_layer::NodegraphLayer) type that contains a node graph.
pub mod nodegraph_layer;
// TODO: Remove shape layers after rewriting the overlay system
/// Contains the [ShapeLayer](shape_layer::ShapeLayer) type, a generic SVG element defined using Bezier paths.
pub mod shape_layer;
/// Contains the [TextLayer](text_layer::TextLayer) type.
pub mod text_layer;

mod render_data;
pub use render_data::RenderData;
Expand Down
2 changes: 1 addition & 1 deletion document-legacy/src/layers/render_data.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::style::ViewMode;
use super::text_layer::FontCache;
use graphene_std::text::FontCache;

use glam::DVec2;

Expand Down
Loading

0 comments on commit d6481b9

Please sign in to comment.