gooey/interface/controller/
mod.rs

1//! Interaction components
2
3use std::cell::RefCell;
4use std::convert::TryFrom;
5use std::iter::FromIterator;
6use log;
7use bitflags::bitflags;
8use key_vec::KeyVec;
9use smallvec::SmallVec;
10use strum::EnumCount;
11
12use crate::prelude::*;
13
14// control trait and types
15pub mod controls;
16pub use self::controls::Controls;
17// serializable bindings and builder
18pub mod bindings;
19pub use self::bindings::Bindings;
20// controller components
21pub mod component;
22pub use self::component::Component;
23// data types
24pub mod alignment;
25pub mod offset;
26pub mod size;
27pub use self::alignment::Alignment;
28pub use self::offset::Offset;
29pub use self::size::Size;
30
31/// A component that holds control bindings and interaction state.
32///
33/// Controllers handle the translation of `view::Input` events to interface
34/// `Action`s via `Control` bindings.
35// TODO: builder pattern? because input_map is private, we can't use .. syntax
36#[derive(Clone, Debug, Default)]
37pub struct Controller {
38  pub component   : Component,
39  /// Defines behavior and appearance
40  pub state       : State,
41  /// View appearance selection for each state
42  pub appearances : Appearances,
43  /// Controls whether the node will be moved to the last sibling position
44  /// ("top") when processed by a `Focus` action (either as the target node or
45  /// an ancestor of the target node).
46  ///
47  /// Defaults to `false`. Note that some widget builders may set this to true
48  /// unless overridden (e.g. free frame widgets).
49  pub focus_top   : bool,
50  /// Controls whether unhandled input is bubbled up to parent: when true
51  /// unhandled input will be trapped (not bubbled), when false unhandled input
52  /// will be passed to the parent node.
53  ///
54  /// Defaults to `InputMask::empty()`
55  pub bubble_trap : InputMask,
56  /// Defines mappings from inputs to controls
57  input_map       : InputMap
58}
59
60/// Determines appearance and behavior
61#[derive(Clone, Debug, Eq, PartialEq, EnumCount)]
62pub enum State {
63  Enabled,
64  Focused,
65  Disabled
66}
67
68#[derive(Clone, Debug, Eq, PartialEq)]
69pub enum Area {
70  /// Specifies the area inside any border (default)
71  Interior,
72  /// Specifies the total area including any border
73  Exterior
74}
75
76/// Flow of child content
77#[derive(Clone, Copy, Debug, Eq, PartialEq)]
78pub enum Orientation {
79  Horizontal,
80  Vertical
81}
82
83/// Selection of an appearance for each state
84#[derive(Clone, Debug, Default, PartialEq)]
85pub struct Appearances (pub [view::Appearance; State::COUNT]);
86#[derive(Default)]
87pub struct AppearancesBuilder ([view::Appearance; State::COUNT]);
88
89bitflags! {
90  #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
91  pub struct InputMask : u8 {
92    const AXIS    = 0b00000001;
93    const BUTTON  = 0b00000010;
94    const MOTION  = 0b00000100;
95    const POINTER = 0b00001000;
96    const SYSTEM  = 0b00010000;
97    const TEXT    = 0b00100000;
98    const WHEEL   = 0b01000000;
99  }
100}
101
102/// Concrete control bindings for all input types.
103///
104/// Given an input event, if a corresponding control is not contained in this
105/// struct, the input will either be trapped (discarded) or else passed up to
106/// the parent node (depending on the state of the Controller `bubble_trap`
107/// flag).
108#[derive(Clone, Debug, Default, Eq, PartialEq)]
109struct InputMap {
110  pub button_any      : Option <controls::Button>,
111  pub buttons         : KeyVec <input::Button, controls::Button>,
112  pub release_buttons : KeyVec <input::Button, controls::Button>,
113  pub axes            : KeyVec <u32, controls::Axis>,
114  pub motion          : Option <controls::Motion>,
115  pub pointer         : Option <controls::Pointer>,
116  pub system          : Option <controls::System>,
117  pub text            : Option <controls::Text>,
118  pub wheel           : Option <controls::Wheel>
119}
120
121/// An input result for registering or removing button release controls.
122///
123/// This is optionally returned by `controller.handle_input()` when a button
124/// release control needs to be registered or removed from the focused node.
125#[derive(Debug)]
126pub (crate) enum ButtonRelease {
127  Insert (input::Button, SmallVec <[(controls::Button, NodeId); 1]>),
128  Remove (input::Button, NodeId)
129}
130
131/// Allows focus directed to a parent frame to be redirected to a different
132/// node:
133///
134/// - Fields
135/// - Menus: if the first child of the focused Frame is a Menu (Selection)
136///   node, focus will be redirected to the appropriate item node
137pub (crate) fn refocus (node_id : &NodeId, elements : &Tree <Element>)
138  -> Option <NodeId>
139{
140  let node    = elements.get (node_id).unwrap();
141  let element = node.data();
142  if element.controller.state != State::Focused {
143    log::warn!("refocus state not focused: {:?}", element.controller.state);
144    debug_assert!(false);
145  }
146  let mut refocus_id = None;
147  // frame
148  if let Ok (_) = Frame::try_from (element) {
149    let mut children_ids = node.children().iter();
150    // first child
151    if let Some (child_id) = children_ids.next() {
152      let child = elements.get_element (child_id);
153      if let Ok (_) = Field::try_from (child) {
154        refocus_id = Some (child_id.clone());
155      } else if let Ok (_) = Numbox::try_from (child) {
156        refocus_id = Some (child_id.clone());
157      } else if let Ok (Widget (selection, _, _)) = Menu::try_from (child) {
158        // refocus menu selection
159        refocus_id = selection.current.clone()
160          .or_else (|| menu::find_first_item (elements, children_ids));
161      }
162    }
163  }
164  refocus_id
165}
166
167impl Controller {
168  #[inline]
169  pub fn with_bindings <A : Application> (bindings : &Bindings <A>) -> Self {
170    Controller { input_map: bindings.into(), .. Controller::default() }
171  }
172
173  #[inline]
174  pub fn get_appearance (&self) -> &view::Appearance {
175    &self.appearances.get (self.state.clone())
176  }
177
178  #[inline]
179  pub fn get_bindings <A : Application> (&self) -> Bindings <A> {
180    self.input_map.to_bindings()
181  }
182
183  /// Replaces all existing bindings
184  #[inline]
185  pub fn set_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
186    self.clear_bindings();
187    self.add_bindings (bindings);
188  }
189
190  /// Must be new bindings or else panics
191  #[inline]
192  pub fn add_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
193    self.input_map.add_bindings (bindings)
194  }
195
196  /// Replaces existing bindings; should not fail
197  #[inline]
198  pub fn insert_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
199    self.input_map.insert_bindings (bindings)
200  }
201
202  /// Remove matching controls
203  #[inline]
204  pub fn remove_bindings (&mut self, controls : &Controls) {
205    self.input_map.remove_bindings (controls)
206  }
207
208  #[inline]
209  pub fn clear_buttons (&mut self) {
210    self.input_map.buttons.clear()
211  }
212
213  #[inline]
214  pub fn remove_any_button (&mut self) {
215    self.input_map.button_any = None
216  }
217
218  #[inline]
219  pub fn remove_system (&mut self) {
220    self.input_map.system = None
221  }
222
223  #[inline]
224  pub fn remove_text (&mut self) {
225    self.input_map.text = None
226  }
227
228  #[inline]
229  pub fn remove_motion (&mut self) {
230    self.input_map.motion = None
231  }
232
233  #[inline]
234  pub fn remove_pointer (&mut self) {
235    self.input_map.pointer = None
236  }
237
238  #[inline]
239  pub fn clear_bindings (&mut self) {
240    self.input_map.clear()
241  }
242
243  pub (crate) fn handle_input <A : Application> (&self,
244    input         : Input,
245    elements      : &Tree <Element>,
246    node_id       : &NodeId,
247    action_buffer : &mut Vec <(NodeId, Action)>
248  ) -> Result <Option <ButtonRelease>, Input> {
249    use controls::Control;
250    log::trace!("handle_input...");
251    let mut button_release = None;
252    match input {
253      Input::Button (ref button, state) => {
254        match self.component {
255          Component::Cursor (ref cursor) => match button.variant {
256            input::button::Variant::Keycode (keycode) => {
257              if !button.modifiers.intersects (
258                input::Modifiers::ALT | input::Modifiers::CTRL |
259                input::Modifiers::SUPER
260              ) {
261                if cursor.ignore.contains (&keycode) {
262                  // if the cursor is configured to ignore this keycode, allow
263                  // the input to bubble
264                  return Err (input)
265                } else if keycode.is_printable() {
266                  // if the keycode is printible, consume the input and the
267                  // cursor will handle the text input
268                  return Ok (None)
269                }
270              }
271            }
272            _ => {}
273          }
274          _ => {}
275        }
276        match state {
277          input::button::State::Pressed => {
278            // if the button matched was an any key or has Modifiers::ANY set,
279            // we need to set the Modifier::ANY flag if a release control is
280            // bound so that it will still be matched if modifiers change
281            let mut any = false;
282            // in backends that don't report key repeat events (Winit), if there
283            // is a release event bound to the button then assumes the press was
284            // a repeat and ignore
285            if self.input_map.release_buttons
286              .binary_search_by_key (&button, |(b, _)| b).is_ok()
287            {
288              return Ok (None)
289            }
290            let control = if let Some (control) = self.input_map.button_any
291              .as_ref()
292            {
293              any = true;
294              Some (control.clone())
295            } else if let Ok (index) = self.input_map.buttons
296              .binary_search_by_key (&button, |(b, _)| b)
297            {
298              let (b, control) = &self.input_map.buttons[index];
299              if b.modifiers.contains (input::Modifiers::ANY) {
300                any = true;
301              }
302              Some (control.clone())
303            } else {
304              None
305            };
306            if let Some (control) = control {
307              let release = Some (RefCell::new (SmallVec::new()));
308              control.fun::<A::ButtonControls>().0
309                (&release, elements, node_id, action_buffer);
310              let controls = release.unwrap().into_inner();
311              if !controls.is_empty() {
312                let mut button = button.clone();
313                if any {
314                  button.modifiers.set (input::Modifiers::ANY, true);
315                }
316                button_release =
317                  Some (ButtonRelease::Insert (button, controls));
318              }
319            }
320          }
321          input::button::State::Released => {
322            let control = if let Ok (index) = self.input_map.release_buttons
323              .binary_search_by_key (&button, |(b, _)| b)
324            {
325              let (_, control) = &self.input_map.release_buttons[index];
326              Some (control.clone())
327            } else {
328              None
329            };
330            if let Some (control) = control {
331              control.fun::<A::ButtonControls>().0
332                (&None, elements, node_id, action_buffer);
333              button_release =
334                Some (ButtonRelease::Remove (button.clone(), node_id.clone()));
335            }
336          }
337        }
338      }
339      Input::Axis ( ref axis) => {
340        if let Ok (index) = self.input_map.axes
341          .binary_search_by_key (&axis.axis, |(a, _)| *a)
342        {
343          let (_, control) = &self.input_map.axes[index];
344          control.clone().fun::<A::AxisControls>().0
345            (&axis.value, elements, node_id, action_buffer)
346        }
347      }
348      Input::Motion ( ref motion) => {
349        if let Some (control) = self.input_map.motion.as_ref() {
350          control.clone().fun::<A::MotionControls>().0
351            (motion, elements, node_id, action_buffer)
352        }
353      }
354      Input::Pointer (ref pointer) => {
355        if let Some (control) = self.input_map.pointer.as_ref() {
356          control.clone().fun::<A::PointerControls>().0
357            (pointer, elements, node_id, action_buffer)
358        }
359      }
360      Input::System (ref system) => {
361        if let Some (control) = self.input_map.system.as_ref() {
362          control.clone().fun::<A::SystemControls>().0
363            (system, elements, node_id, action_buffer)
364        }
365      }
366      Input::Text (ref text) => {
367        if let Some (control) = self.input_map.text.as_ref() {
368          control.clone().fun::<A::TextControls>().0
369            (text, elements, node_id, action_buffer)
370        }
371      }
372      Input::Wheel (ref wheel) => {
373        if let Some (control) = self.input_map.wheel.as_ref() {
374          control.clone().fun::<A::WheelControls>().0
375            (wheel, elements, node_id, action_buffer)
376        }
377      }
378    }
379    log::trace!("...handle_input");
380    if action_buffer.is_empty() && button_release.is_none() {
381      Err (input)
382    } else {
383      Ok (button_release)
384    }
385  }
386
387  pub (crate) fn release_buttons (&mut self) -> Vec <controls::Button> {
388    self.input_map.release_buttons.drain (..).map (|(_, control)| control)
389      .collect()
390  }
391
392  pub (crate) fn release_button_insert (&mut self,
393    input : input::Button, control : controls::Button
394  ) {
395    if self.input_map.release_buttons.insert (input, control.clone()).is_some() {
396      log::debug!("button release control already exists: {:?}",
397        (input, control));
398    }
399  }
400
401  pub (crate) fn release_button_remove (&mut self, input : input::Button) {
402    match self.input_map.release_buttons
403      .binary_search_by_key (&&input, |(b, _)| b)
404    {
405      Ok  (index) => {
406        let _ = self.input_map.release_buttons.remove_index (index);
407      }
408      Err (_) => {
409        log::warn!("remove release button not present: {:?}", input);
410        debug_assert!(false);
411      }
412    }
413  }
414
415  pub (crate) fn update_view_focus (&self, view : &mut View) {
416    view.appearance = self.get_appearance().clone();
417    match &mut view.component {
418      view::Component::Body (body) => match self.component {
419        Component::Cursor (ref cursor) => match self.state {
420          State::Focused  => {
421            let caret = char::try_from (cursor.caret).unwrap();
422            body.0.push (caret);
423          }
424          State::Enabled  => {
425            let _ = body.0.pop().unwrap();
426          }
427          State::Disabled => {}
428        }
429        _ => {}
430      }
431      _ => {}
432    }
433  }
434}
435
436impl From <Component> for Controller {
437  fn from (component : Component) -> Self {
438    Controller { component, .. Controller::default() }
439  }
440}
441
442impl From<&Input> for InputMask {
443  fn from (input : &Input) -> Self {
444    match input {
445      Input::Axis   (_)    => InputMask::AXIS,
446      Input::Button (_, _) => InputMask::BUTTON,
447      Input::Motion (_)    => InputMask::MOTION,
448      Input::Pointer(_)    => InputMask::POINTER,
449      Input::System (_)    => InputMask::SYSTEM,
450      Input::Text   (_)    => InputMask::TEXT,
451      Input::Wheel  (_)    => InputMask::WHEEL
452    }
453  }
454}
455
456impl InputMap {
457  pub fn to_bindings <A : Application> (&self) -> Bindings <A> {
458    let buttons    = self.buttons.iter().cloned().map (Into::into).collect();
459    let any_button = self.button_any.clone().map (Into::into);
460    let system     = self.system.clone().map (Into::into);
461    let text       = self.text.clone().map (Into::into);
462    let motion     = self.motion.clone().map (Into::into);
463    let pointer    = self.pointer.clone().map (Into::into);
464    Bindings { buttons, any_button, system, text, motion, pointer }
465  }
466
467  /// Add new Bindings to the InputMap.
468  ///
469  /// Panics if there is a conflict with current:
470  ///
471  /// ```should_panic
472  /// use gooey::application;
473  /// use gooey::interface::controller::{bindings, controls, Controller};
474  /// use gooey::interface::view::input;
475  /// let bindings = bindings::Builder::<application::Default>::new()
476  ///   .buttons (vec![
477  ///     controls::button::Binding (
478  ///       controls::button::Builtin::FormSubmitCallback.into(),
479  ///       input::button::Keycode::Enter.into(),
480  ///       Default::default()
481  ///     )
482  ///   ])
483  ///   .build();
484  /// let mut controller = Controller::with_bindings(&bindings);
485  /// controller.add_bindings (&bindings);  // panic! duplicate bindings
486  /// ```
487  pub fn add_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
488    let Bindings { buttons, any_button, system, text, motion, pointer } =
489      bindings;
490    // buttons
491    let buttons_len  = self.buttons.len();
492    let bindings_len = buttons.len();
493    self.buttons.extend (buttons.iter().cloned().map (Into::into));
494    assert_eq!(self.buttons.len(), buttons_len + bindings_len);
495    // any button
496    any_button.as_ref().cloned().map (|button| {
497      assert!(self.button_any.is_none());
498      self.button_any = Some (button.into());
499    });
500    // system
501    system.as_ref().cloned().map (|system| {
502      assert!(self.system.is_none());
503      self.system = Some (system.into());
504    });
505    // text
506    text.as_ref().cloned().map (|text| {
507      assert!(self.text.is_none());
508      self.text = Some (text.into());
509    });
510    // motion
511    motion.as_ref().cloned().map (|motion| {
512      assert!(self.motion.is_none());
513      self.motion = Some (motion.into());
514    });
515    // pointer
516    pointer.as_ref().cloned().map (|pointer| {
517      assert!(self.pointer.is_none());
518      self.pointer = Some (pointer.into());
519    });
520  }
521
522  /// Insert Bindings to the InputMap, replacing any existing Bindings
523  pub fn insert_bindings <A : Application> (&mut self, bindings : &Bindings <A>) {
524    let Bindings { buttons, any_button, system, text, motion, pointer } =
525      bindings;
526    // buttons
527    self.buttons.extend (buttons.iter().cloned().map (Into::into));
528    // any button
529    any_button.as_ref().cloned().map (|button| {
530      self.button_any = Some (button.into());
531    });
532    // system
533    system.as_ref().cloned().map (|system| {
534      self.system = Some (system.into());
535    });
536    // text
537    text.as_ref().cloned().map (|text| {
538      self.text = Some (text.into());
539    });
540    // motion
541    motion.as_ref().cloned().map (|motion| {
542      self.motion = Some (motion.into());
543    });
544    // pointer
545    pointer.as_ref().cloned().map (|pointer| {
546      self.pointer = Some (pointer.into());
547    });
548  }
549
550  /// Remove matching controls
551  pub fn remove_bindings (&mut self, controls : &Controls) {
552    let Controls { buttons, any_button, system, text, motion, pointer } =
553      controls;
554    // buttons
555    self.buttons.retain (|(_, button)| !buttons.contains (button));
556    // any button
557    if &self.button_any == any_button {
558      self.button_any = None;
559    }
560    // system
561    if &self.system == system {
562      self.system = None;
563    }
564    // text
565    if &self.text == text {
566      self.text = None;
567    }
568    // motion
569    if &self.motion == motion {
570      self.motion = None;
571    }
572    // pointer
573    if &self.pointer == pointer {
574      self.pointer = None;
575    }
576  }
577
578  #[inline]
579  pub fn clear (&mut self) {
580    *self = InputMap::default()
581  }
582}
583
584impl <A : Application> From <&Bindings <A>> for InputMap {
585  /// Constructs an InputMap with the given Bindings
586  fn from (bindings : &Bindings <A>) -> Self {
587    let Bindings { buttons, any_button, system, text, motion, pointer } =
588      bindings;
589    let buttons    = KeyVec::from_iter (
590      buttons.iter().cloned().map (Into::into));
591    let button_any = any_button.clone().map (Into::into);
592    let system     = system.clone().map (Into::into);
593    let text       = text.clone().map (Into::into);
594    let motion     = motion.clone().map (Into::into);
595    let pointer    = pointer.clone().map (Into::into);
596    InputMap {
597      buttons, button_any, system, text, motion, pointer, .. InputMap::default()
598    }
599  }
600}
601
602impl State {
603  /// Changes state to Focused and issues a warning if state was not Enabled
604  #[inline]
605  pub fn focus (&mut self) {
606    if self != &State::Enabled {
607      log::warn!("focus state not enabled: {:?}", self);
608    }
609    debug_assert_eq!(self, &State::Enabled);
610    *self = State::Focused;
611  }
612  /// Changes state to Enabled and issues a warning if state was not Focused
613  #[inline]
614  pub fn defocus (&mut self) {
615    if self != &State::Focused {
616      log::warn!("defocus state not focused: {:?}", self);
617    }
618    debug_assert_eq!(self, &State::Focused);
619    *self = State::Enabled;
620  }
621  /// Changes state to Enabled and issues a warning if state was not Disabled
622  #[inline]
623  pub fn enable (&mut self) {
624    if self != &State::Disabled {
625      log::warn!("enable state not disabled: {:?}", self);
626    }
627    debug_assert_eq!(self, &State::Disabled);
628    *self = State::Enabled;
629  }
630  /// Changes state to Disabled and issues a warning if state was not Enabled
631  #[inline]
632  pub fn disable (&mut self) {
633    if self != &State::Enabled {
634      log::warn!("disable state not enabled: {:?}", self);
635    }
636    debug_assert_eq!(self, &State::Enabled);
637    *self = State::Disabled;
638  }
639}
640
641impl Default for State {
642  fn default() -> Self {
643    State::Enabled
644  }
645}
646
647impl Appearances {
648  #[inline]
649  pub fn get (&self, state : State) -> &view::Appearance {
650    &self.0[state.clone() as usize]
651  }
652
653  #[inline]
654  pub fn get_mut (&mut self, state : State) -> &mut view::Appearance {
655    &mut self.0[state.clone() as usize]
656  }
657}
658
659impl AppearancesBuilder {
660  pub fn transparent() -> Self {
661    AppearancesBuilder::default()
662      .style_fg (State::Focused,  color::TRANSPARENT.into())
663      .style_bg (State::Focused,  color::TRANSPARENT.into())
664      .style_fg (State::Enabled,  color::TRANSPARENT.into())
665      .style_bg (State::Enabled,  color::TRANSPARENT.into())
666      .style_fg (State::Disabled, color::TRANSPARENT.into())
667      .style_bg (State::Disabled, color::TRANSPARENT.into())
668  }
669
670  #[inline]
671  pub fn state (mut self, state : State, appearance : view::Appearance) -> Self {
672    self.0[state as usize] = appearance;
673    self
674  }
675  #[inline]
676  pub fn style (mut self, state : State, style : view::Style) -> Self {
677    self.0[state as usize].style = Some (style);
678    self
679  }
680  #[inline]
681  pub fn style_default (mut self, state : State) -> Self {
682    self.0[state as usize].style = Some (view::Style::default());
683    self
684  }
685  #[inline]
686  pub fn sound (mut self, state : State, sound : view::Sound) -> Self {
687    self.0[state as usize].sound = Some (sound);
688    self
689  }
690  #[inline]
691  pub fn pointer (mut self, state : State, pointer : view::Pointer) -> Self {
692    self.0[state as usize].pointer = Some (pointer);
693    self
694  }
695  #[inline]
696  pub fn style_fg (mut self, state : State, color : view::Color) -> Self {
697    let state = state as usize;
698    let mut style = self.0[state].style.take().unwrap_or_default();
699    style.fg = color;
700    self.0[state].style = Some (style);
701    self
702  }
703  #[inline]
704  pub fn style_bg (mut self, state : State, color : view::Color) -> Self {
705    let state = state as usize;
706    let mut style = self.0[state].style.take().unwrap_or_default();
707    style.bg = color;
708    self.0[state].style = Some (style);
709    self
710  }
711  #[inline]
712  pub fn style_lo (mut self, state : State, color : view::Color) -> Self {
713    let state = state as usize;
714    let mut style = self.0[state].style.take().unwrap_or_default();
715    style.lo = color;
716    self.0[state].style = Some (style);
717    self
718  }
719  #[inline]
720  pub fn style_hi (mut self, state : State, color : view::Color) -> Self {
721    let state = state as usize;
722    let mut style = self.0[state].style.take().unwrap_or_default();
723    style.hi = color;
724    self.0[state].style = Some (style);
725    self
726  }
727  #[inline]
728  pub fn build (self) -> Appearances {
729    Appearances (self.0)
730  }
731}
732
733impl Default for Area {
734  fn default() -> Self {
735    Area::Interior
736  }
737}
738
739impl Orientation {
740  pub fn toggle (self) -> Self {
741    match self {
742      Orientation::Horizontal => Orientation::Vertical,
743      Orientation::Vertical   => Orientation::Horizontal
744    }
745  }
746}
747
748impl Default for Orientation {
749  fn default() -> Self {
750    Orientation::Horizontal
751  }
752}