use std::sync::mpsc::Receiver;
use glfw::WindowHint;
use glfw::*;
#[derive(Copy, Clone, Debug)]
pub enum Error {
InitError,
WindowCreationError,
NoPrimaryMonitor,
NoVideoMode,
}
impl From<glfw::InitError> for Error {
fn from(_: glfw::InitError) -> Self {
Self::InitError
}
}
pub enum WindowMode {
Windowed,
Fullscreen,
Borderless,
}
pub struct Window {
glfw_window: glfw::Window,
glfw_context: Glfw,
event_receiver: Receiver<(f64, WindowEvent)>,
}
pub use glfw::Key;
pub use glfw::MouseButton;
pub use glfw::WindowEvent;
pub type WindowEventStream<'a> = std::iter::Map<
std::sync::mpsc::TryIter<'a, (f64, WindowEvent)>,
fn((f64, WindowEvent)) -> WindowEvent,
>;
impl Window {
pub fn new(spec: &WindowSpec) -> Result<Self, Error> {
let mut glfw_context = glfw::init(glfw::FAIL_ON_ERRORS)?;
let (mut window, event_receiver) =
glfw_context.with_primary_monitor(|glfw_context, monitor| {
let monitor = monitor.unwrap();
let mode = monitor.get_video_mode().ok_or(Error::NoVideoMode)?;
let (width, height) = match spec.native {
true => (mode.width, mode.height),
false => (spec.width, spec.height),
};
glfw_context.window_hint(WindowHint::Resizable(spec.resizable));
let mode = match spec.mode {
WindowMode::Windowed => glfw::WindowMode::Windowed,
WindowMode::Borderless => {
glfw_context.window_hint(WindowHint::Decorated(false));
glfw::WindowMode::Windowed
}
WindowMode::Fullscreen => {
glfw_context.window_hint(WindowHint::RedBits(Some(mode.red_bits)));
glfw_context.window_hint(WindowHint::GreenBits(Some(mode.green_bits)));
glfw_context.window_hint(WindowHint::BlueBits(Some(mode.blue_bits)));
glfw_context.window_hint(WindowHint::RefreshRate(Some(mode.refresh_rate)));
glfw::WindowMode::FullScreen(monitor)
}
};
glfw_context
.create_window(width, height, &spec.title, mode)
.ok_or(Error::WindowCreationError)
})?;
window.set_all_polling(true);
Ok(Self {
glfw_window: window,
glfw_context,
event_receiver,
})
}
pub fn process_events<'a>(&'a mut self) -> WindowEventStream {
self.glfw_context.poll_events();
(&self.event_receiver)
.try_iter()
.map(map_event as fn((f64, WindowEvent)) -> WindowEvent)
}
pub fn should_close(&self) -> bool {
self.glfw_window.should_close()
}
pub fn width(&self) -> u32 {
self.glfw_window.get_size().0 as u32
}
pub fn height(&self) -> u32 {
self.glfw_window.get_size().1 as u32
}
pub fn size(&self) -> (u32, u32) {
let (w, h) = self.glfw_window.get_size();
(w as u32, h as u32)
}
}
pub struct WindowSpec {
width: u32,
height: u32,
title: String,
native: bool,
resizable: bool,
mode: WindowMode,
}
impl WindowSpec {
pub fn new() -> Self {
Self {
width: 800,
height: 600,
title: String::new(),
native: false,
resizable: true,
mode: WindowMode::Windowed,
}
}
pub fn size(mut self, width: u32, height: u32) -> Self {
self.width = width;
self.height = height;
self
}
pub fn fullscreen(mut self) -> Self {
self.mode = WindowMode::Fullscreen;
self
}
pub fn borderless(mut self) -> Self {
self.mode = WindowMode::Borderless;
self
}
pub fn windowed(mut self) -> Self {
self.mode = WindowMode::Windowed;
self
}
pub fn native(mut self) -> Self {
self.native = true;
self
}
pub fn title(mut self, title: &str) -> Self {
self.title = title.into();
self
}
pub fn resizable(mut self, resizable: bool) -> Self {
self.resizable = resizable;
self
}
pub fn create(&self) -> Result<Window, Error> {
Window::new(&self)
}
}
pub fn map_event(event: (f64, WindowEvent)) -> WindowEvent {
event.1
}