use super::*;
use crate::components::InputKey;
use crate::editor::behavior::graph::Card;
use crate::editor::behavior::navigate::{self, Dir};
use crate::editor::behavior_chart::CARD_POOL;
fn direction(key: InputKey) -> Option<Dir> {
Some(match key {
InputKey::Up => Dir::Up,
InputKey::Down => Dir::Down,
InputKey::Left => Dir::Left,
InputKey::Right => Dir::Right,
_ => return None,
})
}
fn reachable(cards: &[Card]) -> &[Card] {
&cards[..cards.len().min(CARD_POOL)]
}
impl EditorHook {
pub(super) fn behavior_keys(&mut self, world: &mut World, input: &FrameInput) {
if input.escape {
self.cancel_behavior_key(world);
return;
}
let Some(key) = input.captured_key else {
return;
};
if self.behavior_palette_open() {
self.behavior_palette_key(key, world);
return;
}
if input.ctrl {
if !self.behavior_focus && !self.behavior_name_focus {
self.clipboard_behavior_key(key, world);
}
return;
}
match key {
InputKey::Enter => self.commit_behavior_key(world),
_ if self.behavior_name_focus => {}
InputKey::Tab => {
self.apply_behavior_action(BehaviorAction::ToggleView, world, [0.0, 0.0])
}
_ => {
let step = direction(key).filter(|d| !(self.behavior_focus && d.horizontal()));
if let Some(dir) = step {
self.step_behavior_selection(dir, world);
}
}
}
}
fn clipboard_behavior_key(&mut self, key: InputKey, world: &mut World) {
let action = match key {
InputKey::C => BehaviorAction::Copy,
InputKey::V => BehaviorAction::Paste,
InputKey::D => BehaviorAction::Duplicate,
_ => return,
};
self.apply_behavior_action(action, world, [0.0, 0.0]);
}
fn behavior_palette_open(&self) -> bool {
self.behavior_picking && !self.behavior_data().picks.is_empty()
}
fn behavior_palette_key(&mut self, key: InputKey, world: &mut World) {
match key {
InputKey::Enter => {
let Some(&at) = self.behavior_data().matches.get(self.behavior_pick) else {
return;
};
self.apply_behavior_action(BehaviorAction::Choose(at), world, [0.0, 0.0]);
}
InputKey::Up | InputKey::Down => {
let total = self.behavior_data().matches.len();
let delta = if key == InputKey::Up { -1 } else { 1 };
let Some(at) = navigate::step(Some(self.behavior_pick), delta, total) else {
return;
};
self.behavior_pick = at;
self.behavior_pick_scroll =
navigate::scroll_to(at, self.behavior_pick_scroll, behavior_panel::PICK_POOL);
}
_ => {}
}
}
fn cancel_behavior_key(&mut self, world: &mut World) {
if self.behavior_palette_open() {
self.apply_behavior_action(BehaviorAction::Dismiss, world, [0.0, 0.0]);
return;
}
if std::mem::take(&mut self.behavior_remove_armed) {
return;
}
if self.behavior_name_focus {
self.blur_behavior_name(world);
return;
}
self.behavior_focus = false;
}
fn commit_behavior_key(&mut self, world: &mut World) {
if self.behavior_name_focus {
self.rename_behavior(world);
return;
}
if self.behavior_focus {
self.commit_behavior_value(world);
return;
}
let action = match self.behavior_mode {
ViewMode::Overview => match self.behavior_overview_card {
Some(card) => BehaviorAction::OpenCard(card),
None => return,
},
_ if self.behavior_row.is_some() && !self.behavior_data().picks.is_empty() => {
BehaviorAction::Palette
}
_ => return,
};
self.apply_behavior_action(action, world, [0.0, 0.0]);
}
fn step_behavior_selection(&mut self, dir: Dir, world: &mut World) {
match self.behavior_mode {
ViewMode::Outline => {
let Some(delta) = dir.list_step() else {
return;
};
let total = self.behavior_rows().len();
let Some(row) = navigate::step(self.behavior_row, delta, total) else {
return;
};
self.apply_behavior_action(BehaviorAction::Select(row), world, [0.0, 0.0]);
}
ViewMode::Chart => {
let data = self.behavior_data();
let Some(card) = navigate::nearest(reachable(&data.chart.cards), data.card, dir)
else {
return;
};
self.apply_behavior_action(BehaviorAction::SelectCard(card), world, [0.0, 0.0]);
}
ViewMode::Overview => {
let data = self.behavior_data();
let cards = reachable(&data.overview.cards);
let from = self.behavior_overview_card.filter(|&i| i < cards.len());
let Some(card) = navigate::nearest(cards, from, dir) else {
return;
};
self.behavior_overview_card = Some(card);
}
}
self.ensure_behavior_visible();
}
}