gooey-rs 0.12.1

Tile-based UI library with audio support
Documentation
//! Control callback and Id traits.
//!
//! An implementation of Control is defined for each type of Input. These are
//! implemented as newtype structs with inner primitive `ReprType` payload.
//!
//! An implementation of Id is a serializable enum, parameterized by the Control
//! type, and convertable to control `Fun` callbacks and to corresponding
//! `Control` `ReprType`s.
//!
//! To each implementation of Control is an associated Builtin Id type. Each
//! Control type can be extended by the Application by defining a new Id type
//! using the `extend_control!` macro. This macro will ensure that the resulting
//! implementation does not overlap with the Builtin type in its conversion to a
//! `Control` `ReprType`.

use derive_builder::Builder;
use sorted_vec::SortedSet;
use serde::{Deserialize, Serialize};
use crate::{interface, Tree};
use crate::tree::NodeId;

#[macro_use] mod macro_def;

pub mod axis;
pub mod button;
pub mod motion;
pub mod pointer;
pub mod system;
pub mod text;
pub mod wheel;

pub use self::axis::Axis;
pub use self::button::Button;
pub use self::motion::Motion;
pub use self::pointer::Pointer;
pub use self::system::System;
pub use self::text::Text;
pub use self::wheel::Wheel;

pub use ControlsBuilder as Builder;

/// A set of controls for looking up bindings
#[derive(Clone, Debug, Default, Builder)]
#[builder(pattern="owned", build_fn(skip), setter(strip_option))]
pub struct Controls {
  #[builder(default)]
  pub buttons    : SortedSet <Button>,
  #[builder(default)]
  pub any_button : Option <Button>,
  #[builder(default)]
  pub system     : Option <System>,
  #[builder(default)]
  pub text       : Option <Text>,
  #[builder(default)]
  pub motion     : Option <Motion>,
  #[builder(default)]
  pub pointer    : Option <Pointer>
  // TODO: more
}

/// A type of serializable names that map to control callbacks.
///
/// A type implementing Id is convertible with the `C:Control` type and maps to
/// a control [`Fun`] taking the payload specified by the Control type.
///
/// This is the serializable type representing a control callback Fun used for
/// saving and loading bindings.
pub trait Id <C : Control> : Clone + Eq + PartialEq + Into <Fun <C::Payload>> + Into <C>
  + TryFrom <C, Error = C> + std::fmt::Debug + Serialize + serde::de::DeserializeOwned
{ }

/// A newtype wrapper for the parameterized control callback function type with
/// payload type P.
///
/// This is a newtype so that `From <Control <A, ID>>` can be implemented.
#[derive(Clone)]
#[expect(clippy::type_complexity)]
pub struct Fun <P> (pub fn (
  &P,
  &Tree <interface::Element>,
  &NodeId,
  &mut Vec <(NodeId, interface::Action)>
));

/// Primitive control index type alias
pub type ReprType = u16;
/// A primitive control callback index with associated payload and built-in control
/// callback IDs
pub trait Control : Clone + Sized + From <ReprType> + AsRef <ReprType>
  + std::fmt::Debug
{
  type Payload;
  type Builtin : Id <Self>;
  fn fun <E : Id <Self>> (self) -> Fun <Self::Payload> {
    use std::convert::TryFrom;
    match Self::Builtin::try_from (self) {
      Ok  (builtin) => builtin.into(),
      Err (control) => match E::try_from (control) {
        Ok  (extended) => extended.into(),
        Err (_control) => unreachable!()
      }
    }
  }
}

/// A nil type indicating no extra controls
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum Nil {}
impl <P> From <Nil> for Fun <P> {
  fn from (_ : Nil) -> Self {
    unreachable!()
  }
}

impl <P> std::fmt::Debug for Fun <P> {
  fn fmt (&self, f : &mut std::fmt::Formatter) -> Result <(), std::fmt::Error> {
    write!(f, "Fun({:p})", &self.0)
  }
}

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

  pub fn build (self) -> Controls {
    Controls {
      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()
    }
  }
}