Cogent Core Docs

0%

Loading...

Static preview:

Cogent Core DocsAdvanced

Updating

Updating order

The Update() method on core.WidgetBase is the general-purpose update method, which should be called whenever you have finished setting field values on a widget (or any other such configuration changes), and want to have the GUI display reflect those changes. In general, setting field values or other methods that configure a widget should have no side-effects directly, and all the implications thereof should be handled in the context of the Update() method.

It performs these steps in order:

    • calls UpdateWidget() then Style() on itself and each of its children down the full depth of the tree under it.

    • calls NeedsLayout() to trigger a new layout of the widgets.

The UpdateWidget() method first updates the value represented by the widget if any Bind value has been set, and then runs the Updaters functions, including any Maker functions as described in basics/plans, which makes a tree.Plan to update the child elements within the Widget.

Some other important things to keep in mind:

    Update() is automatically called on all widgets when the core.Scene is first shown in the GUI, so it doesn’t need to be called manually prior to that.

    Update() can be called prior to GUI rendering, and in general must be called prior to accessing any children of a given Widget, as they will not in general exist prior to the Update call.

    Restyle() can be called to specifically call Style() and NeedsRender() on a widget (and its children), when its State or other style-relevant data has changed. This is much faster and more efficient than a full Update() call.

How to make a new Widget type

To better understand the Update logic, it is useful to see how the code is organized to configure a given Widget. We will look at elements of the core.Button widget as a familiar example.

The Init() method has everything

In general, all of the configuration code is specified in the Init() method, which specifies styling, event handling, and make / update functions, typically in that order:

Styler

The Styler function should start with a SetAbilities call that specifies what kinds of things this Widget can do, and then it sets style properties based on the current State flags and other field values etc. See styling for more information.

Maker of Plans

The primary maker function for a Widget can start with any general-purpose code needed to coordinate relevant state prior to adding child widgets, which will be run every time the Update() function is called.

Next, children are added with appropriate logic determining whether they are needed or not:

The tree.AddAt adds a child with the given name to the overall tree.Plan for the widget’s children, and the first closure function indicates what to do when that icon is actually made for the first time. This code is run after the standard Init() method for the core.Icon type itself, so it is providing any additional styling and functionality over and above the defaults for that type. You can connect event handlers here, etc. Critically, this code is only ever run once, and like the Init() method itself, it should largely be setting closures that will actually be run later when the widget is actually made.

The Updater closure added here will be called every time Update() is called on the Icon, and it ensures that this icon is always updated to reflect the Icon field on the parent Button object. This is how you establish connections between properties on different widgets to ensure everything is consistent: the button’s Icon field is the definitive source setting for what the icon should be.

In general, it is ideal to be able to specify all of the dynamic updating logic for the children within the Add and Updater functions. Indeed, this ability to put all the logic in one place is a major advantage of this system. Nevertheless, sometimes you also need to provide additional methods that access the ChildByName using its unique name provided to AddAt, and update its properties.

Note that you should never call functions like Styler, Maker, OnClick etc in a situation where they might be called multiple times, because that would end up adding multiple copies of the given closure functions to the list of such functions to be run at the appropriate time, which, aside from being inefficient, could lead to bad effects.

The tree.Add function works just like AddAt except it automatically generates a unique name, based on the point in the source code where it is called. This is convenient for core.Toolbar Makers, where you are often adding multiple buttons and don’t really care about the names because you will not be referring back to these children elsewhere.

Adding more Init functions to children

In a Widget that embeds another widget type and extends its functionality, you can add additional Init closures that override or extend the basic initialization function that was specified in the AddAt call that creates the child widget in the first place. This is done using the tree.AddInit function, e.g., in the case of a core.Spinner that embeds core.TextField and modifies the properties of the leading and trailing icons thereof:

Adding individual children and Makers for sub-children

If a widget does not require dynamic configuration of its children (i.e., it always has the same children), you can save a step of indentation by using the tree.AddChildAt version of tree.AddAt, without enclosing everything in an outer Maker function. These Child versions of all the basic tree.Add* functions simply create a separate Maker function wrapper for you. There is a list of Maker functions that are called to create the overall tree.Plan for the widget, so multiple such functions can be defined, and they are called in the order added.

These Child versions are essential when you need to specify the children of children (and beyond), to configure an entire complex structure. Here’s an example from the Cogent Mail app:

The resulting code nicely captures the tree structure of the overall GUI, and this can be useful even when there aren’t any dynamic elements to it.