add logic now using general movement
This commit is contained in:
@@ -1,199 +1,149 @@
|
||||
// src/pages/admin_panel/add_logic/event.rs
|
||||
use anyhow::Result;
|
||||
use crossterm::event::{Event, KeyCode, KeyModifiers};
|
||||
use crate::config::binds::config::Config;
|
||||
use crate::modes::handlers::event::EventOutcome;
|
||||
use crate::pages::admin_panel::add_logic::state::{AddLogicFormState, AddLogicFocus};
|
||||
use crate::movement::{move_focus, MovementAction};
|
||||
use crate::pages::admin_panel::add_logic::nav::SaveLogicResultSender;
|
||||
use crate::pages::admin_panel::add_logic::state::{AddLogicFocus, AddLogicFormState};
|
||||
use crate::components::common::text_editor::TextEditor;
|
||||
use crate::services::grpc_client::GrpcClient;
|
||||
use crate::pages::admin_panel::add_logic::nav::SaveLogicResultSender; // keep type alias
|
||||
use crate::state::app::state::AppState;
|
||||
use canvas::DataProvider;
|
||||
use crossterm::event::KeyEvent;
|
||||
|
||||
/// Focus traversal order for non-canvas navigation
|
||||
const ADD_LOGIC_FOCUS_ORDER: [AddLogicFocus; 6] = [
|
||||
AddLogicFocus::InputLogicName,
|
||||
AddLogicFocus::InputTargetColumn,
|
||||
AddLogicFocus::InputDescription,
|
||||
AddLogicFocus::ScriptContentPreview,
|
||||
AddLogicFocus::SaveButton,
|
||||
AddLogicFocus::CancelButton,
|
||||
];
|
||||
|
||||
/// Return true if the event was handled and UI should be redrawn.
|
||||
pub fn handle_add_logic_event(
|
||||
event: Event,
|
||||
key_event: KeyEvent,
|
||||
movement: Option<MovementAction>,
|
||||
config: &Config,
|
||||
app_state: &mut AppState,
|
||||
add_logic_page: &mut AddLogicFormState,
|
||||
grpc_client: GrpcClient,
|
||||
save_logic_sender: SaveLogicResultSender,
|
||||
) -> Result<EventOutcome> {
|
||||
if let Event::Key(key_event) = event {
|
||||
let st = &mut add_logic_page.state;
|
||||
let key_code = key_event.code;
|
||||
let modifiers = key_event.modifiers;
|
||||
|
||||
// 1) Fullscreen Script Editor mode
|
||||
if st.current_focus == AddLogicFocus::InsideScriptContent {
|
||||
match key_code {
|
||||
KeyCode::Esc if modifiers == KeyModifiers::NONE => {
|
||||
st.current_focus = AddLogicFocus::ScriptContentPreview;
|
||||
app_state.ui.focus_outside_canvas = true;
|
||||
return Ok(EventOutcome::Ok("Exited script editing.".into()));
|
||||
}
|
||||
_ => {
|
||||
let changed = {
|
||||
let mut editor_borrow = st.script_content_editor.borrow_mut();
|
||||
TextEditor::handle_input(
|
||||
&mut editor_borrow,
|
||||
key_event,
|
||||
&st.editor_keybinding_mode,
|
||||
&mut st.vim_state,
|
||||
)
|
||||
};
|
||||
if changed {
|
||||
st.has_unsaved_changes = true;
|
||||
return Ok(EventOutcome::Ok("Script updated".into()));
|
||||
} else {
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
command_message: &mut String,
|
||||
) -> bool {
|
||||
// 1) Script editor fullscreen mode
|
||||
if add_logic_page.state.current_focus == AddLogicFocus::InsideScriptContent {
|
||||
match key_event.code {
|
||||
crossterm::event::KeyCode::Esc => {
|
||||
add_logic_page.state.current_focus = AddLogicFocus::ScriptContentPreview;
|
||||
app_state.ui.focus_outside_canvas = true;
|
||||
*command_message = "Exited script editing.".to_string();
|
||||
return true;
|
||||
}
|
||||
_ => {
|
||||
let changed = {
|
||||
let mut editor_borrow =
|
||||
add_logic_page.state.script_content_editor.borrow_mut();
|
||||
TextEditor::handle_input(
|
||||
&mut editor_borrow,
|
||||
key_event,
|
||||
&add_logic_page.state.editor_keybinding_mode,
|
||||
&mut add_logic_page.state.vim_state,
|
||||
)
|
||||
};
|
||||
if changed {
|
||||
add_logic_page.state.has_unsaved_changes = true;
|
||||
*command_message = "Script updated".to_string();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Canvas inputs (three fields) – forward to FormEditor
|
||||
let inside_canvas_inputs = matches!(
|
||||
st.current_focus,
|
||||
AddLogicFocus::InputLogicName
|
||||
// 2) Inside canvas: forward to FormEditor
|
||||
let inside_canvas_inputs = matches!(
|
||||
add_logic_page.state.current_focus,
|
||||
AddLogicFocus::InputLogicName
|
||||
| AddLogicFocus::InputTargetColumn
|
||||
| AddLogicFocus::InputDescription
|
||||
);
|
||||
);
|
||||
|
||||
if inside_canvas_inputs {
|
||||
// Handoff from last field to Script Preview on "down"/"next"
|
||||
let last_idx = add_logic_page
|
||||
.editor
|
||||
.data_provider()
|
||||
.field_count()
|
||||
.saturating_sub(1);
|
||||
if inside_canvas_inputs {
|
||||
if let Some(ma) = movement {
|
||||
let last_idx = add_logic_page.editor.data_provider().field_count().saturating_sub(1);
|
||||
let at_last = add_logic_page.editor.current_field() >= last_idx;
|
||||
|
||||
// Map to generic "down/next" via config or raw keys
|
||||
let action_opt = config.get_general_action(key_code, modifiers);
|
||||
let is_down_or_next = matches!(
|
||||
action_opt,
|
||||
Some("down") | Some("next") | Some("move_down") | Some("next_field")
|
||||
)
|
||||
|| matches!(key_code, KeyCode::Down)
|
||||
|| matches!(key_code, KeyCode::Char('j') if modifiers.is_empty());
|
||||
|
||||
if at_last && is_down_or_next {
|
||||
st.last_canvas_field = last_idx;
|
||||
st.current_focus = AddLogicFocus::ScriptContentPreview;
|
||||
add_logic_page.focus_outside_canvas = true;
|
||||
if at_last && matches!(ma, MovementAction::Down | MovementAction::Next) {
|
||||
add_logic_page.state.last_canvas_field = last_idx;
|
||||
add_logic_page.state.current_focus = AddLogicFocus::ScriptContentPreview;
|
||||
app_state.ui.focus_outside_canvas = true;
|
||||
return Ok(EventOutcome::Ok(
|
||||
"Moved to Script Preview".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// Normal canvas input
|
||||
match add_logic_page.editor.handle_key_event(key_event) {
|
||||
canvas::keymap::KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
add_logic_page.sync_from_editor();
|
||||
return Ok(EventOutcome::Ok(msg));
|
||||
}
|
||||
canvas::keymap::KeyEventOutcome::Consumed(None) => {
|
||||
add_logic_page.sync_from_editor();
|
||||
return Ok(EventOutcome::Ok("Input updated".into()));
|
||||
}
|
||||
canvas::keymap::KeyEventOutcome::Pending => {
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
canvas::keymap::KeyEventOutcome::NotMatched => {
|
||||
// fall through to outside handling
|
||||
}
|
||||
*command_message = "Moved to Script Preview".to_string();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Outside-canvas focus (Script Preview, Save, Cancel)
|
||||
let action_opt = config.get_general_action(key_code, modifiers);
|
||||
match add_logic_page.handle_key_event(key_event) {
|
||||
canvas::keymap::KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
add_logic_page.sync_from_editor();
|
||||
if !msg.is_empty() {
|
||||
*command_message = msg;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
canvas::keymap::KeyEventOutcome::Consumed(None) => {
|
||||
add_logic_page.sync_from_editor();
|
||||
return true;
|
||||
}
|
||||
canvas::keymap::KeyEventOutcome::Pending => return true,
|
||||
canvas::keymap::KeyEventOutcome::NotMatched => {}
|
||||
}
|
||||
}
|
||||
|
||||
match action_opt {
|
||||
Some("up") | Some("move_up") | Some("previous") | Some("previous_option") | Some("prev_field") => {
|
||||
match st.current_focus {
|
||||
AddLogicFocus::ScriptContentPreview => {
|
||||
st.current_focus = AddLogicFocus::InputDescription;
|
||||
add_logic_page.focus_outside_canvas = false;
|
||||
app_state.ui.focus_outside_canvas = false;
|
||||
return Ok(EventOutcome::Ok(
|
||||
"Back to Description".to_string(),
|
||||
));
|
||||
}
|
||||
AddLogicFocus::SaveButton => {
|
||||
st.current_focus = AddLogicFocus::ScriptContentPreview;
|
||||
return Ok(EventOutcome::Ok(
|
||||
"Back to Script Preview".to_string(),
|
||||
));
|
||||
}
|
||||
AddLogicFocus::CancelButton => {
|
||||
st.current_focus = AddLogicFocus::SaveButton;
|
||||
return Ok(EventOutcome::Ok("Back to Save".to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Some("down") | Some("move_down") | Some("next") | Some("next_option") | Some("next_field") => {
|
||||
match st.current_focus {
|
||||
AddLogicFocus::ScriptContentPreview => {
|
||||
st.current_focus = AddLogicFocus::SaveButton;
|
||||
return Ok(EventOutcome::Ok("Focus: Save".to_string()));
|
||||
}
|
||||
AddLogicFocus::SaveButton => {
|
||||
st.current_focus = AddLogicFocus::CancelButton;
|
||||
return Ok(EventOutcome::Ok("Focus: Cancel".to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Some("select") => {
|
||||
match st.current_focus {
|
||||
AddLogicFocus::ScriptContentPreview => {
|
||||
st.current_focus = AddLogicFocus::InsideScriptContent;
|
||||
add_logic_page.focus_outside_canvas = false;
|
||||
app_state.ui.focus_outside_canvas = false;
|
||||
return Ok(EventOutcome::Ok(
|
||||
"Fullscreen script editing. Esc to exit.".into(),
|
||||
));
|
||||
}
|
||||
AddLogicFocus::SaveButton => {
|
||||
if let Some(msg) = st.save_logic() {
|
||||
return Ok(EventOutcome::Ok(msg));
|
||||
}
|
||||
return Ok(EventOutcome::Ok(
|
||||
"Saved (no changes)".to_string(),
|
||||
));
|
||||
}
|
||||
AddLogicFocus::CancelButton => {
|
||||
// Keep this simple: you can wire buffer/view navigation where needed
|
||||
return Ok(EventOutcome::Ok(
|
||||
"Cancelled Add Logic".to_string(),
|
||||
));
|
||||
}
|
||||
AddLogicFocus::InputLogicName
|
||||
| AddLogicFocus::InputTargetColumn
|
||||
| AddLogicFocus::InputDescription => {
|
||||
add_logic_page.focus_outside_canvas = false;
|
||||
app_state.ui.focus_outside_canvas = false;
|
||||
return Ok(EventOutcome::Ok(String::new()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Some("esc") => {
|
||||
if st.current_focus == AddLogicFocus::ScriptContentPreview {
|
||||
// Go back to Description (last canvas field)
|
||||
st.current_focus = AddLogicFocus::InputDescription;
|
||||
add_logic_page.focus_outside_canvas = false;
|
||||
// 3) Outside canvas
|
||||
if let Some(ma) = movement {
|
||||
let mut current = add_logic_page.state.current_focus;
|
||||
if move_focus(&ADD_LOGIC_FOCUS_ORDER, &mut current, ma) {
|
||||
add_logic_page.state.current_focus = current;
|
||||
app_state.ui.focus_outside_canvas = !matches!(
|
||||
add_logic_page.state.current_focus,
|
||||
AddLogicFocus::InputLogicName
|
||||
| AddLogicFocus::InputTargetColumn
|
||||
| AddLogicFocus::InputDescription
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
match ma {
|
||||
MovementAction::Select => match add_logic_page.state.current_focus {
|
||||
AddLogicFocus::ScriptContentPreview => {
|
||||
add_logic_page.state.current_focus = AddLogicFocus::InsideScriptContent;
|
||||
app_state.ui.focus_outside_canvas = false;
|
||||
return Ok(EventOutcome::Ok(
|
||||
"Back to Description".to_string(),
|
||||
));
|
||||
*command_message = "Fullscreen script editing. Esc to exit.".to_string();
|
||||
return true;
|
||||
}
|
||||
AddLogicFocus::SaveButton => {
|
||||
if let Some(msg) = add_logic_page.state.save_logic() {
|
||||
*command_message = msg;
|
||||
} else {
|
||||
*command_message = "Saved (no changes)".to_string();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
AddLogicFocus::CancelButton => {
|
||||
*command_message = "Cancelled Add Logic".to_string();
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
MovementAction::Esc => {
|
||||
if add_logic_page.state.current_focus == AddLogicFocus::ScriptContentPreview {
|
||||
add_logic_page.state.current_focus = AddLogicFocus::InputDescription;
|
||||
app_state.ui.focus_outside_canvas = false;
|
||||
*command_message = "Back to Description".to_string();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(EventOutcome::Ok(String::new()))
|
||||
false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user