ashiba 0.1.0

tui framework, based on tui-rs
Documentation
use std::{collections::HashMap};

pub struct FieldDescriptor {
    pub name: &'static str,
    pub hidden: bool,
}

pub trait FormController {
    fn on_enter(&mut self, f: &Fields);
    fn fields() -> Vec<FieldDescriptor>;
    fn placeholder() -> Vec<(&'static str, &'static str)>;
}

pub struct Form<M> {
    fields: Fields,
    model: M,
    editing: bool
}

pub struct Fields {
    values: HashMap<usize, String>,
    names: HashMap<usize, String>,
    active: usize,
}

impl Fields {
    pub fn new<M: FormController>() -> Self {
        Self {
            values: HashMap::from_iter(
                M::fields()
                    .into_iter()
                    .map(|_f| "".to_owned())
                    .enumerate(),
            ),
            names: HashMap::from_iter(
                M::fields()
                    .into_iter()
                    .map(|f| f.name.to_string())
                    .enumerate(),
            ),
            active: Default::default(),
        }
    }

    pub fn by_name(&self, name: &str) -> Option<&String> {
        let result = self.names.iter().find(|r| r.1 == name);
        if let Some(field) = result {
            self.values.get(field.0)
        } else {
            None
        }
    }

    fn field_mut(&mut self, name: &str) -> Option<&mut String> {
        let result = self.names.iter_mut().find(|r| r.1 == name);
        if let Some(field) = result {
            self.values.get_mut(field.0)
        } else {
            None
        }
    }

    pub fn get(&self, k: &usize) -> Option<&String> {
        self.values.get(k)
    }

    fn get_mut(&mut self, k: &usize) -> Option<&mut String> {
        self.values.get_mut(k)
    }

    pub fn get_name(&self, k: &usize) -> Option<&String> {
        self.names.get(k)
    }

    pub fn len(&self) -> usize {
        self.values.len()
    }

    pub fn is_empty(&self) -> bool {
        self.values.is_empty()
    }

    pub fn active(&self) -> &usize {
        &self.active
    }

    fn active_mut(&mut self) -> &mut usize {
        &mut self.active
    }
}

impl<M> Form<M>
where
    M: FormController,
{
    pub fn new(model: M) -> Self {
        Self {
            fields: Fields::new::<M>(),
            model,
            editing: Default::default()
        }
    }

    pub fn with_placeholder(mut self) -> Self {
        for field in M::placeholder().iter() {
            if let Some(v) = self.fields.field_mut(field.0) {
                *v = field.1.to_string();
            }
        }
        self
    }

    pub fn with_values(mut self, data: Vec<(&'static str, String)>) -> Self {
        for field in data.iter() {
            if let Some(v) = self.fields.field_mut(field.0) {
                *v = field.1.clone();
            }
        }
        self
    }

    pub fn data(&self) -> &M {
        &self.model
    }

    pub fn data_mut(&mut self) -> &mut M {
        &mut self.model
    }

    pub fn on_shortcut(&mut self, shortcut: char, ch: char) {
        if !self.editing && shortcut == ch {
            self.editing = true;
        }
    }

    pub fn on_char(&mut self, ch: char) {
        if self.editing {
            let active = *self.fields.active();
            match self.fields.get_mut(&active) {
                Some(field) => field.push(ch),
                None => unreachable!(),
            }
        }
    }

    pub fn on_esc(&mut self) {
        self.editing = false;
    }

    pub fn begin_edit(&mut self) {
        self.editing = true;
    }

    pub fn editing(&self) -> bool {
        self.editing
    }

    pub fn on_backspace(&mut self) {
        if self.editing {
            let active = *self.fields.active();
            match self.fields.get_mut(&active) {
                Some(field) => {
                    field.pop();
                }
                None => unreachable!(),
            }
        }
    }

    pub fn fields(&self) -> &Fields {
        &self.fields
    }

    pub fn on_tab(&mut self) {
        if self.editing {
            let new = self.fields.active() + 1;
            match new >= self.fields.len() {
                true => *self.fields.active_mut() = 0,
                false => *self.fields.active_mut() = new
            }
        }
    }

    pub fn on_enter(&mut self) {
        if self.editing {
            M::on_enter(&mut self.model, &self.fields);
        }
    }
}

impl<M> Default for Form<M>
where M: FormController + Default {
    fn default() -> Self {
        Self { 
            fields: Fields::new::<M>(), 
            model: Default::default(), 
            editing: Default::default()
        }
    }
}