retris 0.3.0

This is a Rust implementation of tetris using the Cursive library
Documentation
use cursive::{
    event::{Event, EventResult, Key},
    View,
    Printer, 
    theme::{Color, ColorStyle},
};
use crate::block::{ Block, BlockWithPos };
use crate::color_grid::ColorGrid;
use crate::lrd::{ LR, LRD };

pub struct Board {
    colors: ColorGrid,
}

impl Board {
    pub fn new(background_color: (ColorStyle, ColorStyle), warning_color: ColorStyle, width: usize, height: usize) -> Self {
        Self {
            colors: ColorGrid::new(
                background_color,
                warning_color,
                width,
                height,
            ),
        }
    }

    pub fn renew(&mut self) {
        self.colors.renew();
    }

    pub fn move_block_lrd(&self, block: &BlockWithPos, lrd: LRD) -> (Option<BlockWithPos>, bool) {
        self.colors.move_block_lrd(block, lrd)
    }

    pub fn on_down(&mut self, is_drop: bool, is_begin: bool) -> (bool, bool) {
        self.colors.on_down(is_drop, is_begin)
    }

    pub fn merge_block(&mut self) -> usize {
        self.colors.merge_block()
    }

    pub fn insert(&mut self, block: Block) {
        self.colors.insert(block);
    }

    fn rotate(&mut self, hit_bottom: bool, clockwise: bool) -> bool {
        self.colors.rotate(hit_bottom, clockwise)
    }

    fn flip_turn(&mut self, hit_bottom: bool) -> bool {
        self.colors.flip_turn(hit_bottom)
    }

    fn handle_lr(&mut self, lr: LR, hit_bottom: bool, is_hard: bool) -> bool {
        self.colors.handle_lr(lr, hit_bottom, is_hard)
    }

    pub fn handle_event(&mut self, event: Event, hit_bottom: bool) -> bool {
        match event {
            Event::Key(Key::Left)  => self.handle_lr(LR::Left, hit_bottom, false),
            Event::Key(Key::Right) => self.handle_lr(LR::Right, hit_bottom, false),
            Event::Key(Key::Up) | Event::Char('e') => self.rotate(hit_bottom, true),
            Event::Char('s') => self.flip_turn(hit_bottom),
            Event::Char('w') => self.rotate(hit_bottom, false),
            Event::Char('a') => self.handle_lr(LR::Left, hit_bottom, true),
            Event::Char('d') => self.handle_lr(LR::Right, hit_bottom, true),
            _ => false,
        }
    }

    fn draw_background(&self, printer: &Printer) {
        let width = self.colors.width();
        let height = self.colors.height();
        for j in 0..height {
            for i in 0..width {
                printer.with_color(self.colors[j][i], |printer| {
                    printer.print((2*i, j), "  ");
                });
            }
        }
    }

    fn draw_block(&self, printer: &Printer) {
        for cell in self.colors.block.cells() {
                printer.with_color(self.colors.block.color(), |printer| {
                    printer.print((2*cell.x, cell.y), "  ");
                });
        }
    }

    fn draw_hint(&self, printer: &Printer) {
        let hint = self.colors.hint();
        let color = ColorStyle::new(Color::Rgb(255,255,255), Color::Rgb(0,0,0));
        for cell in hint.cells() {
                printer.with_color(color, |printer| {
                    printer.print((2*cell.x, cell.y), "░░");
                });
        }
    }

    fn draw_dangerous(&self, printer: &Printer) {
        let width = self.colors.width();
        let mut warning_stage = false;
        for j in 0..3 {
            for i in 0..width {
                if self.colors.is_occupied(i, j) {
                    warning_stage = true;
                    break;
                }
            }
            if warning_stage {
                break;
            }
        }
        if !warning_stage {
            return;
        }
        for j in 0..3 {
            for i in 0..width {
                if !self.colors.is_occupied(i, j) {
                    printer.with_color(self.colors.warning_color, |printer| {
                        printer.print((2*i, j), "  ");
                    });
                }
            }
        }
    }
}

impl View for Board {
    fn draw(&self, printer: &Printer) {
        self.draw_background(printer);
        self.draw_dangerous(printer);
        self.draw_hint(printer);
        self.draw_block(printer)
    }

    fn required_size(&mut self, _constraint: cursive::Vec2) -> cursive::Vec2 {
        let width = self.colors.width();
        let height = self.colors.height();
        cursive::Vec2::new(2*width + 3, height + 10)
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        self.handle_event(event, false);
        EventResult::Consumed(None)
    }
}