Skip to main content

gooey/interface/view/input/button/
mod.rs

1use std;
2use derive_more::{From, TryInto};
3use parse_display::{Display, FromStr};
4use strum::{EnumCount, FromRepr};
5use crate::interface::controller::controls;
6use super::Modifiers;
7
8pub mod keycode;
9pub use self::keycode::Keycode;
10
11#[derive(Clone, Copy, Debug, Eq)]
12pub struct Button {
13  pub variant   : Variant,
14  pub modifiers : Modifiers
15}
16
17#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
18pub enum State {
19  Pressed,
20  Released
21}
22
23/// Identifies which button was pressed.
24///
25/// NOTE: the types contained in this newtype wrapper should have unique
26/// serializations, this is so we can omit the tag when giving bindings in
27/// configuration files (see `control::button::Binding`).
28///
29/// `serde_plain` is unable to parse untagged enums, so we use the
30/// `parse_display::FromStr` derive instead.
31// TODO: joystick buttons ?
32#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Display, FromStr, From,
33  TryInto)]
34#[display("{0:?}")]  // an "untagged" serialization format for FromStr
35pub enum Variant {
36  Keycode (Keycode),
37  Mouse   (Mouse)
38}
39
40/// A mouse button
41#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, EnumCount, FromRepr,
42  FromStr)]
43pub enum Mouse {
44  Mouse1, Mouse2, Mouse3, Mouse4, Mouse5
45}
46
47/// Binds an input button to a button control and implements custom serialization format
48#[derive(Clone, Debug, Eq, PartialEq)]
49pub struct Binding <E : controls::Id <controls::Button> = controls::Nil>
50  (pub Button, pub controls::button::Control <E>, pub std::marker::PhantomData <E>);
51
52impl <E : controls::Id <controls::Button>> Binding <E> {
53  pub fn new (button : Button, control : controls::button::Control <E>) -> Self {
54    Binding (button, control, Default::default())
55  }
56}
57impl <E : controls::Id <controls::Button>>
58  From <controls::button::Binding <E>> for Binding <E>
59{
60  fn from (controls::button::Binding (control, input, _) : controls::button::Binding <E>)
61    -> Self
62  {
63    Binding::new (input, control)
64  }
65}
66impl <E : controls::Id <controls::Button>>
67  From <Binding <E>> for (Button, controls::button::Control <E>)
68{
69  fn from (Binding (input, control, _) : Binding <E>) -> Self {
70    (input, control)
71  }
72}
73impl <E : controls::Id <controls::Button>>
74  From <(Button, controls::button::Control <E>)> for Binding <E>
75{
76  fn from ((input, control) : (Button, controls::button::Control <E>)) -> Self {
77    Binding::new (input, control)
78  }
79}
80
81impl Button {
82  pub const fn with_modifiers (self, modifiers : Modifiers) -> Self {
83    Button { modifiers, .. self }
84  }
85}
86
87impl PartialEq for Button {
88  fn eq (&self, other : &Self) -> bool {
89    if self.variant != other.variant {
90      false
91    } else if self.modifiers.contains (Modifiers::ANY)
92      || other.modifiers.contains (Modifiers::ANY)
93    {
94      true
95    } else {
96      self.modifiers == other.modifiers
97    }
98  }
99}
100
101// NOTE: we need to define partial ord to use custom partial eq comparison
102#[expect(clippy::non_canonical_partial_ord_impl)]
103impl PartialOrd for Button {
104  fn partial_cmp (&self, other : &Self) -> Option <std::cmp::Ordering> {
105    let out = if self == other {
106      std::cmp::Ordering::Equal
107    } else if self.variant > other.variant {
108      std::cmp::Ordering::Greater
109    } else if self.variant < other.variant {
110      std::cmp::Ordering::Less
111    } else if self.modifiers > other.modifiers {
112      std::cmp::Ordering::Greater
113    } else if self.modifiers < other.modifiers {
114      std::cmp::Ordering::Less
115    } else {
116      unreachable!()
117    };
118    Some (out)
119  }
120}
121
122// NOTE: we need to define ord to use custom partial ord comparison
123impl Ord for Button {
124  fn cmp (&self, other : &Self) -> std::cmp::Ordering {
125    self.partial_cmp (other).unwrap()
126  }
127}
128
129impl <K : Into <Variant>> From <K> for Button {
130  fn from (k : K) -> Self {
131    Button {
132      variant:   k.into(),
133      modifiers: Modifiers::empty()
134    }
135  }
136}
137
138//
139// private
140//
141
142struct ButtonVisitor;
143
144impl serde::Serialize for Button {
145  fn serialize <S : serde::Serializer> (&self, serializer : S)
146    -> Result <S::Ok, S::Error>
147  {
148    serializer.serialize_str (&format!("{}{}",
149      self.variant, self.modifiers.to_string().to_uppercase()))
150  }
151}
152
153impl serde::de::Visitor <'_> for ButtonVisitor {
154  type Value = Button;
155  fn expecting (&self, formatter : &mut std::fmt::Formatter) -> std::fmt::Result {
156    formatter.write_str ("A control: button pair")
157  }
158  fn visit_str <ERR : serde::de::Error> (self, v : &str) -> Result <Self::Value, ERR> {
159    use std::str::FromStr;
160    let mut iter = v.split (':').next().unwrap().split ('+');
161    let s        = iter.next().unwrap();
162    let variant  = Variant::from_str (s).map_err (|err|{
163      log::error!(err:?, string=s; "error parsing button");
164      panic!("error parsing button string \"{s}\": {err}")
165    }).unwrap();
166    let mut modifiers = Modifiers::empty();
167    for modifier in iter {
168      match modifier.to_lowercase().as_str() {
169        "shift" => modifiers |= Modifiers::SHIFT,
170        "ctrl"  => modifiers |= Modifiers::CTRL,
171        "alt"   => modifiers |= Modifiers::ALT,
172        "super" => modifiers |= Modifiers::SUPER,
173        "any"   => modifiers |= Modifiers::ANY,
174        _ => return Err (
175          ERR::custom (format!("Unrecognized modifier: {modifier:?}")))
176      }
177    }
178    Ok (Button { variant, modifiers })
179  }
180}
181
182impl <'de> serde::Deserialize <'de> for Button {
183  fn deserialize <D : serde::Deserializer <'de>> (deserializer : D)
184    -> Result <Self, D::Error>
185  {
186    deserializer.deserialize_str (ButtonVisitor)
187  }
188}
189
190struct BindingVisitor <E : controls::Id <controls::Button> = controls::Nil> (
191  std::marker::PhantomData <E>);
192
193impl <E : controls::Id <controls::Button>> serde::Serialize for Binding <E> {
194  fn serialize <S : serde::Serializer> (&self, serializer : S)
195    -> Result <S::Ok, S::Error>
196  {
197    let input   = serde_plain::to_string (&self.0).unwrap();
198    let control = serde_plain::to_string (&self.1).unwrap();
199    serializer.serialize_str (&format!("{input}: {control}"))
200  }
201}
202
203impl <E : controls::Id <controls::Button>>
204  serde::de::Visitor <'_> for BindingVisitor <E>
205{
206  type Value = Binding <E>;
207  fn expecting (&self, formatter : &mut std::fmt::Formatter) -> std::fmt::Result {
208    formatter.write_str ("A button: control pair")
209  }
210  fn visit_str <ERR : serde::de::Error> (self, v : &str) -> Result <Self::Value, ERR> {
211    let input = {
212      let s = v.split (':').next().unwrap();
213      serde_plain::from_str::<Button> (s).unwrap()
214    };
215    let control : controls::button::Control <E> = {
216      let s = v.split (' ').nth (1).unwrap();
217      serde_plain::from_str::<controls::button::Control <E>> (s).unwrap()
218    };
219    Ok (Binding::new (input, control))
220  }
221}
222
223impl <'de, E : controls::Id <controls::Button>>
224  serde::Deserialize <'de> for Binding <E>
225{
226  fn deserialize <D : serde::Deserializer <'de>> (deserializer : D)
227    -> Result <Self, D::Error>
228  {
229    deserializer.deserialize_str (BindingVisitor (Default::default()))
230  }
231}
232
233#[cfg(test)]
234mod test {
235  use strum;
236  use crate::interface::controller::controls;
237
238  use super::*;
239
240  #[test]
241  fn variant_unique_serialization() {
242    use strum::EnumCount;
243    for i in 0..Keycode::COUNT {
244      use std::str::FromStr;
245      let variant = Variant::from (Keycode::from_repr (i).unwrap());
246      let s = variant.to_string();
247      assert_eq!(variant, Variant::from_str (&s).unwrap());
248    }
249
250    for i in 0..Mouse::COUNT {
251      use std::str::FromStr;
252      let variant = Variant::from (Mouse::from_repr (i).unwrap());
253      let s = variant.to_string();
254      assert_eq!(variant, Variant::from_str (&s).unwrap());
255    }
256  }
257
258  #[test]
259  fn button_equality() {
260    let a = Button { modifiers: Modifiers::ANY, .. Button::from (Keycode::A) };
261    let b = Button { modifiers: Modifiers::SHIFT, .. Button::from (Keycode::A) };
262    let c = Button { modifiers: Modifiers::ANY, .. Button::from (Keycode::C) };
263    let d = Button::from (Keycode::C);
264    assert_eq!(a, b);
265    assert_eq!(&a, &b);
266    assert_ne!(a, c);
267    assert_eq!(c, d);
268    assert_eq!(&c, &d);
269    let buttons = [(a, controls::Button (0))];
270    assert_eq!(a.cmp (&b), std::cmp::Ordering::Equal);
271    let _ = buttons.binary_search_by_key (&b, |(button, _)| *button).unwrap();
272  }
273}