UI state, a useful singleton to manage the state of your game UI.
Only one state is current at a given time, it can be get or set using the TUIState.Current property. (Unless you use TUIState.Push, in which case you build a stack of states, all of them are available at the same time.)
Each state has comfortable Start and Finish methods that you can override to perform work when state becomes current, or stops being current. Most importantly, you can add/remove additional state-specific UI controls in Start and Finish methods. Add them in Start method like StateContainer.Controls.InsertFront(...), remove them by StateContainer.Controls.Remove(...).
Current state is also placed on the list of container controls. (Always under state-specific UI controls you added to container in Start method.) This way state is notified about UI events, and can react to them. In case of events that can be "handled" (like TUIControl.Press, TUIControl.Release events) the state is notified about them only if no other state-specific UI control handled them.
This way state can
catch press/release and similar events, when no other state-specific control handled them,
catch update, GL context open/close and other useful events,
can have it's own render function, to directly draw UI.
See the TUIControl class for a lot of useful methods that you can override in your state descendants to capture various events.
function AddDataImage(const Path: string): TDataImageId;
Adds image to the list of automatically loaded images for this state. Path is automatically wrapped in ApplicationData(Path) to get URL. The OpenGL image resource (TGLImage) is loaded when GL context is active, available under DataGLImage(Id). Where Id is the return value of this method.
Container on which state works. By default, this is Application.MainWindow. When the state is current, then Container property (from ancestor, see TUIControl.Container) is equal to this.
Pushing the state adds it above the Current state.
The current state is conceptually at the bottom of state stack, always. When it is nil, then pushing new state sets the Current state. Otherwise Current state is left as-it-is, new state is added on top.
class procedure Pop;
class function StateStackCount: Integer;
class constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Start; virtual;
State becomes current. This is called right before adding the state to the StateContainer.Controls list, so the state methods GLContextOpen and ContainerResize will be called next (as for all normal TUIControl).
procedure Finish; virtual;
State is no longer current. This is called after removing the state from the StateContainer.Controls list.
This is always called to finalize the started state. When the current state is destroyed, it's Finish is called too. So you can use this method to reliably finalize whatever you initialized in Start.
function PositionInside(const Position: TVector2Single): boolean; override;
Current state. In case multiple states are active (only possible if you used Push method), this is the bottom state. Setting this resets whole state stack.