Class TCastleView
Unit
Declaration
type TCastleView = class(TCastleUserInterface)
Description
"View" represents the current state of your application user interface. See also https://castle-engine.io/views for an overview of using TCastleView
.
In a given container (like a window), in the simple case only one TCastleView
is current at a given time, and it can be get or set using the TCastleContainer.View property. In more complex cases, you can use TCastleContainer.PushView and TCastleContainer.PopView to build a stack of views, and in effect multiple views are active at the same time. All of the views on stack are started, but only the top-most is resumed.
Each TCastleView
has Start and Stop methods that you can override to perform work when view becomes part of the current view stack, or stops being part of it.
You can also override Resume and Pause methods, to perform work when the view becomes the top-most view or is no longer the top-most view. The distinction becomes important once you play around with pushing/popping view.
To define view user interface:
It is simplest to set DesignUrl to the design file you created using CGE editor. Such user interface controls will be created right before Start and destroyed right after Stop (so the view UI always "resets" when view starts).
You can always create more UI controls and add them to the view at any point. The view is a TCastleUserInterface descendant and you can add UI to it just by using TCastleUserInterface.InsertFront.
UI children can be added anytime you want, e.g. in Start or in overridden constructor.
UI children can be removed or destroyed anytime you want as well. You can use FreeAtStop as an owner for anything you want to be automatically destroyed at Stop.
Current view is placed on the list of container controls. This way view is notified about UI events, and can react to them. Note that our children will handle events before the view itself is notified about them, following TCastleUserInterface events behavior. This way view can:
See the TCastleUserInterface class for a lot of useful methods that you can override in your view descendants to capture various events.
Hierarchy
- TObject
- TPersistent
- TComponent
- TCastleComponent
- TCastleUserInterface
- TCastleView
Overview
Fields
class var Log: boolean; |
Methods
function ContainerWidth: Cardinal; override; |
|
function ContainerHeight: Cardinal; override; |
|
function ContainerRect: TRectangle; override; |
|
function ContainerSizeKnown: boolean; override; |
|
function StateContainer: TCastleContainer; deprecated 'use Container to get the container in which we are already started, use PredictedContainer if the state is not yet started'; |
|
function Container: TCastleContainer; |
|
function FreeAtStop: TComponent; |
|
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; |
|
function UIScale: Single; override; |
|
procedure InsertUserInterface(const ADesignUrl: String; const FinalOwner: TComponent; out Ui: TCastleUserInterface; out UiOwner: TComponent); overload; deprecated 'instead of this, set DesignUrl in constructor'; |
|
procedure InsertUserInterface(const ADesignUrl: String; const FinalOwner: TComponent; out UiOwner: TComponent); overload; deprecated 'instead of this, set DesignUrl in constructor'; |
|
procedure WaitForRenderAndCall(const Event: TNotifyEvent); |
|
function DesignedComponent(const ComponentName: String): TComponent; |
|
class procedure Push(const NewState: TCastleView); deprecated 'use Container.PushView'; |
|
class procedure Pop; overload; deprecated 'use Container.PopView'; |
|
class procedure Pop(const CurrentTopMostState: TCastleView); overload; deprecated 'use Container.PopView'; |
|
class function StateStackCount: Integer; deprecated 'use Container.ViewStackCount'; |
Properties
property InterceptInput: boolean read FInterceptInput write FInterceptInput
default false; |
|
property DesignUrl: String read FDesignUrl write SetDesignUrl; |
|
property DesignPreload: Boolean read FDesignPreload write SetDesignPreload default false; |
|
class property Current: TCastleView read GetCurrent write SetCurrent; deprecated 'use Container.View'; |
|
class property CurrentTop: TCastleView read GetCurrentTop; deprecated 'use Container.FrontView'; |
|
class property StateStack [const Index: Integer]: TCastleView read GetStateStack; deprecated 'use Container.ViewStack'; |
|
property FullSize default true; |
Description
Fields
class var Log: boolean; |
|
When |
Methods
function ContainerWidth: Cardinal; override; |
|
The container size is always known: we assume that view will be part of PredictedContainer, if the view not yet started. So the view knows container size, regardless if we are between Start / Stop, regardless if the TCastleView is already added to some TCastleContainer.Children. This makes all other routines, like ParentRect, EffectiveRect, EffectiveWidth, EffectiveHeight also work. |
function ContainerHeight: Cardinal; override; |
|
This item has no description. |
function ContainerRect: TRectangle; override; |
|
This item has no description. |
function ContainerSizeKnown: boolean; override; |
|
This item has no description. |
function StateContainer: TCastleContainer; deprecated 'use Container to get the container in which we are already started, use PredictedContainer if the state is not yet started'; |
|
Warning: this symbol is deprecated: use Container to get the container in which we are already started, use PredictedContainer if the state is not yet started This item has no description. |
function Container: TCastleContainer; |
|
The container in which the view works. This is just like Container property (from ancestor, see TCastleUserInterface.Container) but it is already assigned even during Start and Stop. This method deliberately hides the ancestor TCastleUserInterface.Container method. This way it will work always, in particular also during Start method. This allows you to do code like this in overridden Start method: Container.OverrideCursor := mcNone; |
function FreeAtStop: TComponent; |
|
Assign this component as owner for your controls, to make them freed right after nearest Stop. This component is created on-demand (whenever you access it) and always destroyed right after running view Stop method. The idea is that you can assign it as owner (1st parameter to the constructor of MyInstance := TSomeComponent.Create(FreeAtStop);
And in effect, you know that |
constructor Create(AOwner: TComponent); override; |
|
Create an instance of the view. You willl typically create one instance of each view class (like TViewMain, TViewPlay) at the application initialization (e.g. in Application.OnInitialize callback), like ViewMainMenu := TViewMainMenu.Create(Application); ViewPlay := TViewPlay.Create(Application);
Later you switch between views using TCastleContainer.View or TCastleContainer.PushView or TCastleContainer.PopView, like this: Container.View := ViewMain;
See https://castle-engine.io/views and numerous engine examples. |
destructor Destroy; override; |
|
This item has no description. |
constructor CreateUntilStopped; |
|
Create the instance TCastleView that will be automatically freed when the view is stopped. This allows alternative usage of views (as opposed to the ones described in Create docs), where you create short-lived instances of view classes. Use it like this: Container.View := TViewMain.CreateUntilStopped;
The advantages:
The disadvantage is that you cannot store in view fields anything that should "survive" the view Stop. You can instead use "class variables" in view class, or any global variable. |
procedure Start; virtual; |
|
Executed when view becomes active, it's now part of the view stack. Started view is part of the ViewStack, and will soon become running (top-most on the stack). When the view is set to be current, by
|
procedure Stop; virtual; |
|
Executed when view is no longer active, no longer part of view stack. When the view stops becoming active, this happens:
This is always called to finalize the started view. When the view 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; |
|
Executed when view is now the top-most view. See Start and Stop docs about view lifecycle methods. This is called after Start, it is also called when you pop another view, making this view the top-most. |
procedure Pause; virtual; |
|
Executed when view is no longer the top-most view. See Start and Stop docs about view lifecycle methods. This is called before Stop, it is also called when another view is pushed over this view, so this stops being the the top-most view. |
procedure Finish; virtual; deprecated 'use Stop'; |
|
Warning: this symbol is deprecated: use Stop This item has no description. |
function Active: boolean; |
|
View is right now part of the view stack, which means it's between Start and Stop calls. The view 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; |
|
This item has no description. Showing description inherited from TCastleUserInterface.Press.
Override this method to react to user pressing a key, mouse button or mouse wheel. Return When implementing in descendants it is best to override it like this: function TMyControl.Press(const Event: TInputPressRelease): boolean; begin Result := inherited; if Result then Exit; // exit if ancestor already handled this event if Event.IsKey(keyEnter) then begin // do something in reaction to Enter key ... // let engine know that this input event was handled Exit(true); end; if Event.IsMouseButton(buttonLeft) then begin // do something in reaction to left mouse button press ... // let engine know that this input event was handled Exit(true); end; end;
These events are generated for all UI controls, whether they are considered "interactive" or not. These events are generated for non-interactive controls like TCastleRectangleControl or TCastleLabel as well. For example, these events ignore the TCastleButton.Enabled state, they are generated always (see https://github.com/castle-engine/castle-engine/issues/413 ). Use instead TCastleButton.OnClick to detect clicks on a button in a way that honors the TCastleButton.Enabled state. When a control returns The events Press and Release are passed to the parent only after the children had a chance to process this event. Overriding them makes sense if you draw something that "looks clickable" in TCastleUserInterface.Render, which is the standard place you should draw stuff. For example our TCastleButton draws there. In contrast, the events PreviewPress and PreviewRelease are passed first to the parent control, before children have a chance to process this event. In partcular, overriding them makes sense if you draw something that "looks clickable" in TCastleUserInterface.RenderOverChildren. |
function Release(const Event: TInputPressRelease): boolean; override; |
|
This item has no description. Showing description inherited from TCastleUserInterface.Release.
Override this method to react to user releasing a key, mouse button. Return This is counterpart to Press method. See Press for more details. Note: We'd like this method to also be called when user releases a mouse wheel. But currently releasing of the mouse wheel is not reported now by any backend. Only releasing of keys and mouse buttons is reported. |
function Motion(const Event: TInputMotion): boolean; override; |
|
This item has no description. Showing description inherited from TCastleUserInterface.Motion. Motion of mouse or touch. |
procedure Update(const SecondsPassed: Single; var HandleInput: boolean); override; |
|
This item has no description. Showing description inherited from TCastleUserInterface.Update. Control may do here anything that must be continuously repeated. E.g. camera handles here falling down due to gravity, rotating model in Examine mode, and many more.
This method may be used, among many other things, to continuously react to the fact that user pressed some key (or mouse button). For example, if holding some key should move some 3D object, you should do something like: if HandleInput then begin if Container.Pressed[keyArrowRight] then begin Transform.Position := Transform.Position + Vector3(SecondsPassed * 10, 0, 0); HandleInput := false; end; end;
Instead of directly using a key code, consider also using TInputShortcut that makes the input key nicely configurable. See engine tutorial about handling inputs. Multiplying movement by SecondsPassed makes your operation frame-rate independent. Object will move by 10 units in a second, regardless of how many FPS your game has. The code related to HandleInput is important if you write a generally-useful control that should nicely cooperate with all other controls, even when placed on top of them or under them. The correct approach is to only look at pressed keys/mouse buttons if HandleInput is Note that to handle a single press / release (like "switch light on when pressing a key") you should rather use Press and Release methods. Use this method only for continuous handling (like "holding this key makes the light brighter and brighter"). To understand why such HandleInput approach is needed, realize that the "Update" events are called differently than simple mouse and key events like "Press" and "Release". "Press" and "Release" events return whether the event was somehow "handled", and the container passes them only to the controls under the mouse (decided by TCastleUserInterface.CapturesEventsAtPosition). And as soon as some control says it "handled" the event, other controls (even if under the mouse) will not receive the event. This approach is not suitable for Update events. Some controls need to do the Update job all the time, regardless of whether the control is under the mouse and regardless of what other controls already did. So all controls (well, all controls that exist, in case of TCastleUserInterface, see TCastleUserInterface.Exists) receive Update calls. So the "handled" status is passed through HandleInput. If a control is not under the mouse, it will receive HandleInput = |
procedure Render; override; |
|
This item has no description. Showing description inherited from TCastleUserInterface.Render. Render a control. Called only when Exists and render context is initialized. Do not call this method. It will be automatically called by the engine when needed. It will be called when UI is part of TCastleContainer.Controls list or rendered (e.g. for off-screen rendering) by TCastleContainer.RenderControl. You should only override this method. See https://castle-engine.io/manual_2d_ui_custom_drawn.php for examples what you can put here. You can depend on some OpenGL state being set before calling this method. You can depend on it being set, and you can carelessly change it. This state we set:
Beware that GLSL RenderContext.CurrentProgram has undefined value when this is called. You should always set it, before making direct OpenGL drawing calls (all the engine drawing routines do it already, this is only a concern if you make direct OpenGL / OpenGLES calls). |
function UIScale: Single; override; |
|
This item has no description. Showing description inherited from TCastleUserInterface.UIScale. UI scale of this control, derived from container (see TCastleContainer.UIScaling and EnableUIScaling). |
procedure InsertUserInterface(const ADesignUrl: String; const FinalOwner: TComponent; out Ui: TCastleUserInterface; out UiOwner: TComponent); overload; deprecated 'instead of this, set DesignUrl in constructor'; |
|
Warning: this symbol is deprecated: instead of this, set DesignUrl in constructor 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 TCastleView. 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 view 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 view is stopped. |
procedure WaitForRenderAndCall(const Event: TNotifyEvent); |
|
Wait until the render event happens (to redraw current view), and then call Event. The scheduled Event will be called at the Update time. If the view stopped before the scheduled events fired, then the remaining events are ignored. That is, the scheduled events are cleared every time you start the view. One use-case of this is to show a loading view, 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 |
function DesignedComponent(const ComponentName: String): TComponent; |
|
When the DesignUrl is set, and the view is started, you can use this method to find loaded components. Like this: MyButton := DesignedComponent('MyButton') as TCastleButton;
This method is seldom useful now. The published fields of the view are automatically initialized when loading / unloading design using DesignUrl. There's no need to use See also
|
class procedure Push(const NewState: TCastleView); deprecated 'use Container.PushView'; |
|
Warning: this symbol is deprecated: use Container.PushView This item has no description. |
class procedure Pop; overload; deprecated 'use Container.PopView'; |
|
Warning: this symbol is deprecated: use Container.PopView This item has no description. |
class procedure Pop(const CurrentTopMostState: TCastleView); overload; deprecated 'use Container.PopView'; |
|
Warning: this symbol is deprecated: use Container.PopView This item has no description. |
class function StateStackCount: Integer; deprecated 'use Container.ViewStackCount'; |
|
Warning: this symbol is deprecated: use Container.ViewStackCount This item has no description. |
Properties
property InterceptInput: boolean read FInterceptInput write FInterceptInput
default false; |
|
Prevents passing mouse/keyboard events to the UI views underneath. More precisely, when this property is Note that setting this to function TMyView.Press(const Event: TInputPressRelease): Boolean; begin Result := inherited; // ignore the ancestor result, as we use InterceptInput, so ancestor always returns true // if Result the Exit; if Event.IsMouseButton(buttonLeft) then begin ... Exit(true); end; end; |
property DesignUrl: String read FDesignUrl write SetDesignUrl; |
|
Load a designed user interface (from .castle-user-interface file) when this view is started. You typically set this property in overridden constructor, and in effect the given design file will be loaded right before Start and it will be freed right after Stop. Typical use-case looks like this: constructor TViewPlay.Create(AOwner: TComponent); begin inherited; DesignUrl := 'castle-data:/gameviewplay.castle-user-interface'; // DesignPreload := true; // to make future "Container.View := ViewPlay" faster end;
The published fields of this class, if they have equal name to any component in the design, are automatically initialized to the instance of this component. (And they will be set to You can also modify this property when the view has already started (after Start and before Stop) in which case the previous design will be freed and new one will be loaded immediately. Set this to empty string (default) to mean "no design should be loaded". Note that this is not the only way to load a .castle-user-interface file. A more general approach is to use UserInterfaceLoad, and call InsertFront to add it to the view UI. Using this property just adds some comfortable automatic behavior (design is freed at stop, published fields of view are set, you can use comfortable DesignPreload). See also
|
property DesignPreload: Boolean read FDesignPreload write SetDesignPreload default false; |
|
Preload the design file (specified in DesignUrl) as soon as possible, making starting the view much faster. Using this property means that we "preload" the design file, to cache the referenced images / TCastleScene instances etc. as soon as possible, to make the future loading of this design (when view starts) very quick. Typically you set this property in overridden TCastleView constructor, right after (or before, it doesn't matter) setting DesignUrl. It will mean that constructor takes a longer time (which typically means that Application.OnInitialize takes a longer time) but in exchange future starting of the view (when you do e.g. No functional difference should be visible, regardless of the DesignPreload value. Internally the designed component is added/removed from view at the same time. So think of this property as pure optimization – you decide whether to slow down the view constructor, or view start. See also
|
class property Current: TCastleView read GetCurrent write SetCurrent; deprecated 'use Container.View'; |
|
Warning: this symbol is deprecated: use Container.View generic function DesignedComponent<T: TComponent>(const ComponentName: String): T; overload; |
class property CurrentTop: TCastleView read GetCurrentTop; deprecated 'use Container.FrontView'; |
|
Warning: this symbol is deprecated: use Container.FrontView This item has no description. |
class property StateStack [const Index: Integer]: TCastleView read GetStateStack; deprecated 'use Container.ViewStack'; |
|
Warning: this symbol is deprecated: use Container.ViewStack This item has no description. |
property FullSize default true; |
|
TCastleView 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.16.0-snapshot.