From e26fb6c220a10af0f387abddad9bc9c5cb76dbe4 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Sat, 22 Jan 2022 18:49:42 +0000 Subject: [PATCH 01/22] Add text tool --- .gitignore | 1 + Cargo.lock | 60 +++++ .../src/document/document_message_handler.rs | 27 +- editor/src/document/layer_panel.rs | 3 + editor/src/frontend/utility_types.rs | 1 + editor/src/input/input_mapper.rs | 3 + editor/src/lib.rs | 1 + editor/src/viewport_tools/tool.rs | 7 +- editor/src/viewport_tools/tool_message.rs | 3 + editor/src/viewport_tools/tool_options.rs | 2 +- editor/src/viewport_tools/tools/mod.rs | 1 + editor/src/viewport_tools/tools/text.rs | 231 ++++++++++++++++++ frontend/src/components/panels/Document.vue | 19 +- .../widgets/options/ToolOptions.vue | 2 +- frontend/src/dispatcher/js-messages.ts | 3 +- frontend/src/lifetime/input.ts | 14 +- frontend/wasm/src/api.rs | 8 + graphene/Cargo.toml | 4 + graphene/src/document.rs | 49 +++- graphene/src/error.rs | 1 + graphene/src/layers/layer_info.rs | 18 ++ graphene/src/layers/mod.rs | 1 + .../src/layers/text/SourceSansPro/OFL.txt | 93 +++++++ .../SourceSansPro/SourceSansPro-Regular.ttf | Bin 0 -> 248504 bytes graphene/src/layers/text/mod.rs | 123 ++++++++++ graphene/src/layers/text/to_kurbo.rs | 120 +++++++++ graphene/src/operation.rs | 16 ++ 27 files changed, 773 insertions(+), 38 deletions(-) create mode 100644 editor/src/viewport_tools/tools/text.rs create mode 100644 graphene/src/layers/text/SourceSansPro/OFL.txt create mode 100644 graphene/src/layers/text/SourceSansPro/SourceSansPro-Regular.ttf create mode 100644 graphene/src/layers/text/mod.rs create mode 100644 graphene/src/layers/text/to_kurbo.rs diff --git a/.gitignore b/.gitignore index 42f08a0ecb..85219f7b6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target/ *.spv *.exrc +*font_text.svg diff --git a/Cargo.lock b/Cargo.lock index a6047ccaa5..9bc8b7770e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,12 @@ version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +[[package]] +name = "bytemuck" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -110,7 +116,9 @@ dependencies = [ "glam", "kurbo", "log", + "rustybuzz", "serde", + "ttf-parser", ] [[package]] @@ -280,6 +288,22 @@ dependencies = [ "syn", ] +[[package]] +name = "rustybuzz" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44561062e583c4873162861261f16fd1d85fe927c4904d71329a4fe43dc355ef" +dependencies = [ + "bitflags", + "bytemuck", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-general-category", + "unicode-script", +] + [[package]] name = "ryu" version = "1.0.9" @@ -341,6 +365,12 @@ dependencies = [ "serde", ] +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + [[package]] name = "spin" version = "0.9.2" @@ -390,6 +420,36 @@ dependencies = [ "syn", ] +[[package]] +name = "ttf-parser" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694" + +[[package]] +name = "unicode-ccc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" + +[[package]] +name = "unicode-general-category" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742" + +[[package]] +name = "unicode-script" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dd944fd05f2f0b5c674917aea8a4df6af84f2d8de3fe8d988b95d28fb8fb09" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/editor/src/document/document_message_handler.rs b/editor/src/document/document_message_handler.rs index fa9c17b854..69f4dbe1c6 100644 --- a/editor/src/document/document_message_handler.rs +++ b/editor/src/document/document_message_handler.rs @@ -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(), 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, }) }); @@ -205,17 +205,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); diff --git a/editor/src/document/layer_panel.rs b/editor/src/document/layer_panel.rs index 80ff28e21a..3b2babfe81 100644 --- a/editor/src/document/layer_panel.rs +++ b/editor/src/document/layer_panel.rs @@ -98,6 +98,7 @@ pub struct LayerPanelEntry { pub enum LayerDataTypeDiscriminant { Folder, Shape, + Text, } impl fmt::Display for LayerDataTypeDiscriminant { @@ -105,6 +106,7 @@ impl fmt::Display for LayerDataTypeDiscriminant { let name = match self { LayerDataTypeDiscriminant::Folder => "Folder", LayerDataTypeDiscriminant::Shape => "Shape", + LayerDataTypeDiscriminant::Text => "Text", }; formatter.write_str(name) @@ -118,6 +120,7 @@ impl From<&LayerDataType> for LayerDataTypeDiscriminant { match data { Folder(_) => LayerDataTypeDiscriminant::Folder, Shape(_) => LayerDataTypeDiscriminant::Shape, + Text(_) => LayerDataTypeDiscriminant::Text, } } } diff --git a/editor/src/frontend/utility_types.rs b/editor/src/frontend/utility_types.rs index 6bc51118f0..cf0c2fd29b 100644 --- a/editor/src/frontend/utility_types.rs +++ b/editor/src/frontend/utility_types.rs @@ -14,4 +14,5 @@ pub enum MouseCursorIcon { ZoomOut, Grabbing, Crosshair, + Text, } diff --git a/editor/src/input/input_mapper.rs b/editor/src/input/input_mapper.rs index cf5eaa0f3f..c8de42a434 100644 --- a/editor/src/input/input_mapper.rs +++ b/editor/src/input/input_mapper.rs @@ -59,6 +59,8 @@ impl Default for Mapping { // Eyedropper entry! {action=EyedropperMessage::LeftMouseDown, key_down=Lmb}, entry! {action=EyedropperMessage::RightMouseDown, key_down=Rmb}, + // Text + entry! {action=TextMessage::LeftMouseDown, key_down=Lmb}, // Rectangle entry! {action=RectangleMessage::DragStart, key_down=Lmb}, entry! {action=RectangleMessage::DragStop, key_up=Lmb}, @@ -101,6 +103,7 @@ impl Default for Mapping { entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Select }, key_down=KeyV}, entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Navigate }, key_down=KeyZ}, entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Eyedropper }, key_down=KeyI}, + entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Text }, key_down=KeyT}, entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Fill }, key_down=KeyF}, entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Path }, key_down=KeyA}, entry! {action=ToolMessage::ActivateTool { tool_type: ToolType::Pen }, key_down=KeyP}, diff --git a/editor/src/lib.rs b/editor/src/lib.rs index 1b3501b8d2..cc8336f7be 100644 --- a/editor/src/lib.rs +++ b/editor/src/lib.rs @@ -80,6 +80,7 @@ pub mod message_prelude { pub use crate::viewport_tools::tools::rectangle::{RectangleMessage, RectangleMessageDiscriminant}; pub use crate::viewport_tools::tools::select::{SelectMessage, SelectMessageDiscriminant}; pub use crate::viewport_tools::tools::shape::{ShapeMessage, ShapeMessageDiscriminant}; + pub use crate::viewport_tools::tools::text::{TextMessage, TextMessageDiscriminant}; pub use graphite_proc_macros::*; pub use std::collections::VecDeque; diff --git a/editor/src/viewport_tools/tool.rs b/editor/src/viewport_tools/tool.rs index f575287271..30d8b05e61 100644 --- a/editor/src/viewport_tools/tool.rs +++ b/editor/src/viewport_tools/tool.rs @@ -75,7 +75,7 @@ impl Default for ToolFsmState { Crop => crop::Crop, Navigate => navigate::Navigate, Eyedropper => eyedropper::Eyedropper, - // Text => text::Text, + Text => text::Text, Fill => fill::Fill, // Gradient => gradient::Gradient, // Brush => brush::Brush, @@ -207,7 +207,7 @@ impl ToolType { ToolType::Crop => ToolOptions::Crop {}, ToolType::Navigate => ToolOptions::Navigate {}, ToolType::Eyedropper => ToolOptions::Eyedropper {}, - ToolType::Text => ToolOptions::Text {}, + ToolType::Text => ToolOptions::Text { font_size: 14 }, ToolType::Fill => ToolOptions::Fill {}, ToolType::Gradient => ToolOptions::Gradient {}, ToolType::Brush => ToolOptions::Brush {}, @@ -271,6 +271,7 @@ pub fn standard_tool_message(tool: ToolType, message_type: StandardToolMessageTy ToolType::Ellipse => Some(EllipseMessage::Abort.into()), ToolType::Shape => Some(ShapeMessage::Abort.into()), ToolType::Eyedropper => Some(EyedropperMessage::Abort.into()), + ToolType::Text => Some(TextMessage::Abort.into()), ToolType::Fill => Some(FillMessage::Abort.into()), _ => None, }, @@ -285,7 +286,7 @@ pub fn message_to_tool_type(message: &ToolMessage) -> ToolType { Crop(_) => ToolType::Crop, Navigate(_) => ToolType::Navigate, Eyedropper(_) => ToolType::Eyedropper, - // Text(_) => ToolType::Text, + Text(_) => ToolType::Text, Fill(_) => ToolType::Fill, // Gradient(_) => ToolType::Gradient, // Brush(_) => ToolType::Brush, diff --git a/editor/src/viewport_tools/tool_message.rs b/editor/src/viewport_tools/tool_message.rs index 1826ddf8af..24514c51a2 100644 --- a/editor/src/viewport_tools/tool_message.rs +++ b/editor/src/viewport_tools/tool_message.rs @@ -22,6 +22,9 @@ pub enum ToolMessage { Eyedropper(EyedropperMessage), #[remain::unsorted] #[child] + Text(TextMessage), + #[remain::unsorted] + #[child] Fill(FillMessage), #[remain::unsorted] #[child] diff --git a/editor/src/viewport_tools/tool_options.rs b/editor/src/viewport_tools/tool_options.rs index 1963885046..73d5df7185 100644 --- a/editor/src/viewport_tools/tool_options.rs +++ b/editor/src/viewport_tools/tool_options.rs @@ -6,7 +6,7 @@ pub enum ToolOptions { Crop {}, Navigate {}, Eyedropper {}, - Text {}, + Text { font_size: u32 }, Fill {}, Gradient {}, Brush {}, diff --git a/editor/src/viewport_tools/tools/mod.rs b/editor/src/viewport_tools/tools/mod.rs index ea454d46fd..26e5159466 100644 --- a/editor/src/viewport_tools/tools/mod.rs +++ b/editor/src/viewport_tools/tools/mod.rs @@ -10,3 +10,4 @@ pub mod rectangle; pub mod select; pub mod shape; pub mod shared; +pub mod text; diff --git a/editor/src/viewport_tools/tools/text.rs b/editor/src/viewport_tools/tools/text.rs new file mode 100644 index 0000000000..ef049cdebf --- /dev/null +++ b/editor/src/viewport_tools/tools/text.rs @@ -0,0 +1,231 @@ +use crate::consts::SELECTION_TOLERANCE; +use crate::document::DocumentMessageHandler; +use crate::frontend::utility_types::MouseCursorIcon; +use crate::input::keyboard::{Key, MouseMotion}; +use crate::input::InputPreprocessorMessageHandler; +use crate::message_prelude::*; +use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup}; +use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData, ToolType}; +use crate::viewport_tools::tool_options::ToolOptions; + +use glam::{DAffine2, DVec2}; +use graphene::intersection::Quad; +use graphene::layers::style; +use graphene::Operation; +use serde::{Deserialize, Serialize}; + +#[derive(Default)] +pub struct Text { + fsm_state: TextToolFsmState, + data: TextToolData, +} + +#[remain::sorted] +#[impl_message(Message, ToolMessage, Text)] +#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize)] +pub enum TextMessage { + // Standard messages + #[remain::unsorted] + Abort, + + // Tool-specific messages + LeftMouseDown, + TextChange { + new_text: String, + }, +} + +impl<'a> MessageHandler> for Text { + fn process_action(&mut self, action: ToolMessage, data: ToolActionHandlerData<'a>, responses: &mut VecDeque) { + if action == ToolMessage::UpdateHints { + self.fsm_state.update_hints(responses); + return; + } + + if action == ToolMessage::UpdateCursor { + self.fsm_state.update_cursor(responses); + return; + } + + let new_state = self.fsm_state.transition(action, data.0, data.1, &mut self.data, data.2, responses); + + if self.fsm_state != new_state { + self.fsm_state = new_state; + self.fsm_state.update_hints(responses); + self.fsm_state.update_cursor(responses); + } + } + + advertise_actions!(TextMessageDiscriminant; LeftMouseDown); +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum TextToolFsmState { + Ready, + Editing, +} + +impl Default for TextToolFsmState { + fn default() -> Self { + TextToolFsmState::Ready + } +} + +#[derive(Clone, Debug, Default)] +struct TextToolData { + path: Vec, +} + +impl Fsm for TextToolFsmState { + type ToolData = TextToolData; + + fn transition( + self, + event: ToolMessage, + document: &DocumentMessageHandler, + tool_data: &DocumentToolData, + data: &mut Self::ToolData, + input: &InputPreprocessorMessageHandler, + responses: &mut VecDeque, + ) -> Self { + use TextMessage::*; + use TextToolFsmState::*; + + if let ToolMessage::Text(event) = event { + match (self, event) { + (state, LeftMouseDown) => { + let mouse_pos = input.mouse.position; + let tolerance = DVec2::splat(SELECTION_TOLERANCE); + let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]); + + let new_state = if let Some(l) = document + .graphene_document + .intersects_quad_root(quad) + .last() + .filter(|l| document.graphene_document.layer(l).map(|l| l.as_text().is_ok()).unwrap_or(false)) + // Editing existing text + { + if state == TextToolFsmState::Editing { + let editable = false; + responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + } + + data.path = l.clone(); + + let editable = true; + responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + + Editing + } + // Creating new text + else if state == TextToolFsmState::Ready { + let transform = DAffine2::from_translation(input.mouse.position).to_cols_array(); + let font_size = match tool_data.tool_options.get(&ToolType::Text) { + Some(&ToolOptions::Text { font_size }) => font_size, + _ => 14, + }; + data.path = vec![generate_uuid()]; + + responses.push_back( + Operation::AddText { + path: data.path.clone(), + transform: DAffine2::ZERO.to_cols_array(), + insert_index: -1, + text: r#"The quick brown +fox jumped over the lazy cat. +In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before the final copy is available. It is also used to temporarily replace text in a process called greeking, which allows designers to consider the form of a webpage or publication, without the meaning of the text influencing the design. + +Lorem ipsum is typically a corrupted version of De finibus bonorum et malorum, a 1st-century BC text by the Roman statesman and philosopher Cicero, with words altered, added, and removed to make it nonsensical and improper Latin. + +Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"#.to_string(), + style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, 0.)), None), + size: font_size as f64, + } + .into(), + ); + responses.push_back(Operation::SetLayerTransformInViewport { path: data.path.clone(), transform }.into()); + + let editable = true; + responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + + Editing + } else + // Removing old text as editable + { + let editable = false; + responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + Ready + }; + + new_state + } + (Editing, Abort) => { + responses.push_back(DocumentMessage::AbortTransaction.into()); + Ready + } + (_, TextChange { new_text }) => { + let editable = false; + responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + + responses.push_back(Operation::SetTextContent { path: data.path.clone(), new_text }.into()); + + Ready + } + _ => self, + } + } else { + self + } + } + + fn update_hints(&self, responses: &mut VecDeque) { + let hint_data = match self { + TextToolFsmState::Ready => HintData(vec![HintGroup(vec![ + HintInfo { + key_groups: vec![], + mouse: Some(MouseMotion::Lmb), + label: String::from("Add text"), + plus: false, + }, + HintInfo { + key_groups: vec![], + mouse: Some(MouseMotion::Lmb), + label: String::from("Edit text"), + plus: false, + }, + ])]), + TextToolFsmState::Editing => HintData(vec![HintGroup(vec![ + HintInfo { + key_groups: vec![], + mouse: Some(MouseMotion::Lmb), + label: String::from("Complete edit"), + plus: false, + }, + HintInfo { + key_groups: vec![KeysGroup(vec![Key::KeyEscape])], + mouse: None, + label: String::from("Cancel edit"), + plus: false, + }, + HintInfo { + key_groups: vec![KeysGroup(vec![Key::KeyEnter])], + mouse: None, + label: String::from("New line"), + plus: false, + }, + HintInfo { + key_groups: vec![], + mouse: Some(MouseMotion::Lmb), + label: String::from("Complete edit"), + plus: false, + }, + ])]), + }; + + responses.push_back(FrontendMessage::UpdateInputHints { hint_data }.into()); + } + + fn update_cursor(&self, responses: &mut VecDeque) { + responses.push_back(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Text }.into()); + } +} diff --git a/frontend/src/components/panels/Document.vue b/frontend/src/components/panels/Document.vue index fc76829e6e..73fdb6cab8 100644 --- a/frontend/src/components/panels/Document.vue +++ b/frontend/src/components/panels/Document.vue @@ -76,7 +76,7 @@ - + { const cssNames: Record = { @@ -209,6 +209,7 @@ const ToCssCursorProperty = Transform(({ value }) => { ZoomOut: "zoom-out", Grabbing: "grabbing", Crosshair: "crosshair", + Text: "text", }; return cssNames[value] || "default"; diff --git a/frontend/src/lifetime/input.ts b/frontend/src/lifetime/input.ts index 6befe70ab6..589bcd6f1c 100644 --- a/frontend/src/lifetime/input.ts +++ b/frontend/src/lifetime/input.ts @@ -27,6 +27,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement, ]; let viewportPointerInteractionOngoing = false; + let textInput = undefined as undefined | HTMLTextAreaElement; // Keyboard events @@ -114,7 +115,12 @@ export function createInputManager(editor: EditorState, container: HTMLElement, e.stopPropagation(); } - if (inCanvas) viewportPointerInteractionOngoing = true; + if (target instanceof HTMLTextAreaElement) { + textInput = target; + } else if (textInput) { + editor.instance.on_change_text(textInput.value); + textInput = undefined; + } else if (inCanvas) viewportPointerInteractionOngoing = true; if (viewportPointerInteractionOngoing) { const modifiers = makeModifiersBitfield(e); @@ -125,8 +131,10 @@ export function createInputManager(editor: EditorState, container: HTMLElement, const onPointerUp = (e: PointerEvent): void => { if (!e.buttons) viewportPointerInteractionOngoing = false; - const modifiers = makeModifiersBitfield(e); - editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers); + if (!textInput) { + const modifiers = makeModifiersBitfield(e); + editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers); + } }; // Mouse events diff --git a/frontend/wasm/src/api.rs b/frontend/wasm/src/api.rs index 7ed30d156e..43eeed678c 100644 --- a/frontend/wasm/src/api.rs +++ b/frontend/wasm/src/api.rs @@ -296,6 +296,14 @@ impl JsEditorHandle { self.dispatch(message); } + /// A text box was changed + pub fn on_change_text(&self, new_text: String) -> Result<(), JsValue> { + let message = TextMessage::TextChange { new_text }; + self.dispatch(message); + + Ok(()) + } + /// Update primary color pub fn update_primary_color(&self, red: f32, green: f32, blue: f32, alpha: f32) -> Result<(), JsValue> { let primary_color = match Color::from_rgbaf32(red, green, blue, alpha) { diff --git a/graphene/Cargo.toml b/graphene/Cargo.toml index 43ce0a38c7..9c303bbd0c 100644 --- a/graphene/Cargo.toml +++ b/graphene/Cargo.toml @@ -18,3 +18,7 @@ kurbo = { git = "https://github.com/GraphiteEditor/kurbo.git", features = [ ] } serde = { version = "1.0", features = ["derive"] } glam = { version = "0.17", features = ["serde"] } + +# Font rendering +rustybuzz = "*" +ttf-parser = "*" # Version from rustybuzz diff --git a/graphene/src/document.rs b/graphene/src/document.rs index 604d0bca3d..a6a296e8a9 100644 --- a/graphene/src/document.rs +++ b/graphene/src/document.rs @@ -4,6 +4,7 @@ use crate::layers::folder::Folder; use crate::layers::layer_info::{Layer, LayerData, LayerDataType}; use crate::layers::simple_shape::Shape; use crate::layers::style::ViewMode; +use crate::layers::text::Text; use crate::{DocumentError, DocumentResponse, Operation}; use glam::{DAffine2, DVec2}; @@ -108,7 +109,7 @@ impl Document { Ok(match self.layer(common_prefix_of_path)?.data { LayerDataType::Folder(_) => common_prefix_of_path, - LayerDataType::Shape(_) => &common_prefix_of_path[..common_prefix_of_path.len() - 1], + _ => &common_prefix_of_path[..common_prefix_of_path.len() - 1], }) } @@ -239,6 +240,7 @@ impl Document { } } } + LayerDataType::Text(_) => layer.cache_dirty = true, } layer.cache_dirty } @@ -435,6 +437,32 @@ impl Document { Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }]].concat()) } + Operation::AddText { + path, + insert_index, + transform, + text, + + style, + size, + } => { + let layer = Layer::new(LayerDataType::Text(Text::new(text.clone(), *style, *size)), *transform); + + self.set_layer(path, layer, *insert_index)?; + + Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(path)].concat()) + } + Operation::SetTextEditable { path, editable } => { + self.layer_mut(path)?.as_text_mut()?.editable = *editable; + self.mark_as_dirty(path)?; + Some(vec![DocumentChanged]) + } + Operation::SetTextContent { path, new_text } => { + self.layer_mut(path)?.as_text_mut()?.update_text(new_text.clone()); + self.mark_as_dirty(path)?; + + Some([vec![DocumentChanged], update_thumbnails_upstream(path)].concat()) + } Operation::AddNgon { path, insert_index, @@ -570,11 +598,8 @@ impl Document { Operation::SetShapePath { path, bez_path } => { self.mark_as_dirty(path)?; - match &mut self.layer_mut(path)?.data { - LayerDataType::Shape(shape) => { - shape.path = bez_path.clone(); - } - LayerDataType::Folder(_) => (), + if let LayerDataType::Shape(shape) = &mut self.layer_mut(path)?.data { + shape.path = bez_path.clone(); } Some(vec![DocumentChanged, LayerChanged { path: path.clone() }]) } @@ -583,11 +608,13 @@ impl Document { self.set_transform_relative_to_viewport(path, transform)?; self.mark_as_dirty(path)?; - match &mut self.layer_mut(path)?.data { - LayerDataType::Shape(shape) => { - shape.path = bez_path.clone(); - } - LayerDataType::Folder(_) => (), + if let LayerDataType::Text(t) = &mut self.layer_mut(path)?.data { + let bezpath = t.to_bez_path(); + self.layer_mut(path)?.data = layers::layer_info::LayerDataType::Shape(Shape::from_bez_path(bezpath, t.style, true)); + } + + if let LayerDataType::Shape(shape) = &mut self.layer_mut(path)?.data { + shape.path = bez_path.clone(); } Some([vec![DocumentChanged, LayerChanged { path: path.clone() }], update_thumbnails_upstream(path)].concat()) } diff --git a/graphene/src/error.rs b/graphene/src/error.rs index 917c3e17de..a7f81520f9 100644 --- a/graphene/src/error.rs +++ b/graphene/src/error.rs @@ -8,5 +8,6 @@ pub enum DocumentError { NotAFolder, NonReorderableSelection, NotAShape, + NotText, InvalidFile(String), } diff --git a/graphene/src/layers/layer_info.rs b/graphene/src/layers/layer_info.rs index 47917f5b01..ff3e74612d 100644 --- a/graphene/src/layers/layer_info.rs +++ b/graphene/src/layers/layer_info.rs @@ -2,6 +2,7 @@ use super::blend_mode::BlendMode; use super::folder::Folder; use super::simple_shape::Shape; use super::style::ViewMode; +use super::text::Text; use crate::intersection::Quad; use crate::DocumentError; use crate::LayerId; @@ -14,6 +15,7 @@ use std::fmt::Write; pub enum LayerDataType { Folder(Folder), Shape(Shape), + Text(Text), } impl LayerDataType { @@ -21,6 +23,7 @@ impl LayerDataType { match self { LayerDataType::Shape(s) => s, LayerDataType::Folder(f) => f, + LayerDataType::Text(t) => t, } } @@ -28,6 +31,7 @@ impl LayerDataType { match self { LayerDataType::Shape(s) => s, LayerDataType::Folder(f) => f, + LayerDataType::Text(t) => t, } } } @@ -158,6 +162,20 @@ impl Layer { _ => Err(DocumentError::NotAFolder), } } + + pub fn as_text_mut(&mut self) -> Result<&mut Text, DocumentError> { + match &mut self.data { + LayerDataType::Text(t) => Ok(t), + _ => Err(DocumentError::NotText), + } + } + + pub fn as_text(&self) -> Result<&Text, DocumentError> { + match &self.data { + LayerDataType::Text(t) => Ok(t), + _ => Err(DocumentError::NotText), + } + } } impl Clone for Layer { diff --git a/graphene/src/layers/mod.rs b/graphene/src/layers/mod.rs index 4763c743ea..5a02c5942e 100644 --- a/graphene/src/layers/mod.rs +++ b/graphene/src/layers/mod.rs @@ -3,3 +3,4 @@ pub mod folder; pub mod layer_info; pub mod simple_shape; pub mod style; +pub mod text; diff --git a/graphene/src/layers/text/SourceSansPro/OFL.txt b/graphene/src/layers/text/SourceSansPro/OFL.txt new file mode 100644 index 0000000000..bce8032814 --- /dev/null +++ b/graphene/src/layers/text/SourceSansPro/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name ‘Source’. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/graphene/src/layers/text/SourceSansPro/SourceSansPro-Regular.ttf b/graphene/src/layers/text/SourceSansPro/SourceSansPro-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..56238468c07e47636aeee0283d0c442843950d0e GIT binary patch literal 248504 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 MI=Pku4^a630MEzyEC2ui literal 0 HcmV?d00001 diff --git a/graphene/src/layers/text/mod.rs b/graphene/src/layers/text/mod.rs new file mode 100644 index 0000000000..8dd25ba5b4 --- /dev/null +++ b/graphene/src/layers/text/mod.rs @@ -0,0 +1,123 @@ +use super::layer_info::LayerData; +use super::style::{self, PathStyle, ViewMode}; +use crate::intersection::{intersect_quad_bez_path, Quad}; +use crate::LayerId; + +use glam::{DAffine2, DMat2, DVec2}; +use kurbo::{Affine, BezPath, Shape}; +use serde::{Deserialize, Serialize}; +use std::fmt::Write; + +mod to_kurbo; + +fn glam_to_kurbo(transform: DAffine2) -> Affine { + Affine::new(transform.to_cols_array()) +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct Text { + pub text: String, + pub style: style::PathStyle, + pub size: f64, + pub line_width: f64, + #[serde(skip)] + pub editable: bool, + #[serde(skip)] + cached_path: BezPath, +} + +impl LayerData for Text { + fn render(&mut self, svg: &mut String, transforms: &mut Vec, view_mode: ViewMode) { + let transform = self.transform(transforms, view_mode); + let inverse = transform.inverse(); + if !inverse.is_finite() { + let _ = write!(svg, ""); + return; + } + let _ = writeln!(svg, r#""#); + + if self.editable { + let _ = write!( + svg, + r#""#, + transform + .to_cols_array() + .iter() + .enumerate() + .map(|(i, entry)| { entry.to_string() + if i == 5 { "" } else { "," } }) + .collect::(), + self.line_width, + ); + let _ = write!(svg, r#""#, self.style.render(view_mode), self.text,); + } else { + let mut path = self.to_bez_path(); + + path.apply_affine(glam_to_kurbo(transform)); + + let _ = write!(svg, r#""#, path.to_svg(), self.style.render(view_mode)); + } + let _ = svg.write_str(""); + } + + fn bounding_box(&self, transform: glam::DAffine2) -> Option<[DVec2; 2]> { + let mut path = self.to_bez_path(); + + if transform.matrix2 == DMat2::ZERO { + return None; + } + path.apply_affine(glam_to_kurbo(transform)); + + let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box(); + Some([(x0, y0).into(), (x1, y1).into()]) + } + + fn intersects_quad(&self, quad: Quad, path: &mut Vec, intersections: &mut Vec>) { + if intersect_quad_bez_path(quad, &self.to_bez_path().bounding_box().to_path(0.), true) { + intersections.push(path.clone()); + } + } +} + +impl Text { + pub fn transform(&self, transforms: &[DAffine2], mode: ViewMode) -> DAffine2 { + let start = match mode { + ViewMode::Outline => 0, + _ => (transforms.len() as i32 - 1).max(0) as usize, + }; + transforms.iter().skip(start).cloned().reduce(|a, b| a * b).unwrap_or(DAffine2::IDENTITY) + } + + pub fn new(text: String, style: PathStyle, size: f64) -> Self { + let mut new = Self { + text, + style, + size, + line_width: 300., + editable: false, + cached_path: BezPath::new(), + }; + + new.regenerate_path(); + + new + } + + #[inline] + pub fn to_bez_path(&self) -> BezPath { + self.cached_path.clone() + } + + pub fn regenerate_path(&mut self) { + let buzz_face = rustybuzz::Face::from_slice(include_bytes!("SourceSansPro/SourceSansPro-Regular.ttf"), 0).unwrap(); + self.cached_path = to_kurbo::to_kurbo(&self.text, buzz_face, self.size, self.line_width); + } + + pub fn update_text(&mut self, text: String) { + self.text = text; + self.regenerate_path(); + } +} diff --git a/graphene/src/layers/text/to_kurbo.rs b/graphene/src/layers/text/to_kurbo.rs new file mode 100644 index 0000000000..8683cbf117 --- /dev/null +++ b/graphene/src/layers/text/to_kurbo.rs @@ -0,0 +1,120 @@ +use std::str::Chars; + +use kurbo::{BezPath, Point, Vec2}; +use rustybuzz::{GlyphPosition, UnicodeBuffer}; +use ttf_parser::{GlyphId, OutlineBuilder}; + +struct Builder { + path: BezPath, + pos: Point, + offset: Vec2, + ascender: f64, + scale: f64, +} + +impl OutlineBuilder for Builder { + fn move_to(&mut self, x: f32, y: f32) { + self.path.move_to(self.pos + self.offset + Vec2::new(x as f64, self.ascender - y as f64) * self.scale); + } + + fn line_to(&mut self, x: f32, y: f32) { + self.path.line_to(self.pos + self.offset + Vec2::new(x as f64, self.ascender - y as f64) * self.scale); + } + + fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) { + self.path.quad_to( + self.pos + self.offset + Vec2::new(x1 as f64, self.ascender - y1 as f64) * self.scale, + self.pos + self.offset + Vec2::new(x2 as f64, self.ascender - y2 as f64) * self.scale, + ); + } + + fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) { + self.path.curve_to( + self.pos + self.offset + Vec2::new(x1 as f64, self.ascender - y1 as f64) * self.scale, + self.pos + self.offset + Vec2::new(x2 as f64, self.ascender - y2 as f64) * self.scale, + self.pos + self.offset + Vec2::new(x3 as f64, self.ascender - y3 as f64) * self.scale, + ); + } + + fn close(&mut self) { + self.path.close_path(); + } +} + +fn word_over_length(mut str: Chars, positions: &[GlyphPosition], mut index: usize, mut pos: f64, scale: f64, line_width: f64) -> bool { + assert_eq!(str.nth(index), Some(' ')); + pos += positions[index].x_advance as f64 * scale; + + for c in str { + index += 1; + + if c == ' ' || c == '\n' { + return false; + } + + pos += positions[index].x_advance as f64 * scale; + + if pos > line_width { + return true; + } + } + false +} + +pub fn to_kurbo(str: &str, buzz_face: rustybuzz::Face, font_size: f64, line_width: f64) -> BezPath { + let scale = (buzz_face.units_per_em() as f64).recip() * font_size; + let line_hight = font_size; + + let mut buffer = UnicodeBuffer::new(); + buffer.push_str(str); + let glyph_buffer = rustybuzz::shape(&buzz_face, &[], buffer); + + let mut builder = Builder { + path: BezPath::new(), + pos: Point::ZERO, + offset: Vec2::ZERO, + ascender: buzz_face.ascender() as f64, + scale, + }; + + let positions = glyph_buffer.glyph_positions(); + + for (index, ((char, pos), info)) in str.chars().zip(positions).zip(glyph_buffer.glyph_infos()).enumerate() { + if char == '\n' || (char == ' ' && word_over_length(str.chars(), positions, index, builder.pos.x, scale, line_width)) { + builder.pos = Point::new(0., builder.pos.y + line_hight); + } else { + if builder.pos.x + (pos.x_advance as f64 * scale) >= line_width { + builder.pos = Point::new(0., builder.pos.y + line_hight); + } + builder.offset = Vec2::new(pos.x_offset as f64, pos.y_offset as f64) * scale; + buzz_face.outline_glyph(GlyphId(info.glyph_id as u16), &mut builder); + builder.pos += Vec2::new(pos.x_advance as f64, pos.y_advance as f64) * scale; + } + } + builder.path +} + +#[test] +fn test() { + use std::fs::File; + use std::io::Write; + + let buzz_face = rustybuzz::Face::from_slice(include_bytes!("SourceSansPro/SourceSansPro-Regular.ttf"), 0).unwrap(); + + let text = r#"The quick brown +fox jumped over the lazy cat. +In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before the final copy is available. It is also used to temporarily replace text in a process called greeking, which allows designers to consider the form of a webpage or publication, without the meaning of the text influencing the design. + +Lorem ipsum is typically a corrupted version of De finibus bonorum et malorum, a 1st-century BC text by the Roman statesman and philosopher Cicero, with words altered, added, and removed to make it nonsensical and improper Latin. + +Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"#; + let svg = to_kurbo(text, buzz_face, 20., 400.).to_svg(); + + let mut file = File::create("src/layers/text/SourceSansPro/font_text.svg").unwrap(); + write!( + &mut file, + r#""#, + svg + ) + .unwrap(); +} diff --git a/graphene/src/operation.rs b/graphene/src/operation.rs index 5e07c14297..772c70aa93 100644 --- a/graphene/src/operation.rs +++ b/graphene/src/operation.rs @@ -44,6 +44,22 @@ pub enum Operation { transform: [f64; 6], style: style::PathStyle, }, + AddText { + path: Vec, + transform: [f64; 6], + insert_index: isize, + text: String, + style: style::PathStyle, + size: f64, + }, + SetTextEditable { + path: Vec, + editable: bool, + }, + SetTextContent { + path: Vec, + new_text: String, + }, AddPen { path: Vec, transform: [f64; 6], From 009e3ac46acb58568463dcf55ad13265fc1e3373 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Mon, 24 Jan 2022 20:11:45 +0000 Subject: [PATCH 02/22] Double click with the select tool to edit text --- editor/src/input/input_mapper.rs | 11 ++++++-- editor/src/input/input_mapper_message.rs | 1 + .../src/input/input_preprocessor_message.rs | 1 + .../input_preprocessor_message_handler.rs | 8 ++++++ editor/src/viewport_tools/tools/select.rs | 27 ++++++++++++++++--- editor/src/viewport_tools/tools/text.rs | 5 ++-- frontend/src/lifetime/input.ts | 10 +++++++ frontend/wasm/src/api.rs | 9 +++++++ 8 files changed, 63 insertions(+), 9 deletions(-) diff --git a/editor/src/input/input_mapper.rs b/editor/src/input/input_mapper.rs index c8de42a434..ade4462ded 100644 --- a/editor/src/input/input_mapper.rs +++ b/editor/src/input/input_mapper.rs @@ -14,6 +14,7 @@ pub struct Mapping { pub key_down: [KeyMappingEntries; NUMBER_OF_KEYS], pub pointer_move: KeyMappingEntries, pub mouse_scroll: KeyMappingEntries, + pub double_click: KeyMappingEntries, } impl Default for Mapping { @@ -44,6 +45,7 @@ impl Default for Mapping { entry! {action=SelectMessage::MouseMove { snap_angle: KeyShift }, message=InputMapperMessage::PointerMove}, entry! {action=SelectMessage::DragStart { add_to_selection: KeyShift }, key_down=Lmb}, entry! {action=SelectMessage::DragStop, key_up=Lmb}, + entry! {action=SelectMessage::EditText, message=InputMapperMessage::DoubleClick}, entry! {action=SelectMessage::Abort, key_down=Rmb}, entry! {action=SelectMessage::Abort, key_down=KeyEscape}, // Navigate @@ -201,7 +203,7 @@ impl Default for Mapping { entry! {action=GlobalMessage::LogDebug, key_down=Key2}, entry! {action=GlobalMessage::LogTrace, key_down=Key3}, ]; - let (mut key_up, mut key_down, mut pointer_move, mut mouse_scroll) = mappings; + let (mut key_up, mut key_down, mut pointer_move, mut mouse_scroll, mut double_click) = mappings; // TODO: Hardcode these 10 lines into 10 lines of declarations, or make this use a macro to do all 10 in one line const NUMBER_KEYS: [Key; 10] = [Key0, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9]; @@ -224,12 +226,14 @@ impl Default for Mapping { } sort(&mut pointer_move); sort(&mut mouse_scroll); + sort(&mut double_click); Self { key_up, key_down, pointer_move, mouse_scroll, + double_click, } } } @@ -241,6 +245,7 @@ impl Mapping { let list = match message { KeyDown(key) => &self.key_down[key as usize], KeyUp(key) => &self.key_up[key as usize], + DoubleClick => &self.double_click, MouseScroll => &self.mouse_scroll, PointerMove => &self.pointer_move, }; @@ -329,6 +334,7 @@ mod input_mapper_macros { let mut key_down = KeyMappingEntries::key_array(); let mut pointer_move: KeyMappingEntries = Default::default(); let mut mouse_scroll: KeyMappingEntries = Default::default(); + let mut double_click: KeyMappingEntries = Default::default(); $( for entry in $entry { let arr = match entry.trigger { @@ -336,11 +342,12 @@ mod input_mapper_macros { InputMapperMessage::KeyUp(key) => &mut key_up[key as usize], InputMapperMessage::MouseScroll => &mut mouse_scroll, InputMapperMessage::PointerMove => &mut pointer_move, + InputMapperMessage::DoubleClick => &mut double_click, }; arr.push(entry.clone()); } )* - (key_up, key_down, pointer_move, mouse_scroll) + (key_up, key_down, pointer_move, mouse_scroll, double_click) }}; } diff --git a/editor/src/input/input_mapper_message.rs b/editor/src/input/input_mapper_message.rs index 829376b60d..454ebcaa56 100644 --- a/editor/src/input/input_mapper_message.rs +++ b/editor/src/input/input_mapper_message.rs @@ -16,6 +16,7 @@ pub enum InputMapperMessage { KeyUp(Key), // Messages + DoubleClick, MouseScroll, PointerMove, } diff --git a/editor/src/input/input_preprocessor_message.rs b/editor/src/input/input_preprocessor_message.rs index 04c287c813..53297fa891 100644 --- a/editor/src/input/input_preprocessor_message.rs +++ b/editor/src/input/input_preprocessor_message.rs @@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize}; #[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] pub enum InputPreprocessorMessage { BoundsOfViewports { bounds_of_viewports: Vec }, + DoubleClick { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, KeyDown { key: Key, modifier_keys: ModifierKeys }, KeyUp { key: Key, modifier_keys: ModifierKeys }, MouseDown { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, diff --git a/editor/src/input/input_preprocessor_message_handler.rs b/editor/src/input/input_preprocessor_message_handler.rs index 025bc70a55..93a4d58eca 100644 --- a/editor/src/input/input_preprocessor_message_handler.rs +++ b/editor/src/input/input_preprocessor_message_handler.rs @@ -49,6 +49,14 @@ impl MessageHandler for InputPreprocessorMessageHa ); } } + InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => { + self.handle_modifier_keys(modifier_keys, responses); + + let mouse_state = editor_mouse_state.to_mouse_state(&self.viewport_bounds); + self.mouse.position = mouse_state.position; + + responses.push_back(InputMapperMessage::DoubleClick.into()); + } InputPreprocessorMessage::KeyDown { key, modifier_keys } => { self.handle_modifier_keys(modifier_keys, responses); self.keyboard.set(key as usize); diff --git a/editor/src/viewport_tools/tools/select.rs b/editor/src/viewport_tools/tools/select.rs index 8d3dff87ca..aad74b0255 100644 --- a/editor/src/viewport_tools/tools/select.rs +++ b/editor/src/viewport_tools/tools/select.rs @@ -8,7 +8,7 @@ use crate::input::InputPreprocessorMessageHandler; use crate::message_prelude::*; use crate::misc::{HintData, HintGroup, HintInfo, KeysGroup}; use crate::viewport_tools::snapping::SnapHandler; -use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData}; +use crate::viewport_tools::tool::{DocumentToolData, Fsm, ToolActionHandlerData, ToolType}; use graphene::document::Document; use graphene::intersection::Quad; @@ -43,6 +43,7 @@ pub enum SelectMessage { add_to_selection: Key, }, DragStop, + EditText, FlipHorizontal, FlipVertical, MouseMove { @@ -75,9 +76,9 @@ impl<'a> MessageHandler> for Select { use SelectToolFsmState::*; match self.fsm_state { - Ready => actions!(SelectMessageDiscriminant; DragStart), - Dragging => actions!(SelectMessageDiscriminant; DragStop, MouseMove), - DrawingBox => actions!(SelectMessageDiscriminant; DragStop, MouseMove, Abort), + Ready => actions!(SelectMessageDiscriminant; DragStart, EditText), + Dragging => actions!(SelectMessageDiscriminant; DragStop, MouseMove, EditText), + DrawingBox => actions!(SelectMessageDiscriminant; DragStop, MouseMove, Abort, EditText), } } } @@ -173,6 +174,24 @@ impl Fsm for SelectToolFsmState { buffer.into_iter().rev().for_each(|message| responses.push_front(message)); self } + (_, EditText) => { + let mouse_pos = input.mouse.position; + let tolerance = DVec2::splat(SELECTION_TOLERANCE); + let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]); + + if document + .graphene_document + .intersects_quad_root(quad) + .last() + .map(|l| document.graphene_document.layer(l).map(|l| l.as_text().is_ok()).unwrap_or(false)) + .unwrap_or(false) + { + responses.push_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }.into()); + responses.push_back(TextMessage::LeftMouseDown.into()); + } + + self + } (Ready, DragStart { add_to_selection }) => { data.drag_start = input.mouse.position; data.drag_current = input.mouse.position; diff --git a/editor/src/viewport_tools/tools/text.rs b/editor/src/viewport_tools/tools/text.rs index ef049cdebf..a008c56717 100644 --- a/editor/src/viewport_tools/tools/text.rs +++ b/editor/src/viewport_tools/tools/text.rs @@ -149,9 +149,8 @@ Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); Editing - } else - // Removing old text as editable - { + } else { + // Removing old text as editable let editable = false; responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); Ready diff --git a/frontend/src/lifetime/input.ts b/frontend/src/lifetime/input.ts index 589bcd6f1c..ae15f58878 100644 --- a/frontend/src/lifetime/input.ts +++ b/frontend/src/lifetime/input.ts @@ -22,6 +22,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement, { target: window, eventName: "pointermove", action: (e: PointerEvent): void => onPointerMove(e) }, { target: window, eventName: "pointerdown", action: (e: PointerEvent): void => onPointerDown(e) }, { target: window, eventName: "pointerup", action: (e: PointerEvent): void => onPointerUp(e) }, + { target: window, eventName: "dblclick", action: (e: PointerEvent): void => onDoubleClick(e) }, { target: window, eventName: "mousedown", action: (e: MouseEvent): void => onMouseDown(e) }, { target: window, eventName: "wheel", action: (e: WheelEvent): void => onMouseScroll(e), options: { passive: false } }, ]; @@ -137,6 +138,15 @@ export function createInputManager(editor: EditorState, container: HTMLElement, } }; + const onDoubleClick = (e: PointerEvent): void => { + if (!e.buttons) viewportPointerInteractionOngoing = false; + + if (!textInput) { + const modifiers = makeModifiersBitfield(e); + editor.instance.on_double_click(e.clientX, e.clientY, e.buttons, modifiers); + } + }; + // Mouse events const onMouseDown = (e: MouseEvent): void => { diff --git a/frontend/wasm/src/api.rs b/frontend/wasm/src/api.rs index 43eeed678c..ba524eccdc 100644 --- a/frontend/wasm/src/api.rs +++ b/frontend/wasm/src/api.rs @@ -274,6 +274,15 @@ impl JsEditorHandle { self.dispatch(message); } + /// Mouse double clicked + pub fn on_double_click(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) { + let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); + let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); + + let message = InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys }; + self.dispatch(message); + } + /// A keyboard button depressed within screenspace the bounds of the viewport pub fn on_key_down(&self, name: String, modifiers: u8) { let key = translate_key(&name); From bfacd20791c10e2b5bdb01149ff09661afa68968 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Mon, 24 Jan 2022 20:21:16 +0000 Subject: [PATCH 03/22] Fix (I think?) transitioning to select tool --- editor/src/viewport_tools/tools/text.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/editor/src/viewport_tools/tools/text.rs b/editor/src/viewport_tools/tools/text.rs index a008c56717..7122dc193c 100644 --- a/editor/src/viewport_tools/tools/text.rs +++ b/editor/src/viewport_tools/tools/text.rs @@ -159,7 +159,8 @@ Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa new_state } (Editing, Abort) => { - responses.push_back(DocumentMessage::AbortTransaction.into()); + let editable = false; + responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); Ready } (_, TextChange { new_text }) => { From a461640492e6a635a5536d9ba3d98b7f2b7e0cca Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Mon, 24 Jan 2022 20:59:38 +0000 Subject: [PATCH 04/22] Commit and abort text editing --- editor/src/frontend/frontend_message.rs | 1 + editor/src/input/input_mapper.rs | 2 ++ editor/src/viewport_tools/tools/text.rs | 45 +++++++++++++++++-------- frontend/src/dispatcher/js-messages.ts | 3 ++ frontend/src/lifetime/input.ts | 16 ++++++--- frontend/wasm/src/api.rs | 4 +-- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/editor/src/frontend/frontend_message.rs b/editor/src/frontend/frontend_message.rs index 6bcaff992c..1f1ac4e3f6 100644 --- a/editor/src/frontend/frontend_message.rs +++ b/editor/src/frontend/frontend_message.rs @@ -24,6 +24,7 @@ pub enum FrontendMessage { TriggerFileUpload, TriggerIndexedDbRemoveDocument { document_id: u64 }, TriggerIndexedDbWriteDocument { document: String, details: FrontendDocumentDetails, version: String }, + TriggerTextCommit, // Update prefix: give the frontend a new value or state for it to use UpdateActiveDocument { document_id: u64 }, diff --git a/editor/src/input/input_mapper.rs b/editor/src/input/input_mapper.rs index ade4462ded..0589b48db9 100644 --- a/editor/src/input/input_mapper.rs +++ b/editor/src/input/input_mapper.rs @@ -63,6 +63,8 @@ impl Default for Mapping { entry! {action=EyedropperMessage::RightMouseDown, key_down=Rmb}, // Text entry! {action=TextMessage::LeftMouseDown, key_down=Lmb}, + entry! {action=TextMessage::Abort, key_down=KeyEscape}, + entry! {action=TextMessage::CommitText, key_down=KeyControl, modifiers=[KeyControl]}, // Rectangle entry! {action=RectangleMessage::DragStart, key_down=Lmb}, entry! {action=RectangleMessage::DragStop, key_up=Lmb}, diff --git a/editor/src/viewport_tools/tools/text.rs b/editor/src/viewport_tools/tools/text.rs index 7122dc193c..851ad4493a 100644 --- a/editor/src/viewport_tools/tools/text.rs +++ b/editor/src/viewport_tools/tools/text.rs @@ -29,9 +29,11 @@ pub enum TextMessage { Abort, // Tool-specific messages + CommitText, LeftMouseDown, TextChange { new_text: String, + cancel_editing: bool, }, } @@ -56,7 +58,14 @@ impl<'a> MessageHandler> for Text { } } - advertise_actions!(TextMessageDiscriminant; LeftMouseDown); + fn actions(&self) -> ActionList { + use TextToolFsmState::*; + + match self.fsm_state { + Ready => actions!(TextMessageDiscriminant; LeftMouseDown), + Editing => actions!(TextMessageDiscriminant; LeftMouseDown, Abort, CommitText), + } + } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -163,13 +172,21 @@ Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); Ready } - (_, TextChange { new_text }) => { - let editable = false; - responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); - + (Editing, CommitText) => { + responses.push_back(FrontendMessage::TriggerTextCommit.into()); + Editing + } + (Editing, TextChange { new_text, cancel_editing }) => { responses.push_back(Operation::SetTextContent { path: data.path.clone(), new_text }.into()); - Ready + if cancel_editing { + let editable = false; + responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + + Ready + } else { + Editing + } } _ => self, } @@ -198,25 +215,25 @@ Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa HintInfo { key_groups: vec![], mouse: Some(MouseMotion::Lmb), - label: String::from("Complete edit"), + label: String::from("Complete Edit"), plus: false, }, HintInfo { - key_groups: vec![KeysGroup(vec![Key::KeyEscape])], + key_groups: vec![KeysGroup(vec![Key::KeyControl, Key::KeyEnter])], mouse: None, - label: String::from("Cancel edit"), + label: String::from("Commit edit"), plus: false, }, HintInfo { - key_groups: vec![KeysGroup(vec![Key::KeyEnter])], + key_groups: vec![KeysGroup(vec![Key::KeyEscape])], mouse: None, - label: String::from("New line"), + label: String::from("Abort Edit"), plus: false, }, HintInfo { - key_groups: vec![], - mouse: Some(MouseMotion::Lmb), - label: String::from("Complete edit"), + key_groups: vec![KeysGroup(vec![Key::KeyEnter])], + mouse: None, + label: String::from("New line"), plus: false, }, ])]), diff --git a/frontend/src/dispatcher/js-messages.ts b/frontend/src/dispatcher/js-messages.ts index 5381ddaf9a..2c8d5df168 100644 --- a/frontend/src/dispatcher/js-messages.ts +++ b/frontend/src/dispatcher/js-messages.ts @@ -376,6 +376,8 @@ export class TriggerIndexedDbRemoveDocument extends JsMessage { document_id!: string; } +export class TriggerTextCommit extends JsMessage {} + // Any is used since the type of the object should be known from the rust side // eslint-disable-next-line @typescript-eslint/no-explicit-any type JSMessageFactory = (data: any, wasm: WasmInstance, instance: RustEditorInstance) => JsMessage; @@ -405,6 +407,7 @@ export const messageConstructors: Record = { DisplayDialogAboutGraphite, TriggerIndexedDbWriteDocument, TriggerIndexedDbRemoveDocument, + TriggerTextCommit, UpdateDocumentArtboards, } as const; export type JsMessageType = keyof typeof messageConstructors; diff --git a/frontend/src/lifetime/input.ts b/frontend/src/lifetime/input.ts index 6f520e96b5..d5563827c1 100644 --- a/frontend/src/lifetime/input.ts +++ b/frontend/src/lifetime/input.ts @@ -1,3 +1,4 @@ +import { TriggerTextCommit } from "@/dispatcher/js-messages"; import { DialogState } from "@/state/dialog"; import { DocumentsState } from "@/state/documents"; import { FullscreenState } from "@/state/fullscreen"; @@ -33,16 +34,17 @@ export function createInputManager(editor: EditorState, container: HTMLElement, // Keyboard events const shouldRedirectKeyboardEventToBackend = (e: KeyboardEvent): boolean => { - // Don't redirect user input from text entry into HTML elements - const { target } = e; - if (target instanceof HTMLElement && (target.nodeName === "INPUT" || target.nodeName === "TEXTAREA" || target.isContentEditable)) return false; - // Don't redirect when a modal is covering the workspace if (dialog.dialogIsVisible()) return false; const key = getLatinKey(e); if (!key) return false; + // Don't redirect user input from text entry into HTML elements + const { target } = e; + if (key !== "escape" && !(key === "enter" && e.ctrlKey) && target instanceof HTMLElement && (target.nodeName === "INPUT" || target.nodeName === "TEXTAREA" || target.isContentEditable)) + return false; + // Don't redirect a fullscreen request if (key === "f11" && e.type === "keydown" && !e.repeat) { e.preventDefault(); @@ -119,7 +121,7 @@ export function createInputManager(editor: EditorState, container: HTMLElement, if (target instanceof HTMLTextAreaElement) { textInput = target; } else if (textInput) { - editor.instance.on_change_text(textInput.value); + editor.instance.on_change_text(textInput.value, true); textInput = undefined; } else if (inCanvas) viewportPointerInteractionOngoing = true; @@ -214,6 +216,10 @@ export function createInputManager(editor: EditorState, container: HTMLElement, listeners.forEach(({ target, eventName, action }) => target.removeEventListener(eventName, action)); }; + editor.dispatcher.subscribeJsMessage(TriggerTextCommit, () => { + if (textInput) editor.instance.on_change_text(textInput.value, false); + }); + // Run on creation addListeners(); onWindowResize(container); diff --git a/frontend/wasm/src/api.rs b/frontend/wasm/src/api.rs index ba524eccdc..648b63f7f1 100644 --- a/frontend/wasm/src/api.rs +++ b/frontend/wasm/src/api.rs @@ -306,8 +306,8 @@ impl JsEditorHandle { } /// A text box was changed - pub fn on_change_text(&self, new_text: String) -> Result<(), JsValue> { - let message = TextMessage::TextChange { new_text }; + pub fn on_change_text(&self, new_text: String, cancel_editing: bool) -> Result<(), JsValue> { + let message = TextMessage::TextChange { new_text, cancel_editing }; self.dispatch(message); Ok(()) From 03cb9444d3ccb19ae035f5c9b2ebd2348d35703d Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 26 Jan 2022 20:01:56 +0000 Subject: [PATCH 05/22] Transition to a contenteditable div and autosize --- editor/src/document/document_message.rs | 4 + .../src/document/document_message_handler.rs | 15 ++++ editor/src/frontend/frontend_message.rs | 2 + editor/src/input/input_mapper.rs | 2 +- editor/src/viewport_tools/tools/select.rs | 2 +- editor/src/viewport_tools/tools/text.rs | 20 ++--- frontend/src/App.vue | 1 + frontend/src/components/panels/Document.vue | 90 ++++++++++++++++--- frontend/src/dispatcher/js-messages.ts | 10 +++ frontend/src/lifetime/input.ts | 33 ++++--- graphene/src/layers/text/mod.rs | 9 +- graphene/src/layers/text/to_kurbo.rs | 34 +++---- 12 files changed, 162 insertions(+), 60 deletions(-) diff --git a/editor/src/document/document_message.rs b/editor/src/document/document_message.rs index 4532129ea7..b1b655444c 100644 --- a/editor/src/document/document_message.rs +++ b/editor/src/document/document_message.rs @@ -111,6 +111,10 @@ pub enum DocumentMessage { SetSnapping { snap: bool, }, + SetTextboxEditable { + path: Vec, + editable: bool, + }, SetViewMode { view_mode: ViewMode, }, diff --git a/editor/src/document/document_message_handler.rs b/editor/src/document/document_message_handler.rs index 564624e7f7..c7c9e413ca 100644 --- a/editor/src/document/document_message_handler.rs +++ b/editor/src/document/document_message_handler.rs @@ -949,6 +949,21 @@ impl MessageHandler for Docum SetSnapping { snap } => { self.snapping_enabled = snap; } + SetTextboxEditable { path, editable } => { + let text = self.graphene_document.layer(&path).unwrap().as_text().unwrap(); + responses.push_back(DocumentOperation::SetTextEditable { path, editable }.into()); + if editable { + responses.push_back( + FrontendMessage::DisplayEditableTextbox { + text: text.text.clone(), + line_width: text.line_width, + } + .into(), + ); + } else { + responses.push_back(FrontendMessage::DisplayRemoveEditableTextbox.into()); + } + } SetViewMode { view_mode } => { self.view_mode = view_mode; responses.push_front(DocumentMessage::DirtyRenderDocument.into()); diff --git a/editor/src/frontend/frontend_message.rs b/editor/src/frontend/frontend_message.rs index 1f1ac4e3f6..ef6e181c71 100644 --- a/editor/src/frontend/frontend_message.rs +++ b/editor/src/frontend/frontend_message.rs @@ -18,6 +18,8 @@ pub enum FrontendMessage { DisplayDialogError { title: String, description: String }, DisplayDialogPanic { panic_info: String, title: String, description: String }, DisplayDocumentLayerTreeStructure { data_buffer: RawBuffer }, + DisplayEditableTextbox { text: String, line_width: Option }, + DisplayRemoveEditableTextbox, // Trigger prefix: cause a browser API to do something TriggerFileDownload { document: String, name: String }, diff --git a/editor/src/input/input_mapper.rs b/editor/src/input/input_mapper.rs index 0589b48db9..8aa1ea94aa 100644 --- a/editor/src/input/input_mapper.rs +++ b/editor/src/input/input_mapper.rs @@ -62,7 +62,7 @@ impl Default for Mapping { entry! {action=EyedropperMessage::LeftMouseDown, key_down=Lmb}, entry! {action=EyedropperMessage::RightMouseDown, key_down=Rmb}, // Text - entry! {action=TextMessage::LeftMouseDown, key_down=Lmb}, + entry! {action=TextMessage::Interact, key_up=Lmb}, entry! {action=TextMessage::Abort, key_down=KeyEscape}, entry! {action=TextMessage::CommitText, key_down=KeyControl, modifiers=[KeyControl]}, // Rectangle diff --git a/editor/src/viewport_tools/tools/select.rs b/editor/src/viewport_tools/tools/select.rs index aad74b0255..cb0af22175 100644 --- a/editor/src/viewport_tools/tools/select.rs +++ b/editor/src/viewport_tools/tools/select.rs @@ -187,7 +187,7 @@ impl Fsm for SelectToolFsmState { .unwrap_or(false) { responses.push_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }.into()); - responses.push_back(TextMessage::LeftMouseDown.into()); + responses.push_back(TextMessage::Interact.into()); } self diff --git a/editor/src/viewport_tools/tools/text.rs b/editor/src/viewport_tools/tools/text.rs index 851ad4493a..3008264639 100644 --- a/editor/src/viewport_tools/tools/text.rs +++ b/editor/src/viewport_tools/tools/text.rs @@ -30,7 +30,7 @@ pub enum TextMessage { // Tool-specific messages CommitText, - LeftMouseDown, + Interact, TextChange { new_text: String, cancel_editing: bool, @@ -62,8 +62,8 @@ impl<'a> MessageHandler> for Text { use TextToolFsmState::*; match self.fsm_state { - Ready => actions!(TextMessageDiscriminant; LeftMouseDown), - Editing => actions!(TextMessageDiscriminant; LeftMouseDown, Abort, CommitText), + Ready => actions!(TextMessageDiscriminant; Interact), + Editing => actions!(TextMessageDiscriminant; Interact, Abort, CommitText), } } } @@ -102,7 +102,7 @@ impl Fsm for TextToolFsmState { if let ToolMessage::Text(event) = event { match (self, event) { - (state, LeftMouseDown) => { + (state, Interact) => { let mouse_pos = input.mouse.position; let tolerance = DVec2::splat(SELECTION_TOLERANCE); let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]); @@ -116,13 +116,13 @@ impl Fsm for TextToolFsmState { { if state == TextToolFsmState::Editing { let editable = false; - responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + responses.push_back(DocumentMessage::SetTextboxEditable { path: data.path.clone(), editable }.into()); } data.path = l.clone(); let editable = true; - responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + responses.push_back(DocumentMessage::SetTextboxEditable { path: data.path.clone(), editable }.into()); Editing } @@ -155,13 +155,13 @@ Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa responses.push_back(Operation::SetLayerTransformInViewport { path: data.path.clone(), transform }.into()); let editable = true; - responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + responses.push_back(DocumentMessage::SetTextboxEditable { path: data.path.clone(), editable }.into()); Editing } else { // Removing old text as editable let editable = false; - responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + responses.push_back(DocumentMessage::SetTextboxEditable { path: data.path.clone(), editable }.into()); Ready }; @@ -169,7 +169,7 @@ Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa } (Editing, Abort) => { let editable = false; - responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + responses.push_back(DocumentMessage::SetTextboxEditable { path: data.path.clone(), editable }.into()); Ready } (Editing, CommitText) => { @@ -181,7 +181,7 @@ Test for really long word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if cancel_editing { let editable = false; - responses.push_back(Operation::SetTextEditable { path: data.path.clone(), editable }.into()); + responses.push_back(DocumentMessage::SetTextboxEditable { path: data.path.clone(), editable }.into()); Ready } else { diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 22b3735d5f..b4192a2243 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -262,6 +262,7 @@ export default defineComponent({ dialog: this.dialog, documents: this.documents, fullscreen: this.fullscreen, + inputManager: this.inputManager, }; }, data() { diff --git a/frontend/src/components/panels/Document.vue b/frontend/src/components/panels/Document.vue index fe90e65c89..12e4d010ca 100644 --- a/frontend/src/components/panels/Document.vue +++ b/frontend/src/components/panels/Document.vue @@ -246,15 +246,28 @@ pointer-events: auto; } } - textarea { - color: black; - background: none; - cursor: text; - width: 100%; - height: 100%; - border: none; - margin: 0; - padding: 0; + foreignObject { + overflow: visible; + width: 1px; + height: 1px; + + div { + color: black; + background: none; + cursor: text; + border: none; + margin: 0; + padding: 0; + overflow: visible; + white-space: pre-wrap; + display: inline-block; + } + + div:focus { + border: 1px solid var(--color-accent-hover); + outline: none; + margin: -1px; + } } } } @@ -263,7 +276,7 @@