gooey/interface/view/input/button/
mod.rs1use std;
2use derive_more::{From, TryInto};
3use parse_display::{Display, FromStr};
4use strum::{EnumCount, FromRepr};
5use super::Modifiers;
6
7pub mod keycode;
8pub use self::keycode::Keycode;
9
10#[derive(Clone, Copy, Debug, Eq)]
11pub struct Button {
12 pub variant : Variant,
13 pub modifiers : Modifiers
14}
15
16#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
17pub enum State {
18 Pressed,
19 Released
20}
21
22#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd,
32 Display, FromStr, From, TryInto)]
33#[display("{0:?}")] pub enum Variant {
35 Keycode (Keycode),
36 Mouse (Mouse)
37}
38
39#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, EnumCount, FromRepr,
41 FromStr)]
42pub enum Mouse {
43 Mouse1, Mouse2, Mouse3, Mouse4, Mouse5
44}
45
46impl PartialEq for Button {
47 fn eq (&self, other : &Self) -> bool {
48 if self.variant != other.variant {
49 false
50 } else if self.modifiers.contains (Modifiers::ANY)
51 || other.modifiers.contains (Modifiers::ANY)
52 {
53 true
54 } else {
55 self.modifiers == other.modifiers
56 }
57 }
58}
59
60#[expect(clippy::non_canonical_partial_ord_impl)]
62impl PartialOrd for Button {
63 fn partial_cmp (&self, other : &Self) -> Option <std::cmp::Ordering> {
64 let out = if self == other {
65 std::cmp::Ordering::Equal
66 } else if self.variant > other.variant {
67 std::cmp::Ordering::Greater
68 } else if self.variant < other.variant {
69 std::cmp::Ordering::Less
70 } else if self.modifiers > other.modifiers {
71 std::cmp::Ordering::Greater
72 } else if self.modifiers < other.modifiers {
73 std::cmp::Ordering::Less
74 } else {
75 unreachable!()
76 };
77 Some (out)
78 }
79}
80
81impl Ord for Button {
83 fn cmp (&self, other : &Self) -> std::cmp::Ordering {
84 self.partial_cmp (other).unwrap()
85 }
86}
87
88impl <K : Into <Variant>> From <K> for Button {
89 fn from (k : K) -> Self {
90 Button {
91 variant: k.into(),
92 modifiers: Modifiers::empty()
93 }
94 }
95}
96
97#[cfg(test)]
98mod test {
99 use strum;
100 use crate::interface::controller::controls;
101
102 use super::*;
103
104 #[test]
105 fn variant_unique_serialization() {
106 use strum::EnumCount;
107 for i in 0..Keycode::COUNT {
108 use std::str::FromStr;
109 let variant = Variant::from (Keycode::from_repr (i).unwrap());
110 let s = variant.to_string();
111 assert_eq!(variant, Variant::from_str (&s).unwrap());
112 }
113
114 for i in 0..Mouse::COUNT {
115 use std::str::FromStr;
116 let variant = Variant::from (Mouse::from_repr (i).unwrap());
117 let s = variant.to_string();
118 assert_eq!(variant, Variant::from_str (&s).unwrap());
119 }
120 }
121
122 #[test]
123 fn button_equality() {
124 let a = Button { modifiers: Modifiers::ANY, .. Button::from (Keycode::A) };
125 let b = Button { modifiers: Modifiers::SHIFT, .. Button::from (Keycode::A) };
126 let c = Button { modifiers: Modifiers::ANY, .. Button::from (Keycode::C) };
127 let d = Button::from (Keycode::C);
128 assert_eq!(a, b);
129 assert_eq!(&a, &b);
130 assert_ne!(a, c);
131 assert_eq!(c, d);
132 assert_eq!(&c, &d);
133 let buttons = [(a, controls::Button (0))];
134 assert_eq!(a.cmp (&b), std::cmp::Ordering::Equal);
135 let _ = buttons.binary_search_by_key (&b, |(button, _)| *button).unwrap();
136 }
137}