Native Windows Derive: Controls
The first thing to define in a derive UI are the controls. Native windows derive maps a list of attributes to the builder api.
This way, definining the control parameters will only take a single line above the struct member definition.
Also, be sure to check out the
controls docs.
Attributes
As mentioned in the controls docs, almost every components of NWG use the same builder based approach. Builders API are easy
to understand at the cost of being verbose. In order to keep UI the initialization to a minimum, NWD translates the builder API
into a list of
nwg_control(builder_field: builder_value,*)
This has the benefits of keeping boilerplate code to a minimal amount and it also keep the control parameters next to the type definition,
making things easier to understand for anyone reading the code.
Example:
#[nwg_control(text: "Heisenberg", size: (280, 25), position: (10, 10))]
name_edit: nwg::TextInput,
// is the same as
nwg::TextInput::builder()
.text("Heisenberg")
.size((280, 25))
.position((10, 10))
.build(&mut data.text_edit);
Parent detection
In most circumstances, the controls in a UI will have the same parent; the window. Because nobody wants to copy and paste "
parent: window
"
on each children controls, the derive macro can guess the parent by looking up the fields defined before the control in the UI struct. Derive will choose the first
control marked with
nwg_control
that supports children.
If no parent is defined in the attributes, and no parent can be guessed the parent value will be left empty. The derive macro will not panic, but the resulting
code will raise a
ControlCreationError("no parent")
error.
Here is an example that shows how NWD guess the parents:
#[derive(NwgUi)]
struct MyUi {
// No auto parent
label: nwg::Label,
// No auto parent
window: nwg::Window,
// parent: window
label: nwg::Label,
// parent: window
frame: nwg::Frame,
// parent: frame
button: nwg::Button
}
Compressed flags
Defining flags can take alot of space. In order to fix this, NWG supports a "compressed" flags format. Where the flag enum is ignored.
This only works with the
flags
parameters because it's possible for NWD to guess the right type. For example, here's the
compressed flag definition VS the normal flag definition.
It's also worth noting that there is no need to import NWG in the local scope of your module when using native window values (such as flags definition).
#[derive(NwgUi)]
struct MyUi {
#[nwg_control(flags: "WINDOW|VISIBLE")]
window1: nwg::Window,
#[nwg_control(flags: WindowFlags::WINDOW | WindowFlags::VISIBLE)]
window1: nwg::Window,
}
Subclassed controls
By default, NWD can guess the control builder by looking up the structure member type. When a user type is used, this is no longer possible.
To fix this, it's possible to pass the
ty
parameter to the
nwg_control
attribute.
ty
won't be evaluated
as a builder parameter.
When not using
ty
and still using custom values, NWD will try to instance a custom builder object by calling
MyType::builder
.
The custom builder must work in the same way built-in builders works.
For an example see:
the subclassing example.
struct CustomButton1 {
base: nwg::Button
}
struct CustomButton2 {
base: nwg::Button
}
struct CustomButton2Builder {
pub fn build(btn: &mut CustomButton2) -> Result<(), nwg::NwgError> {
//...
}
}
subclass_control!(CustomButton1, Button, base);
subclass_control!(CustomButton2, Button, base);
#[derive(NwgUi)]
struct MyUi {
#[nwg_control]
window1: nwg::Window,
#[nwg_control(ty=Button)]
test_button1: CustomButton1,
#[nwg_control]
test_button2: CustomButton2,
}