cedar 0.1.1

Reactive, functional library for creating GUI applications

use tree;

#[derive(PartialEq, Clone, Debug)]
pub enum Kind {
    Stack,
    Button,
    Label,
    Field,
}

#[derive(PartialEq, Clone, Debug)]
pub enum Attribute<S> {
    Text(String),
    Click(S),
    Placeholder(String),
    Change(fn(String) -> S),
}

pub type Attributes<S> = Vec<Attribute<S>>;

pub type Value<S> = (Kind, Attributes<S>);
pub type Object<S> = tree::Node<Value<S>>;

pub type Change<S> = tree::Change<Value<S>>;
pub type Changeset<S> = tree::Changeset<Value<S>>;

pub fn diff<S: PartialEq>(old: Object<S>, new: Object<S>) -> Changeset<S> {
    fn comparator<S: PartialEq>(t: &Object<S>, u: &Object<S>) -> Option<tree::Difference> {
        if t.value.0 != u.value.0 {
            Some(tree::Difference::Kind)
        } else if t.value.1 != u.value.1 {
            Some(tree::Difference::Value)
        } else {
            None
        }
    }

    tree::diff(vec![old], vec![new], comparator)
}

pub trait Builder<S> {
    fn add(self, object: Self) -> Self;

    fn text(self, text: String) -> Self;
    fn click(self, action: S) -> Self;
    fn placeholder(self, text: String) -> Self;
    fn change(self, messenger: fn(String) -> S) -> Self;
}

impl<S> Builder<S> for Object<S> {
    fn add(mut self, object: Self) -> Self {
        self.children.push(object);
        self
    }

    fn text(mut self, text: String) -> Self {
        self.value.1.push(Attribute::Text(text));
        self
    }
    fn click(mut self, action: S) -> Self {
        self.value.1.push(Attribute::Click(action));
        self
    }
    fn placeholder(mut self, text: String) -> Self {
        self.value.1.push(Attribute::Placeholder(text));
        self
    }
    fn change(mut self, messenger: fn(String) -> S) -> Self {
        self.value.1.push(Attribute::Change(messenger));
        self
    }
}

pub fn stack<S>() -> Object<S> {
    node![(Kind::Stack, vec![])]
}

pub fn label<S>() -> Object<S> {
    node![(Kind::Label, vec![])]
}

pub fn button<S>() -> Object<S> {
    node![(Kind::Button, vec![])]
}

pub fn field<S>() -> Object<S> {
    node![(Kind::Field, vec![])]
}