Skip to main content

hexga_utils/
button.rs

1use super::*;
2
3pub mod prelude
4{
5    pub use super::traits::*;
6    pub use super::{ButtonEvolution, ButtonRepeat, ButtonState, ButtonStateEvolution, ButtonToggle};
7}
8pub mod traits
9{
10    pub use super::{ButtonEvolutionExtension, ButtonRepeatExtension, ButtonStateExtension, ButtonToggleExtension};
11}
12
13pub type ButtonEvolution = PreviousValue<ButtonState>;
14
15#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
16#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
17pub enum ButtonToggle
18{
19    /// False
20    #[default]
21    Hold,
22    /// True
23    Toggle,
24}
25pub trait ButtonToggleExtension: Has<ButtonToggle>
26{
27    fn is_hold(&self) -> bool { self.retrieve().is_hold() }
28    fn is_toggle(&self) -> bool { self.retrieve().is_toggle() }
29}
30impl<T> ButtonToggleExtension for T where T: Has<ButtonToggle> {}
31
32impl ButtonToggle
33{
34    pub const fn is_hold(self) -> bool { matches!(self, Self::Hold) }
35    pub const fn is_toggle(self) -> bool { matches!(self, Self::Toggle) }
36}
37impl From<bool> for ButtonToggle
38{
39    fn from(value: bool) -> Self { if value { Self::Toggle } else { Self::Hold } }
40}
41impl From<ButtonToggle> for bool
42{
43    fn from(value: ButtonToggle) -> Self { value.is_toggle() }
44}
45
46/// Describes the state of a button.
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
49pub enum ButtonState
50{
51    /// True
52    #[default]
53    Down,
54    /// False
55    Up,
56}
57pub trait ButtonStateExtension: Has<ButtonState>
58{
59    fn is_up(&self) -> bool { self.retrieve().is_up() }
60    fn is_down(&self) -> bool { self.retrieve().is_down() }
61}
62impl<T> ButtonStateExtension for T where T: Has<ButtonState> {}
63
64impl ButtonState
65{
66    pub const fn is_up(self) -> bool { matches!(self, ButtonState::Up) }
67    pub const fn is_down(self) -> bool { matches!(self, ButtonState::Down) }
68}
69impl From<bool> for ButtonState
70{
71    fn from(value: bool) -> Self { if value { Self::Down } else { Self::Up } }
72}
73impl From<ButtonState> for bool
74{
75    fn from(value: ButtonState) -> Self { value.is_down() }
76}
77
78#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
80pub enum ButtonRepeat
81{
82    #[default]
83    NotRepeated,
84    Repeated,
85}
86pub trait ButtonRepeatExtension: Has<ButtonRepeat>
87{
88    fn is_repeated(&self) -> bool { self.retrieve().is_repeated() }
89    fn is_not_repeated(&self) -> bool { self.retrieve().is_not_repeated() }
90}
91impl<T> ButtonRepeatExtension for T where T: Has<ButtonRepeat> {}
92
93impl ButtonRepeat
94{
95    pub const fn is_repeated(self) -> bool { matches!(self, ButtonRepeat::Repeated) }
96    pub const fn is_not_repeated(self) -> bool { matches!(self, ButtonRepeat::NotRepeated) }
97}
98impl From<bool> for ButtonRepeat
99{
100    fn from(value: bool) -> Self { if value { Self::Repeated } else { Self::NotRepeated } }
101}
102impl From<ButtonRepeat> for bool
103{
104    fn from(value: ButtonRepeat) -> Self { value.is_repeated() }
105}
106
107#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
108pub enum ButtonStateEvolution
109{
110    Down,
111    Up,
112    /// Can be use for toggle
113    Pressed,
114    /// Can be use for toggle
115    Released,
116}
117impl From<ButtonState> for ButtonStateEvolution
118{
119    fn from(value: ButtonState) -> Self
120    {
121        match value
122        {
123            ButtonState::Down => Self::Down,
124            ButtonState::Up => Self::Up,
125        }
126    }
127}
128impl Evolution<ButtonState> for ButtonStateEvolution
129{
130    fn value(&self) -> ButtonState { matches!(self, Self::Down | Self::Pressed).into() }
131    fn old_value(&self) -> ButtonState { matches!(self, Self::Down | Self::Released).into() }
132}
133
134pub trait ButtonEvolutionExtension: Evolution<ButtonState>
135{
136    fn is_down(&self) -> bool;
137    fn was_down(&self) -> bool;
138
139    fn is_up(&self) -> bool { !self.is_down() }
140    fn was_up(&self) -> bool { !self.was_down() }
141
142    /// Pull up, `false` to `true`, `0` to `1`,
143    fn is_pressed(&self) -> bool { self.is_down() && (!self.was_down()) }
144    /// Pull down, `true` to `false`, `1` to `0`
145    fn is_released(&self) -> bool { self.was_down() && (!self.is_down()) }
146
147    fn is_toggled(&self) -> bool { self.is_down() != self.was_down() }
148    fn is_constant(&self) -> bool { self.is_down() == self.was_down() }
149
150    fn is_hold(&self) -> bool { self.is_constant() && self.is_down() }
151
152    fn evolution(&self) -> ButtonStateEvolution
153    {
154        match (self.is_down(), self.was_down())
155        {
156            (true, true) => ButtonStateEvolution::Down,
157            (true, false) => ButtonStateEvolution::Pressed,
158            (false, true) => ButtonStateEvolution::Released,
159            (false, false) => ButtonStateEvolution::Up,
160        }
161    }
162}
163
164impl<T> ButtonEvolutionExtension for T
165where
166    T: Evolution<ButtonState>,
167{
168    fn is_down(&self) -> bool { self.value().is_down() }
169    fn was_down(&self) -> bool { self.old_value().is_down() }
170}