From 0575fc7c10b8833042ce9a657563efa5c3a74b56 Mon Sep 17 00:00:00 2001 From: Sidharth-Singh10 Date: Wed, 18 Dec 2024 02:16:25 +0530 Subject: [PATCH 1/5] properties panel remains active when user edits text layer --- .../document/document_message_handler.rs | 9 ++++++ .../messages/tool/tool_messages/text_tool.rs | 29 +++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 3258ecafe5..40001513f4 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -17,6 +17,7 @@ use crate::messages::portfolio::document::properties_panel::utility_types::Prope use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ}; use crate::messages::portfolio::document::utility_types::nodes::RawBuffer; +use crate::messages::portfolio::utility_types::PanelType; use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_opacity}; @@ -90,6 +91,8 @@ pub struct DocumentMessageHandler { pub graph_view_overlay_open: bool, /// The current opacity of the faded node graph background that covers up the artwork. pub graph_fade_artwork_percentage: f64, + /// Tracks the currently active panel in the application interface. + pub active_panel: PanelType, // ============================================= // Fields omitted from the saved document format @@ -144,6 +147,7 @@ impl Default for DocumentMessageHandler { graph_view_overlay_open: false, snapping_state: SnappingState::default(), graph_fade_artwork_percentage: 80., + active_panel: PanelType::Document, // ============================================= // Fields omitted from the saved document format // ============================================= @@ -994,6 +998,7 @@ impl MessageHandler> for DocumentMessag } DocumentMessage::SetActivePanel { active_panel: panel } => { use crate::messages::portfolio::utility_types::PanelType; + self.active_panel = panel; match panel { PanelType::Document => { if self.graph_view_overlay_open { @@ -1376,6 +1381,10 @@ impl MessageHandler> for DocumentMessag } impl DocumentMessageHandler { + /// Returns the currently active panel in the application interface. + pub fn get_active_panel(&self) -> PanelType { + self.active_panel + } /// Runs an intersection test with all layers and a viewport space quad pub fn intersect_quad<'a>(&'a self, viewport_quad: graphene_core::renderer::Quad, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + 'a { let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 311952eef1..1bb6c94c65 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -5,6 +5,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; +use crate::messages::portfolio::utility_types::PanelType; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name}; @@ -242,7 +243,7 @@ struct TextToolData { impl TextToolData { /// Set the editing state of the currently modifying layer - fn set_editing(&self, editable: bool, font_cache: &FontCache, responses: &mut VecDeque) { + fn set_editing(&self, document: &DocumentMessageHandler, editable: bool, font_cache: &FontCache, responses: &mut VecDeque) { if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) { responses.add(FrontendMessage::DisplayEditableTextbox { text: editing_text.text.clone(), @@ -254,8 +255,18 @@ impl TextToolData { }); } else { responses.add(FrontendMessage::DisplayRemoveEditableTextbox); - // Clear all selected nodes when no longer editing - responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() }); + let panel_type = document.get_active_panel(); + match panel_type { + // If Properties panel is clicked, keep the nodes selected + PanelType::Properties => { + // Do nothing, keep current selection + } + // For other panels, clear selected nodes + _ => { + // Clear all selected nodes when no longer editing + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() }); + } + } } } @@ -282,14 +293,14 @@ impl TextToolData { } if tool_state == TextToolFsmState::Editing { - self.set_editing(false, font_cache, responses); + self.set_editing(document, false, font_cache, responses); } self.layer = layer; if self.load_layer_text_node(document).is_some() { responses.add(DocumentMessage::AddTransaction); - self.set_editing(true, font_cache, responses); + self.set_editing(document, true, font_cache, responses); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] }); // Make the rendered text invisible while editing @@ -359,7 +370,7 @@ impl TextToolData { skip_rerender: true, }); - self.set_editing(true, font_cache, responses); + self.set_editing(document, true, font_cache, responses); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] }); @@ -367,7 +378,7 @@ impl TextToolData { TextToolFsmState::Editing } else { // Removing old text as editable - self.set_editing(false, font_cache, responses); + self.set_editing(document, false, font_cache, responses); TextToolFsmState::Ready } @@ -468,7 +479,7 @@ impl Fsm for TextToolFsmState { } (state, TextToolMessage::Abort) => { if state == TextToolFsmState::Editing { - tool_data.set_editing(false, font_cache, responses); + tool_data.set_editing(document, false, font_cache, responses); } TextToolFsmState::Ready @@ -479,7 +490,7 @@ impl Fsm for TextToolFsmState { TextToolFsmState::Editing } (TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => { - tool_data.set_editing(false, font_cache, responses); + tool_data.set_editing(document, false, font_cache, responses); responses.add(NodeGraphMessage::SetInput { input_connector: InputConnector::node(graph_modification_utils::get_text_id(tool_data.layer, &document.network_interface).unwrap(), 1), From ccce8cfea885b5c990517a8d24c128750722e205 Mon Sep 17 00:00:00 2001 From: Sidharth-Singh10 Date: Sat, 21 Dec 2024 02:38:23 +0530 Subject: [PATCH 2/5] Keep text layers selected after editing --- .../document/document_message_handler.rs | 10 +----- .../messages/tool/tool_messages/text_tool.rs | 31 +++++++------------ 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 40001513f4..8b83bf65d0 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -17,7 +17,6 @@ use crate::messages::portfolio::document::properties_panel::utility_types::Prope use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ}; use crate::messages::portfolio::document::utility_types::nodes::RawBuffer; -use crate::messages::portfolio::utility_types::PanelType; use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_blend_mode, get_opacity}; @@ -91,8 +90,6 @@ pub struct DocumentMessageHandler { pub graph_view_overlay_open: bool, /// The current opacity of the faded node graph background that covers up the artwork. pub graph_fade_artwork_percentage: f64, - /// Tracks the currently active panel in the application interface. - pub active_panel: PanelType, // ============================================= // Fields omitted from the saved document format @@ -147,7 +144,7 @@ impl Default for DocumentMessageHandler { graph_view_overlay_open: false, snapping_state: SnappingState::default(), graph_fade_artwork_percentage: 80., - active_panel: PanelType::Document, + // ============================================= // Fields omitted from the saved document format // ============================================= @@ -998,7 +995,6 @@ impl MessageHandler> for DocumentMessag } DocumentMessage::SetActivePanel { active_panel: panel } => { use crate::messages::portfolio::utility_types::PanelType; - self.active_panel = panel; match panel { PanelType::Document => { if self.graph_view_overlay_open { @@ -1381,10 +1377,6 @@ impl MessageHandler> for DocumentMessag } impl DocumentMessageHandler { - /// Returns the currently active panel in the application interface. - pub fn get_active_panel(&self) -> PanelType { - self.active_panel - } /// Runs an intersection test with all layers and a viewport space quad pub fn intersect_quad<'a>(&'a self, viewport_quad: graphene_core::renderer::Quad, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + 'a { let document_to_viewport = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz); diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 1bb6c94c65..478b8fe32e 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -5,7 +5,6 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; -use crate::messages::portfolio::utility_types::PanelType; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name}; @@ -243,7 +242,7 @@ struct TextToolData { impl TextToolData { /// Set the editing state of the currently modifying layer - fn set_editing(&self, document: &DocumentMessageHandler, editable: bool, font_cache: &FontCache, responses: &mut VecDeque) { + fn set_editing(&self, editable: bool, font_cache: &FontCache, responses: &mut VecDeque) { if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) { responses.add(FrontendMessage::DisplayEditableTextbox { text: editing_text.text.clone(), @@ -254,18 +253,12 @@ 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); - let panel_type = document.get_active_panel(); - match panel_type { - // If Properties panel is clicked, keep the nodes selected - PanelType::Properties => { - // Do nothing, keep current selection - } - // For other panels, clear selected nodes - _ => { - // 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() }); } } } @@ -293,14 +286,14 @@ impl TextToolData { } if tool_state == TextToolFsmState::Editing { - self.set_editing(document, false, font_cache, responses); + self.set_editing(false, font_cache, responses); } self.layer = layer; if self.load_layer_text_node(document).is_some() { responses.add(DocumentMessage::AddTransaction); - self.set_editing(document, true, font_cache, responses); + self.set_editing(true, font_cache, responses); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] }); // Make the rendered text invisible while editing @@ -370,7 +363,7 @@ impl TextToolData { skip_rerender: true, }); - self.set_editing(document, true, font_cache, responses); + self.set_editing(true, font_cache, responses); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] }); @@ -378,7 +371,7 @@ impl TextToolData { TextToolFsmState::Editing } else { // Removing old text as editable - self.set_editing(document, false, font_cache, responses); + self.set_editing(false, font_cache, responses); TextToolFsmState::Ready } @@ -479,7 +472,7 @@ impl Fsm for TextToolFsmState { } (state, TextToolMessage::Abort) => { if state == TextToolFsmState::Editing { - tool_data.set_editing(document, false, font_cache, responses); + tool_data.set_editing(false, font_cache, responses); } TextToolFsmState::Ready @@ -490,7 +483,7 @@ impl Fsm for TextToolFsmState { TextToolFsmState::Editing } (TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => { - tool_data.set_editing(document, false, font_cache, responses); + tool_data.set_editing(false, font_cache, responses); responses.add(NodeGraphMessage::SetInput { input_connector: InputConnector::node(graph_modification_utils::get_text_id(tool_data.layer, &document.network_interface).unwrap(), 1), From cd857cba0d11a409a06322e9dd0fdffc9c3d85c6 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Fri, 20 Dec 2024 13:44:54 -0800 Subject: [PATCH 3/5] Update editor/src/messages/portfolio/document/document_message_handler.rs --- .../src/messages/portfolio/document/document_message_handler.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 8b83bf65d0..3258ecafe5 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -144,7 +144,6 @@ impl Default for DocumentMessageHandler { graph_view_overlay_open: false, snapping_state: SnappingState::default(), graph_fade_artwork_percentage: 80., - // ============================================= // Fields omitted from the saved document format // ============================================= From e2bef959db4277358a7998a8ee1ca6ef76782ea0 Mon Sep 17 00:00:00 2001 From: Sidharth-Singh10 Date: Sun, 22 Dec 2024 00:42:02 +0530 Subject: [PATCH 4/5] Delete Empty Text Layer on Escape or Right Click --- .../src/messages/input_mapper/input_mappings.rs | 1 + .../src/messages/tool/tool_messages/text_tool.rs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs index 9ff6e41294..19eb25d0cd 100644 --- a/editor/src/messages/input_mapper/input_mappings.rs +++ b/editor/src/messages/input_mapper/input_mappings.rs @@ -156,6 +156,7 @@ pub fn input_mappings() -> Mapping { // TextToolMessage entry!(KeyUp(MouseLeft); action_dispatch=TextToolMessage::Interact), entry!(KeyDown(Escape); action_dispatch=TextToolMessage::CommitText), + entry!(KeyUp(MouseRight); action_dispatch=TextToolMessage::CommitText), entry!(KeyDown(Enter); modifiers=[Accel], action_dispatch=TextToolMessage::CommitText), // // GradientToolMessage diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 478b8fe32e..7922dd2f46 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -478,8 +478,21 @@ impl Fsm for TextToolFsmState { TextToolFsmState::Ready } (TextToolFsmState::Editing, TextToolMessage::CommitText) => { - responses.add(FrontendMessage::TriggerTextCommit); + if tool_data.new_text.is_empty() { + // Remove the editable textbox UI first + tool_data.set_editing(false, font_cache, responses); + + // Delete the empty text layer and update the graph + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![tool_data.layer.to_node()], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + return TextToolFsmState::Ready; + } + + responses.add(FrontendMessage::TriggerTextCommit); TextToolFsmState::Editing } (TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => { From 42d72a762c2b7a26d0bde8c3dd914c8916d8386f Mon Sep 17 00:00:00 2001 From: Sidharth-Singh10 Date: Mon, 23 Dec 2024 16:56:40 +0530 Subject: [PATCH 5/5] Fix: delete empty text layer on right click --- .../messages/input_mapper/input_mappings.rs | 1 - .../messages/tool/tool_messages/text_tool.rs | 54 ++++++++++++------- .../src/components/panels/Document.svelte | 2 +- frontend/src/io-managers/input.ts | 3 +- frontend/wasm/src/editor_api.rs | 4 +- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs index 19eb25d0cd..9ff6e41294 100644 --- a/editor/src/messages/input_mapper/input_mappings.rs +++ b/editor/src/messages/input_mapper/input_mappings.rs @@ -156,7 +156,6 @@ pub fn input_mappings() -> Mapping { // TextToolMessage entry!(KeyUp(MouseLeft); action_dispatch=TextToolMessage::Interact), entry!(KeyDown(Escape); action_dispatch=TextToolMessage::CommitText), - entry!(KeyUp(MouseRight); action_dispatch=TextToolMessage::CommitText), entry!(KeyDown(Enter); modifiers=[Accel], action_dispatch=TextToolMessage::CommitText), // // GradientToolMessage diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 7922dd2f46..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) { @@ -479,32 +492,33 @@ impl Fsm for TextToolFsmState { } (TextToolFsmState::Editing, TextToolMessage::CommitText) => { if tool_data.new_text.is_empty() { - // Remove the editable textbox UI first - tool_data.set_editing(false, font_cache, responses); - - // Delete the empty text layer and update the graph - responses.add(NodeGraphMessage::DeleteNodes { - node_ids: vec![tool_data.layer.to_node()], - delete_children: true, - }); - responses.add(NodeGraphMessage::RunDocumentGraph); - - return TextToolFsmState::Ready; + 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(())