initial editor mode

This commit is contained in:
2026-06-15 22:02:15 -05:00
parent f2dc7861d9
commit d1d0824d37
7 changed files with 507 additions and 63 deletions
+48 -6
View File
@@ -1,7 +1,9 @@
use ratatui::crossterm::event::{Event, KeyCode, MouseEventKind};
use ratatui::crossterm::event::{Event, KeyCode, MouseButton, MouseEventKind};
use kiln_core::Direction;
use kiln_core::game::{GameState, ScrollLine};
use crate::editor::{editor_menu_items, EditorState};
use crate::menu::{MenuItem, MenuKey, pause_menu_items, ActionRc as MenuActionRc};
use crate::mode::Mode;
use crate::ui::Ui;
/// Moves the player and, if the move crosses a portal, captures both board Rcs
@@ -25,6 +27,8 @@ pub enum InputMode {
Scroll,
/// A menu overlay is active; all input is captured for menu navigation.
Menu,
/// Editing a world: arrow keys move the cursor, the sidebar is shown.
Editor,
/// An animation is running and has not claimed any input mode; all input is discarded.
Ignore,
/// Reserved for a post-transition freeze; nothing currently produces this mode.
@@ -32,15 +36,20 @@ pub enum InputMode {
Frozen,
}
/// Determines the current input mode from game and UI state.
pub(crate) fn current_input_mode(game: &GameState, ui: &Ui) -> InputMode {
/// Determines the current input mode from the active [`Mode`] and UI state.
pub(crate) fn current_input_mode(mode: &Mode, ui: &Ui) -> InputMode {
// An active animation declares its own input mode; pending transitions ignore input.
if let Some(anim) = &ui.active_animation {
return anim.input_mode_during();
}
if ui.pending_transition.is_some() { return InputMode::Ignore; }
if ui.menu.is_some() { return InputMode::Menu; }
if game.active_scroll.is_some() { InputMode::Scroll } else { InputMode::Board }
match mode {
Mode::Edit(_) => InputMode::Editor,
Mode::Play(game) => {
if game.active_scroll.is_some() { InputMode::Scroll } else { InputMode::Board }
}
}
}
/// Handles an input event in [`InputMode::Board`]. Returns `true` if the player quit.
@@ -72,6 +81,39 @@ pub(crate) fn handle_board_input(event: Event, log_open: bool, terminal_h: u16,
false
}
/// Handles an input event in [`InputMode::Editor`].
///
/// Arrow keys move the cursor; `l` toggles the log; `Esc` opens the editor menu.
/// A right-click jumps the cursor to the clicked board cell, and dragging the
/// board/sidebar divider resizes the sidebar (the divider sits at `term_w -
/// sidebar_width`, mirroring the log's bottom divider).
pub(crate) fn handle_editor_input(
event: Event,
term_w: u16,
ed: &mut EditorState,
ui: &mut Ui,
) {
match event {
Event::Key(key) => match key.code {
KeyCode::Esc => ui.open_menu(editor_menu_items()),
KeyCode::Up => ed.move_cursor(0, -1),
KeyCode::Down => ed.move_cursor(0, 1),
KeyCode::Left => ed.move_cursor(-1, 0),
KeyCode::Right => ed.move_cursor(1, 0),
KeyCode::Char('l') => ui.log.toggle(),
_ => {}
},
Event::Mouse(m) => match m.kind {
// Right-click moves the cursor to the clicked cell (if on the board).
MouseEventKind::Down(MouseButton::Right) => ed.set_cursor_at_screen(m.column, m.row),
// Dragging the divider resizes the sidebar.
MouseEventKind::Drag(_) => ed.resize_sidebar(term_w.saturating_sub(m.column), term_w),
_ => {}
},
_ => {}
}
}
/// Returns the choice string for the given key character, scanning the scroll lines.
fn resolve_choice(lines: &[ScrollLine], c: char) -> Option<String> {
let mut letter = b'a';
@@ -117,7 +159,7 @@ pub(crate) fn handle_scroll_input(event: Event, game: &mut GameState, ui: &mut U
///
/// Uses the clone-then-dispatch pattern: the action `Rc` is cloned to release
/// the immutable borrow on `ui.menu`, then the action is called with full `&mut Ui`.
pub(crate) fn handle_menu_input(event: Event, game: &mut GameState, ui: &mut Ui) {
pub(crate) fn handle_menu_input(event: Event, ui: &mut Ui) {
match event {
Event::Key(key) => {
let pressed = match key.code {
@@ -133,7 +175,7 @@ pub(crate) fn handle_menu_input(event: Event, game: &mut GameState, ui: &mut Ui)
.and_then(|m| m.items.iter().find(|i| i.key == mk))
.map(|i| i.action_rc());
if let Some(action) = action {
MenuItem::call_action_rc(action, game, ui);
MenuItem::call_action_rc(action, ui);
}
}
}