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