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 <keavon@keavon.com>
This commit is contained in:
Sidharth-Singh10
2024-12-31 14:28:56 -08:00
committed by GitHub
co-authored by Keavon Chambers
parent 39a7b76ade
commit f225756655
4 changed files with 48 additions and 16 deletions
@@ -56,7 +56,7 @@ pub enum TextToolMessage {
CommitText, CommitText,
EditSelected, EditSelected,
Interact, Interact,
TextChange { new_text: String }, TextChange { new_text: String, is_right_click: bool },
UpdateBounds { new_text: String }, UpdateBounds { new_text: String },
UpdateOptions(TextOptionsUpdate), UpdateOptions(TextOptionsUpdate),
} }
@@ -241,6 +241,19 @@ struct TextToolData {
} }
impl TextToolData { impl TextToolData {
fn delete_empty_layer(&mut self, font_cache: &FontCache, responses: &mut VecDeque<Message>) -> 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 /// Set the editing state of the currently modifying layer
fn set_editing(&self, editable: bool, font_cache: &FontCache, responses: &mut VecDeque<Message>) { fn set_editing(&self, editable: bool, font_cache: &FontCache, responses: &mut VecDeque<Message>) {
if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) { 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(), transform: editing_text.transform.to_cols_array(),
}); });
} else { } 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); 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::Ready
} }
(TextToolFsmState::Editing, TextToolMessage::CommitText) => { (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
} }
(TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => { (TextToolFsmState::Editing, TextToolMessage::TextChange { new_text, is_right_click }) => {
tool_data.set_editing(false, font_cache, responses); tool_data.new_text = new_text;
responses.add(NodeGraphMessage::SetInput { if !is_right_click {
input_connector: InputConnector::node(graph_modification_utils::get_text_id(tool_data.layer, &document.network_interface).unwrap(), 1), tool_data.set_editing(false, font_cache, responses);
input: NodeInput::value(TaggedValue::String(new_text), false),
});
responses.add(NodeGraphMessage::RunDocumentGraph);
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 }) => { (TextToolFsmState::Editing, TextToolMessage::UpdateBounds { new_text }) => {
tool_data.new_text = new_text; tool_data.new_text = new_text;
@@ -300,7 +300,7 @@
export function triggerTextCommit() { export function triggerTextCommit() {
if (!textInput) return; if (!textInput) return;
const textCleaned = textInputCleanup(textInput.innerText); const textCleaned = textInputCleanup(textInput.innerText);
editor.handle.onChangeText(textCleaned); editor.handle.onChangeText(textCleaned, false);
} }
export async function displayEditableTextbox(displayEditableTextbox: DisplayEditableTextbox) { export async function displayEditableTextbox(displayEditableTextbox: DisplayEditableTextbox) {
+2 -1
View File
@@ -172,7 +172,8 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli
} }
if (!inTextInput && !inContextMenu) { 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; else viewportPointerInteractionOngoing = isTargetingCanvas instanceof Element;
} }
+2 -2
View File
@@ -433,8 +433,8 @@ impl EditorHandle {
/// A text box was committed /// A text box was committed
#[wasm_bindgen(js_name = onChangeText)] #[wasm_bindgen(js_name = onChangeText)]
pub fn on_change_text(&self, new_text: String) -> Result<(), JsValue> { pub fn on_change_text(&self, new_text: String, is_right_click: bool) -> Result<(), JsValue> {
let message = TextToolMessage::TextChange { new_text }; let message = TextToolMessage::TextChange { new_text, is_right_click };
self.dispatch(message); self.dispatch(message);
Ok(()) Ok(())