kansas/
lib.rs

1// 2017 tinaun
2//! a simple canvas-like drawing api for putting pixels on a screen
3//! 
4//! ```rust
5//! extern crate wcanvas;
6//! use wcanvas::Canvas;  
7//!
8//! let ctx = Canvas::new(640, 480);
9//!
10//! ctx.fill_color(0x0000FF);
11//! ctx.fill_rect(40, 80, 100, 200);
12//! ctx.pause();
13//! ```
14//!
15#[macro_use]
16extern crate gfx;
17
18extern crate gfx_window_glutin;
19extern crate gfx_device_gl;
20
21extern crate glutin;
22
23pub mod context;
24pub mod color;
25pub mod events;
26mod pipeline;
27
28pub use context::Context;
29
30
31use std::thread;
32use std::sync::mpsc;
33use std::ops::{Deref, DerefMut};
34
35pub struct Canvas {
36    ev_loop_handle: mpsc::Receiver<glutin::Event>,
37    ctx: context::Context,
38    listeners: events::ActiveListeners,
39}
40
41impl Canvas {
42
43    /// create a new Canvas
44    pub fn new() -> Self {
45        let ev_loop = glutin::EventsLoop::new();
46        let ctx = context::Context::new(800, 600, &ev_loop);
47
48        let (tx, ev_loop_handle) = mpsc::channel();
49
50        thread::spawn(move ||{
51            use glutin::ControlFlow;
52            let mut ev_loop = ev_loop;
53
54            ev_loop.run_forever(|e|{
55                match e {
56                    //Closed => ControlFlow::Break,
57                    _ => {
58                        match tx.send(e) {
59                            Ok(_) => ControlFlow::Continue,
60                            Err(_) => ControlFlow::Break,
61                        }
62                    }
63                }
64            });
65        });
66
67        Canvas {
68            ev_loop_handle,
69            ctx,
70            listeners: events::ActiveListeners::new(),
71        }
72    }
73
74
75    /// register a function to be used as an event handler
76    /// 
77    /// note: as of right now, registering the same event twice will overwrite the previous handler
78    /// function
79    pub fn on<E: events::Listener>(&mut self, handler: events::Callback<E>) 
80    {
81        self.listeners.add::<E>(handler);
82    }
83
84    pub fn off<E: events::Listener>(&mut self) {
85        self.listeners.remove(E::event_id());
86    }
87
88    /// get a mutable reference to the canvas's context
89    pub fn context_mut(&mut self) -> &mut context::Context {
90        &mut self.ctx
91    }
92
93    /// hold execution until user hits `Esc`
94    pub fn pause(&mut self) {
95        let mut running = true;
96
97        while running {
98            while let Ok(e) = self.ev_loop_handle.try_recv() {
99                use glutin::Event::WindowEvent;
100                use glutin::VirtualKeyCode;
101                use glutin::WindowEvent::*;
102
103                fn is_break(input: glutin::KeyboardInput) -> bool {
104                    input.virtual_keycode == Some(VirtualKeyCode::Escape) ||
105                    (input.state == glutin::ElementState::Pressed && 
106                    input.virtual_keycode == Some(VirtualKeyCode::Space))
107                }
108
109                if let WindowEvent {window_id: _, event} = e {
110                    match event {
111                        Closed => running = false,
112                        KeyboardInput { device_id: _, input } if is_break(input) 
113                            => running = false,
114                        Resized(width, height) => {
115                            self.ctx.window.update_views(gfx_window_glutin::update_views);
116                            //println!("resized: ({}, {})", width, height);
117                            self.ctx.resize(width, height);
118
119                            if let Some(cb) = self.listeners.resize.as_mut() {
120                                cb(&mut self.ctx, (width, height));
121                            }
122                        },
123                        MouseMoved { device_id: _, position } => {
124                            if let Some(cb) = self.listeners.mouse_move.as_mut() {
125                                cb(&mut self.ctx, position);
126                            }
127                        },
128                        MouseInput { device_id: _, state, button } => {
129                            if let Some(cb) = self.listeners.mouse_click.as_mut() {
130                                cb(&mut self.ctx, (state, button));
131                            }
132                        },
133                        MouseWheel { device_id: _, delta, phase: _ } => {
134                            if let Some(cb) = self.listeners.mouse_scroll.as_mut() {
135                                println!("delta: {:?}", delta);
136                                if let glutin::MouseScrollDelta::LineDelta(_, y) = delta {
137                                    cb(&mut self.ctx, events::ScrollEvent::new(y));
138                                }
139                            }
140                        },
141                        KeyboardInput { device_id: _, input } => {
142                            if let Some(cb) = self.listeners.key_press.as_mut() {
143                                cb(&mut self.ctx, input);
144                            }
145                        },
146                        _ => (),
147                    }
148                }
149            }
150
151            self.ctx.window.draw();
152            ::std::thread::sleep(::std::time::Duration::from_millis(10));
153        }
154    }
155}
156
157impl Deref for Canvas {
158    type Target = context::Context;
159    fn deref(&self) -> &Self::Target {
160        &self.ctx
161    }
162}
163
164impl DerefMut for Canvas {
165    fn deref_mut(&mut self) -> &mut Self::Target {
166        &mut self.ctx
167    }
168}
169
170
171
172#[cfg(test)]
173mod tests {
174    #[test]
175    fn it_works() {
176    }
177}