Controls, resources and values
In NWG, Uis are filled controls and resources and user values.
Controls are (usually) visual components that the user can interact with (ex: a Button).
Resources are non visual components that cannot be directly interacted with. Instead, resources must be used by controls. (ex: A Font)
Values can be any kind of data. These are application specific values defined by the programmer.
In NWG, controls or resources are split in two objects: the
Templates and the actual
Controls/Resources.
In the NWG standard control library, the structure representing templates ends with a
T. For example,
ButtonT
is a template
that define a control and
Button
is the control.
In NWG, controls are not directly created by the programmer, instead templates are passed to a Ui object. The Ui object then instance the controls
and manage them.
Defining a template is boring. NWG introduce "sane defaults" using the Rust macro system. In the NWG standard control library, every control
has its own macro to initialize its template. The macro use the following format:
nwg_{control_name}!(required_fields; [optional_fields])
The macro take as parameters a list of
member_name=member_value
separated by a semicolon.
Having trouble remembering the parameters of a macro? No problem, every macro is exhaustively documented in the NWG API.
let button_t: ButtonT = nwg_button!(parent="MyWindow"; text="MyButton");
In order to send a template to a control, one of the following method must be used
pack_control(&ID, Template)
,
pack_resource(&ID, Template)
,
pack_value(&id, Value)
.
•
ID
is the unique ID that will identify the control in the Ui. Its type must match the type of the Ui.
•
Template
is the template of the control or the resource.
•
Value
can be anything boxable.
The
pack_*
commands are not executed right away. If the command fails inside of a
commit
, an error will be returned. If many pack commands are
sent, they will be executed in the order they were sent.
ui.pack_control(&"ControlId", nwg_button!(parent="MyWindow"; text="Hello World!"));
In order to remove any value from a UI, it must be
unpacked. This is done using the
unpack(&ID)
method.
Just like the
pack_*
commands, the command is not executed right away. The command will fail if the ID is not found in the UI or if the control or the resource
is currently borrowed.
When a control is unpacked from a UI, the special event
Destroyed
is triggered. During the callback execution, it is ensured that the control and its children are still alive.
If a control with children is unpacked, the
unpack
command is also sent to its children in a random order.
The Ui will unpack the children controls before the parent control.
Finally, when a UI goes out of scope,
unpack
commands are sent to every controls, resources and values in a random order.
ui.unpack(&"MyControl");
ui.unpack(&"MyResource");
ui.unpack(&"MyValue");
In order to access a control, a resource or a value stored in a UI, the component must first be borrowed using the
get(&ID)
or the
get_mut(&ID)
methods.
The method return a reference to the component. A component can be borrowed many time immutably, but only
one mutable
borrow can exists at a given time.
Finally, while a component is borrowed, some actions cannot be executed on it (ex: unpack).
if let Ok(your_name) = ui.get::<nwg::TextInput>(&"YourName") {
simple_message("Hello", &format!("Hello {}!", your_name.get_text()) );
} else {
panic!()
}
NWG has the
nwg_get!
and the
nwg_get_mut!
macros to quicky borrow a component from a Ui.
Note that the macro will panic if the borrow fails.
let control = nwg_get!(ui; ("MyButton", Button))
let (control1, control2) = nwg_get!(ui; [("MyRadio1", RadioButton), ("MyRadio2", RadioButton)])