Widgets
On this page I will explain the fundamental principles of Widgets in more detail.
The fundamentals
Widgets are constructors
In gooey, widgets are GameMaker constructors. More specifically, we have a base __UIWidget constructor with properties and methods, and then more specific widgets that inherit from the __UIWidget constructor (for example, panels, via the UIPanel constructor, or sprites, via the UISprite constructor). You will not have to mess with the __UIWidget constructor, but it is important for you to understand the hierarchical relationship between it and the derived constructors - this is, that all specific widgets will have a common set of properties and methods (inherited from the __UIWidget constructor), as well as their own properties and methods, which will be specific to each one of them.
All widgets should be inside panels
When using gooey, we should always use panels as containers for other widgets (except other panels). The system will not prevent you from creating widgets that are not inside a panel, but since it is not designed to work this way, you'll likely encounter roadblocks or problems.
Note that this does not imply that you cannot add widgets inside other (non-panel) widgets - in fact, there are some (like groups) that are made specifically for packing together a bunch of widgets, and others (like grids) which allow containing other widgets laid out in a table-like format. However, those container widgets must also be inside a panel.
When we add a widget into another, the former becomes the parent of the latter. In the end, given the facts described above, this means that only panels will not have a parent - or, equivalently, the parent for panels is the GUI layer itself.
Widgets have setters and getters
As we saw in the Hello World example, we should always use setter and getter methods to interact with (get or modify) their properties. If you are curious and view the gooey source code, you'll see that properties are exposed as GameMaker does not have private variables[^1], but you should not access them directly and you should instead rely on the methods for manipulation.
gooey setters and getters use camel case and have specific prefixes (set and get) to make them easier to remember. For example, panels have a setTitle setter which expects a Scribble-formatted string and sets the title of a panel. You will learn about these throughout the tutorials, but you can also access the full API reference directly.
Widgets have a unique string ID
All widgets created in gooey have a unique string ID. This is actually the identifier with which we can later interact with them.
The string ID is especially important when trying to refer to a previously created widget. This is normally done with convenience functions such as ui_get and ui_exists. Say, for example, in another part of our code, we would like to refer to the HelloWorld_Panel panel created in the previous tutorial. We can refer to it using the string ID:
Automatic handling of duplicate string IDs
If you try to create a widget with the same string ID as another one, gooey will automatically rename the new widget by adding digits to the end of the string, until it finds a unique ID. Additionally, gooey will let you know in the GameMaker log.
Widget constructors return self
The constructors in gooey return themselves. This is why we can store the result of their instantiation to a temporary variable, like we did in the Hello World example.
Setters return self
Similarly, widget setters also return the calling object. This allows for using method-chaning (aka fluent interface) to ease writing code.
For example, if we have a panel already created and a reference to it, we can chain two setters and obtain the same result as if we had two separate lines of code. Compare:
Wrapping up
In this tutorial we have seen the basic principles of widgets in gooey. There is another critical concept, however, that deserves its own tutorial: widget positioning. It is one of the key features of gooey and understanding it is critical to use the library correctly. Let's go!