Class TUIState
Unit
Declaration
type TUIState = class(TCastleUserInterface)
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.
It's simplest and best to add/keep children controls as real children of the current state, so add them using methods TCastleUserInterface.InsertFront and TCastleUserInterface.InsertBack.
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 theStateContainer.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 usingStateContainer.Controls.InsertFront(...)
, remove them byStateContainer.Controls.Remove(...)
, and make sure to override InsertAtPosition method such that state instance is inserted inStateContainer.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 TCastleUserInterface.Press, TCastleUserInterface.Release events) the state-specific UI controls will handle them before the state itself (if you override TCastleUserInterface.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 TCastleUserInterface class for a lot of useful methods that you can override in your state descendants to capture various events.
Hierarchy
- TObject
- TPersistent
- TComponent
- TCastleComponent
- TInputListener
- TCastleUserInterface
- TUIState
Overview
Fields
![]() |
class var Log: boolean; |
Methods
![]() |
function StateContainer: TUIContainer; virtual; |
![]() |
function InsertAtPosition: Integer; virtual; |
![]() |
function FreeAtStop: TComponent; |
![]() |
class procedure Push(const NewState: TUIState); |
![]() |
class procedure Pop; |
![]() |
class procedure Pop(const CurrentTopMostState: TUIState); |
![]() |
class function StateStackCount: Integer; |
![]() |
constructor Create(AOwner: TComponent); override; |
![]() |
destructor Destroy; override; |
![]() |
constructor CreateUntilStopped; |
![]() |
procedure Start; virtual; |
![]() |
procedure Stop; virtual; |
![]() |
procedure Resume; virtual; |
![]() |
procedure Pause; virtual; |
![]() |
procedure Finish; virtual; deprecated 'use Stop'; |
![]() |
function Active: boolean; |
![]() |
function Press(const Event: TInputPressRelease): boolean; override; |
![]() |
function Release(const Event: TInputPressRelease): boolean; override; |
![]() |
function Motion(const Event: TInputMotion): boolean; override; |
![]() |
procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override; |
![]() |
procedure Render; override; |
![]() |
procedure InsertUserInterface(const DesignUrl: String; const FinalOwner: TComponent; out Ui: TCastleUserInterface; out UiOwner: TComponent); |
![]() |
procedure InsertUserInterface(const DesignUrl: String; const FinalOwner: TComponent; out UiOwner: TComponent); |
![]() |
procedure WaitForRenderAndCall(const Event: TNotifyEvent); |
Properties
![]() |
class property Current: TUIState read GetCurrent write SetCurrent; |
![]() |
class property CurrentTop: TUIState read GetCurrentTop; |
![]() |
class property StateStack [constIndex:Integer]: TUIState read GetStateStack; |
![]() |
property InterceptInput: boolean read FInterceptInput write FInterceptInput
default false; |
![]() |
property FullSize default true; |
Description
Fields
![]() |
class var Log: boolean; |
When |
Methods
![]() |
function StateContainer: TUIContainer; virtual; |
Container on which state works. By default, this is Application.MainWindow if you use CastleWindow or TCastleControlBase.MainControl if you use CastleControl. When the state is current, then Container property (from ancestor, see TCastleUserInterface.Container) is equal to this. |
![]() |
function FreeAtStop: TComponent; |
Assign this component as owner for your controls, to make them freed during nearest Stop. |
![]() |
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. |
![]() |
class procedure Pop; |
Pop the current top-most state, whatever it is. |
![]() |
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. |
![]() |
class function StateStackCount: Integer; |
![]() |
constructor Create(AOwner: TComponent); override; |
Create an instance of the state. You willl typically create one instance of each state class (like TStateMain, TStatePlay) at the application initialization (e.g. in Application.OnInitialize callback), like StateMainMenu := TStateMainMenu.Create(Application); StatePlay := TStatePlay.Create(Application);
Later you switch between states using Current or Push or Pop, like this: TUIState.Current := StateMain;
See https://castle-engine.io/manual_2d_user_interface.php and numerous engine examples, like examples/user_interface/zombie_fighter/ . |
![]() |
destructor Destroy; override; |
![]() |
constructor CreateUntilStopped; |
Create the instance TUIState that will be automatically freed when the state is stopped. This allows alternative usage of states (as opposed to the ones described in Create docs), where you create short-lived instances of state classes. Use it like this: TUIState.Current := TStateMain.CreateUntilStopped;
The advantages:
The disadvantage is that you cannot store in state fields anything that should "survive" the state Stop. You can instead use "class variables" in state class, or any global variable. |
![]() |
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
|
![]() |
procedure Stop; virtual; |
State is no longer active, no longer part of state stack. When the state stops becoming active, this happens:
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. |
![]() |
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. |
![]() |
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. |
![]() |
procedure Finish; virtual; deprecated 'use Stop'; |
Warning: this symbol is deprecated: use Stop |
![]() |
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 |
![]() |
function Press(const Event: TInputPressRelease): boolean; override; |
![]() |
function Release(const Event: TInputPressRelease): boolean; override; |
![]() |
function Motion(const Event: TInputMotion): boolean; override; |
![]() |
procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override; |
![]() |
procedure Render; override; |
![]() |
procedure InsertUserInterface(const DesignUrl: String; const FinalOwner: TComponent; out Ui: TCastleUserInterface; out UiOwner: TComponent); |
Load and show a user interface from a .castle-user-interface file, designed in Castle Game Engine Editor. This is an utility method, loading a UI in a typical way into the TUIState. It is not the only way to load a .castle-user-interface file, a more general approach is to use UserInterfaceLoad from CastleComponentSerialize unit, and manually call InsertFront to add it to the state UI. The loaded UI is returned under the It is owned by ButtonQuit := UiOwner.FindRequiredComponent('ButtonQuit') as TCastleButton;
The UiOwner, in turn, is owned by the FinalOwner. You typically use this method inside overridden Start, and as FinalOwner you pass FreeAtStop – this way the user interface is freed when the state is stopped. |
![]() |
procedure InsertUserInterface(const DesignUrl: String; const FinalOwner: TComponent; out UiOwner: TComponent); |
![]() |
procedure WaitForRenderAndCall(const Event: TNotifyEvent); |
Wait until the render event happens (to redraw current state), and then call Event. The scheduled Event will be called at the Update time. If the state stopped before the scheduled events fired, then the remaining events are ignored. That is, the scheduled events are cleared every time you start the state. One use-case of this is to show a loading state, where you load things, but also update the loading progress from time to time. Be careful in this case to not call this too often, as then your loading time will be tied to rendering time. For example, when the monitor refresh rate is 60, and the "vertical sync" is "on", then the render events happen at most 60 times per second. So if you call |
Properties
![]() |
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. |
![]() |
class property CurrentTop: TUIState read GetCurrentTop; |
![]() |
class property StateStack [constIndex:Integer]: TUIState read GetStateStack; |
![]() |
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 |
![]() |
property FullSize default true; |
TUIState control makes most sense when it is This way it always captures events on the whole container. And the child controls (anchored to this) behave like anchored to the whole container. |
Generated by PasDoc 0.15.0.