summaryrefslogtreecommitdiff
path: root/sys/src/window.rs
blob: 19de5e7bc4ce6e28652415cf837e1e5f67d0d255 (plain)
use std::ffi::{c_void, CString};
use std::ops::ControlFlow;

use crate::{CWindowConfig, CWindowEvent};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct WindowConfig {
	pub title: String,
	pub default_width: u32,
	pub default_height: u32,
	pub default_x: u32,
	pub default_y: u32,
	pub visible: bool,
	pub borderless_fullscreen: bool,
}

pub struct Window {
	pub(crate) ptr: *mut (),
}

pub enum WindowEvent {
	Other = 1,
	CloseRequest,
	ScaleFactorChange,
	Resume,
	RedrawRequest,
}

impl Drop for Window {
	fn drop(&mut self) {
		unsafe { crate::destroy_window(self.ptr) }
	}
}

impl Window {
	pub fn new(config: WindowConfig) -> Self {
		let title = CString::new(config.title.as_bytes()).unwrap();
		let config = CWindowConfig {
			default_width: config.default_width,
			default_height: config.default_height,
			default_x: config.default_x,
			default_y: config.default_y,
			visible: config.visible,
			borderless_fullscreen: config.borderless_fullscreen,
			title: title.as_ptr(),
		};

		let window = unsafe { crate::create_window(config) };

		Self { ptr: window }
	}

	pub fn set_visible(&mut self, visible: bool) {
		unsafe { crate::set_visible(self.ptr, visible) }
	}

	pub fn set_title(&mut self, title: &str) {
		let string = CString::new(title.to_string().as_bytes()).unwrap();
		let bytes = string.as_ptr();
		unsafe { crate::set_title(self.ptr, bytes) }
	}

	pub fn resize(&mut self, width: u32, height: u32) {
		unsafe { crate::resize_window(self.ptr, width, height) }
	}

	pub fn set_fullscreen(&mut self, fullscreen: bool) {
		unsafe { crate::set_fullscreen(self.ptr, fullscreen) }
	}

	fn translate_event(event: CWindowEvent) -> Option<WindowEvent> {
		let event = match event {
			CWindowEvent::AboutToWait => return None,
			CWindowEvent::Other => WindowEvent::Other,
			CWindowEvent::CloseRequest => WindowEvent::CloseRequest,
			CWindowEvent::ScaleFactorChange => WindowEvent::ScaleFactorChange,
			CWindowEvent::Resume => WindowEvent::Resume,
			CWindowEvent::RedrawRequest => WindowEvent::RedrawRequest,
		};
		Some(event)
	}

	pub fn wait_for_event(&self) {
		unsafe { crate::wait_for_event(self.ptr) }
	}

	pub fn pop_event(&self) -> bool {
		unsafe { crate::pop_event(self.ptr) }
	}

	pub fn wait_for_resume(&mut self) {
		unsafe { crate::wait_for_resume(self.ptr) }
	}

	pub fn run(&mut self, mut handler: impl FnMut(&mut Window, Option<WindowEvent>)) -> ! {
		let window_ptr = self.ptr;

		unsafe {
			let closure = |c_event: CWindowEvent| {
				handler(self, Self::translate_event(c_event));
			};
			let closure_data: Box<Box<dyn FnMut(CWindowEvent)>> = Box::new(Box::new(closure));
			crate::set_event_handler(window_ptr, Box::into_raw(closure_data) as *mut _);
		}

		loop {
			if !self.pop_event() {
				unsafe { crate::run_event_handler(window_ptr, CWindowEvent::AboutToWait) };
			}
		}
	}

	pub fn request_redraw(&mut self) {
		unsafe { crate::request_redraw(self.ptr) }
	}
}