// 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}; use std::cell::RefCell; use std::rc::Rc; use tui_textarea::TextArea; #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum AddLogicFocus { #[default] InputLogicName, InputTargetColumn, InputDescription, ScriptContentPreview, // Like ColumnsTable - can be highlighted/selected InsideScriptContent, // Like InsideColumnsTable - full editing mode SaveButton, CancelButton, } #[derive(Clone, Debug)] pub struct AddLogicState { pub profile_name: String, pub selected_table_id: Option, pub selected_table_name: Option, pub logic_name_input: String, pub target_column_input: String, 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, } impl AddLogicState { pub fn new(editor_config: &EditorConfig) -> Self { let editor = TextEditor::new_textarea(editor_config); AddLogicState { profile_name: "default".to_string(), selected_table_id: None, selected_table_name: None, logic_name_input: String::new(), target_column_input: String::new(), 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(), } } pub const INPUT_FIELD_COUNT: usize = 3; } impl Default for AddLogicState { fn default() -> Self { Self::new(&EditorConfig::default()) } } impl CanvasState for AddLogicState { fn current_field(&self) -> usize { match self.current_focus { AddLogicFocus::InputLogicName => 0, AddLogicFocus::InputTargetColumn => 1, AddLogicFocus::InputDescription => 2, _ => self.last_canvas_field, } } fn current_cursor_pos(&self) -> usize { match self.current_focus { AddLogicFocus::InputLogicName => self.logic_name_cursor_pos, AddLogicFocus::InputTargetColumn => self.target_column_cursor_pos, AddLogicFocus::InputDescription => self.description_cursor_pos, _ => 0, } } fn has_unsaved_changes(&self) -> bool { self.has_unsaved_changes } fn inputs(&self) -> Vec<&String> { vec![ &self.logic_name_input, &self.target_column_input, &self.description_input, ] } fn get_current_input(&self) -> &str { match self.current_focus { AddLogicFocus::InputLogicName => &self.logic_name_input, AddLogicFocus::InputTargetColumn => &self.target_column_input, AddLogicFocus::InputDescription => &self.description_input, _ => "", } } fn get_current_input_mut(&mut self) -> &mut String { match self.current_focus { AddLogicFocus::InputLogicName => &mut self.logic_name_input, AddLogicFocus::InputTargetColumn => &mut self.target_column_input, AddLogicFocus::InputDescription => &mut self.description_input, _ => &mut self.logic_name_input, } } fn fields(&self) -> Vec<&str> { vec!["Logic Name", "Target Column", "Description"] } fn set_current_field(&mut self, index: usize) { self.current_focus = match index { 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, }; } fn set_current_cursor_pos(&mut self, pos: usize) { match self.current_focus { AddLogicFocus::InputLogicName => { self.logic_name_cursor_pos = pos.min(self.logic_name_input.len()); } AddLogicFocus::InputTargetColumn => { self.target_column_cursor_pos = pos.min(self.target_column_input.len()); } AddLogicFocus::InputDescription => { self.description_cursor_pos = pos.min(self.description_input.len()); } _ => {} } } fn set_has_unsaved_changes(&mut self, changed: bool) { self.has_unsaved_changes = changed; } fn get_suggestions(&self) -> Option<&[String]> { None } fn get_selected_suggestion_index(&self) -> Option { None } }