9eead719b0
Full project snapshot migrated to new Gitea remote without history: engine, editor, physics, script, examples, tests, docs, and assets. Relicensed from GPLv3 to MIT and updated repo URLs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
119 lines
5.0 KiB
Rust
119 lines
5.0 KiB
Rust
//! Default editor input bindings + the action-name constants the bindings
|
||
//! UI and any debug overlay address.
|
||
//!
|
||
//! Living in the editor library (not the binary) so the Stage-7
|
||
//! [`InputBindings`](crate::shell::Shell) preferences page and any future
|
||
//! editor module can re-register or remap the same actions without
|
||
//! depending on the binary's private module.
|
||
|
||
use oxide_engine::input::{ActionMap, AxisBinding, Binding};
|
||
use oxide_engine::winit::keyboard::KeyCode;
|
||
|
||
/// The settings-section name under which the editor's
|
||
/// [`ActionOverrides`](oxide_engine::input::ActionOverrides) are persisted.
|
||
///
|
||
/// The shell registers this section automatically in
|
||
/// [`EditorState::new`](crate::state::EditorState::new); UI code that wants
|
||
/// to refresh the section after a binding change addresses it by this name.
|
||
pub const SETTINGS_SECTION: &str = "input.bindings";
|
||
|
||
/// Stable action names addressed throughout the editor — the bindings
|
||
/// preferences page, the camera input poll in the runner, and any future
|
||
/// debug overlay all reference these strings.
|
||
pub mod action {
|
||
/// Button: toggle between orbit and flythrough viewport cameras.
|
||
pub const TOGGLE_FLYTHROUGH: &str = "editor.camera.toggle_flythrough";
|
||
/// Button (held): accelerate flythrough translation while engaged.
|
||
pub const SPRINT: &str = "editor.camera.sprint";
|
||
/// 1D axis: strafe right (+) / strafe left (−) in flythrough mode.
|
||
pub const MOVE_RIGHT: &str = "editor.camera.move_right";
|
||
/// 1D axis: forward (+) / back (−) in flythrough mode.
|
||
pub const MOVE_FORWARD: &str = "editor.camera.move_forward";
|
||
/// 1D axis: ascend (+) / descend (−) in flythrough mode.
|
||
pub const MOVE_UP: &str = "editor.camera.move_up";
|
||
|
||
/// Button: switch the transform gizmo to Translate mode (orbit camera only).
|
||
pub const GIZMO_TRANSLATE: &str = "editor.gizmo.translate";
|
||
/// Button: switch the transform gizmo to Rotate mode (orbit camera only).
|
||
pub const GIZMO_ROTATE: &str = "editor.gizmo.rotate";
|
||
/// Button: switch the transform gizmo to Scale mode (orbit camera only).
|
||
pub const GIZMO_SCALE: &str = "editor.gizmo.scale";
|
||
}
|
||
|
||
/// Registers the editor's default action set on `actions`. Defaults follow
|
||
/// the DCC-tools convention (WASD + QE, Shift sprint, F toggles the
|
||
/// flythrough camera) so users coming from Blender / Maya / Unity feel at
|
||
/// home.
|
||
///
|
||
/// Idempotent on the action names — re-registering preserves any user-
|
||
/// remapped current bindings while refreshing the defaults that the
|
||
/// "Restore defaults" button reverts to.
|
||
pub fn register_defaults(actions: &mut ActionMap) {
|
||
actions
|
||
.register(action::TOGGLE_FLYTHROUGH, [Binding::Key(KeyCode::KeyF)])
|
||
.register(
|
||
action::SPRINT,
|
||
[
|
||
Binding::Key(KeyCode::ShiftLeft),
|
||
Binding::Key(KeyCode::ShiftRight),
|
||
],
|
||
)
|
||
.register_axis(
|
||
action::MOVE_RIGHT,
|
||
AxisBinding::new([Binding::Key(KeyCode::KeyD)], [Binding::Key(KeyCode::KeyA)]),
|
||
)
|
||
.register_axis(
|
||
action::MOVE_FORWARD,
|
||
AxisBinding::new([Binding::Key(KeyCode::KeyW)], [Binding::Key(KeyCode::KeyS)]),
|
||
)
|
||
.register_axis(
|
||
action::MOVE_UP,
|
||
AxisBinding::new([Binding::Key(KeyCode::KeyE)], [Binding::Key(KeyCode::KeyQ)]),
|
||
)
|
||
// Gizmo tool hotkeys (W/E/R). These share physical keys with
|
||
// flythrough movement, so the host gates them on the camera being
|
||
// in orbit mode — in flythrough W/E move the camera, in orbit
|
||
// they switch the gizmo tool.
|
||
.register(action::GIZMO_TRANSLATE, [Binding::Key(KeyCode::KeyW)])
|
||
.register(action::GIZMO_ROTATE, [Binding::Key(KeyCode::KeyE)])
|
||
.register(action::GIZMO_SCALE, [Binding::Key(KeyCode::KeyR)]);
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn defaults_register_every_advertised_action() {
|
||
let mut actions = ActionMap::new();
|
||
register_defaults(&mut actions);
|
||
|
||
assert!(actions.has(action::TOGGLE_FLYTHROUGH));
|
||
assert!(actions.has(action::SPRINT));
|
||
assert!(actions.has_axis(action::MOVE_RIGHT));
|
||
assert!(actions.has_axis(action::MOVE_FORWARD));
|
||
assert!(actions.has_axis(action::MOVE_UP));
|
||
}
|
||
|
||
#[test]
|
||
fn defaults_are_idempotent_and_preserve_remaps() {
|
||
let mut actions = ActionMap::new();
|
||
register_defaults(&mut actions);
|
||
|
||
// User remaps Toggle to Tab.
|
||
actions.set_bindings(action::TOGGLE_FLYTHROUGH, vec![Binding::Key(KeyCode::Tab)]);
|
||
|
||
// Re-running register_defaults must not stomp the user's remap.
|
||
register_defaults(&mut actions);
|
||
assert_eq!(
|
||
actions.bindings(action::TOGGLE_FLYTHROUGH),
|
||
&[Binding::Key(KeyCode::Tab)]
|
||
);
|
||
// But the defaults — what "Restore defaults" reverts to — are still F.
|
||
assert_eq!(
|
||
actions.defaults(action::TOGGLE_FLYTHROUGH),
|
||
&[Binding::Key(KeyCode::KeyF)]
|
||
);
|
||
}
|
||
}
|