diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index bae9602..2faf82a 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -665,19 +665,24 @@ impl EventHandler { // First let the canvas editor try to handle the key if app_state.ui.show_form { if let Some(editor) = &mut app_state.form_editor { - match editor.handle_key_event(key_event) { + let outcome = editor.handle_key_event(key_event); + let new_mode = AppMode::from(editor.mode()); + match outcome { KeyEventOutcome::Consumed(Some(msg)) => { + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(msg)); } KeyEventOutcome::Consumed(None) => { + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(String::new())); } KeyEventOutcome::Pending => { - // Waiting for multi-key sequence (e.g. after pressing 'g') + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(String::new())); } KeyEventOutcome::NotMatched => { - // Fall through to client-level actions + app_state.update_mode(new_mode); + // Fall through } } } @@ -721,18 +726,24 @@ impl EventHandler { AppMode::Highlight => { if app_state.ui.show_form { if let Some(editor) = &mut app_state.form_editor { - match editor.handle_key_event(key_event) { + let outcome = editor.handle_key_event(key_event); + let new_mode = AppMode::from(editor.mode()); + match outcome { KeyEventOutcome::Consumed(Some(msg)) => { + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(msg)); } KeyEventOutcome::Consumed(None) => { + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(String::new())); } KeyEventOutcome::Pending => { + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(String::new())); } KeyEventOutcome::NotMatched => { - // Fall through to client-level actions + app_state.update_mode(new_mode); + // Fall through } } } @@ -764,20 +775,25 @@ impl EventHandler { // Let the canvas editor handle edit-mode keys if app_state.ui.show_form { if let Some(editor) = &mut app_state.form_editor { - match editor.handle_key_event(key_event) { + let outcome = editor.handle_key_event(key_event); + let new_mode = AppMode::from(editor.mode()); + match outcome { KeyEventOutcome::Consumed(Some(msg)) => { self.command_message = msg.clone(); + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(msg)); } KeyEventOutcome::Consumed(None) => { + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(String::new())); } KeyEventOutcome::Pending => { - // Rare in edit mode, but allow multi-key sequences if defined + app_state.update_mode(new_mode); return Ok(EventOutcome::Ok(String::new())); } KeyEventOutcome::NotMatched => { - // Fall through to client-level actions + app_state.update_mode(new_mode); + // Fall through } } } diff --git a/client/src/modes/handlers/mode_manager.rs b/client/src/modes/handlers/mode_manager.rs index 15fbd10..9e0a713 100644 --- a/client/src/modes/handlers/mode_manager.rs +++ b/client/src/modes/handlers/mode_manager.rs @@ -10,51 +10,58 @@ pub enum AppMode { General, // For intro and admin screens ReadOnly, // Canvas read-only mode Edit, // Canvas edit mode - Highlight, // Cnavas highlight/visual mode + Highlight, // Canvas highlight/visual mode Command, // Command mode overlay } +impl From for AppMode { + fn from(mode: canvas::AppMode) -> Self { + match mode { + canvas::AppMode::General => AppMode::General, + canvas::AppMode::ReadOnly => AppMode::ReadOnly, + canvas::AppMode::Edit => AppMode::Edit, + canvas::AppMode::Highlight => AppMode::Highlight, + canvas::AppMode::Command => AppMode::Command, + } + } +} + pub struct ModeManager; impl ModeManager { - // Determine current mode based on app state + /// Determine current mode based on app state pub fn derive_mode( app_state: &AppState, event_handler: &EventHandler, admin_state: &AdminState, ) -> AppMode { + // Navigation palette always forces General if event_handler.navigation_state.active { return AppMode::General; } + // Explicit command mode flag if event_handler.command_mode { return AppMode::Command; } - // NEW: delegate highlight detection to FormEditor + // ✅ Always trust the FormEditor when a form is active if let Some(editor) = &app_state.form_editor { - if editor.mode() == CanvasMode::Highlight { - return AppMode::Highlight; - } + return AppMode::from(editor.mode()); } - let is_canvas_view = app_state.ui.show_login - || app_state.ui.show_register - || app_state.ui.show_form - || app_state.ui.show_add_table - || app_state.ui.show_add_logic; - + // --- Non-form views (add_logic, add_table, etc.) --- if app_state.ui.show_add_logic { match admin_state.add_logic_state.current_focus { AddLogicFocus::InputLogicName - | AddLogicFocus::InputTargetColumn - | AddLogicFocus::InputDescription => { - if event_handler.is_edit_mode { - AppMode::Edit - } else { - AppMode::ReadOnly - } + | AddLogicFocus::InputTargetColumn + | AddLogicFocus::InputDescription => { + if event_handler.is_edit_mode { + AppMode::Edit + } else { + AppMode::ReadOnly } + } _ => AppMode::General, } } else if app_state.ui.show_add_table { @@ -65,10 +72,11 @@ impl ModeManager { } else { AppMode::ReadOnly } - } else if is_canvas_view { - if app_state.ui.focus_outside_canvas { - AppMode::General - } else if event_handler.is_edit_mode { + } else if app_state.ui.show_login + || app_state.ui.show_register + { + // login/register still use the old flag + if event_handler.is_edit_mode { AppMode::Edit } else { AppMode::ReadOnly @@ -79,7 +87,7 @@ impl ModeManager { } // Mode transition rules -pub fn can_enter_command_mode(current_mode: AppMode) -> bool { + pub fn can_enter_command_mode(current_mode: AppMode) -> bool { !matches!(current_mode, AppMode::Edit) } @@ -88,7 +96,10 @@ pub fn can_enter_command_mode(current_mode: AppMode) -> bool { } pub fn can_enter_read_only_mode(current_mode: AppMode) -> bool { - matches!(current_mode, AppMode::Edit | AppMode::Command | AppMode::Highlight) + matches!( + current_mode, + AppMode::Edit | AppMode::Command | AppMode::Highlight + ) } pub fn can_enter_highlight_mode(current_mode: AppMode) -> bool {