From 85eb3adec72d5acf74a1f12d1363a537a5e1bd31 Mon Sep 17 00:00:00 2001 From: filipriec Date: Sun, 25 May 2025 15:09:38 +0200 Subject: [PATCH] logic is being implemented properly well --- client/src/components/admin/add_logic.rs | 51 ++- .../modes/navigation/add_logic_nav.rs | 378 ++++++++---------- .../functions/modes/read_only/add_logic_ro.rs | 31 +- client/src/state/pages/add_logic.rs | 29 +- 4 files changed, 238 insertions(+), 251 deletions(-) diff --git a/client/src/components/admin/add_logic.rs b/client/src/components/admin/add_logic.rs index a786dfa..198bfca 100644 --- a/client/src/components/admin/add_logic.rs +++ b/client/src/components/admin/add_logic.rs @@ -14,7 +14,6 @@ use ratatui::{ use crate::components::handlers::canvas::render_canvas; use crate::components::common::dialog; use crate::config::binds::config::EditorKeybindingMode; -use crate::components::common::text_editor::TextEditor; pub fn render_add_logic( f: &mut Frame, @@ -35,7 +34,8 @@ pub fn render_add_logic( let inner_area = main_block.inner(area); f.render_widget(main_block, area); - if add_logic_state.current_focus == AddLogicFocus::InputScriptContent { + // Handle full-screen script editing + if add_logic_state.current_focus == AddLogicFocus::InsideScriptContent { let mut editor_ref = add_logic_state.script_content_editor.borrow_mut(); let border_style_color = if is_edit_mode { theme.highlight } else { theme.secondary }; let border_style = Style::default().fg(border_style_color); @@ -44,18 +44,18 @@ pub fn render_add_logic( let script_title_hint = match add_logic_state.editor_keybinding_mode { EditorKeybindingMode::Vim => { - let vim_mode_status = TextEditor::get_vim_mode_status(&add_logic_state.vim_state); + let vim_mode_status = crate::components::common::text_editor::TextEditor::get_vim_mode_status(&add_logic_state.vim_state); if is_edit_mode { - format!("Script (VIM {}) - Esc for Normal. Tab navigates from Normal.", vim_mode_status) + format!("Script (VIM {}) - Esc for Normal. Esc again to exit.", vim_mode_status) } else { - format!("Script (VIM {}) - 'i'/'a'/'o' for Insert. Tab to navigate.", vim_mode_status) + format!("Script (VIM {}) - 'i'/'a'/'o' for Insert. Esc to exit.", vim_mode_status) } } EditorKeybindingMode::Emacs | EditorKeybindingMode::Default => { if is_edit_mode { - "Script (Editing - Esc to exit edit. Tab navigates after exit.)".to_string() + "Script (Editing - Esc to exit edit. Esc again to exit script.)".to_string() } else { - "Script (Press Enter or Ctrl+E to edit. Tab to navigate.)".to_string() + "Script (Press Enter or Ctrl+E to edit. Esc to exit.)".to_string() } } }; @@ -68,19 +68,18 @@ pub fn render_add_logic( .border_type(BorderType::Rounded) .border_style(border_style), ); - // Remove .widget() call - just pass the reference directly f.render_widget(&*editor_ref, inner_area); return; } - // ... rest of the layout code ... + // Regular layout with preview let main_chunks = Layout::default() .direction(Direction::Vertical) .constraints([ - Constraint::Length(3), - Constraint::Length(9), - Constraint::Min(5), - Constraint::Length(3), + Constraint::Length(3), // Top info + Constraint::Length(9), // Canvas + Constraint::Min(5), // Script preview + Constraint::Length(3), // Buttons ]) .split(inner_area); @@ -89,6 +88,7 @@ pub fn render_add_logic( let script_content_area = main_chunks[2]; let buttons_area = main_chunks[3]; + // Top info let profile_text = Paragraph::new(vec![ Line::from(Span::styled( format!("Profile: {}", add_logic_state.profile_name), @@ -114,6 +114,7 @@ pub fn render_add_logic( ); f.render_widget(profile_text, top_info_area); + // Canvas let focus_on_canvas_inputs = matches!( add_logic_state.current_focus, AddLogicFocus::InputLogicName @@ -132,32 +133,41 @@ pub fn render_add_logic( highlight_state, ); + // Script content preview (like table preview in add_table) { let mut editor_ref = add_logic_state.script_content_editor.borrow_mut(); editor_ref.set_cursor_line_style(Style::default()); - let border_style_color = if add_logic_state.current_focus == AddLogicFocus::InputScriptContent { - theme.highlight + let is_script_focused = add_logic_state.current_focus == AddLogicFocus::ScriptContentPreview; + let border_style_color = if is_script_focused { + theme.highlight // Green highlight when focused and ready to select } else { theme.secondary }; - let title_hint = match add_logic_state.editor_keybinding_mode { - EditorKeybindingMode::Vim => "Script Preview (VIM - Focus with Tab, then 'i'/'a'/'o' to edit)", - _ => "Script Preview (Focus with Tab, then Enter/Ctrl+E to edit)", + let title_text = if is_script_focused { + "Script Preview (Press Enter to edit) [FOCUSED]" + } else { + "Script Preview" + }; + + let title_style = if is_script_focused { + Style::default().fg(theme.highlight).add_modifier(Modifier::BOLD) + } else { + Style::default().fg(theme.fg) }; editor_ref.set_block( Block::default() - .title(title_hint) + .title(Span::styled(title_text, title_style)) .borders(Borders::ALL) .border_type(BorderType::Rounded) .border_style(Style::default().fg(border_style_color)), ); - // Remove .widget() call here too f.render_widget(&*editor_ref, script_content_area); } + // Buttons let get_button_style = |button_focus: AddLogicFocus, current_focus| { let is_focused = current_focus == button_focus; let base_style = Style::default().fg(if is_focused { @@ -222,6 +232,7 @@ pub fn render_add_logic( ); f.render_widget(cancel_button, button_chunks[1]); + // Dialog if app_state.ui.dialog.dialog_show { dialog::render_dialog( f, diff --git a/client/src/functions/modes/navigation/add_logic_nav.rs b/client/src/functions/modes/navigation/add_logic_nav.rs index e67e7d9..8406f3f 100644 --- a/client/src/functions/modes/navigation/add_logic_nav.rs +++ b/client/src/functions/modes/navigation/add_logic_nav.rs @@ -10,9 +10,7 @@ use crossterm::event::{KeyEvent, KeyCode, KeyModifiers}; use crate::services::GrpcClient; use tokio::sync::mpsc; use anyhow::Result; -use common::proto::multieko2::table_script::PostTableScriptRequest; use crate::components::common::text_editor::TextEditor; -use tui_textarea::Input as TextAreaInput; pub type SaveLogicResultSender = mpsc::Sender>; @@ -27,236 +25,214 @@ pub fn handle_add_logic_navigation( save_logic_sender: SaveLogicResultSender, command_message: &mut String, ) -> bool { - let mut handled = false; - let general_action = config.get_general_action(key_event.code, key_event.modifiers); - - if add_logic_state.current_focus == AddLogicFocus::InputScriptContent { + // === FULLSCREEN SCRIPT EDITING - COMPLETE ISOLATION === + if add_logic_state.current_focus == AddLogicFocus::InsideScriptContent { let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut(); - match add_logic_state.editor_keybinding_mode { - EditorKeybindingMode::Vim => { - if *is_edit_mode { // App considers textarea to be in "typing" (Insert) mode - let changed = TextEditor::handle_input( - &mut editor_borrow, - key_event, - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state, - ); - if changed { add_logic_state.has_unsaved_changes = true; } - - // Check if we've transitioned to Normal mode - if key_event.code == KeyCode::Esc && TextEditor::is_vim_normal_mode(&add_logic_state.vim_state) { - *is_edit_mode = false; - *command_message = "VIM: Normal Mode. Tab to navigate.".to_string(); - } - handled = true; - } else { // App considers textarea to be in "navigation" (Normal) mode - match key_event.code { - // Keys to enter Vim Insert mode - KeyCode::Char('i') | KeyCode::Char('a') | KeyCode::Char('o') | - KeyCode::Char('I') | KeyCode::Char('A') | KeyCode::Char('O') => { - *is_edit_mode = true; - TextEditor::handle_input( - &mut editor_borrow, - key_event, - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state - ); - *command_message = "VIM: Insert Mode.".to_string(); - handled = true; - } - _ => { - if general_action.is_none() { - let changed = TextEditor::handle_input( - &mut editor_borrow, - key_event, - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state, - ); - if changed { add_logic_state.has_unsaved_changes = true; } - handled = true; - } - } - } - } - } - EditorKeybindingMode::Emacs | EditorKeybindingMode::Default => { - if *is_edit_mode { - if key_event.code == KeyCode::Esc && key_event.modifiers == KeyModifiers::NONE { - *is_edit_mode = false; - *command_message = "Exited script edit. Tab to navigate.".to_string(); - handled = true; - } else if general_action.is_some() && (general_action.unwrap() == "next_field" || general_action.unwrap() == "prev_field") { - let changed = TextEditor::handle_input( - &mut editor_borrow, - key_event, - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state + // Handle ONLY Escape to exit fullscreen mode + if key_event.code == KeyCode::Esc && key_event.modifiers == KeyModifiers::NONE { + match add_logic_state.editor_keybinding_mode { + EditorKeybindingMode::Vim => { + if *is_edit_mode { + // First escape: try to go to Vim Normal mode + TextEditor::handle_input( + &mut editor_borrow, + key_event, + &add_logic_state.editor_keybinding_mode, + &mut add_logic_state.vim_state, ); - if changed { add_logic_state.has_unsaved_changes = true; } - handled = true; + if TextEditor::is_vim_normal_mode(&add_logic_state.vim_state) { + *is_edit_mode = false; + *command_message = "VIM: Normal Mode. Esc again to exit script.".to_string(); + } } else { - let changed = TextEditor::handle_input( - &mut editor_borrow, - key_event, - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state - ); - if changed { add_logic_state.has_unsaved_changes = true; } - handled = true; + // Second escape: exit fullscreen + add_logic_state.current_focus = AddLogicFocus::ScriptContentPreview; + app_state.ui.focus_outside_canvas = true; + *is_edit_mode = false; + *command_message = "Exited script editing.".to_string(); + } + } + _ => { + if *is_edit_mode { + *is_edit_mode = false; + *command_message = "Exited script edit. Esc again to exit script.".to_string(); + } else { + // Exit fullscreen + add_logic_state.current_focus = AddLogicFocus::ScriptContentPreview; + app_state.ui.focus_outside_canvas = true; + *is_edit_mode = false; + *command_message = "Exited script editing.".to_string(); } } } + return true; } - if handled { return true; } + + // ALL OTHER KEYS: Pass directly to textarea without any interference + let changed = TextEditor::handle_input( + &mut editor_borrow, + key_event, + &add_logic_state.editor_keybinding_mode, + &mut add_logic_state.vim_state, + ); + if changed { + add_logic_state.has_unsaved_changes = true; + } + + // Update edit mode status for Vim + if add_logic_state.editor_keybinding_mode == EditorKeybindingMode::Vim { + *is_edit_mode = !TextEditor::is_vim_normal_mode(&add_logic_state.vim_state); + } + + return true; // Always consume the event in fullscreen mode } + // === END FULLSCREEN ISOLATION === - // If not handled above (e.g., Tab/Shift+Tab, or Enter when script content not in edit mode), - // process general application-level actions. - let action_str = general_action.map(String::from); - match action_str.as_deref() { - Some("exit_view") | Some("cancel_action") => { - buffer_state.update_history(AppView::Admin); - app_state.ui.show_add_logic = false; - *command_message = "Exited Add Logic".to_string(); - *is_edit_mode = false; - handled = true; + // Regular navigation logic for non-fullscreen elements + let action = config.get_general_action(key_event.code, key_event.modifiers); + let current_focus = add_logic_state.current_focus; + let mut handled = true; + let mut new_focus = current_focus; + + match action.as_deref() { + Some("exit_table_scroll") => { + // This shouldn't happen since we handle InsideScriptContent above + handled = false; } - Some("next_field") | Some("prev_field") => { - let is_next = action_str.as_deref() == Some("next_field"); - let previous_focus = add_logic_state.current_focus; - - add_logic_state.current_focus = if is_next { - match add_logic_state.current_focus { - AddLogicFocus::InputLogicName => AddLogicFocus::InputTargetColumn, - AddLogicFocus::InputTargetColumn => AddLogicFocus::InputDescription, - AddLogicFocus::InputDescription => AddLogicFocus::InputScriptContent, - AddLogicFocus::InputScriptContent => AddLogicFocus::SaveButton, - AddLogicFocus::SaveButton => AddLogicFocus::CancelButton, - AddLogicFocus::CancelButton => AddLogicFocus::InputLogicName, + Some("move_up") => { + match current_focus { + AddLogicFocus::InputLogicName => { + // Stay at top } - } else { - match add_logic_state.current_focus { - AddLogicFocus::InputLogicName => AddLogicFocus::CancelButton, - AddLogicFocus::InputTargetColumn => AddLogicFocus::InputLogicName, - AddLogicFocus::InputDescription => AddLogicFocus::InputTargetColumn, - AddLogicFocus::InputScriptContent => AddLogicFocus::InputDescription, - AddLogicFocus::SaveButton => AddLogicFocus::InputScriptContent, - AddLogicFocus::CancelButton => AddLogicFocus::SaveButton, - } - }; - - if add_logic_state.current_focus == AddLogicFocus::InputScriptContent { - *is_edit_mode = false; - let mode_hint = match add_logic_state.editor_keybinding_mode { - EditorKeybindingMode::Vim => "'i'/'a'/'o' to insert", - _ => "Enter/Ctrl+E to edit", - }; - *command_message = format!("Focus: Script Content. Press {} or Tab.", mode_hint); - } else if matches!(add_logic_state.current_focus, AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription) { - *is_edit_mode = true; - *command_message = format!("Focus: {:?}. Edit mode ON.", add_logic_state.current_focus); - } else { - *is_edit_mode = false; - *command_message = format!("Focus: {:?}", add_logic_state.current_focus); + AddLogicFocus::InputTargetColumn => new_focus = AddLogicFocus::InputLogicName, + AddLogicFocus::InputDescription => new_focus = AddLogicFocus::InputTargetColumn, + AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::InputDescription, + AddLogicFocus::SaveButton => new_focus = AddLogicFocus::ScriptContentPreview, + AddLogicFocus::CancelButton => new_focus = AddLogicFocus::SaveButton, + _ => handled = false, } - - app_state.ui.focus_outside_canvas = !matches!( - add_logic_state.current_focus, - AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription | AddLogicFocus::InputScriptContent - ); - handled = true; + } + Some("move_down") => { + match current_focus { + AddLogicFocus::InputLogicName => new_focus = AddLogicFocus::InputTargetColumn, + AddLogicFocus::InputTargetColumn => new_focus = AddLogicFocus::InputDescription, + AddLogicFocus::InputDescription => { + add_logic_state.last_canvas_field = 2; + new_focus = AddLogicFocus::ScriptContentPreview; + }, + AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::SaveButton, + AddLogicFocus::SaveButton => new_focus = AddLogicFocus::CancelButton, + AddLogicFocus::CancelButton => { + // Stay at bottom + } + _ => handled = false, + } + } + Some("next_option") => { + match current_focus { + AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => + { new_focus = AddLogicFocus::ScriptContentPreview; } + AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::SaveButton, + AddLogicFocus::SaveButton => new_focus = AddLogicFocus::CancelButton, + AddLogicFocus::CancelButton => { /* Stay at last */ } + _ => handled = false, + } + } + Some("previous_option") => { + match current_focus { + AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => + { /* Stay at first */ } + AddLogicFocus::ScriptContentPreview => new_focus = AddLogicFocus::InputDescription, + AddLogicFocus::SaveButton => new_focus = AddLogicFocus::ScriptContentPreview, + AddLogicFocus::CancelButton => new_focus = AddLogicFocus::SaveButton, + _ => handled = false, + } + } + Some("next_field") => { + new_focus = match current_focus { + AddLogicFocus::InputLogicName => AddLogicFocus::InputTargetColumn, + AddLogicFocus::InputTargetColumn => AddLogicFocus::InputDescription, + AddLogicFocus::InputDescription => AddLogicFocus::ScriptContentPreview, + AddLogicFocus::ScriptContentPreview => AddLogicFocus::SaveButton, + AddLogicFocus::SaveButton => AddLogicFocus::CancelButton, + AddLogicFocus::CancelButton => AddLogicFocus::InputLogicName, + _ => current_focus, + }; + } + Some("prev_field") => { + new_focus = match current_focus { + AddLogicFocus::InputLogicName => AddLogicFocus::CancelButton, + AddLogicFocus::InputTargetColumn => AddLogicFocus::InputLogicName, + AddLogicFocus::InputDescription => AddLogicFocus::InputTargetColumn, + AddLogicFocus::ScriptContentPreview => AddLogicFocus::InputDescription, + AddLogicFocus::SaveButton => AddLogicFocus::ScriptContentPreview, + AddLogicFocus::CancelButton => AddLogicFocus::SaveButton, + _ => current_focus, + }; } Some("select") => { - match add_logic_state.current_focus { - AddLogicFocus::InputScriptContent => { - *is_edit_mode = true; - let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut(); - match add_logic_state.editor_keybinding_mode { - EditorKeybindingMode::Vim => { - TextEditor::handle_input( - &mut editor_borrow, - KeyEvent::new(KeyCode::Char('i'), KeyModifiers::NONE), - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state, - ); - *command_message = "VIM: Insert Mode.".to_string(); - } - _ => { - *command_message = "Entered script edit mode.".to_string(); - } - } - handled = true; + match current_focus { + AddLogicFocus::ScriptContentPreview => { + new_focus = AddLogicFocus::InsideScriptContent; + *is_edit_mode = false; // Start in preview mode + app_state.ui.focus_outside_canvas = false; // Script is like canvas + let mode_hint = match add_logic_state.editor_keybinding_mode { + EditorKeybindingMode::Vim => "VIM mode - 'i'/'a'/'o' to edit", + _ => "Enter/Ctrl+E to edit", + }; + *command_message = format!("Fullscreen script editing. {} or Esc to exit.", mode_hint); + } + AddLogicFocus::SaveButton => { + *command_message = "Save logic action".to_string(); + } + AddLogicFocus::CancelButton => { + buffer_state.update_history(AppView::Admin); + app_state.ui.show_add_logic = false; + *command_message = "Cancelled Add Logic".to_string(); + *is_edit_mode = false; } - AddLogicFocus::SaveButton => { handled = true; } - AddLogicFocus::CancelButton => { *is_edit_mode = false; handled = true; } AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => { *is_edit_mode = !*is_edit_mode; *command_message = format!("Field edit mode: {}", if *is_edit_mode { "ON" } else { "OFF" }); - handled = true; } + _ => handled = false, } } Some("toggle_edit_mode") => { - match add_logic_state.current_focus { - AddLogicFocus::InputScriptContent => { - let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut(); - match add_logic_state.editor_keybinding_mode { - EditorKeybindingMode::Vim => { - if *is_edit_mode { - TextEditor::handle_input( - &mut editor_borrow, - KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE), - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state, - ); - if TextEditor::is_vim_normal_mode(&add_logic_state.vim_state) { - *is_edit_mode = false; - *command_message = "VIM: Normal Mode. Tab to navigate.".to_string(); - } else { - *command_message = "VIM: Still in Insert Mode (toggle error?).".to_string(); - } - } else { - TextEditor::handle_input( - &mut editor_borrow, - KeyEvent::new(KeyCode::Char('i'), KeyModifiers::NONE), - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state, - ); - *is_edit_mode = true; - *command_message = "VIM: Insert Mode.".to_string(); - } - } - _ => { - *is_edit_mode = !*is_edit_mode; - *command_message = format!("Script edit mode: {}", if *is_edit_mode { "ON" } else { "OFF. Tab to navigate." }); - } - } - handled = true; - } + match current_focus { AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription => { *is_edit_mode = !*is_edit_mode; *command_message = format!("Canvas field edit mode: {}", if *is_edit_mode { "ON" } else { "OFF" }); - handled = true; } - _ => { *command_message = "Cannot toggle edit mode here.".to_string(); handled = true; } + _ => { + *command_message = "Cannot toggle edit mode here.".to_string(); + } } } - _ => { - if add_logic_state.current_focus == AddLogicFocus::InputScriptContent && - !*is_edit_mode && - add_logic_state.editor_keybinding_mode == EditorKeybindingMode::Vim { - let mut editor_borrow = add_logic_state.script_content_editor.borrow_mut(); - let changed = TextEditor::handle_input( - &mut editor_borrow, - key_event, - &add_logic_state.editor_keybinding_mode, - &mut add_logic_state.vim_state - ); - if changed { add_logic_state.has_unsaved_changes = true; } - handled = true; + _ => handled = false, + } + + if handled && current_focus != new_focus { + add_logic_state.current_focus = new_focus; + + // Set edit mode and canvas focus based on new focus + let new_is_canvas_input_focus = matches!(new_focus, + AddLogicFocus::InputLogicName | AddLogicFocus::InputTargetColumn | AddLogicFocus::InputDescription + ); + + if new_is_canvas_input_focus { + // Entering canvas - start in readonly mode + *is_edit_mode = false; + app_state.ui.focus_outside_canvas = false; + } else { + // Outside canvas + app_state.ui.focus_outside_canvas = true; + if matches!(new_focus, AddLogicFocus::ScriptContentPreview) { + *is_edit_mode = false; } } } + handled } diff --git a/client/src/functions/modes/read_only/add_logic_ro.rs b/client/src/functions/modes/read_only/add_logic_ro.rs index fd9421f..b7dc4da 100644 --- a/client/src/functions/modes/read_only/add_logic_ro.rs +++ b/client/src/functions/modes/read_only/add_logic_ro.rs @@ -67,7 +67,7 @@ fn find_prev_word_end(text: &str, current_pos: usize) -> usize { pub async fn execute_action( action: &str, app_state: &mut AppState, - state: &mut AddLogicState, // Changed + state: &mut AddLogicState, ideal_cursor_column: &mut usize, key_sequence_tracker: &mut KeySequenceTracker, command_message: &mut String, @@ -75,7 +75,7 @@ pub async fn execute_action( match action { "move_up" => { key_sequence_tracker.reset(); - let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + let num_fields = AddLogicState::INPUT_FIELD_COUNT; if num_fields == 0 { return Ok("No fields.".to_string()); } let current_field = state.current_field(); @@ -87,20 +87,13 @@ pub async fn execute_action( let new_pos = (*ideal_cursor_column).min(max_cursor_pos); state.set_current_cursor_pos(new_pos); } else { - // Moving up from the first field (InputLogicName) - app_state.ui.focus_outside_canvas = true; - // Focus should go to the element logically above the canvas. - // Based on AddLogicFocus, this might be CancelButton or another element. - // For AddLogic, let's assume it's CancelButton, similar to AddTable. - state.current_focus = crate::state::pages::add_logic::AddLogicFocus::CancelButton; // Changed - key_sequence_tracker.reset(); - return Ok("Focus moved above canvas".to_string()); + *command_message = "At top of form.".to_string(); } - Ok("".to_string()) + Ok(command_message.clone()) } "move_down" => { key_sequence_tracker.reset(); - let num_fields = AddLogicState::INPUT_FIELD_COUNT; // Changed + let num_fields = AddLogicState::INPUT_FIELD_COUNT; if num_fields == 0 { return Ok("No fields.".to_string()); } let current_field = state.current_field(); let last_field_index = num_fields - 1; @@ -113,17 +106,13 @@ pub async fn execute_action( let new_pos = (*ideal_cursor_column).min(max_cursor_pos); state.set_current_cursor_pos(new_pos); } else { - // Moving down from the last field (InputDescription) + // Move focus outside canvas when moving down from the last field app_state.ui.focus_outside_canvas = true; - // Focus should go to the element logically below the canvas. - // This is likely InputScriptContent or SaveButton. - // The add_logic_nav.rs handles transitions to InputScriptContent. - // If moving from canvas directly to buttons, it would be SaveButton. - state.current_focus = crate::state::pages::add_logic::AddLogicFocus::InputScriptContent; // Or SaveButton - key_sequence_tracker.reset(); - return Ok("Focus moved to script/button area".to_string()); + state.last_canvas_field = 2; + state.current_focus = crate::state::pages::add_logic::AddLogicFocus::SaveButton; + *command_message = "Focus moved below canvas".to_string(); } - Ok("".to_string()) + Ok(command_message.clone()) } "move_first_line" => { key_sequence_tracker.reset(); diff --git a/client/src/state/pages/add_logic.rs b/client/src/state/pages/add_logic.rs index 9577fc7..025bf85 100644 --- a/client/src/state/pages/add_logic.rs +++ b/client/src/state/pages/add_logic.rs @@ -1,7 +1,7 @@ // src/state/pages/add_logic.rs use crate::config::binds::config::{EditorConfig, EditorKeybindingMode}; use crate::state::pages::canvas_state::CanvasState; -use crate::components::common::text_editor::{TextEditor, VimState}; // Add VimState import +use crate::components::common::text_editor::{TextEditor, VimState}; use std::cell::RefCell; use std::rc::Rc; use tui_textarea::TextArea; @@ -11,8 +11,9 @@ pub enum AddLogicFocus { #[default] InputLogicName, InputTargetColumn, - InputScriptContent, InputDescription, + ScriptContentPreview, // Like ColumnsTable - can be highlighted/selected + InsideScriptContent, // Like InsideColumnsTable - full editing mode SaveButton, CancelButton, } @@ -27,12 +28,13 @@ pub struct AddLogicState { pub script_content_editor: Rc>>, pub description_input: String, pub current_focus: AddLogicFocus, + pub last_canvas_field: usize, pub logic_name_cursor_pos: usize, pub target_column_cursor_pos: usize, pub description_cursor_pos: usize, pub has_unsaved_changes: bool, pub editor_keybinding_mode: EditorKeybindingMode, - pub vim_state: VimState, // Add this field + pub vim_state: VimState, } impl AddLogicState { @@ -47,12 +49,13 @@ impl AddLogicState { script_content_editor: Rc::new(RefCell::new(editor)), description_input: String::new(), current_focus: AddLogicFocus::InputLogicName, + last_canvas_field: 2, logic_name_cursor_pos: 0, target_column_cursor_pos: 0, description_cursor_pos: 0, has_unsaved_changes: false, editor_keybinding_mode: editor_config.keybinding_mode.clone(), - vim_state: VimState::default(), // Add this field initialization + vim_state: VimState::default(), } } @@ -65,14 +68,13 @@ impl Default for AddLogicState { } } -// ... rest of the CanvasState implementation remains the same impl CanvasState for AddLogicState { fn current_field(&self) -> usize { match self.current_focus { AddLogicFocus::InputLogicName => 0, AddLogicFocus::InputTargetColumn => 1, AddLogicFocus::InputDescription => 2, - _ => 0, + _ => self.last_canvas_field, } } @@ -121,9 +123,18 @@ impl CanvasState for AddLogicState { fn set_current_field(&mut self, index: usize) { self.current_focus = match index { - 0 => AddLogicFocus::InputLogicName, - 1 => AddLogicFocus::InputTargetColumn, - 2 => AddLogicFocus::InputDescription, + 0 => { + self.last_canvas_field = 0; + AddLogicFocus::InputLogicName + }, + 1 => { + self.last_canvas_field = 1; + AddLogicFocus::InputTargetColumn + }, + 2 => { + self.last_canvas_field = 2; + AddLogicFocus::InputDescription + }, _ => self.current_focus, }; }