use std::marker::PhantomData;
use bevy::log::error;
use bevy::prelude::Reflect;
use serde::{Deserialize, Serialize};
use crate::bindings::{AnalogInput, Chord, ChordLike, InputBinding, PulseBinding};
use crate::phantom::{IBWrp, Pulse, SingleAxis};
#[derive(Debug, Default, Serialize, Deserialize, Reflect, Clone, PartialEq)]
pub enum SingleAxisBinding {
#[default]
Dummy,
Analog {
input: AnalogInput,
#[serde(default)]
inversion: Inversion,
#[serde(default)]
sensitivity: Sensitivity,
},
Hold(Chord, Chord),
Toggle(PulseBinding, PulseBinding),
}
#[derive(Debug, Default, Serialize, Deserialize, Reflect, Clone, PartialEq, Eq, Hash)]
pub enum Inversion {
#[default]
NotInverted,
Inverted,
}
impl Inversion {
pub fn maybe_invert(&self, value: f32) -> f32 {
match self {
Inversion::NotInverted => value,
Inversion::Inverted => -1.0 * value,
}
}
pub fn multiplier(&self) -> f32 {
match self {
Inversion::NotInverted => 1.0,
Inversion::Inverted => -1.0,
}
}
}
#[derive(Debug, Serialize, Deserialize, Reflect, Clone, PartialEq)]
pub struct Sensitivity(f32);
impl Sensitivity {
pub fn multiplier(&self) -> f32 {
self.0
}
}
impl Default for Sensitivity {
fn default() -> Self {
Sensitivity(1.0)
}
}
impl SingleAxisBinding {
pub fn analog(input: AnalogInput) -> SingleAxisAnalogBuilder {
SingleAxisAnalogBuilder::new(input)
}
#[must_use]
pub fn hold() -> SingleAxisHoldBuilder {
SingleAxisHoldBuilder::default()
}
#[must_use]
pub fn toggle() -> SingleAxisToggleBuilder {
SingleAxisToggleBuilder::default()
}
}
#[derive(Debug)]
pub struct SingleAxisAnalogBuilder {
input: AnalogInput,
inversion: Inversion,
sensitivity: Sensitivity,
}
impl SingleAxisAnalogBuilder {
#[must_use]
pub fn new(input: AnalogInput) -> Self {
Self {
input,
inversion: Inversion::default(),
sensitivity: Sensitivity::default(),
}
}
#[must_use]
pub fn invert(mut self) -> Self {
self.inversion = if matches!(self.inversion, Inversion::Inverted) {
Inversion::NotInverted
} else {
Inversion::Inverted
};
self
}
#[must_use]
pub fn set_sensitivity(mut self, sensitivity: f32) -> Self {
self.sensitivity.0 = sensitivity;
self
}
#[must_use]
pub fn build(self) -> IBWrp<SingleAxis> {
let binding = InputBinding::SingleAxis(SingleAxisBinding::Analog {
input: self.input,
inversion: self.inversion,
sensitivity: self.sensitivity,
});
IBWrp::<SingleAxis>(binding, PhantomData)
}
}
#[derive(Debug, Default)]
pub struct SingleAxisHoldBuilder {
negative: Option<Chord>,
positive: Option<Chord>,
}
impl SingleAxisHoldBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn set_negative(mut self, input: impl Into<ChordLike>) -> Self {
self.negative = Some(input.into().into());
self
}
#[must_use]
pub fn set_positive(mut self, input: impl Into<ChordLike>) -> Self {
self.positive = Some(input.into().into());
self
}
#[must_use]
pub fn build(self) -> IBWrp<SingleAxis> {
let binding = InputBinding::SingleAxis(SingleAxisBinding::Hold(
self.negative.unwrap_or_default(),
self.positive.unwrap_or_default(),
));
IBWrp::<SingleAxis>(binding, PhantomData)
}
}
#[derive(Debug, Default)]
pub struct SingleAxisToggleBuilder {
negative: Option<PulseBinding>,
positive: Option<PulseBinding>,
}
impl SingleAxisToggleBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn set_negative(mut self, input: IBWrp<Pulse>) -> Self {
self.negative = Some(Self::unwrap_pulse(input));
self
}
#[must_use]
pub fn set_positive(mut self, input: IBWrp<Pulse>) -> Self {
self.positive = Some(Self::unwrap_pulse(input));
self
}
#[must_use]
pub fn build(self) -> IBWrp<SingleAxis> {
let binding = InputBinding::SingleAxis(SingleAxisBinding::Toggle(
self.negative.unwrap_or(PulseBinding::Dummy),
self.positive.unwrap_or(PulseBinding::Dummy),
));
IBWrp::<SingleAxis>(binding, PhantomData)
}
fn unwrap_pulse(input: IBWrp<Pulse>) -> PulseBinding {
if let InputBinding::Pulse(pulse) = input.0 {
pulse
} else {
error!("SingleAxisBinding::Toggle requires a pulse input: every time it pulses, the axis input switches direction.\n\
\tWe didn't get a pulse input, so this binding is not going to work.\n\
\tTry to call this function like this:\n\
\t`SingleAxisBinding::toggle().with_negative(PulseBinding::just_pressed(KeyCode::Left)).build()`");
PulseBinding::Dummy
}
}
}