Implement the Text Tool and text layer MVP (#492)

* Add text tool

* Double click with the select tool to edit text

* Fix (I think?) transitioning to select tool

* Commit and abort text editing

* Transition to a contenteditable div and autosize

* Fix right click blocking

* Cleanup hints

* Ctrl + enter leaves text edit mode

* Render indervidual bounding boxes for text

* Re-format space indents

* Reflect font size in the textarea

* Fix change tool behaviour

* Remove starting text

* Populate the cache (caused doc load bug)

* Remove console log

* Chrome display the flashing text entry cursor

* Update overlay on input

* Cleanup input.ts

* Fix bounding boxes

* Apply review feedback

* Remove manual test

* Remove svg from gitignore

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2022-01-30 15:10:10 +00:00
committed by Keavon Chambers
parent 0da8dabba9
commit a66920aa1c
33 changed files with 1152 additions and 56 deletions

View File

@@ -1,5 +1,5 @@
use super::clipboards::Clipboard;
use super::layer_panel::{layer_panel_entry, LayerMetadata, LayerPanelEntry, RawBuffer};
use super::layer_panel::{layer_panel_entry, LayerDataTypeDiscriminant, LayerMetadata, LayerPanelEntry, RawBuffer};
use super::utility_types::{AlignAggregate, AlignAxis, DocumentSave, FlipAxis, VectorManipulatorSegment, VectorManipulatorShape};
use super::vectorize_layer_metadata;
use super::{ArtboardMessageHandler, MovementMessageHandler, OverlaysMessageHandler, TransformLayerMessageHandler};
@@ -146,11 +146,11 @@ impl DocumentMessageHandler {
_ => return None,
};
let shape = match &layer.ok()?.data {
LayerDataType::Shape(shape) => Some(shape),
LayerDataType::Folder(_) => None,
let (path, closed) = match &layer.ok()?.data {
LayerDataType::Shape(shape) => Some((shape.path.clone(), shape.closed)),
LayerDataType::Text(text) => Some((text.to_bez_path_nonmut(), true)),
_ => None,
}?;
let path = shape.path.clone();
let segments = path
.segments()
@@ -170,7 +170,7 @@ impl DocumentMessageHandler {
path,
segments,
transform: viewport_transform,
closed: shape.closed,
closed,
})
});
@@ -204,6 +204,16 @@ impl DocumentMessageHandler {
})
}
pub fn selected_visible_text_layers(&self) -> impl Iterator<Item = &[LayerId]> {
self.selected_layers().filter(|path| match self.graphene_document.layer(path) {
Ok(layer) => {
let discriminant: LayerDataTypeDiscriminant = (&layer.data).into();
layer.visible && discriminant == LayerDataTypeDiscriminant::Text
}
Err(_) => false,
})
}
pub fn visible_layers(&self) -> impl Iterator<Item = &[LayerId]> {
self.all_layers().filter(|path| match self.graphene_document.layer(path) {
Ok(layer) => layer.visible,
@@ -216,17 +226,14 @@ impl DocumentMessageHandler {
for (id, layer) in folder.layer_ids.iter().zip(folder.layers()).rev() {
data.push(*id);
space += 1;
match layer.data {
LayerDataType::Shape(_) => (),
LayerDataType::Folder(ref folder) => {
path.push(*id);
if self.layer_metadata(path).expanded {
structure.push(space);
self.serialize_structure(folder, structure, data, path);
space = 0;
}
path.pop();
if let LayerDataType::Folder(ref folder) = layer.data {
path.push(*id);
if self.layer_metadata(path).expanded {
structure.push(space);
self.serialize_structure(folder, structure, data, path);
space = 0;
}
path.pop();
}
}
structure.push(space | 1 << 63);
@@ -962,6 +969,22 @@ impl MessageHandler<DocumentMessage, &InputPreprocessorMessageHandler> for Docum
SetSnapping { snap } => {
self.snapping_enabled = snap;
}
SetTexboxEditability { path, editable } => {
let text = self.graphene_document.layer(&path).unwrap().as_text().unwrap();
responses.push_back(DocumentOperation::SetTextEditability { path, editable }.into());
if editable {
responses.push_back(
FrontendMessage::DisplayEditableTextbox {
text: text.text.clone(),
line_width: text.line_width,
font_size: text.size,
}
.into(),
);
} else {
responses.push_back(FrontendMessage::DisplayRemoveEditableTextbox.into());
}
}
SetViewMode { view_mode } => {
self.view_mode = view_mode;
responses.push_front(DocumentMessage::DirtyRenderDocument.into());