use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::time::Duration;
pub use raw_window_handle::RawWindowHandle;
use crate::{Rect, ViewRef};
#[derive(Clone, Debug, PartialEq)]
pub struct WindowConfig {
pub title: String,
pub size: [f64; 2],
pub position: Option<[f64; 2]>,
pub decorations: bool,
pub resizable: bool,
pub level: WindowLevel,
pub activating: bool,
pub all_desktops: bool,
pub background: WindowBackground,
pub shadow: bool,
pub visible: bool,
}
impl Default for WindowConfig {
fn default() -> WindowConfig {
WindowConfig {
title: String::new(),
size: [400.0, 300.0],
position: None,
decorations: true,
resizable: true,
level: WindowLevel::Normal,
activating: true,
all_desktops: false,
background: WindowBackground::Solid,
shadow: true,
visible: true,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum WindowLevel {
#[default]
Normal,
AlwaysOnTop,
AlwaysOnBottom,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum WindowBackground {
#[default]
Solid,
Transparent,
Blurred,
Glass,
}
impl WindowBackground {
pub fn sees_through(self) -> bool {
self != WindowBackground::Solid
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum WindowError {
Unsupported,
Failed(String),
}
impl fmt::Display for WindowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
WindowError::Unsupported => f.write_str("the host does not support this window"),
WindowError::Failed(reason) => {
write!(f, "the host could not make the window: {reason}")
}
}
}
}
impl std::error::Error for WindowError {}
pub type WindowFuture = Pin<Box<dyn Future<Output = Result<WindowRef, WindowError>>>>;
pub type WindowRef = Rc<dyn HostWindow>;
pub trait HostWindow: 'static {
fn view(&self) -> ViewRef;
fn frame(&self) -> Rect;
fn set_frame(&self, frame: Rect, animate: Option<Duration>);
fn set_title(&self, title: &str);
fn show(&self);
fn hide(&self);
fn close(&self);
fn native_handle(&self) -> Option<RawWindowHandle>;
fn set_close_requested(&self, handler: Option<Rc<dyn Fn()>>);
}
pub trait WindowingOwner: 'static {
fn create(&self, config: WindowConfig) -> WindowFuture;
fn adopt(&self, handle: RawWindowHandle) -> WindowFuture {
let _ = handle;
Box::pin(async { Err(WindowError::Unsupported) })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_default_window_is_an_ordinary_visible_one() {
let config = WindowConfig::default();
assert!(config.decorations && config.visible && config.activating);
assert_eq!(config.level, WindowLevel::Normal);
assert_eq!(config.background, WindowBackground::Solid);
}
#[test]
fn every_background_but_solid_sees_through() {
assert!(!WindowBackground::Solid.sees_through());
assert!(WindowBackground::Transparent.sees_through());
assert!(WindowBackground::Blurred.sees_through());
assert!(WindowBackground::Glass.sees_through());
}
struct NoWindows;
impl WindowingOwner for NoWindows {
fn create(&self, _config: WindowConfig) -> WindowFuture {
Box::pin(async { Err(WindowError::Unsupported) })
}
}
#[test]
fn adoption_is_unsupported_unless_a_host_says_otherwise() {
let owner = NoWindows;
let mut future = owner.adopt(RawWindowHandle::Web(
raw_window_handle::WebWindowHandle::new(1),
));
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
match future.as_mut().poll(&mut cx) {
std::task::Poll::Ready(Err(WindowError::Unsupported)) => {}
other => panic!(
"expected Unsupported, got {:?}",
other.map(|r| r.map(|_| ()))
),
}
}
}