auto_spaces 0.1.0

Spaces where worlds are able to be rendered
Documentation
use std::time::Duration;

use auto_cellular::{
    cell::BasicCell,
    common::{DoubleVec, Index},
    space::{OutputField, Space},
    world::BasicWorld,
};
use cursive::views::{LinearLayout, TextContent, TextView};

use crate::common::OutputManager;

type Out = OutputManager<DoubleVec<TextContent>>;

impl<C> OutputField<C, char> for Out
where
    C: BasicCell,
{
    fn set_unit(&mut self, (x, y): Index, unit: char, _refresh: bool) -> Result<(), String> {
        self.field[y][x].set_content(unit);
        Ok(())
    }
    fn show(&mut self) {}
}

struct Terminal<W, C>
where
    W: BasicWorld<C>,
    C: BasicCell,
{
    world: W,
    output: Out,
    reprer: fn(C) -> char,
}

impl<W, C> Space<W, C, Out> for Terminal<W, C>
where
    C: BasicCell,
    W: BasicWorld<C>,
{
    type CellRepr = char;
    type Reprer = fn(C) -> char;
    fn world_mut(&mut self) -> &mut W {
        &mut self.world
    }

    fn world(&self) -> &W {
        &self.world
    }

    fn output_mut(&mut self) -> &mut Out {
        &mut self.output
    }

    fn reprer(&self) -> Self::Reprer {
        self.reprer
    }
}

impl<W, C> Terminal<W, C>
where
    W: BasicWorld<C>,
    C: BasicCell,
{
    fn new(world: W, output: Out, reprer: <Self as Space<W, C, Out>>::Reprer) -> Self {
        Self {
            world,
            output,
            reprer,
        }
    }
}

pub fn run<W, C>(world: W, repr: fn(C) -> char, update_millis: usize) -> Result<(), String>
where
    W: BasicWorld<C> + Send + 'static,
    C: BasicCell + Send + 'static,
{
    let mut siv = cursive::default();
    siv.set_autorefresh(true);

    let texts: Vec<Vec<TextContent>> = vec![vec![(); world.dimensions().0]; world.dimensions().1]
        .into_iter()
        .map(|r| r.into_iter().map(|_| TextContent::new("")).collect())
        .collect();
    let textboxes = texts.iter().map(|row| {
        let mut layout_row = LinearLayout::horizontal();
        for child in row
            .iter()
            .map(|text| TextView::new_with_content(text.clone()))
        {
            layout_row.add_child(child)
        }
        layout_row
    });
    let mut layout = LinearLayout::vertical();
    for textbox in textboxes {
        layout.add_child(textbox);
    }
    siv.add_layer(layout);

    let mut canvas = Terminal::new(
        world,
        OutputManager {
            field: texts,
            pixel_size: 1,
        },
        repr,
    );
    siv.add_global_callback('q', |s| s.quit());
    canvas.draw_whole()?;

    std::thread::spawn(move || loop {
        let _ = canvas.tick_delta();
        std::thread::sleep(Duration::from_millis(update_millis as u64));
    });

    siv.run();

    Ok(())
}