Class TUIState

Unit

Declaration

type TUIState = class(TUIControl)

Description

UI state, to manage the state of your game UI. See also https://castle-engine.io/manual_2d_user_interface.php#section_ui_state for an overview of using TUIState.

In simple cases, only one state is current at a given time, and it can be get or set using the TUIState.Current property. In more complex cases, you can use TUIState.Push and TUIState.Pop to build a stack of states, and in effect multiple states are active at the same time. All of the states on stack are started, but only the top-most is resumed.

Each state has Start and Stop methods that you can override to perform work when state becomes part of the current state stack, or stops being part of it. You can also override Resume and Pause methods, to perform work when the state becomes the top-most state or is no longer the top-most state. The distinction becomes important once you play around with pushing/popping states. The names are deliberaly similar to Android lifecycle callback names.

You can add/remove state-specific UI controls in various ways. You can add them in the constructor of this state (and then free in destructor), or add them in Start, free in Stop.

  1. It's simplest and best to add/keep children controls as real children of the current state, so add them using methods TUIControl.InsertFront and TUIControl.InsertBack.

  2. Eventually, for special tricks, you can add controls that are conceptually the state "children" directly to the StateContainer.Controls list. This allows to keep some children on the StateContainer.Controls list for a longer time (not only when this state is active), which may be useful for optimization, to not reinitialize GL resources too often. To do this, add controls using StateContainer.Controls.InsertFront(...), remove them by StateContainer.Controls.Remove(...), and make sure to override InsertAtPosition method such that state instance is inserted in StateContainer.Controls right behind your UI.

Current state is also placed on the list of container controls. This way state is notified about UI events, and can react to them. Since state-specific UI should always be at the front of us, or our children, so in case of events that can be "handled" (like TUIControl.Press, TUIControl.Release events) the state-specific UI controls will handle them before the state itself (if you override TUIControl.Press or such in state, be sure to call inherited first, to make sure it really happens).

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.

Hierarchy

Overview

Fields

Public class var Log: boolean;

Methods

Protected function StateContainer: TUIContainer; virtual;
Protected function InsertAtPosition: Integer; virtual;
Protected function FreeAtStop: TComponent;
Public class procedure Push(const NewState: TUIState);
Public class procedure Pop;
Public class procedure Pop(const CurrentTopMostState: TUIState);
Public class function StateStackCount: Integer;
Public constructor Create(AOwner: TComponent); override;
Public destructor Destroy; override;
Public procedure Start; virtual;
Public procedure Stop; virtual;
Public procedure Resume; virtual;
Public procedure Pause; virtual;
Public procedure Finish; virtual; deprecated 'use Stop';
Public function Rect: TRectangle; override;
Public function Active: boolean;
Public function Press(const Event: TInputPressRelease): boolean; override;
Public function Release(const Event: TInputPressRelease): boolean; override;
Public function Motion(const Event: TInputMotion): boolean; override;
Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override;

Properties

Public class property Current: TUIState read GetCurrent write SetCurrent;
Public class property CurrentTop: TUIState read GetCurrentTop;
Public class property StateStack [constIndex:Integer]: TUIState read GetStateStack;
Public property InterceptInput: boolean read FInterceptInput write FInterceptInput default false;

Description

Fields

Public class var Log: boolean;

When True, state operations will send a log to CastleLog.

Methods

Protected function StateContainer: TUIContainer; virtual;

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.

Protected function InsertAtPosition: Integer; virtual;

Position on StateContainer.Controls where we insert this state. By default, state is inserted as the front-most control, so position is equal to StateContainer.Controls.Count.

Protected function FreeAtStop: TComponent;

Assign this component as owner for your controls, to make them freed during nearest Stop.

Public class procedure Push(const NewState: TUIState);

Pushing the state adds it at the top of the state stack.

The state known as Current 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.

Public class procedure Pop;

Pop the current top-most state, whatever it is.

Public class procedure Pop(const CurrentTopMostState: TUIState);

Pop the top-most state, checking it is as expected. Makes a warning, and does nothing, if the current top-most state is different than indicated. This is usually a safer (more chance to easily catch bugs) version of Pop than the parameter-less version.

Public class function StateStackCount: Integer;
 
Public constructor Create(AOwner: TComponent); override;
 
Public destructor Destroy; override;
 
Public procedure Start; virtual;

State becomes active, it's now part of the state stack.

Started state is part of the StateStack, and will soon become running (top-most on the stack). When the state is set to be current, by TUIState.Current := MyState, this happens:

  1. MyStart is pushed as the top-most state on state stack.

  2. MyStart.Start is called.

  3. MyStart is added to the StateContainer.Controls list, so the state methods GLContextOpen and Resize are called (as for all normal TUIControl instances).

  4. MyStar.Resume is called.

Public procedure Stop; virtual;

State is no longer active, no longer part of state stack.

When the state stops becoming active, this happens:

  1. MyStart.Pause is called.

  2. MyStart is removed from the StateContainer.Controls list. So the state method GLContextClose is called (as for all normal TUIControl instances).

  3. MyStart.Stop is called.

  4. MyStart is removed from the on state stack.

This is always called to finalize the started state. When the state is destroyed, it's Pause and Stop are called too, so you can use this method to reliably finalize whatever you initialized in Start.

Public procedure Resume; virtual;

State is now the top-most state. See Start and Stop docs about state lifecycle methods. This is called after Start, it is also called when you pop another state, making this state the top-most.

Public procedure Pause; virtual;

State is no longer the top-most state. See Start and Stop docs about state lifecycle methods. This is called before Stop, it is also called when another state is pushed over this state, so this stops being the the top-most state.

Public procedure Finish; virtual; deprecated 'use Stop';

Warning: this symbol is deprecated: use Stop

 
Public function Rect: TRectangle; override;
 
Public function Active: boolean;

State is right now part of the state stack, which means it's between Start and Stop calls. The state is added to the stack before the Start call, and removed after the Stop call, so this returns True during all the methods — Start, Resume, Pause, Stop.

Public function Press(const Event: TInputPressRelease): boolean; override;
 
Public function Release(const Event: TInputPressRelease): boolean; override;
 
Public function Motion(const Event: TInputMotion): boolean; override;
 
Public procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override;
 

Properties

Public class property Current: TUIState read GetCurrent write SetCurrent;

Current state. In case multiple states are active (only possible if you used Push method), this is the bottom state (use CurrentTop to get top state). Setting this resets whole state stack.

Public class property CurrentTop: TUIState read GetCurrentTop;
 
Public class property StateStack [constIndex:Integer]: TUIState read GetStateStack;
 
Public property InterceptInput: boolean read FInterceptInput write FInterceptInput default false;

Prevents passing mouse/keyboard events to the UI states underneath.

More precisely, when this property is True, then the Press, Release and Motion events are marked as "handled" in this UI state. This means that they will not be processed further, by UI controls under this state, in particular by UI states that are underneath this state in state stack (created by Push method). They will also not be passed to final container (TCastleWindowCustom, TCastleControlCustom) callbacks like TCastleWindowCustom.OnPress (as these callbacks are always used at the end, when nothing else handled the event).


Generated by PasDoc 0.15.0.