diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 311952eef1..2a4c5cba21 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -56,7 +56,7 @@ pub enum TextToolMessage { CommitText, EditSelected, Interact, - TextChange { new_text: String }, + TextChange { new_text: String, is_right_click: bool }, UpdateBounds { new_text: String }, UpdateOptions(TextOptionsUpdate), } @@ -241,6 +241,19 @@ struct TextToolData { } impl TextToolData { + fn delete_empty_layer(&mut self, font_cache: &FontCache, responses: &mut VecDeque) -> TextToolFsmState { + // Remove the editable textbox UI first + self.set_editing(false, font_cache, responses); + + // Delete the empty text layer and update the graph + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![self.layer.to_node()], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + + TextToolFsmState::Ready + } /// Set the editing state of the currently modifying layer fn set_editing(&self, editable: bool, font_cache: &FontCache, responses: &mut VecDeque) { if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) { @@ -253,9 +266,13 @@ impl TextToolData { transform: editing_text.transform.to_cols_array(), }); } else { + // Check if DisplayRemoveEditableTextbox is already in the responses queue + let has_remove_textbox = responses.iter().any(|msg| matches!(msg, Message::Frontend(FrontendMessage::DisplayRemoveEditableTextbox))); responses.add(FrontendMessage::DisplayRemoveEditableTextbox); - // Clear all selected nodes when no longer editing - responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() }); + + if has_remove_textbox { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() }); + } } } @@ -474,20 +491,34 @@ impl Fsm for TextToolFsmState { TextToolFsmState::Ready } (TextToolFsmState::Editing, TextToolMessage::CommitText) => { - responses.add(FrontendMessage::TriggerTextCommit); + if tool_data.new_text.is_empty() { + return tool_data.delete_empty_layer(font_cache, responses); + } + responses.add(FrontendMessage::TriggerTextCommit); TextToolFsmState::Editing } - (TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => { - tool_data.set_editing(false, font_cache, responses); + (TextToolFsmState::Editing, TextToolMessage::TextChange { new_text, is_right_click }) => { + tool_data.new_text = new_text; - responses.add(NodeGraphMessage::SetInput { - input_connector: InputConnector::node(graph_modification_utils::get_text_id(tool_data.layer, &document.network_interface).unwrap(), 1), - input: NodeInput::value(TaggedValue::String(new_text), false), - }); - responses.add(NodeGraphMessage::RunDocumentGraph); + if !is_right_click { + tool_data.set_editing(false, font_cache, responses); - TextToolFsmState::Ready + responses.add(NodeGraphMessage::SetInput { + input_connector: InputConnector::node(graph_modification_utils::get_text_id(tool_data.layer, &document.network_interface).unwrap(), 1), + input: NodeInput::value(TaggedValue::String(tool_data.new_text.clone()), false), + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + + TextToolFsmState::Ready + } else { + if tool_data.new_text.is_empty() { + return tool_data.delete_empty_layer(font_cache, responses); + } + + responses.add(FrontendMessage::TriggerTextCommit); + TextToolFsmState::Editing + } } (TextToolFsmState::Editing, TextToolMessage::UpdateBounds { new_text }) => { tool_data.new_text = new_text; diff --git a/frontend/src/components/panels/Document.svelte b/frontend/src/components/panels/Document.svelte index 52139b5b7f..64433a38e7 100644 --- a/frontend/src/components/panels/Document.svelte +++ b/frontend/src/components/panels/Document.svelte @@ -300,7 +300,7 @@ export function triggerTextCommit() { if (!textInput) return; const textCleaned = textInputCleanup(textInput.innerText); - editor.handle.onChangeText(textCleaned); + editor.handle.onChangeText(textCleaned, false); } export async function displayEditableTextbox(displayEditableTextbox: DisplayEditableTextbox) { diff --git a/frontend/src/io-managers/input.ts b/frontend/src/io-managers/input.ts index 484f4f735e..f67f56cfeb 100644 --- a/frontend/src/io-managers/input.ts +++ b/frontend/src/io-managers/input.ts @@ -172,7 +172,8 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli } if (!inTextInput && !inContextMenu) { - if (textToolInteractiveInputElement) editor.handle.onChangeText(textInputCleanup(textToolInteractiveInputElement.innerText)); + const isRightClick = e.button === 2; + if (textToolInteractiveInputElement) editor.handle.onChangeText(textInputCleanup(textToolInteractiveInputElement.innerText), isRightClick); else viewportPointerInteractionOngoing = isTargetingCanvas instanceof Element; } diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 94341aa1e4..c1b0f2c129 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -433,8 +433,8 @@ impl EditorHandle { /// A text box was committed #[wasm_bindgen(js_name = onChangeText)] - pub fn on_change_text(&self, new_text: String) -> Result<(), JsValue> { - let message = TextToolMessage::TextChange { new_text }; + pub fn on_change_text(&self, new_text: String, is_right_click: bool) -> Result<(), JsValue> { + let message = TextToolMessage::TextChange { new_text, is_right_click }; self.dispatch(message); Ok(())