Native Windows GUI: Helpers
Outside of the controls, the resources, and the layouts NWG also has some utility functions. This section will go over them.
Automatic styling
NWG use a hack to implement visual style in applications without having to use a manifest file (
see this)
This is a good thing because linking a manifest requires a third party library (such as
rust-embed-resource)
If automatic styling is not needed, enable the feature
no-styling
Message box
In a GUI application, there's no console to display error messages to the end user. In cases like this, a message box is used.
NWG wraps the winapi message box function with the
message
or the
modal_message
function.
The modal variant takes a parent window parameter. The parent window is disabled during the message box duration.
use native_windows_gui as nwg;
let p = nwg::MessageParams {
title: "Hey",
content: "Cats are cute",
buttons: nwg::MessageButtons::Ok,
icons: nwg::MessageIcons::Warning
};
assert!(nwg::message(&p) == nwg::MessageChoice::Ok)
This function might be a little to verbose for most use case, that's why NWG implements six simple interfaces (3 modal and 3 without):
fatal_message
: a message box with an error icon. This function panics
error_message
: a message box with an error icon.
simple_message
: a message box with an information icon.
modal_fatal_message
: a message box with an error icon. This function panics
modal_error_message
: a message box with an error icon.
modal_info_message
: a message box with an information icon.
pub fn fatal_message<'a>(title: &'a str, content: &'a str) {}
pub fn error_message<'a>(title: &'a str, content: &'a str) {}
pub fn simple_message<'a>(title: &'a str, content: &'a str) {}
Global Cursor
NWG wraps the system cursor with the
GlobalCursor
object. Not to be confused with a
Cursor
object, a cursor resource file (*.cur).
GlobalCursor is hidden behind the
cursor
feature. Once enabled, it can be used to get/set the mouse position on screen, capture the cursor
outside of the application, detect a dragging gesture, and set the image of the cursor globally.
See
https://docs.rs/native-windows-gui/1.0.12/native_windows_gui/struct.GlobalCursor.html
The GlobalCursor object cannot be instanced. It must be used as it is:
use native_windows_gui as nwg;
let (x,y) = nwg::GlobalCursor::position();
Monitor
Sometimes you need to know the dimensions of the desktop to position Windows control. The
Monitor
object handles this. With Monitor,
it is possible to query the main screen dimensions, the virtual screen dimensions, and the monitor screen that a top level window is currently in
See
https://docs.rs/native-windows-gui/1.0.12/native_windows_gui/struct.Monitor.html
The Monitor object cannot be instanced. It must be used as it is:
// Creating and centering a window in the main monitor
use native_windows_gui as nwg;
fn create_window(width: i32, height: i32) -> nwg::Window {
let [total_width, total_height] = [nwg::Monitor::width(), nwg::Monitor::height()];
let mut window = nwg::Window::default();
let x = (total_width-width)/2;
let y = (total_height-height)/2;
nwg::Window::builder()
.size((width, height))
.position((x, y))
.build(&mut window)
.unwrap();
window
}
Clipboard
NWG also wraps the system clipboard in order to write or read data from it. The clipboard is a way to copy arbritary data from within an application
or even between two different applications.
See
https://docs.rs/native-windows-gui/1.0.12/native_windows_gui/struct.Clipboard.html
Note that NWG clipboard intentionally keeps things simple and close to the metal. If you want to more robust API, then I recommend you look into
https://github.com/DoumanAsh/clipboard-win
Clipboard is hidden behind the
clipboard
feature.
Writing/Reading text
Because reading or writing text will probably be the most used feature, NWG includes helpers functions that handles the unsafy bits.
One thing to note is that Windows clipboard functions always take a control parameter. This can be any
HWND
based controls (ex: Window, Button, etc).
use native_windows_gui as nwg;
fn clipboard_text(window: &nwg::Window) {
nwg::Clipboard::set_data_text(window, "Hello!");
let text = nwg::Clipboard::data_text(window);
assert!(text.is_some());
assert!(&text.unwrap() == &"Hello!");
}
Handling custom data
It's possible to pass data structure around using the low level clipboard functions. Note that those function are unsafe because there is no way to
validate the data.
When using the low level functions, the clipboard must be manually
opened and then
closed. Also, when setting data, it's up to the developer
to
empty whatever content was in the clipboard. Failure to do so will result in unknown errors.
use native_windows_gui as nwg;
#[repr(C)]
#[derive(Clone, Copy)]
struct Hello {
foo: usize,
bar: [u16; 3]
}
fn write_custom_data(window: &nwg::Window) {
let data = Hello {
foo: 6529,
bar: [0, 100, 20]
};
nwg::Clipboard::open(window);
nwg::Clipboard::empty();
unsafe {
nwg::Clipboard::set_data(
nwg::ClipboardFormat::Global("Hello"),
&data as *const Hello,
1
);
}
nwg::Clipboard::close();
}
fn read_custom_data(window: &nwg::Window) -> Option<Hello> {
unsafe {
nwg::Clipboard::open(window);
let data = nwg::Clipboard::data(nwg::ClipboardFormat::Global("Hello"));
nwg::Clipboard::close();
data
}
}
fn read_custom_data_handle(window: &nwg::Window) -> Option<Hello> {
unsafe {
nwg::Clipboard::open(window);
let handle = nwg::Clipboard::data_handle(nwg::ClipboardFormat::Global("Hello"));
let data = match handle {
Some(h) => {
let data_ptr: *const Hello = h.cast();
let data = *data_ptr;
h.release();
Some(data)
},
None => None
};
nwg::Clipboard::close();
data
}
}