1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::callbacks::{CallbackArgs, CallbackTrigger};
use crate::window_config::WindowConfig;
pub use crate::Coloured;
use piston_window::*;
pub use piston_window::{Key, MouseButton};
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};

pub struct Window<T: Coloured + Debug> {
    callbacks: HashMap<CallbackTrigger, Box<dyn Fn(CallbackArgs)>>,
    win: PistonWindow,
    to_draw: Vec<Vec<T>>,
    conf: WindowConfig,
    mouse_pos: (f64, f64),
}

impl<T: Coloured + Debug> Window<T> {
    pub fn new(conf: WindowConfig) -> Self {
        Window {
            callbacks: HashMap::new(),
            win: conf.get_window(),
            to_draw: Vec::new(),
            conf,
            mouse_pos: (0.0, 0.0),
        }
    }
    pub fn set_grid(&mut self, nu: Vec<Vec<T>>) {
        self.to_draw = nu;
    }

    pub fn as_str(&self) -> String {
        format!("Window Conf: {}\nMouse Pos: {:?}\nPlatform Info: {}", self.conf.as_str(), self.mouse_pos, self.win.device.get_info().platform_name.vendor)
    }

    pub fn can_continue<F>(&mut self, mut afterwards: F)
    where
        F: FnMut(&mut Self),
    {
        while let Some(e) = self.win.next() {
            e.mouse_cursor(|pos| {
                self.mouse_pos = arr_to_tuple(pos);
            });

            //region render
            if let Some(r_) = e.render_args() {
                let grid = &self.to_draw;
                println!("doodle");

                self.win.draw_2d(&e, |c, gl, _device| {
                    clear([1.0; 4], gl);

                    if !grid.is_empty() {
                        let (width, height) = match c.viewport.iter().nth(0) {
                            None => {
                                eprintln!("Couldn't get viewport!");
                                (0.0, 0.0)
                            }
                            Some(vp) => arr_to_tuple(vp.window_size),
                        };
                        let cell_width = width / grid[0].len() as f64;
                        let cell_height = height / grid.len() as f64;
                        let rect = [0.0, 0.0, cell_width, cell_height];

                        for x in 0..grid.len() {
                            for y in 0..grid[0].len() {
                                let xpos = y as f64 * cell_width;
                                let ypos = x as f64 * cell_height;
                                let trans = c.transform.trans(xpos, ypos);
                                rectangle(grid[x][y].get_colour(), rect, trans, gl);
                            }
                        }
                    }
                });
            }
            //endregion

            //region callbacks
            for (callback, func) in self.callbacks.iter() {
                match callback {
                    CallbackTrigger::Mouse(m, expected_release) => {
                        if let Some(Button::Mouse(btn)) = e.press_args() {
                            if m == &btn {
                                if !expected_release {
                                    func(CallbackArgs::Mouse(self.mouse_pos));
                                }
                            }
                        }
                        if let Some(Button::Mouse(btn)) = e.release_args() {
                            if m == &btn {
                                if !(!expected_release) {
                                    func(CallbackArgs::Mouse(self.mouse_pos));
                                }
                            }
                        }
                    }
                    CallbackTrigger::Scroll => {
                        if let Some(s) = e.mouse_scroll_args() {
                            func(CallbackArgs::Scroll(arr_to_tuple(s)));
                        }
                    }
                    CallbackTrigger::Keyboard(expected_key) => {
                        if let Some(Button::Keyboard(key)) = e.press_args() {
                            if &key == expected_key {
                                func(CallbackArgs::None);
                            }
                        }
                    }
                }
            }
            //endregion

            if e.update_args().is_some() {
                afterwards(self);
            }
        }
    }

    pub fn add_callback<F>(mut self, cb: CallbackTrigger, f: &'static F) -> Self
    where
        F: Fn(CallbackArgs),
    {
        self.callbacks.insert(cb, Box::new(f));
        self
    }
}

fn arr_to_tuple<T: Copy>(a: [T; 2]) -> (T, T) {
    (a[0], a[1])
}