-
Notifications
You must be signed in to change notification settings - Fork 57
Data Binding & Events
To make the generated code dynamic ImRAD implements data binding and events. While other ImGui tools traditionally offered little to no support for this important functionality ImRAD was designed to support it since the beginning.
Data binding - a way to dynamically change widget state or to report widget state back to the program
Event - member function which will be called upon something happens (button click, text input character filter, window appearance...)
One-way binding is changing a widget state by assigning an expression to one of its properties. For example Button.size_x can be bound to a member variable so it can be changed programmatically.
Two-way binding requires an l-value expression (such as variable reference). It allows for both programmatic widget state change and user interaction where the entered widget value is reported back to the program. An example of this is the Input widget value.
Flexible binding allows for both types of expressions. ImRAD will try to determine if the entered expression is a reference or not and output the appropriate code. This can be useful for certain widgets which support both types of binding.
The expression becomes a part of the generated Draw() method. That means it will be continuously evaluated during the widget drawing phase. It's up to the programmer to provide early calculation and caching if the performance is a concern.
The format of the binding expression depends on the property type:
-
other than string property - the expression is a regular C++ expression. It may contain literals, variables, operators, function calls etc. For example
numRows + 1is a validintexpression. -
string property - follows
std::formatrules but the argument expressions are placed directly within the{}replacement fields. For exampleList of all {showError ? "errors" : "notes"}is a valid format expression. Width and precision substitution (e.g.{:{}}) is not supported.To make the substitution obvious replacement fields are visualized in the designer:

Note: ImRAD performs only basic format string checking. Incorrect binding expressions may cause the generated code to stop compiling.
This allows to modify widget state but not letting the user to change it (apart from hovered/focused/activated state). Examples are Text.text, Selectable.label, Button.size_x, tooltip, disabled and visible state.
Some properties which don't have sensible default values will let you enter the expression directly:

And the binding button on right will turn orange. Either way you can use the binding button to type the binding expression using the Binding dialog:

This will show you a list of all available fields and lets you to create new as well.
This lets you to change widget state programmatically and still allow user to interact with the widget as well. Examples are Input.value, Checkbox.checked, MenuItem.checked etc.
Two-way binding properties are found inside the Bindings section:

Here the combo lets you perform common tasks (Rename, New variable) as well as quickly selecting one of the existing field with compatible type. If you want to enter the binding expression manually use the binding button.
Some ImGui controls come in two overloads. One used for two-way binding accepts a pointer to store the value:
Selectable(label, &value)
and one used for one-way binding:
Selectable(label, true)
ImRAD supports both. Upon entering the expression ImRAD will try to detect if the expression is a reference and if so it uses the two-way binding variant. One-way binding variant is used otherwise. Other examples are RadioButton.checked and special forceFocus property.
If you entered a variable reference but you still want to use one-way binding (so the user can't change the widget state) use parenthesis like this:
(checkedVar)
Not all widgets support flexible data binding. You will be warned if one-way binding expression is entered but only two-way binding is supported.
Note: Reference detection may not always work as detecting it requires a full C++ compiler. Use parenthesis to disambiguate.
Some widgets allow to bind into arrays and show a list of items. These are Table which presents items in rows and Child which may present them in columns.
-
You start by binding the parent
item/rowCountproperty:
Here ImRad already offers a list of containers available as fields. This currently supports
std::vector,std::array,std::spancontainer types and their smart / raw pointers.Successful array binding is signaled in the Hierarchy tree:
It advises you to use special $item and $index variables for data binding
-
Next place child widgets to visualize the item. You only need to place widgets for one item. The generated code will use a
forcycle to show all of them.For accessing the current item you may use
myArray[i]because the default name for the index isi.
But the for loop variable may change. To prevent that your binding expression can refer to a special
$itemand$indexvariables. So following binding is preferred:
-
In some cases you want to persist the current item index. For example to access it from an event handler. In that case use
row/itemIndexproperty:
Note: In some cases ImGui may provide you with the current item index without creating a new field. Look into
ImGui::TableGetRowIndex()and similar (imgui_internal.h).
Class wizard lets you manage class fields, rename the window class or create a new inner struct. It is accessible from the toolbar:

To assign a new event double click the event property or choose New Method from the popup menu. Existing events can be assigned by picking it from the list:

You can inspect the code to see what happened (but not code preview as that only shows the content of the Draw() method).