use winapi::um::winuser::{WS_OVERLAPPEDWINDOW, WS_CLIPCHILDREN, WS_VISIBLE, WS_DISABLED, WS_MAXIMIZE, WS_MINIMIZE, WS_CAPTION,
WS_MINIMIZEBOX, WS_MAXIMIZEBOX, WS_SYSMENU, WS_THICKFRAME, WS_POPUP, WS_EX_TOPMOST, WS_EX_ACCEPTFILES};
use crate::win32::window_helper as wh;
use crate::win32::base_helper::check_hwnd;
use crate::{NwgError, Icon};
use super::{ControlBase, ControlHandle};
const NOT_BOUND: &'static str = "Window is not yet bound to a winapi object";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: Window handle is not HWND!";
bitflags! {
pub struct WindowFlags: u32 {
const MAIN_WINDOW = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX;
const WINDOW = WS_CAPTION | WS_SYSMENU;
const MINIMIZE_BOX = WS_MINIMIZEBOX;
const MAXIMIZE_BOX = WS_MAXIMIZEBOX;
const SYS_MENU = WS_SYSMENU;
const VISIBLE = WS_VISIBLE;
const DISABLED = WS_DISABLED;
const MAXIMIZED = WS_MAXIMIZE;
const MINIMIZED = WS_MINIMIZE;
const RESIZABLE = WS_THICKFRAME | WS_MAXIMIZEBOX;
const POPUP = WS_POPUP;
}
}
#[derive(Default, PartialEq, Eq)]
pub struct Window {
pub handle: ControlHandle
}
impl Window {
pub fn builder<'a>() -> WindowBuilder<'a> {
WindowBuilder {
title: "New Window",
size: (500, 500),
position: (300, 300),
accept_files: false,
topmost: false,
center: false,
maximized: false,
minimized: false,
flags: None,
ex_flags: 0,
icon: None,
parent: None
}
}
pub fn maximize(&self) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::maximize_window(handle);
}
pub fn minimize(&self) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::minimize_window(handle);
}
pub fn restore(&self) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::restore_window(handle);
}
pub fn invalidate(&self) {
use winapi::um::winuser::InvalidateRect;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { InvalidateRect(handle, ::std::ptr::null(), 1); }
}
pub fn close(&self) {
use winapi::um::winuser::WM_CLOSE;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::post_message(handle, WM_CLOSE, 0, 0);
}
pub fn icon(&self) -> Option<Icon> {
use winapi::um::winuser::WM_GETICON;
use winapi::um::winnt::HANDLE;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let handle = wh::send_message(handle, WM_GETICON, 0, 0);
if handle == 0 {
None
} else {
Some(Icon { handle: handle as HANDLE, owned: false })
}
}
pub fn set_icon(&self, icon: Option<&Icon>) {
use winapi::um::winuser::WM_SETICON;
use std::{mem, ptr};
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let image_handle = icon.map(|i| i.handle).unwrap_or(ptr::null_mut());
unsafe {
wh::send_message(handle, WM_SETICON, 0, mem::transmute(image_handle));
}
}
pub fn focus(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::get_focus(handle) }
}
pub fn set_focus(&self) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::set_focus(handle); }
}
pub fn enabled(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::get_window_enabled(handle) }
}
pub fn set_enabled(&self, v: bool) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::set_window_enabled(handle, v) }
}
pub fn visible(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::get_window_visibility(handle) }
}
pub fn set_visible(&self, v: bool) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::set_window_visibility(handle, v) }
}
pub fn size(&self) -> (u32, u32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::get_window_size(handle) }
}
pub fn set_size(&self, x: u32, y: u32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::set_window_size(handle, x, y, true) }
}
pub fn position(&self) -> (i32, i32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::get_window_position(handle) }
}
pub fn set_position(&self, x: i32, y: i32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::set_window_position(handle, x, y) }
}
pub fn text(&self) -> String {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::get_window_text(handle) }
}
pub fn set_text<'a>(&self, v: &'a str) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
unsafe { wh::set_window_text(handle, v) }
}
pub fn class_name(&self) -> &'static str {
"NativeWindowsGuiWindow"
}
pub fn flags(&self) -> u32 {
WS_OVERLAPPEDWINDOW | WS_VISIBLE
}
pub fn forced_flags(&self) -> u32 {
WS_CLIPCHILDREN
}
}
impl Drop for Window {
fn drop(&mut self) {
self.handle.destroy();
}
}
#[cfg(feature = "raw-win-handle")]
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, windows::WindowsHandle};
#[cfg(feature = "raw-win-handle")]
unsafe impl HasRawWindowHandle for Window {
fn raw_window_handle(&self) -> RawWindowHandle {
use winapi::um::winuser::GWL_HINSTANCE;
match self.handle {
ControlHandle::Hwnd(hwnd) => {
let hinstance = wh::get_window_long(hwnd, GWL_HINSTANCE);
RawWindowHandle::Windows(WindowsHandle {
hwnd: hwnd as _,
hinstance: hinstance as _,
..WindowsHandle::empty()
})
}
_ => RawWindowHandle::Windows(WindowsHandle::empty())
}
}
}
pub struct WindowBuilder<'a> {
title: &'a str,
size: (i32, i32),
position: (i32, i32),
accept_files: bool,
center: bool,
topmost: bool,
maximized: bool,
minimized: bool,
flags: Option<WindowFlags>,
ex_flags: u32,
icon: Option<&'a Icon>,
parent: Option<ControlHandle>
}
impl<'a> WindowBuilder<'a> {
pub fn flags(mut self, flags: WindowFlags) -> WindowBuilder<'a> {
self.flags = Some(flags);
self
}
pub fn ex_flags(mut self, flags: u32) -> WindowBuilder<'a> {
self.ex_flags = flags;
self
}
pub fn title(mut self, text: &'a str) -> WindowBuilder<'a> {
self.title = text;
self
}
pub fn size(mut self, size: (i32, i32)) -> WindowBuilder<'a> {
self.size = size;
self
}
pub fn position(mut self, pos: (i32, i32)) -> WindowBuilder<'a> {
self.position = pos;
self
}
pub fn icon(mut self, ico: Option<&'a Icon>) -> WindowBuilder<'a> {
self.icon = ico;
self
}
pub fn accept_files(mut self, accept_files: bool) -> WindowBuilder<'a> {
self.accept_files = accept_files;
self
}
pub fn topmost(mut self, topmost: bool) -> WindowBuilder<'a> {
self.topmost = topmost;
self
}
pub fn center(mut self, center: bool) -> WindowBuilder<'a> {
self.center = center;
self
}
pub fn maximized(mut self, maximized: bool) -> WindowBuilder<'a> {
self.maximized = maximized;
self
}
pub fn minimized(mut self, minimized: bool) -> WindowBuilder<'a> {
self.minimized = minimized;
self
}
pub fn parent<C: Into<ControlHandle>>(mut self, p: Option<C>) -> WindowBuilder<'a> {
self.parent = p.map(|p2| p2.into());
self
}
pub fn build(self, out: &mut Window) -> Result<(), NwgError> {
use crate::win32::high_dpi::physical_to_logical;
let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
let mut ex_flags = self.ex_flags;
if self.topmost { ex_flags |= WS_EX_TOPMOST; }
if self.accept_files { ex_flags |= WS_EX_ACCEPTFILES; }
*out = Default::default();
out.handle = ControlBase::build_hwnd()
.class_name(out.class_name())
.forced_flags(out.forced_flags())
.ex_flags(ex_flags)
.flags(flags)
.size(self.size)
.position(self.position)
.text(self.title)
.parent(self.parent)
.build()?;
if self.icon.is_some() {
out.set_icon(self.icon);
}
if self.center {
let [left, top, right, bottom] = crate::Monitor::monitor_rect_from_window(out as &Window);
let (m_width, m_height) = unsafe { physical_to_logical(right-left, bottom-top) };
let (width, height) = self.size;
let x = left + ((m_width-width)/2);
let y = top + ((m_height-height)/2);
out.set_position(x, y);
} else if self.maximized {
out.maximize();
} else if self.minimized {
out.minimize();
}
Ok(())
}
}