gooey-rs 0.12.1

Tile-based UI library with audio support
Documentation
//! Serializable parameterized bindings

use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use crate::{application, Application};
use crate::interface::controller::controls;
use crate::interface::view::input;

use super::Controls;

pub use BindingsBuilder as Builder;

/// Associates inputs with controls for a specific application
#[derive(Clone, Debug, Builder, Deserialize, Serialize)]
#[builder(pattern="owned", build_fn(skip), setter(strip_option))]
pub struct Bindings <A : Application = application::Default> {
  #[builder(default)]
  #[serde(skip_serializing_if = "Vec::is_empty")]
  pub buttons    : Vec <controls::button::Binding <A::ButtonControls>>,
  #[builder(default)]
  #[serde(skip_serializing_if = "Option::is_none")]
  pub any_button : Option <controls::button::Control <A::ButtonControls>>,
  #[builder(default)]
  #[serde(skip_serializing_if = "Option::is_none")]
  pub system     : Option <controls::system::Control <A::SystemControls>>,
  #[builder(default)]
  #[serde(skip_serializing_if = "Option::is_none")]
  pub text       : Option <controls::text::Control <A::TextControls>>,
  #[builder(default)]
  #[serde(skip_serializing_if = "Option::is_none")]
  pub motion     : Option <controls::motion::Control <A::MotionControls>>,
  #[builder(default)]
  #[serde(skip_serializing_if = "Option::is_none")]
  pub pointer    : Option <controls::pointer::Control <A::PointerControls>>
  // TODO: axis bindings: each axis can be bound to a different function
  // TODO: other bindings
}

impl <A : Application> Bindings <A> {
  /// Get a subset of the bindings for the given controls
  pub fn get_bindings (&self, controls : &Controls) -> Self {
    let buttons = {
      let mut buttons = vec![];
      for c in controls.buttons.iter() {
        let mut found : Vec <controls::button::Binding <_>> = self.buttons.iter()
          .filter (|controls::button::Binding (control, _, _)| &control.0 == c)
          .cloned().collect();
        if found.is_empty() {
          log::debug!("get_bindings: unbound controls: {c:?}");
        } else {
          buttons.append (&mut found);
        }
      }
      buttons
    };
    let any_button = self.any_button.clone()
      .filter (|control| controls.buttons.contains (&control.0));
    let system     = self.system.clone().filter (|control|
      Some (control) == controls.system.map (Into::into).as_ref());
    let text       = self.text.clone().filter (|control|
      Some (control) == controls.text.map (Into::into).as_ref());
    let motion     = self.motion.clone().filter (|control|
      Some (control) == controls.motion.map (Into::into).as_ref());
    let pointer    = self.pointer.clone().filter (|control|
      Some (control) == controls.pointer.map (Into::into).as_ref());
    Bindings { buttons, any_button, system, text, motion, pointer }
  }

  /// Returns an empty vector if the controls was unbound
  pub fn get_buttons (&self, control : controls::button::Control <A::ButtonControls>)
    -> Vec <input::Button>
  {
    use controls::button;
    let mut buttons = vec![];
    for button::Binding (c, button, _) in self.buttons.iter() {
      if c == &control {
        buttons.push (*button);
      }
    }
    buttons
  }
}

impl <A : Application> Bindings <A> {
  pub const fn empty() -> Self {
    Bindings {
      buttons:    vec![],
      any_button: None,
      system:     None,
      text:       None,
      motion:     None,
      pointer:    None
    }
  }
}

impl <A : Application> BindingsBuilder <A> {
  pub const fn new() -> Self {
    BindingsBuilder {
      buttons:    None,
      any_button: None,
      system:     None,
      text:       None,
      motion:     None,
      pointer:    None
    }
  }

  pub fn build (self) -> Bindings <A> {
    Bindings {
      buttons:    self.buttons.unwrap_or_default(),
      any_button: self.any_button.unwrap_or_default(),
      system:     self.system.unwrap_or_default(),
      text:       self.text.unwrap_or_default(),
      motion:     self.motion.unwrap_or_default(),
      pointer:    self.pointer.unwrap_or_default()
    }
  }
}