Skip to main content

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, Default, Eq, PartialEq, EnumCount)]
22pub enum State {
23  On,
24  #[default]
25  Off
26}
27
28/// (appearances, label) for each state
29#[derive(Clone, Debug, Default)]
30pub struct Appearances (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 = (self.enter().clone(), self.appearances().clone(), self.label().clone());
79    (from, to)
80  }
81
82  /// Returns (exit, (enter, appearances, label))
83  #[inline]
84  pub fn off (&mut self) -> (
85    Option <Trigger>,
86    (Option <Trigger>, controller::Appearances, Option <String>)
87  ) {
88    if cfg!(debug_assertions) && self.state != State::On {
89      log::debug!("switch off state not on: {:?}", self.state);
90    }
91    let from = self.exit().clone();
92    self.state = State::Off;
93    let to = (self.enter().clone(), self.appearances().clone(), self.label().clone());
94    (from, to)
95  }
96}
97
98impl Builder {
99  #[inline]
100  pub const fn appearance (mut self,
101    state      : (State, controller::State),
102    appearance : view::Appearance
103  ) -> Self {
104    *self.appearances.appearance_mut (state) = appearance;
105    self
106  }
107  /// Overrides labels set with `label_on`, `label_off`
108  #[inline]
109  pub fn label (mut self, label : String) -> Self {
110    for (_, l) in self.appearances.0.iter_mut() {
111      *l = Some (label.clone());
112    }
113    self
114  }
115  #[inline]
116  pub fn label_on (mut self, label : String) -> Self {
117    self.appearances.0[State::On as usize].1 = Some (label);
118    self
119  }
120  #[inline]
121  pub fn label_off (mut self, label : String) -> Self {
122    self.appearances.0[State::Off as usize].1 = Some (label);
123    self
124  }
125  #[inline]
126  pub const fn enter (mut self, state : State, trigger : Trigger) -> Self {
127    *self.enter.get_mut (state) = Some (trigger);
128    self
129  }
130  #[inline]
131  pub const fn exit (mut self, state : State, trigger : Trigger) -> Self {
132    *self.exit.get_mut (state) = Some (trigger);
133    self
134  }
135  #[inline]
136  pub const fn style (mut self, state : (State, controller::State), style : view::Style)
137    -> Self
138  {
139    self.appearances.appearance_mut (state).style = Some(style);
140    self
141  }
142  #[inline]
143  pub fn style_default (mut self, state : (State, controller::State)) -> Self {
144    let style = Some (view::Style::default());
145    self.appearances.appearance_mut (state).style = style;
146    self
147  }
148  #[inline]
149  pub const fn sound (mut self, state : (State, controller::State), sound : view::Sound)
150    -> Self
151  {
152    self.appearances.appearance_mut (state).sound = Some (sound);
153    self
154  }
155  #[inline]
156  pub fn style_fg (mut self, state : (State, controller::State), color : view::Color)
157    -> Self
158  {
159    let style = &mut self.appearances.appearance_mut (state).style;
160    let mut s = style.take().unwrap_or_default();
161    s.fg      = color;
162    *style    = Some (s);
163    self
164  }
165  #[inline]
166  pub fn style_bg (mut self, state : (State, controller::State), color : view::Color)
167    -> Self
168  {
169    let appearance   = &mut self.appearances.0[state.0 as usize].0.0[state.1 as usize];
170    let mut style    = appearance.style.take().unwrap_or_default();
171    style.bg         = color;
172    appearance.style = Some (style);
173    self
174  }
175  #[inline]
176  pub fn style_lo (mut self, state : (State, controller::State), color : view::Color)
177    -> Self
178  {
179    let appearance   = &mut self.appearances.0[state.0 as usize].0.0[state.1 as usize];
180    let mut style    = appearance.style.take().unwrap_or_default();
181    style.lo         = color;
182    appearance.style = Some (style);
183    self
184  }
185  #[inline]
186  pub fn style_hi (mut self, state : (State, controller::State), color : view::Color)
187    -> Self
188  {
189    let appearance   = &mut self.appearances.0[state.0 as usize].0.0[state.1 as usize];
190    let mut style    = appearance.style.take().unwrap_or_default();
191    style.hi         = color;
192    appearance.style = Some (style);
193    self
194  }
195  pub const fn toggle (mut self, toggle : bool) -> Self {
196    self.toggle = toggle;
197    self
198  }
199  #[inline]
200  pub fn build (self) -> Switch {
201    Switch {
202      appearances: self.appearances,
203      enter:       self.enter,
204      exit:        self.exit,
205      toggle:      self.toggle,
206      .. Switch::default()
207    }
208  }
209}
210
211impl Appearances {
212  #[inline]
213  pub const fn appearance (&self, state : (State, controller::State))
214    -> &view::Appearance
215  {
216    self.0[state.0 as usize].0.get (state.1)
217  }
218
219  #[inline]
220  pub const fn appearance_mut (&mut self, state : (State, controller::State))
221    -> &mut view::Appearance
222  {
223    self.0[state.0 as usize].0.get_mut (state.1)
224  }
225}
226
227impl Triggers {
228  #[inline]
229  pub const fn get (&self, state : State) -> &Option <Trigger> {
230    &self.0[state as usize]
231  }
232
233  #[inline]
234  pub const fn get_mut (&mut self, state : State) -> &mut Option <Trigger> {
235    &mut self.0[state as usize]
236  }
237}
238
239impl Trigger {
240  /// Creates a switch that triggers a control function when set to 'On'
241  #[inline]
242  pub fn new <A : Application> (control : controls::Button, target : Option <NodeId>)
243    -> Self
244  {
245    use controller::controls::Control;
246    let control_fun = control.fun::<A::ButtonControls>();
247    Trigger { control_fun, target }
248  }
249}