gooey/interface/controller/component/
switch.rs

1use strum::EnumCount;
2use crate::Application;
3use crate::tree::NodeId;
4use crate::interface::view;
5use crate::interface::controller::{self, controls};
6use super::impl_kind;
7
8// TODO: do we really need separate enter/exit actions for both On/Off states?
9#[derive(Clone, Debug, Default)]
10pub struct Switch {
11  pub state       : State,
12  pub appearances : Appearances,
13  pub enter       : Triggers,
14  pub exit        : Triggers,
15  pub toggle      : bool
16  // TODO: trigger while
17  //pub while_ : [Option <Trigger>; State::COUNT]
18}
19impl_kind!(Switch);
20
21#[derive(Clone, Debug, Eq, PartialEq, EnumCount)]
22pub enum State {
23  On,
24  Off
25}
26
27/// (appearances, label) for each state
28#[derive(Clone, Debug, Default)]
29pub struct Appearances (
30  pub [(controller::Appearances, Option <String>); State::COUNT]);
31
32#[derive(Clone, Debug, Default)]
33pub struct Triggers (pub [Option <Trigger>; State::COUNT]);
34
35#[derive(Clone, Debug)]
36pub struct Trigger {
37  pub control_fun : controls::Fun <controls::button::Release>,
38  pub target      : Option <NodeId>
39}
40
41#[derive(Clone, Default)]
42pub struct Builder {
43  pub appearances : Appearances,
44  pub enter       : Triggers,
45  pub exit        : Triggers,
46  pub toggle      : bool
47}
48
49impl Switch {
50  #[inline]
51  pub fn enter (&self) -> &Option <Trigger> {
52    &self.enter.0[self.state.clone() as usize]
53  }
54  #[inline]
55  pub fn exit (&self) -> &Option <Trigger> {
56    &self.exit.0[self.state.clone() as usize]
57  }
58  #[inline]
59  pub fn appearances (&self) -> &controller::Appearances {
60    &self.appearances.0[self.state.clone() as usize].0
61  }
62  #[inline]
63  pub fn label (&self) -> &Option <String> {
64    &self.appearances.0[self.state.clone() as usize].1
65  }
66
67  /// Returns (exit, (enter, appearances, label))
68  #[inline]
69  pub fn on (&mut self) -> (
70    Option <Trigger>,
71    (Option <Trigger>, controller::Appearances, Option <String>)
72  ) {
73    if cfg!(debug_assertions) && self.state != State::Off {
74      log::debug!("switch on state not off: {:?}", self.state);
75    }
76    let from   = self.exit().clone();
77    self.state = State::On;
78    let to     =
79      (self.enter().clone(), self.appearances().clone(), self.label().clone());
80    (from, to)
81  }
82
83  /// Returns (exit, (enter, appearances, label))
84  #[inline]
85  pub fn off (&mut self) -> (
86    Option <Trigger>,
87    (Option <Trigger>, controller::Appearances, Option <String>)
88  ) {
89    if cfg!(debug_assertions) && self.state != State::On {
90      log::debug!("switch off state not on: {:?}", self.state);
91    }
92    let from   = self.exit().clone();
93    self.state = State::Off;
94    let to     =
95      (self.enter().clone(), self.appearances().clone(), self.label().clone());
96    (from, to)
97  }
98}
99
100impl Builder {
101  #[inline]
102  pub fn appearance (mut self,
103    state      : (State, controller::State),
104    appearance : view::Appearance
105  ) -> Self {
106    *self.appearances.appearance_mut (state) = appearance;
107    self
108  }
109  /// Overrides labels set with `label_on`, `label_off`
110  #[inline]
111  pub fn label (mut self, label : String) -> Self {
112    for (_, l) in self.appearances.0.iter_mut() {
113      *l = Some (label.clone());
114    }
115    self
116  }
117  #[inline]
118  pub fn label_on (mut self, label : String) -> Self {
119    self.appearances.0[State::On as usize].1 = Some (label);
120    self
121  }
122  #[inline]
123  pub fn label_off (mut self, label : String) -> Self {
124    self.appearances.0[State::Off as usize].1 = Some (label);
125    self
126  }
127  #[inline]
128  pub fn enter (mut self, state : State, trigger : Trigger) -> Self {
129    *self.enter.get_mut (state) = Some (trigger);
130    self
131  }
132  #[inline]
133  pub fn exit (mut self, state : State, trigger : Trigger) -> Self {
134    *self.exit.get_mut (state) = Some (trigger);
135    self
136  }
137  #[inline]
138  pub fn style (mut self,
139    state : (State, controller::State), style : view::Style
140  ) -> Self {
141    self.appearances.appearance_mut (state).style = Some(style);
142    self
143  }
144  #[inline]
145  pub fn style_default (mut self, state : (State, controller::State)) -> Self {
146    let style = Some (view::Style::default());
147    self.appearances.appearance_mut (state).style = style;
148    self
149  }
150  #[inline]
151  pub fn sound (mut self,
152    state : (State, controller::State), sound : view::Sound
153  ) -> Self {
154    self.appearances.appearance_mut (state).sound = Some (sound);
155    self
156  }
157  #[inline]
158  pub fn style_fg (mut self,
159    state : (State, controller::State), color : view::Color
160  ) -> Self {
161    let style = &mut self.appearances.appearance_mut (state).style;
162    let mut s = style.take().unwrap_or_default();
163    s.fg      = color;
164    *style    = Some (s);
165    self
166  }
167  #[inline]
168  pub fn style_bg (mut self,
169    state : (State, controller::State), color : view::Color
170  ) -> Self {
171    let appearance   = &mut self.appearances.0[state.0 as usize]
172      .0.0[state.1 as usize];
173    let mut style    = appearance.style.take().unwrap_or_default();
174    style.bg         = color;
175    appearance.style = Some (style);
176    self
177  }
178  #[inline]
179  pub fn style_lo (mut self,
180    state : (State, controller::State), color : view::Color
181  ) -> Self {
182    let appearance   = &mut self.appearances.0[state.0 as usize]
183      .0.0[state.1 as usize];
184    let mut style    = appearance.style.take().unwrap_or_default();
185    style.lo         = color;
186    appearance.style = Some (style);
187    self
188  }
189  #[inline]
190  pub fn style_hi (mut self,
191    state : (State, controller::State), color : view::Color
192  ) -> Self {
193    let appearance   = &mut self.appearances.0[state.0 as usize]
194      .0.0[state.1 as usize];
195    let mut style    = appearance.style.take().unwrap_or_default();
196    style.hi         = color;
197    appearance.style = Some (style);
198    self
199  }
200  pub fn toggle (mut self, toggle : bool) -> Self {
201    self.toggle = toggle;
202    self
203  }
204  #[inline]
205  pub fn build (self) -> Switch {
206    Switch {
207      appearances: self.appearances,
208      enter:       self.enter,
209      exit:        self.exit,
210      toggle:      self.toggle,
211      .. Switch::default()
212    }
213  }
214}
215
216impl Appearances {
217  #[inline]
218  pub fn appearance (&self, state : (State, controller::State))
219    -> &view::Appearance
220  {
221    self.0[state.0 as usize].0.get (state.1)
222  }
223
224  #[inline]
225  pub fn appearance_mut (&mut self, state : (State, controller::State))
226    -> &mut view::Appearance
227  {
228    self.0[state.0 as usize].0.get_mut (state.1)
229  }
230}
231
232impl Triggers {
233  #[inline]
234  pub fn get (&self, state : State) -> &Option <Trigger> {
235    &self.0[state as usize]
236  }
237
238  #[inline]
239  pub fn get_mut (&mut self, state : State) -> &mut Option <Trigger> {
240    &mut self.0[state as usize]
241  }
242}
243
244impl Trigger {
245  /// Creates a switch that triggers a control function when set to 'On'
246  #[inline]
247  pub fn new <A : Application>
248    (control : controls::Button, target : Option <NodeId>) -> Self
249  {
250    use controller::controls::Control;
251    let control_fun = control.fun::<A::ButtonControls>();
252    Trigger { control_fun, target }
253  }
254}
255
256impl Default for State {
257  fn default() -> Self {
258    State::Off
259  }
260}