minesweeper 1.0.0

Simple minesweeper in Rust
use piston_window::*;
use common::{ParamType, MoveDestination};

struct Block<'a> {
    name: &'a str, 
    num: u32,
    old_num: u32,
    hotkey: char,
    selected: bool,
    min_val: u32,
    max_val: u32,
    param_type: ParamType
}

impl<'a> Block<'a> {
    pub fn new(name: &'a str,
               num: u32,
               hotkey: char,
               min_val: u32,
               max_val: u32,
               param_type: ParamType) -> Block<'a>
    {
        Block {
            name: name,
            num: num,
            old_num: num,
            hotkey: hotkey,
            selected: false,
            min_val: min_val,
            max_val: max_val,
            param_type: param_type
        }
    }

    pub fn draw(&self,
                context: Context,
                graphics: &mut G2d,
                rect: &mut [u32; 4],
                glyps: &mut Glyphs)
    {
        let margin = 10;
        let text_height = 20;
        let block_height = 30;
        let text_padding = 7;
        let color = if self.selected {
            [0.0, 1.0, 0.0, 1.0]
        } else {
            [1.0, 1.0, 1.0, 1.0]
        };
        rect[1] += 20;
        rectangle(color,
                  [
                    (rect[0] + margin) as f64,
                    (rect[1]) as f64,
                    (rect[2] - 2*margin) as f64,
                    block_height as f64
                  ],
                  context.transform,
                  graphics);
        rect[1] += block_height;
        let transform = context.transform.trans((rect[0] + margin + text_padding) as f64,
                                                (rect[1] - text_padding) as f64);
        text::Text::colored([0.0, 0.0, 0.0, 1.0], text_height).draw(
                            &*format!("{}: {}", self.name, self.num),
                            glyps,
                            &context.draw_state,
                            transform,
                            graphics
                        );
        rect[1] += margin + text_height/2;
        let transform = context.transform.trans((rect[0] + margin) as f64,
                                                (rect[1]) as f64);
        let s = if self.selected {
            format!("Use arrows, press \"{}\" to apply changes", self.hotkey)
        } else {
            format!("Press \"{}\" to change", self.hotkey)
        };
        text::Text::colored([1.0, 1.0, 1.0, 1.0], text_height).draw(
                            &*s,
                            glyps,
                            &context.draw_state,
                            transform,
                            graphics
                        );
    }

    pub fn inc_safe(&mut self) {
        if self.num < self.max_val {
            self.num += 1;
        }
    }

    pub fn dec_safe(&mut self) {
        if self.num > self.min_val {
            self.num -= 1;
        }
    }

    pub fn apply_changes(&mut self) {
        self.old_num = self.num;
    }

    pub fn discard_changes(&mut self) {
        self.num = self.old_num;
    }
}

pub struct UI<'a> {
    blocks: Vec<Block<'a>>,
    selected_block: i32
}    

impl<'a> UI<'a> {
    pub fn new(height: u32, width: u32, mines: u32) -> UI<'a> {
        UI {
            blocks: vec![Block::new("Field width", width, 'W', 5, 50, ParamType::Width),
                         Block::new("Field height", height, 'H', 5, 50, ParamType::Height),
                         Block::new("Mines", mines, 'M', 1, 2500, ParamType::Mines),
            ],
            selected_block: -1
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            mut rect: [u32; 4],
            glyps: &mut Glyphs)
    {
        for b in self.blocks.iter() {
            b.draw(context, graphics, &mut rect, glyps);
        }
    }

    pub fn proc_key(&mut self, block: ParamType) -> Option<u32> {
        if self.selected_block >= 0 {
            let selected = self.blocks.get_mut(self.selected_block as usize).unwrap();
            if selected.param_type == block {
                selected.selected = false;
                selected.apply_changes();
                self.selected_block = -1;
                return Some(selected.num);
            }
        }
        for i in 0..self.blocks.len() {
            let item = self.blocks.get_mut(i).unwrap();
            let b = item.param_type == block;
            item.selected = b;
            if b {
                self.selected_block = i as i32;
            } else {
                item.discard_changes();
            }
        }
        None
    }

    pub fn change_selected(&mut self, dest: MoveDestination) {
        assert!(self.selected_block >= 0);
        let selected = self.blocks.get_mut(self.selected_block as usize).unwrap();
        match dest {
            MoveDestination::Up | MoveDestination::Right => selected.inc_safe(),
            MoveDestination::Down | MoveDestination::Left => selected.dec_safe()
        }
    }
}