use std;
use derive_more::{From, TryInto};
use parse_display::{Display, FromStr};
use strum::{EnumCount, FromRepr};
use crate::interface::controller::controls;
use super::Modifiers;
pub mod keycode;
pub use self::keycode::Keycode;
#[derive(Clone, Copy, Debug, Eq)]
pub struct Button {
pub variant : Variant,
pub modifiers : Modifiers
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum State {
Pressed,
Released
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Display, FromStr, From,
TryInto)]
#[display("{0:?}")] pub enum Variant {
Keycode (Keycode),
Mouse (Mouse)
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, EnumCount, FromRepr,
FromStr)]
pub enum Mouse {
Mouse1, Mouse2, Mouse3, Mouse4, Mouse5
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Binding <E : controls::Id <controls::Button> = controls::Nil>
(pub Button, pub controls::button::Control <E>, pub std::marker::PhantomData <E>);
impl <E : controls::Id <controls::Button>> Binding <E> {
pub fn new (button : Button, control : controls::button::Control <E>) -> Self {
Binding (button, control, Default::default())
}
}
impl <E : controls::Id <controls::Button>>
From <controls::button::Binding <E>> for Binding <E>
{
fn from (controls::button::Binding (control, input, _) : controls::button::Binding <E>)
-> Self
{
Binding::new (input, control)
}
}
impl <E : controls::Id <controls::Button>>
From <Binding <E>> for (Button, controls::button::Control <E>)
{
fn from (Binding (input, control, _) : Binding <E>) -> Self {
(input, control)
}
}
impl <E : controls::Id <controls::Button>>
From <(Button, controls::button::Control <E>)> for Binding <E>
{
fn from ((input, control) : (Button, controls::button::Control <E>)) -> Self {
Binding::new (input, control)
}
}
impl Button {
pub const fn with_modifiers (self, modifiers : Modifiers) -> Self {
Button { modifiers, .. self }
}
}
impl PartialEq for Button {
fn eq (&self, other : &Self) -> bool {
if self.variant != other.variant {
false
} else if self.modifiers.contains (Modifiers::ANY)
|| other.modifiers.contains (Modifiers::ANY)
{
true
} else {
self.modifiers == other.modifiers
}
}
}
#[expect(clippy::non_canonical_partial_ord_impl)]
impl PartialOrd for Button {
fn partial_cmp (&self, other : &Self) -> Option <std::cmp::Ordering> {
let out = if self == other {
std::cmp::Ordering::Equal
} else if self.variant > other.variant {
std::cmp::Ordering::Greater
} else if self.variant < other.variant {
std::cmp::Ordering::Less
} else if self.modifiers > other.modifiers {
std::cmp::Ordering::Greater
} else if self.modifiers < other.modifiers {
std::cmp::Ordering::Less
} else {
unreachable!()
};
Some (out)
}
}
impl Ord for Button {
fn cmp (&self, other : &Self) -> std::cmp::Ordering {
self.partial_cmp (other).unwrap()
}
}
impl <K : Into <Variant>> From <K> for Button {
fn from (k : K) -> Self {
Button {
variant: k.into(),
modifiers: Modifiers::empty()
}
}
}
struct ButtonVisitor;
impl serde::Serialize for Button {
fn serialize <S : serde::Serializer> (&self, serializer : S)
-> Result <S::Ok, S::Error>
{
serializer.serialize_str (&format!("{}{}",
self.variant, self.modifiers.to_string().to_uppercase()))
}
}
impl serde::de::Visitor <'_> for ButtonVisitor {
type Value = Button;
fn expecting (&self, formatter : &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str ("A control: button pair")
}
fn visit_str <ERR : serde::de::Error> (self, v : &str) -> Result <Self::Value, ERR> {
use std::str::FromStr;
let mut iter = v.split (':').next().unwrap().split ('+');
let s = iter.next().unwrap();
let variant = Variant::from_str (s).map_err (|err|{
log::error!(err:?, string=s; "error parsing button");
panic!("error parsing button string \"{s}\": {err}")
}).unwrap();
let mut modifiers = Modifiers::empty();
for modifier in iter {
match modifier.to_lowercase().as_str() {
"shift" => modifiers |= Modifiers::SHIFT,
"ctrl" => modifiers |= Modifiers::CTRL,
"alt" => modifiers |= Modifiers::ALT,
"super" => modifiers |= Modifiers::SUPER,
"any" => modifiers |= Modifiers::ANY,
_ => return Err (
ERR::custom (format!("Unrecognized modifier: {modifier:?}")))
}
}
Ok (Button { variant, modifiers })
}
}
impl <'de> serde::Deserialize <'de> for Button {
fn deserialize <D : serde::Deserializer <'de>> (deserializer : D)
-> Result <Self, D::Error>
{
deserializer.deserialize_str (ButtonVisitor)
}
}
struct BindingVisitor <E : controls::Id <controls::Button> = controls::Nil> (
std::marker::PhantomData <E>);
impl <E : controls::Id <controls::Button>> serde::Serialize for Binding <E> {
fn serialize <S : serde::Serializer> (&self, serializer : S)
-> Result <S::Ok, S::Error>
{
let input = serde_plain::to_string (&self.0).unwrap();
let control = serde_plain::to_string (&self.1).unwrap();
serializer.serialize_str (&format!("{input}: {control}"))
}
}
impl <E : controls::Id <controls::Button>>
serde::de::Visitor <'_> for BindingVisitor <E>
{
type Value = Binding <E>;
fn expecting (&self, formatter : &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str ("A button: control pair")
}
fn visit_str <ERR : serde::de::Error> (self, v : &str) -> Result <Self::Value, ERR> {
let input = {
let s = v.split (':').next().unwrap();
serde_plain::from_str::<Button> (s).unwrap()
};
let control : controls::button::Control <E> = {
let s = v.split (' ').nth (1).unwrap();
serde_plain::from_str::<controls::button::Control <E>> (s).unwrap()
};
Ok (Binding::new (input, control))
}
}
impl <'de, E : controls::Id <controls::Button>>
serde::Deserialize <'de> for Binding <E>
{
fn deserialize <D : serde::Deserializer <'de>> (deserializer : D)
-> Result <Self, D::Error>
{
deserializer.deserialize_str (BindingVisitor (Default::default()))
}
}
#[cfg(test)]
mod test {
use strum;
use crate::interface::controller::controls;
use super::*;
#[test]
fn variant_unique_serialization() {
use strum::EnumCount;
for i in 0..Keycode::COUNT {
use std::str::FromStr;
let variant = Variant::from (Keycode::from_repr (i).unwrap());
let s = variant.to_string();
assert_eq!(variant, Variant::from_str (&s).unwrap());
}
for i in 0..Mouse::COUNT {
use std::str::FromStr;
let variant = Variant::from (Mouse::from_repr (i).unwrap());
let s = variant.to_string();
assert_eq!(variant, Variant::from_str (&s).unwrap());
}
}
#[test]
fn button_equality() {
let a = Button { modifiers: Modifiers::ANY, .. Button::from (Keycode::A) };
let b = Button { modifiers: Modifiers::SHIFT, .. Button::from (Keycode::A) };
let c = Button { modifiers: Modifiers::ANY, .. Button::from (Keycode::C) };
let d = Button::from (Keycode::C);
assert_eq!(a, b);
assert_eq!(&a, &b);
assert_ne!(a, c);
assert_eq!(c, d);
assert_eq!(&c, &d);
let buttons = [(a, controls::Button (0))];
assert_eq!(a.cmp (&b), std::cmp::Ordering::Equal);
let _ = buttons.binary_search_by_key (&b, |(button, _)| *button).unwrap();
}
}