use crossbeam::atomic::AtomicCell;
use dpi::*;
use std::sync::Arc;
use vulkano::swapchain::Surface;
pub use winit::{
dpi,
window::{CursorGrabMode, CursorIcon, Icon, UserAttentionType, WindowLevel},
};
use winit::{
error::ExternalError,
window::{Fullscreen, WindowButtons},
};
use crate::utils::color_art_to_array;
#[derive(Clone)]
pub struct Window {
window: Arc<winit::window::Window>,
clear_color: Arc<AtomicCell<[f32; 4]>>,
}
impl Window {
pub fn new(surface: Arc<Surface>, clear_color: [f32; 4]) -> Self {
Self {
window: surface
.object()
.unwrap()
.clone()
.downcast::<winit::window::Window>()
.unwrap(),
clear_color: Arc::new(AtomicCell::new(clear_color)),
}
}
#[inline]
pub fn request_redraw(&self) {
self.window.request_redraw();
}
#[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.window.inner_size()
}
#[inline]
pub fn set_inner_size(&self, size: impl Into<Size>) {
self.window.set_inner_size(size);
}
#[inline]
pub fn outer_size(&self) -> PhysicalSize<u32> {
self.window.outer_size()
}
#[inline]
pub fn set_min_inner_size(&self, size: Option<impl Into<Size>>) {
self.window.set_min_inner_size(size);
}
#[inline]
pub fn set_max_inner_size(&self, size: Option<impl Into<Size>>) {
self.window.set_max_inner_size(size);
}
#[inline]
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
self.window.resize_increments()
}
#[inline]
pub fn set_resize_increments(&self, increments: Option<impl Into<Size>>) {
self.window.set_resize_increments(increments);
}
#[inline]
pub fn title(&self) -> String {
self.window.title()
}
#[inline]
pub fn set_title(&self, title: &str) {
self.window.set_title(title)
}
#[inline]
fn set_transparent(&self, transparent: bool) {
self.window.set_transparent(transparent)
}
#[inline]
pub fn set_visible(&self, visible: bool) {
self.window.set_visible(visible)
}
#[inline]
pub fn visible(&self) -> Option<bool> {
self.window.is_visible()
}
#[inline]
pub fn set_resizable(&self, resizable: bool) {
self.window.set_resizable(resizable)
}
#[inline]
pub fn resizable(&self) -> bool {
self.window.is_resizable()
}
#[inline]
pub fn set_enabled_buttons(&self, close: bool, minimize: bool, maximize: bool) {
let mut buttons = WindowButtons::empty();
if close {
buttons.toggle(WindowButtons::CLOSE);
};
if minimize {
buttons.toggle(WindowButtons::MINIMIZE);
};
if maximize {
buttons.toggle(WindowButtons::MAXIMIZE);
};
self.window.set_enabled_buttons(buttons)
}
#[inline]
pub fn enabled_buttons(&self) -> (bool, bool, bool) {
let mut result = (false, false, false);
let enabled = self.window.enabled_buttons();
if enabled.contains(WindowButtons::CLOSE) {
result.0 = true;
};
if enabled.contains(WindowButtons::MINIMIZE) {
result.1 = true;
};
if enabled.contains(WindowButtons::MAXIMIZE) {
result.2 = true;
};
result
}
#[inline]
pub fn set_minimized(&self, minimized: bool) {
self.window.set_minimized(minimized)
}
#[inline]
pub fn minimized(&self) -> Option<bool> {
self.window.is_minimized()
}
#[inline]
pub fn set_maximized(&self, maximized: bool) {
self.window.set_maximized(maximized)
}
#[inline]
pub fn maximized(&self) -> bool {
self.window.is_maximized()
}
#[inline]
pub fn set_fullscreen(&self, fullscreen: bool) {
let fullscreen = if fullscreen {
Some(Fullscreen::Borderless(None))
} else {
None
};
self.window.set_fullscreen(fullscreen)
}
#[inline]
pub fn fullscreen(&self) -> bool {
self.window.fullscreen().is_some()
}
#[inline]
pub fn set_decorations(&self, decorations: bool) {
self.window.set_decorations(decorations)
}
#[inline]
pub fn decorated(&self) -> bool {
self.window.is_decorated()
}
#[inline]
pub fn set_window_level(&self, level: WindowLevel) {
self.window.set_window_level(level)
}
#[inline]
pub fn set_window_icon(&self, icon: Option<Icon>) {
self.window.set_window_icon(icon);
}
#[inline]
pub fn focus(&self) {
self.window.focus_window();
}
#[inline]
pub fn has_focus(&self) -> bool {
self.window.has_focus()
}
#[inline]
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
self.window.request_user_attention(request_type);
}
#[inline]
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
self.window.set_cursor_icon(cursor);
}
#[inline]
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
self.window.set_cursor_grab(mode)
}
#[inline]
pub fn set_cursor_visible(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
self.window.set_cursor_grab(mode)
}
#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
self.window.drag_window()
}
#[inline]
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
self.window.set_cursor_hittest(hittest)
}
pub fn set_clear_color(&self, color: color_art::Color) {
let clear_color = [
color.red() as f32 / 255.0,
color.green() as f32 / 255.0,
color.blue() as f32 / 255.0,
color.alpha() as f32,
];
self.set_transparent(clear_color[3] != 1.0);
self.clear_color.store(clear_color);
}
pub fn clear_color(&self) -> [f32; 4] {
self.clear_color.load()
}
}
#[derive(Clone)]
#[must_use]
pub struct WindowBuilder {
attributes: winit::window::WindowBuilder,
pub(crate) clear_color: [f32; 4],
}
impl WindowBuilder {
pub fn new() -> Self {
let attributes = winit::window::WindowBuilder::new().with_title("Game");
Self {
attributes,
clear_color: [0.0, 0.0, 0.0, 1.0],
}
}
#[inline]
pub fn from_winit_builder(builder: winit::window::WindowBuilder) -> Self {
Self {
attributes: builder,
clear_color: [0.0, 0.0, 0.0, 1.0],
}
}
#[inline]
pub fn inner_size(mut self, size: impl Into<Size>) -> Self {
self.attributes = self.attributes.with_inner_size(size);
self
}
#[inline]
pub fn max_inner_size(mut self, size: impl Into<Size>) -> Self {
self.attributes = self.attributes.with_max_inner_size(size);
self
}
#[inline]
pub fn min_inner_size(mut self, size: impl Into<Size>) -> Self {
self.attributes = self.attributes.with_min_inner_size(size);
self
}
#[inline]
pub fn position(mut self, position: impl Into<Position>) -> Self {
self.attributes = self.attributes.with_position(position);
self
}
#[inline]
pub fn resizable(mut self, resizable: bool) -> Self {
self.attributes = self.attributes.with_resizable(resizable);
self
}
#[inline]
pub fn enabled_buttons(mut self, close: bool, minimize: bool, maximize: bool) -> Self {
let mut buttons = WindowButtons::empty();
if close {
buttons.toggle(WindowButtons::CLOSE);
};
if minimize {
buttons.toggle(WindowButtons::MINIMIZE);
};
if maximize {
buttons.toggle(WindowButtons::MAXIMIZE);
};
self.attributes = self.attributes.with_enabled_buttons(buttons);
self
}
#[inline]
pub fn title(mut self, title: impl Into<String>) -> Self {
self.attributes = self.attributes.with_title(title);
self
}
#[inline]
pub fn fullscreen(mut self, fullscreen: bool) -> Self {
let fullscreen = if fullscreen {
Some(Fullscreen::Borderless(None))
} else {
None
};
self.attributes = self.attributes.with_fullscreen(fullscreen);
self
}
#[inline]
pub fn maximized(mut self, maximized: bool) -> Self {
self.attributes = self.attributes.with_maximized(maximized);
self
}
#[inline]
pub fn visible(mut self, visible: bool) -> Self {
self.attributes = self.attributes.with_visible(visible);
self
}
pub fn clear_color(mut self, color: color_art::Color) -> Self {
let clear_color = color_art_to_array(color);
self.attributes = self.attributes.with_transparent(clear_color[3] != 1.0);
self.clear_color = clear_color;
self
}
#[inline]
pub fn decorations(mut self, decorations: bool) -> Self {
self.attributes = self.attributes.with_decorations(decorations);
self
}
#[inline]
pub fn window_level(mut self, level: WindowLevel) -> Self {
self.attributes = self.attributes.with_window_level(level);
self
}
#[inline]
pub fn icon(mut self, icon: Option<Icon>) -> Self {
self.attributes = self.attributes.with_window_icon(icon);
self
}
#[inline]
pub fn resize_increments(mut self, increments: impl Into<Size>) -> Self {
self.attributes = self.attributes.with_resize_increments(increments);
self
}
#[inline]
pub fn active(mut self, active: bool) -> Self {
self.attributes = self.attributes.with_active(active);
self
}
}
impl From<WindowBuilder> for winit::window::WindowBuilder {
fn from(val: WindowBuilder) -> Self {
val.attributes
}
}
impl Default for WindowBuilder {
fn default() -> Self {
Self::new()
}
}