patica 0.0.3

A terminal based pixel art editor
Documentation
use crate::{
    command::Command,
    config::Config,
    model::Model,
    view::{View, WindowCanvas},
};
use pagurus::{
    event::{Event, TimeoutTag},
    failure::OrFail,
    image::Canvas,
    video::VideoFrame,
    Result, System,
};
use std::time::Duration;

const TICK_TIMEOUT_TAG: TimeoutTag = TimeoutTag::new(0);

#[derive(Debug, Default)]
pub struct Game {
    video_frame: VideoFrame,
    view: View,
    model: Model,
}

impl Game {
    pub fn set_config(&mut self, config: Config) {
        self.view.set_key_config(config.key);

        self.model
            .apply(&Command::BackgroundColor(config.initial.background_color));
        for (name, point) in &config.initial.anchors {
            let command = pati::Command::anchor(name.clone(), Some(*point));
            self.model.canvas_mut().apply(&command);
        }
    }

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

    pub fn model_mut(&mut self) -> &mut Model {
        &mut self.model
    }

    fn render<S: System>(&mut self, system: &mut S) {
        let size = self.video_frame.spec().resolution;
        let mut canvas = WindowCanvas::new(Canvas::new(&mut self.video_frame), size);
        self.view.render(&self.model, &mut canvas);
        system.video_draw(self.video_frame.as_ref());
    }

    fn set_tick_timeout<S: System>(&mut self, system: &mut S) {
        system.clock_set_timeout(TICK_TIMEOUT_TAG, Duration::from_secs(1) / self.model.fps());
    }
}

impl<S: System> pagurus::Game<S> for Game {
    fn initialize(&mut self, system: &mut S) -> Result<()> {
        self.model.initialize().or_fail()?;
        self.set_tick_timeout(system);
        Ok(())
    }

    fn handle_event(&mut self, system: &mut S, event: Event) -> Result<bool> {
        let mut set_timeout = false;
        match event {
            Event::WindowResized(size) => {
                self.video_frame = VideoFrame::new(system.video_init(size));
            }
            Event::Timeout(TICK_TIMEOUT_TAG) => {
                self.model.tick();
                set_timeout = true;
            }
            _ => {}
        }
        self.view
            .handle_event(system, &mut self.model, event)
            .or_fail()?;
        self.render(system);
        if set_timeout {
            self.set_tick_timeout(system);
        }
        Ok(!self.model.quit())
    }
}