summaryrefslogtreecommitdiff
path: root/sys/src/window.rs
blob: e66747d8c094357104653e7e8bb221556c3142e9 (plain)
use std::ffi::CString;
use std::num::NonZeroU32;

use crate::{CWindowConfig, CWindowEvent};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct WindowConfig {
	pub title: Option<String>,
	pub default_width: NonZeroU32,
	pub default_height: NonZeroU32,
	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 = config
			.title
			.map(|title| CString::new(title.as_bytes()).unwrap());
		let config = CWindowConfig {
			default_width: config.default_width.get(),
			default_height: config.default_height.get(),
			default_x: config.default_x,
			default_y: config.default_y,
			visible: config.visible,
			borderless_fullscreen: config.borderless_fullscreen,
			title: title
				.as_ref()
				.map(|title| title.as_ptr())
				.unwrap_or(std::ptr::null()),
		};

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

		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) }
		drop(string);
	}

	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) }
	}
}