use std::fmt::Debug;
use bevy::math::{Vec2, Vec3};
use bevy::prelude::{Gamepad, World};
use bevy::reflect::{erased_serde, Reflect};
use dyn_clone::DynClone;
use dyn_eq::DynEq;
use dyn_hash::DynHash;
use serde::Serialize;
use updating::CentralInputStore;
use crate::clashing_inputs::BasicInputs;
use crate::InputControlKind;
pub use self::chord::*;
#[cfg(feature = "gamepad")]
pub use self::gamepad::*;
#[cfg(feature = "keyboard")]
pub use self::keyboard::*;
#[cfg(feature = "mouse")]
pub use self::mouse::*;
pub use self::trait_serde::RegisterUserInput;
pub mod chord;
#[cfg(feature = "gamepad")]
pub mod gamepad;
#[cfg(feature = "keyboard")]
pub mod keyboard;
#[cfg(feature = "mouse")]
pub mod mouse;
pub mod testing_utils;
mod trait_reflection;
mod trait_serde;
pub mod updating;
pub trait UserInput: Send + Sync + Debug {
fn kind(&self) -> InputControlKind;
fn decompose(&self) -> BasicInputs;
}
pub trait Buttonlike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
fn pressed(&self, input_store: &CentralInputStore, gamepad: Gamepad) -> bool;
fn released(&self, input_store: &CentralInputStore, gamepad: Gamepad) -> bool {
!self.pressed(input_store, gamepad)
}
fn press(&self, world: &mut World) {
self.press_as_gamepad(world, None);
}
fn press_as_gamepad(&self, world: &mut World, _gamepad: Option<Gamepad>) {
self.press(world);
}
fn release(&self, world: &mut World) {
self.release_as_gamepad(world, None);
}
fn release_as_gamepad(&self, world: &mut World, _gamepad: Option<Gamepad>) {
self.release(world);
}
}
pub trait Axislike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
fn value(&self, input_store: &CentralInputStore, gamepad: Gamepad) -> f32;
fn set_value(&self, world: &mut World, value: f32) {
self.set_value_as_gamepad(world, value, None);
}
fn set_value_as_gamepad(&self, world: &mut World, value: f32, _gamepad: Option<Gamepad>) {
self.set_value(world, value);
}
}
pub trait DualAxislike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
fn axis_pair(&self, input_store: &CentralInputStore, gamepad: Gamepad) -> Vec2;
fn set_axis_pair(&self, world: &mut World, value: Vec2) {
self.set_axis_pair_as_gamepad(world, value, None);
}
fn set_axis_pair_as_gamepad(&self, world: &mut World, value: Vec2, _gamepad: Option<Gamepad>) {
self.set_axis_pair(world, value);
}
}
pub trait TripleAxislike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
fn axis_triple(&self, input_store: &CentralInputStore, gamepad: Gamepad) -> Vec3;
fn set_axis_triple(&self, world: &mut World, value: Vec3) {
self.set_axis_triple_as_gamepad(world, value, None);
}
fn set_axis_triple_as_gamepad(
&self,
world: &mut World,
value: Vec3,
_gamepad: Option<Gamepad>,
) {
self.set_axis_triple(world, value);
}
}
#[derive(Reflect, Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub enum UserInputWrapper {
Button(Box<dyn Buttonlike>),
Axis(Box<dyn Axislike>),
DualAxis(Box<dyn DualAxislike>),
TripleAxis(Box<dyn TripleAxislike>),
}
impl UserInput for UserInputWrapper {
#[track_caller]
fn kind(&self) -> InputControlKind {
match self {
UserInputWrapper::Button(input) => {
debug_assert!(input.kind() == InputControlKind::Button);
input.kind()
}
UserInputWrapper::Axis(input) => {
debug_assert!(input.kind() == InputControlKind::Axis);
input.kind()
}
UserInputWrapper::DualAxis(input) => {
debug_assert!(input.kind() == InputControlKind::DualAxis);
input.kind()
}
UserInputWrapper::TripleAxis(input) => {
debug_assert!(input.kind() == InputControlKind::TripleAxis);
input.kind()
}
}
}
fn decompose(&self) -> BasicInputs {
match self {
UserInputWrapper::Button(input) => input.decompose(),
UserInputWrapper::Axis(input) => input.decompose(),
UserInputWrapper::DualAxis(input) => input.decompose(),
UserInputWrapper::TripleAxis(input) => input.decompose(),
}
}
}