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.

Templates and controls

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.

Templates macro

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");

Packing

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!"));

Unpacking

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");

Borrowing elements

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!()
}

Get macro

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)])