gooey-rs 0.12.1

Tile-based UI library with audio support
Documentation
use std::cell::RefCell;
use serde_plain;
use smallvec::SmallVec;
use crate::interface::view::input;
use crate::tree::NodeId;
use crate::widget;

use super::{Id, Nil};

impl_control_builtin!{
  Button <Release> {
    ActivatePointer          => widget::frame::activate_pointer,
    ButtonPush               => widget::button::push,
    ButtonRelease            => widget::button::release,
    FieldBackspace           => widget::field::backspace,
    FormSubmitCallback       => widget::form::submit_callback,
    FrameClose               => widget::frame::close,
    FrameRefresh             => widget::frame::refresh,
    FrameToggleOrientation   => widget::frame::toggle_orientation,
    FrameFreeGrowWidth       => widget::frame::free::grow_width,
    FrameFreeGrowHeight      => widget::frame::free::grow_height,
    FrameFreeMoveDown        => widget::frame::free::move_down,
    FrameFreeMoveLeft        => widget::frame::free::move_left,
    FrameFreeMoveRight       => widget::frame::free::move_right,
    FrameFreeMoveUp          => widget::frame::free::move_up,
    FrameFreeShrinkHeight    => widget::frame::free::shrink_height,
    FrameFreeShrinkWidth     => widget::frame::free::shrink_width,
    FrameTiledDecreaseSize   => widget::frame::tiled::decrease_size,
    FrameTiledIncreaseSize   => widget::frame::tiled::increase_size,
    MenuNextItem             => widget::menu::next_item,
    MenuPreviousItem         => widget::menu::previous_item,
    MenuFirstItem            => widget::menu::first_item,
    MenuLastItem             => widget::menu::last_item,
    NumboxDecrease           => widget::numbox::decrease,
    NumboxIncrease           => widget::numbox::increase,
    NumboxDecrease10x        => widget::numbox::decrease_10x,
    NumboxIncrease10x        => widget::numbox::increase_10x,
    PlaybackLoop             => widget::playback::loop_,
    PlaybackPlay             => widget::playback::play,
    PlaybackReady            => widget::playback::ready,
    TextboxScrollRight       => widget::textbox::scroll_right,
    TextboxScrollLeft        => widget::textbox::scroll_left,
    TextboxScrollUp          => widget::textbox::scroll_up,
    TextboxScrollDown        => widget::textbox::scroll_down,
    TextboxPageRight         => widget::textbox::page_right,
    TextboxPageLeft          => widget::textbox::page_left,
    TextboxPageUp            => widget::textbox::page_up,
    TextboxPageDown          => widget::textbox::page_down
  }
}

impl_control_serdes!{ Button }

/// Argument type for button callbacks
pub type Release = Option <RefCell <SmallVec <[(Button, NodeId); 1]>>>;

/// Binds a button control to an input button and implements custom serialization format
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Binding <E : Id <Button> = Nil>
  (pub Control <E>, pub input::Button, pub std::marker::PhantomData <E>);

impl <E : Id <Button>> Binding <E> {
  pub fn new (control : Control <E>, button : input::Button) -> Self {
    Binding (control, button, Default::default())
  }
}
impl <E : Id <Button>> From <input::button::Binding <E>> for Binding <E> {
  fn from (input::button::Binding (button, control, _) : input::button::Binding <E>)
    -> Self
  {
    Binding::new (control, button)
  }
}
impl <E : Id <Button>> From <Binding <E>> for (Control <E>, input::Button) {
  fn from (Binding (control, button, _) : Binding <E>) -> Self {
    (control, button)
  }
}
impl <E : Id <Button>> From <(Control <E>, input::Button)> for Binding <E> {
  fn from ((control, button) : (Control <E>,input::Button)) -> Self {
    Binding::new (control, button)
  }
}

//
// private
//

struct BindingVisitor <E : Id <Button> = Nil> (std::marker::PhantomData <E>);

impl <E : Id <Button>> serde::Serialize for Binding <E> {
  fn serialize <S : serde::Serializer> (&self, serializer : S)
    -> Result <S::Ok, S::Error>
  {
    let control = serde_plain::to_string (&self.0).unwrap();
    let input   = serde_plain::to_string (&self.1).unwrap();
    serializer.serialize_str (&format!("{control}: {input}"))
  }
}

impl <E : Id <Button>> serde::de::Visitor <'_> for BindingVisitor <E> {
  type Value = Binding <E>;
  fn expecting (&self, formatter : &mut std::fmt::Formatter) -> std::fmt::Result {
    formatter.write_str ("A control: button pair")
  }
  fn visit_str <ERR : serde::de::Error> (self, v : &str) -> Result <Self::Value, ERR> {
    let control = {
      let s = v.split (':').next().unwrap();
      serde_plain::from_str::<Control <E>> (s).unwrap()
    };
    let button = {
      let s = v.split (' ').nth (1).unwrap();
      serde_plain::from_str::<input::Button> (s).unwrap()
    };
    Ok (Binding::new (control, button))
  }
}

impl <'de, E : Id <Button>> serde::Deserialize <'de> for Binding <E> {
  fn deserialize <D : serde::Deserializer <'de>> (deserializer : D)
    -> Result <Self, D::Error>
  {
    deserializer.deserialize_str (BindingVisitor (Default::default()))
  }
}