From f22575665579def32ed211075eb0d662e93e9c96 Mon Sep 17 00:00:00 2001 From: Sidharth-Singh10 <70999945+Sidharth-Singh10@users.noreply.github.com> Date: Wed, 1 Jan 2025 03:58:56 +0530 Subject: [PATCH] Fix text layer getting deselected after clicking out of Text tool interactive editing (#2144) * properties panel remains active when user edits text layer * Keep text layers selected after editing * Update editor/src/messages/portfolio/document/document_message_handler.rs * Delete Empty Text Layer on Escape or Right Click * Fix: delete empty text layer on right click --------- Co-authored-by: Keavon Chambers --- .../messages/tool/tool_messages/text_tool.rs | 55 +++++++++++++++---- .../src/components/panels/Document.svelte | 2 +- frontend/src/io-managers/input.ts | 3 +- frontend/wasm/src/editor_api.rs | 4 +- 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 311952ee..2a4c5cba 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 52139b5b..64433a38 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 484f4f73..f67f56cf 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 94341aa1..c1b0f2c1 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(())