native_windows_gui/controls/
window.rs1use winapi::um::winuser::{WS_OVERLAPPEDWINDOW, WS_CLIPCHILDREN, WS_VISIBLE, WS_DISABLED, WS_MAXIMIZE, WS_MINIMIZE, WS_CAPTION,
2WS_MINIMIZEBOX, WS_MAXIMIZEBOX, WS_SYSMENU, WS_THICKFRAME, WS_POPUP, WS_EX_TOPMOST, WS_EX_ACCEPTFILES};
3
4use crate::win32::window_helper as wh;
5use crate::win32::base_helper::check_hwnd;
6use crate::{NwgError, Icon};
7use super::{ControlBase, ControlHandle};
8
9const NOT_BOUND: &'static str = "Window is not yet bound to a winapi object";
10const BAD_HANDLE: &'static str = "INTERNAL ERROR: Window handle is not HWND!";
11
12
13bitflags! {
14
15 pub struct WindowFlags: u32 {
32 const MAIN_WINDOW = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX;
33 const WINDOW = WS_CAPTION | WS_SYSMENU;
34 const MINIMIZE_BOX = WS_MINIMIZEBOX;
35 const MAXIMIZE_BOX = WS_MAXIMIZEBOX;
36 const SYS_MENU = WS_SYSMENU;
37 const VISIBLE = WS_VISIBLE;
38 const DISABLED = WS_DISABLED;
39 const MAXIMIZED = WS_MAXIMIZE;
40 const MINIMIZED = WS_MINIMIZE;
41 const RESIZABLE = WS_THICKFRAME | WS_MAXIMIZEBOX;
42 const POPUP = WS_POPUP;
43 }
44}
45
46
47#[derive(Default, PartialEq, Eq)]
86pub struct Window {
87 pub handle: ControlHandle
88}
89
90impl Window {
91
92 pub fn builder<'a>() -> WindowBuilder<'a> {
93 WindowBuilder {
94 title: "New Window",
95 size: (500, 500),
96 position: (300, 300),
97 accept_files: false,
98 topmost: false,
99 center: false,
100 maximized: false,
101 minimized: false,
102 flags: None,
103 ex_flags: 0,
104 icon: None,
105 parent: None
106 }
107 }
108
109 pub fn maximize(&self) {
111 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
112 wh::maximize_window(handle);
113 }
114
115 pub fn minimize(&self) {
117 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
118 wh::minimize_window(handle);
119 }
120
121 pub fn restore(&self) {
123 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
124 wh::restore_window(handle);
125 }
126
127 pub fn invalidate(&self) {
129 use winapi::um::winuser::InvalidateRect;
130
131 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
132 unsafe { InvalidateRect(handle, ::std::ptr::null(), 1); }
133 }
134
135 pub fn close(&self) {
137 use winapi::um::winuser::WM_CLOSE;
138
139 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
140 wh::post_message(handle, WM_CLOSE, 0, 0);
141 }
142
143 pub fn icon(&self) -> Option<Icon> {
145 use winapi::um::winuser::WM_GETICON;
146 use winapi::um::winnt::HANDLE;
147
148 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
149 let handle = wh::send_message(handle, WM_GETICON, 0, 0);
150 if handle == 0 {
151 None
152 } else {
153 Some(Icon { handle: handle as HANDLE, owned: false })
154 }
155 }
156
157 pub fn set_icon(&self, icon: Option<&Icon>) {
160 use winapi::um::winuser::WM_SETICON;
161 use std::{mem, ptr};
162
163 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
164
165 let image_handle = icon.map(|i| i.handle).unwrap_or(ptr::null_mut());
166 unsafe {
167 wh::send_message(handle, WM_SETICON, 0, mem::transmute(image_handle));
168 }
169 }
170
171 pub fn focus(&self) -> bool {
173 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
174 unsafe { wh::get_focus(handle) }
175 }
176
177 pub fn set_focus(&self) {
179 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
180 unsafe { wh::set_focus(handle); }
181 }
182
183 pub fn enabled(&self) -> bool {
185 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
186 unsafe { wh::get_window_enabled(handle) }
187 }
188
189 pub fn set_enabled(&self, v: bool) {
191 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
192 unsafe { wh::set_window_enabled(handle, v) }
193 }
194
195 pub fn visible(&self) -> bool {
198 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
199 unsafe { wh::get_window_visibility(handle) }
200 }
201
202 pub fn set_visible(&self, v: bool) {
204 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
205 unsafe { wh::set_window_visibility(handle, v) }
206 }
207
208 pub fn size(&self) -> (u32, u32) {
210 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
211 unsafe { wh::get_window_size(handle) }
212 }
213
214 pub fn set_size(&self, x: u32, y: u32) {
216 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
217 unsafe { wh::set_window_size(handle, x, y, true) }
218 }
219
220 pub fn position(&self) -> (i32, i32) {
222 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
223 unsafe { wh::get_window_position(handle) }
224 }
225
226 pub fn set_position(&self, x: i32, y: i32) {
228 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
229 unsafe { wh::set_window_position(handle, x, y) }
230 }
231
232 pub fn text(&self) -> String {
234 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
235 unsafe { wh::get_window_text(handle) }
236 }
237
238 pub fn set_text<'a>(&self, v: &'a str) {
240 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
241 unsafe { wh::set_window_text(handle, v) }
242 }
243
244 pub fn class_name(&self) -> &'static str {
246 "NativeWindowsGuiWindow"
247 }
248
249 pub fn flags(&self) -> u32 {
251 WS_OVERLAPPEDWINDOW | WS_VISIBLE
252 }
253
254 pub fn forced_flags(&self) -> u32 {
256 WS_CLIPCHILDREN
257 }
258}
259
260impl Drop for Window {
261 fn drop(&mut self) {
262 self.handle.destroy();
263 }
264}
265
266#[cfg(feature = "raw-win-handle")]
267use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, windows::WindowsHandle};
268
269#[cfg(feature = "raw-win-handle")]
270unsafe impl HasRawWindowHandle for Window {
271 fn raw_window_handle(&self) -> RawWindowHandle {
272 use winapi::um::winuser::GWL_HINSTANCE;
273 match self.handle {
274 ControlHandle::Hwnd(hwnd) => {
275 let hinstance = wh::get_window_long(hwnd, GWL_HINSTANCE);
276
277 RawWindowHandle::Windows(WindowsHandle {
278 hwnd: hwnd as _,
279 hinstance: hinstance as _,
280 ..WindowsHandle::empty()
281 })
282 }
283 _ => RawWindowHandle::Windows(WindowsHandle::empty())
285 }
286 }
287}
288
289pub struct WindowBuilder<'a> {
290 title: &'a str,
291 size: (i32, i32),
292 position: (i32, i32),
293 accept_files: bool,
294 center: bool,
295 topmost: bool,
296 maximized: bool,
297 minimized: bool,
298 flags: Option<WindowFlags>,
299 ex_flags: u32,
300 icon: Option<&'a Icon>,
301 parent: Option<ControlHandle>
302}
303
304impl<'a> WindowBuilder<'a> {
305
306 pub fn flags(mut self, flags: WindowFlags) -> WindowBuilder<'a> {
307 self.flags = Some(flags);
308 self
309 }
310
311 pub fn ex_flags(mut self, flags: u32) -> WindowBuilder<'a> {
312 self.ex_flags = flags;
313 self
314 }
315
316 pub fn title(mut self, text: &'a str) -> WindowBuilder<'a> {
317 self.title = text;
318 self
319 }
320
321 pub fn size(mut self, size: (i32, i32)) -> WindowBuilder<'a> {
322 self.size = size;
323 self
324 }
325
326 pub fn position(mut self, pos: (i32, i32)) -> WindowBuilder<'a> {
327 self.position = pos;
328 self
329 }
330
331 pub fn icon(mut self, ico: Option<&'a Icon>) -> WindowBuilder<'a> {
332 self.icon = ico;
333 self
334 }
335
336 pub fn accept_files(mut self, accept_files: bool) -> WindowBuilder<'a> {
337 self.accept_files = accept_files;
338 self
339 }
340
341 pub fn topmost(mut self, topmost: bool) -> WindowBuilder<'a> {
342 self.topmost = topmost;
343 self
344 }
345
346 pub fn center(mut self, center: bool) -> WindowBuilder<'a> {
347 self.center = center;
348 self
349 }
350
351 pub fn maximized(mut self, maximized: bool) -> WindowBuilder<'a> {
352 self.maximized = maximized;
353 self
354 }
355
356 pub fn minimized(mut self, minimized: bool) -> WindowBuilder<'a> {
357 self.minimized = minimized;
358 self
359 }
360
361 pub fn parent<C: Into<ControlHandle>>(mut self, p: Option<C>) -> WindowBuilder<'a> {
362 self.parent = p.map(|p2| p2.into());
363 self
364 }
365
366 pub fn build(self, out: &mut Window) -> Result<(), NwgError> {
367 use crate::win32::high_dpi::physical_to_logical;
368
369 let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
370
371 let mut ex_flags = self.ex_flags;
372 if self.topmost { ex_flags |= WS_EX_TOPMOST; }
373 if self.accept_files { ex_flags |= WS_EX_ACCEPTFILES; }
374
375 *out = Default::default();
376
377 out.handle = ControlBase::build_hwnd()
378 .class_name(out.class_name())
379 .forced_flags(out.forced_flags())
380 .ex_flags(ex_flags)
381 .flags(flags)
382 .size(self.size)
383 .position(self.position)
384 .text(self.title)
385 .parent(self.parent)
386 .build()?;
387
388 if self.icon.is_some() {
389 out.set_icon(self.icon);
390 }
391
392 if self.center {
393 let [left, top, right, bottom] = crate::Monitor::monitor_rect_from_window(out as &Window);
394 let (m_width, m_height) = unsafe { physical_to_logical(right-left, bottom-top) };
395 let (width, height) = self.size;
396
397 let x = left + ((m_width-width)/2);
398 let y = top + ((m_height-height)/2);
399
400 out.set_position(x, y);
401 } else if self.maximized {
402 out.maximize();
403 } else if self.minimized {
404 out.minimize();
405 }
406
407 Ok(())
408 }
409
410}