use std::fmt;
use crate::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error::{ExternalError, NotSupportedError, OsError},
event_loop::EventLoopWindowTarget,
menu::MenuBar,
monitor::{MonitorHandle, VideoMode},
platform_impl,
};
pub use crate::icon::{BadIcon, Icon};
pub struct Window {
pub(crate) window: platform_impl::Window,
}
impl fmt::Debug for Window {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
fmtr.pad("Window { .. }")
}
}
impl Drop for Window {
fn drop(&mut self) {
if let Some(Fullscreen::Exclusive(_)) = self.fullscreen() {
self.set_fullscreen(None);
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(pub(crate) platform_impl::WindowId);
impl WindowId {
pub unsafe fn dummy() -> Self {
WindowId(platform_impl::WindowId::dummy())
}
}
#[derive(Clone, Default)]
pub struct WindowBuilder {
pub window: WindowAttributes,
pub(crate) platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes,
}
impl fmt::Debug for WindowBuilder {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
fmtr
.debug_struct("WindowBuilder")
.field("window", &self.window)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct WindowAttributes {
pub inner_size: Option<Size>,
pub min_inner_size: Option<Size>,
pub max_inner_size: Option<Size>,
pub position: Option<Position>,
pub resizable: bool,
pub fullscreen: Option<Fullscreen>,
pub title: String,
pub maximized: bool,
pub visible: bool,
pub transparent: bool,
pub decorations: bool,
pub always_on_top: bool,
pub window_icon: Option<Icon>,
pub window_menu: Option<platform_impl::Menu>,
}
impl Default for WindowAttributes {
#[inline]
fn default() -> WindowAttributes {
WindowAttributes {
inner_size: None,
min_inner_size: None,
max_inner_size: None,
position: None,
resizable: true,
title: "tao window".to_owned(),
maximized: false,
fullscreen: None,
visible: true,
transparent: false,
decorations: true,
always_on_top: false,
window_icon: None,
window_menu: None,
}
}
}
impl WindowBuilder {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn with_inner_size<S: Into<Size>>(mut self, size: S) -> Self {
self.window.inner_size = Some(size.into());
self
}
#[inline]
pub fn with_min_inner_size<S: Into<Size>>(mut self, min_size: S) -> Self {
self.window.min_inner_size = Some(min_size.into());
self
}
#[inline]
pub fn with_max_inner_size<S: Into<Size>>(mut self, max_size: S) -> Self {
self.window.max_inner_size = Some(max_size.into());
self
}
#[inline]
pub fn with_position<P: Into<Position>>(mut self, position: P) -> Self {
self.window.position = Some(position.into());
self
}
#[inline]
pub fn with_resizable(mut self, resizable: bool) -> Self {
self.window.resizable = resizable;
self
}
#[inline]
pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
self.window.title = title.into();
self
}
#[inline]
pub fn with_menu(mut self, menu: MenuBar) -> Self {
self.window.window_menu = Some(menu.0.menu_platform);
self
}
#[inline]
pub fn with_fullscreen(mut self, fullscreen: Option<Fullscreen>) -> Self {
self.window.fullscreen = fullscreen;
self
}
#[inline]
pub fn with_maximized(mut self, maximized: bool) -> Self {
self.window.maximized = maximized;
self
}
#[inline]
pub fn with_visible(mut self, visible: bool) -> Self {
self.window.visible = visible;
self
}
#[inline]
pub fn with_transparent(mut self, transparent: bool) -> Self {
self.window.transparent = transparent;
self
}
#[inline]
pub fn with_decorations(mut self, decorations: bool) -> Self {
self.window.decorations = decorations;
self
}
#[inline]
pub fn with_always_on_top(mut self, always_on_top: bool) -> Self {
self.window.always_on_top = always_on_top;
self
}
#[inline]
pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> Self {
self.window.window_icon = window_icon;
self
}
#[inline]
pub fn build<T: 'static>(
self,
window_target: &EventLoopWindowTarget<T>,
) -> Result<Window, OsError> {
platform_impl::Window::new(&window_target.p, self.window, self.platform_specific).map(
|window| {
window.request_redraw();
Window { window }
},
)
}
}
impl Window {
#[inline]
pub fn new<T: 'static>(event_loop: &EventLoopWindowTarget<T>) -> Result<Window, OsError> {
let builder = WindowBuilder::new();
builder.build(event_loop)
}
#[inline]
pub fn id(&self) -> WindowId {
WindowId(self.window.id())
}
#[inline]
pub fn scale_factor(&self) -> f64 {
self.window.scale_factor()
}
#[inline]
pub fn request_redraw(&self) {
self.window.request_redraw()
}
}
impl Window {
#[inline]
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
self.window.inner_position()
}
#[inline]
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
self.window.outer_position()
}
#[inline]
pub fn set_outer_position<P: Into<Position>>(&self, position: P) {
self.window.set_outer_position(position.into())
}
#[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.window.inner_size()
}
#[inline]
pub fn set_inner_size<S: Into<Size>>(&self, size: S) {
self.window.set_inner_size(size.into())
}
#[inline]
pub fn outer_size(&self) -> PhysicalSize<u32> {
self.window.outer_size()
}
#[inline]
pub fn set_min_inner_size<S: Into<Size>>(&self, min_size: Option<S>) {
self.window.set_min_inner_size(min_size.map(|s| s.into()))
}
#[inline]
pub fn set_max_inner_size<S: Into<Size>>(&self, max_size: Option<S>) {
self.window.set_max_inner_size(max_size.map(|s| s.into()))
}
}
impl Window {
#[inline]
pub fn set_title(&self, title: &str) {
self.window.set_title(title)
}
#[inline]
pub fn set_menu(&self, menu: Option<MenuBar>) {
if let Some(menu) = menu {
self.window.set_menu(Some(menu.0.menu_platform))
} else {
self.window.set_menu(None)
}
}
#[inline]
pub fn set_visible(&self, visible: bool) {
self.window.set_visible(visible)
}
#[inline]
pub fn set_focus(&self) {
self.window.set_focus()
}
#[inline]
pub fn set_resizable(&self, resizable: bool) {
self.window.set_resizable(resizable)
}
#[inline]
pub fn set_minimized(&self, minimized: bool) {
self.window.set_minimized(minimized);
}
#[inline]
pub fn set_maximized(&self, maximized: bool) {
self.window.set_maximized(maximized)
}
#[inline]
pub fn is_maximized(&self) -> bool {
self.window.is_maximized()
}
#[inline]
pub fn is_visible(&self) -> bool {
self.window.is_visible()
}
#[inline]
pub fn is_resizable(&self) -> bool {
self.window.is_resizable()
}
pub fn is_decorated(&self) -> bool {
self.window.is_decorated()
}
#[inline]
pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
self.window.set_fullscreen(fullscreen)
}
#[inline]
pub fn fullscreen(&self) -> Option<Fullscreen> {
self.window.fullscreen()
}
#[inline]
pub fn set_decorations(&self, decorations: bool) {
self.window.set_decorations(decorations)
}
#[inline]
pub fn set_always_on_top(&self, always_on_top: bool) {
self.window.set_always_on_top(always_on_top)
}
#[inline]
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
self.window.set_window_icon(window_icon)
}
#[inline]
pub fn set_ime_position<P: Into<Position>>(&self, position: P) {
self.window.set_ime_position(position.into())
}
#[inline]
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
self.window.request_user_attention(request_type)
}
#[inline]
pub fn hide_menu(&self) {
self.window.hide_menu();
}
#[inline]
pub fn show_menu(&self) {
self.window.show_menu();
}
pub fn is_menu_visible(&self) -> bool {
self.window.is_menu_visible()
}
}
impl Window {
#[inline]
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
self.window.set_cursor_icon(cursor);
}
#[inline]
pub fn set_cursor_position<P: Into<Position>>(&self, position: P) -> Result<(), ExternalError> {
self.window.set_cursor_position(position.into())
}
#[inline]
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
self.window.set_cursor_grab(grab)
}
#[inline]
pub fn set_cursor_visible(&self, visible: bool) {
self.window.set_cursor_visible(visible)
}
#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
self.window.drag_window()
}
}
impl Window {
#[inline]
pub fn current_monitor(&self) -> Option<MonitorHandle> {
self.window.current_monitor()
}
#[inline]
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
self
.window
.available_monitors()
.into_iter()
.map(|inner| MonitorHandle { inner })
}
#[inline]
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
self.window.primary_monitor()
}
}
unsafe impl raw_window_handle::HasRawWindowHandle for Window {
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
self.window.raw_window_handle()
}
}
#[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum CursorIcon {
Default,
Crosshair,
Hand,
Arrow,
Move,
Text,
Wait,
Help,
Progress,
NotAllowed,
ContextMenu,
Cell,
VerticalText,
Alias,
Copy,
NoDrop,
Grab,
Grabbing,
AllScroll,
ZoomIn,
ZoomOut,
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
}
impl Default for CursorIcon {
fn default() -> Self {
CursorIcon::Default
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub enum Fullscreen {
Exclusive(VideoMode),
Borderless(Option<MonitorHandle>),
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Theme {
Light,
Dark,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UserAttentionType {
Critical,
Informational,
}
impl Default for UserAttentionType {
fn default() -> Self {
UserAttentionType::Informational
}
}
pub const BORDERLESS_RESIZE_INSET: i32 = 5;