Castle Game EngineIntroduction Units Class Hierarchy Classes, Interfaces, Objects and Records Types Variables Constants Functions and Procedures Identifiers
|
Class TUIControl
Unit
CastleUIControls
Declaration
type TUIControl = class abstract(TInputListener)
Description
Basic 2D control class. All controls derive from this class, overriding chosen methods to react to some events. Various user interface containers (things that directly receive messages from something outside, like operating system, windowing library etc.) implement support for such controls.
Control has children controls, see Controls and ControlsCount. Parent control is recorded inside Parent. A control may only be a child of one other control — that is, you cannot insert to the 2D hierarchy the same control multiple times (in TCastleTransform hierarchy, such trick is allowed).
Control may handle mouse/keyboard input, see Press and Release methods.
Various methods return boolean saying if input event is handled. The idea is that not handled events are passed to the next control suitable. Handled events are generally not processed more — otherwise the same event could be handled by more than one listener, which is bad. Generally, return ExclusiveEvents if anything (possibly) was done (you changed any field value etc.) as a result of this, and only return False when you're absolutely sure that nothing was done by this control.
Every control also has a position and takes some rectangular space on the container.
The position is controlled using the Left, Bottom fields. The rectangle where the control is visible can be queried using the Rect or ScreenRect methods.
Note that each descendant has it's own definition of the size of the control. E.g. some descendants may automatically calculate the size (based on text or images or such placed within the control). Some descendants may allow to control the size explicitly using fields like Width, Height, FullSize. Some descendants may allow both approaches, switchable by property like TCastleButton.AutoSize or TCastleImageControl.Stretch. The base TUIControl.Rect returns always an empty rectangle, most descendants will want to override it (you can also ignore the issue in your own TUIControl descendants, if the given control size will never be used for anything).
All screen (mouse etc.) coordinates passed here should be in the usual window system coordinates, that is (0, 0) is left-top window corner. (Note that this is contrary to the usual OpenGL 2D system, where (0, 0) is left-bottom window corner.)
Hierarchy
Overview
Methods
Properties
Description
Methods
 |
procedure DefineProperties(Filer: TFiler); override; |
|
 |
procedure SetContainer(const Value: TUIContainer); override; |
|
 |
function LeftBottomScaled: TVector2Integer; |
The left-bottom corner scaled by UIScale, useful for implementing overridden Rect methods.
|
 |
procedure UIScaleChanged; virtual; |
|
 |
constructor Create(AOwner: TComponent); override; |
procedure DoCursorChange; override;
|
 |
destructor Destroy; override; |
|
 |
function ControlsCount: Integer; |
|
 |
procedure InsertFront(const NewItem: TUIControl); overload; |
Add child control, at the front of other children.
|
 |
procedure InsertFrontIfNotExists(const NewItem: TUIControl); |
|
 |
procedure InsertBack(const NewItem: TUIControl); overload; |
Add child control, at the back of other children.
|
 |
procedure InsertBackIfNotExists(const NewItem: TUIControl); |
|
 |
function GetExists: boolean; virtual; |
Return whether item really exists, see Exists. Non-existing item does not receive any of the render or input or update calls. They only receive GLContextOpen, GLContextClose, Resize calls.
It TUIControl class, this returns the value of Exists property. May be overridden in descendants, to return something more complicated, but it should always be a logical "and" with the inherited GetExists implementation (so setting the Exists := false will always work), like
Result := (inherited GetExists) and MyComplicatedConditionForExists;
|
 |
function CapturesEventsAtPosition(const Position: TVector2): boolean; virtual; |
Does this control capture events under this screen position. The default implementation simply checks whether Position is inside ScreenRect now. It also checks whether CapturesEvents is True .
Always treated like False when GetExists returns False , so the implementation of this method only needs to make checks assuming that GetExists = True .
|
 |
procedure Render; virtual; |
Render a control. Called only when GetExists and GLInitialized, you can depend on it in the implementation of this method.
Do not explicitly call this method. Instead, render controls by adding them to the TUIContainer.Controls list, or render them explicitly (for off-screen rendering) by TGLContainer.RenderControl. This is method should only be overridden in your own code.
Before calling this method we always set some OpenGL state, and you can depend on it (and you can carelessly change it, as it will be reset again before rendering other control).
OpenGL state always set:
glViewport is set to include whole container.
Depth test is off.
(For fixed-function pipeline:) The 2D orthographic projection is always set at the beginning. Useful for 2D controls, 3D controls can just override projection matrix, e.g. use CastleGLUtils.PerspectiveProjection.
(For fixed-function pipeline:) The modelview matrix is set to identity. The matrix mode is always modelview.
(For fixed-function pipeline:) The raster position is set to (0,0). The (deprecated) WindowPos is also set to (0,0).
(For fixed-function pipeline:) Texturing, lighting, fog is off.
Beware that GLSL TGLSLProgram.Current has undefined value when this is called. You should always set it, before making direct OpenGL drawing calls (all the engine drawing routines of course do it already, this is only a concern if you make direct OpenGL / OpenGLES calls).
|
 |
procedure RenderOverChildren; virtual; |
Render a control contents over the children controls. This is analogous to Render, but it executes after children are drawn. You should usually prefer to override Render instead of this method, as the convention is that the parent is underneath children.
|
 |
function TooltipStyle: TRenderStyle; virtual; deprecated 'do not use this to control front-back UI controls order, better to use controls order and TUIControl.KeepInFront'; |
Warning: this symbol is deprecated: do not use this to control front-back UI controls order, better to use controls order and TUIControl.KeepInFront
Render a tooltip of this control. If you want to have tooltip for this control detected, you have to override TooltipExists. Then the TCastleWindowCustom.TooltipVisible will be detected, and your TooltipRender will be called.
The values of rs2D and rs3D are interpreted in the same way as RenderStyle. And TooltipRender is called in the same way as Render, so e.g. you can safely assume that modelview matrix is identity and (for 2D) WindowPos is zero. TooltipRender is always called as a last (front-most) 2D or 3D control.
|
 |
function TooltipExists: boolean; virtual; |
|
 |
procedure TooltipRender; virtual; |
|
 |
procedure GLContextOpen; virtual; |
Initialize your OpenGL resources.
This is called when OpenGL context of the container is created, or when the control is added to the already existing context. In other words, this is the moment when you can initialize OpenGL resources, like display lists, VBOs, OpenGL texture names, etc.
As an exception, this is called regardless of the GetExists value. This way a control can prepare it's resources, regardless if it exists now.
|
 |
procedure GLContextClose; virtual; |
Destroy your OpenGL resources.
Called when OpenGL context of the container is destroyed. Also called when controls is removed from the container Controls list. Also called from the destructor.
You should release here any resources that are tied to the OpenGL context. In particular, the ones created in GLContextOpen.
As an exception, this is called regardless of the GetExists value. This way a control can release it's resources, regardless if it exists now.
|
 |
procedure SetFocused(const Value: boolean); virtual; |
Called when this control becomes or stops being focused, that is: under the mouse cursor and will receive events. In this class, they simply update Focused property. You can override this to react to mouse enter / mouse exit events.
|
 |
function Rect: TRectangle; virtual; |
Position and size of this control, assuming it exists, in local coordinates (relative to parent 2D control).
This must ignore the current value of the GetExists method and Exists property, that is: the result of this function assumes that control does exist.
This must ignore the anchors. Their effect is applied outside of this method.
This must take into account UI scaling. This method must calculate a result already multiplied by UIScale. In simple cases, this can be done easily, like this:
function TMyControl.Rect: TRectangle;
begin
Result := Rectangle(Left, Bottom, Width, Height).ScaleAround0(UIScale);
end;
In fact, TUIControlSizeable already provides such implementation for you.
In this class, returns empty rectangle (zero width and height) with Left and Bottom correctly set (scaled by UIScale).
See also
- CalculatedRect
- Final position and size of this control, assuming it exists, in local coordinates (relative to parent 2D control), without UI scaling.
|
 |
function CalculatedRect: TRectangle; |
Final position and size of this control, assuming it exists, in local coordinates (relative to parent 2D control), without UI scaling. Useful if you want to base other controls size/position on this control calculated size/position.
This is similar to Rect, but:
If you implement descendants of this class: Note that you cannot override this method. It is implemented by simply taking RectWithAnchors result (which in turn is derived from Rect result) and dividing it by UIScale. This should always be correct.
Maybe in the future overriding this can be possible, but only for the sake of more optimal implementation.
If you implement descendants, you should rather think about overriding the Rect method, if your control has special sizing mechanism. The reason why we prefer overriding Rect (and CalculatedRect is just derived from it), not the other way around: it is because font measurements are already done in scaled coordinates (because UI scaling changes font size for TUIControlFont). So things like TCastleLabel have to calculate size in scaled coordinates anyway, and the unscaled size can only be derived from it by division.
See also
- Rect
- Position and size of this control, assuming it exists, in local coordinates (relative to parent 2D control).
|
 |
function CalculatedWidth: Cardinal; |
Calculated width of the control, without UI scaling. Useful if you want to base other controls size/position on this control calculated size.
Unlike various other width properties of descendants (like TUIControlSizeable.Width or TCastleImageControl.Width), this is the calculated size, not the desired size. So this is already processed by any auto-sizing mechanism (e.g. TCastleImageControl may adjust it's own size to the underlying image, depending on settings).
Unlike Rect.Width , this does not have UI scaling applied.
It is always equal to just CalculatedRect.Width .
See also
- CalculatedRect
- Final position and size of this control, assuming it exists, in local coordinates (relative to parent 2D control), without UI scaling.
|
 |
function CalculatedHeight: Cardinal; |
Calculated height of the control, without UI scaling. Useful if you want to base other controls size/position on this control calculated size.
Unlike various other height properties of descendants (like TUIControlSizeable.Height or TCastleImageControl.Height), this is the calculated size, not the desired size. So this is already processed by any auto-sizing mechanism (e.g. TCastleImageControl may adjust it's own size to the underlying image, depending on settings).
Unlike Rect.Height , this does not have UI scaling applied.
It is always equal to just CalculatedRect.Height .
See also
- CalculatedRect
- Final position and size of this control, assuming it exists, in local coordinates (relative to parent 2D control), without UI scaling.
|
 |
function ScreenRect: TRectangle; |
Position and size of this control, assuming it exists, in screen (container) coordinates.
|
 |
function LocalToScreenTranslation: TVector2Integer; |
How to translate local coords to screen. If you use UI scaling, this works in final coordinates (after scaling, real pixels on screen).
|
 |
function ParentRect: TRectangle; |
Rectangle filling the parent control (or coordinates), in local coordinates. Since this is in local coordinates, the returned rectangle Left and Bottom are always zero. This is already scaled by UI scaling, since it's derived from Rect size that should also be already scaled.
|
 |
procedure Align( const ControlPosition: THorizontalPosition; const ContainerPosition: THorizontalPosition; const X: Integer = 0); overload; |
Immediately position the control with respect to the parent by adjusting Left.
Note that using Anchor is often more comfortable than this method, since you only need to set anchor once (for example, right after creating the control). In contract, adjusting position using this method will typically need to be repeated at each window on resize, like in TCastleWindowCustom.OnResize.
|
 |
procedure Align( const ControlPosition: TVerticalPosition; const ContainerPosition: TVerticalPosition; const Y: Integer = 0); overload; |
Immediately position the control with respect to the parent by adjusting Bottom.
Note that using Anchor is often more comfortable than this method, since you only need to set anchor once (for example, right after creating the control). In contract, adjusting position using this method will typically need to be repeated at each window on resize, like in TCastleWindowCustom.OnResize.
|
 |
procedure Center; |
Immediately center the control within the parent, both horizontally and vertically.
Note that using Anchor is often more comfortable than this method, since you only need to set anchor once. For example, right after creating the control call Anchor(hpMiddle); Anchor(vpMiddle); . In contrast, adjusting position using this method will typically need to be repeated at each window on resize, like in TCastleWindowCustom.OnResize.
|
 |
function UIScale: Single; |
UI scale of this control, derived from container (see TUIContainer.UIScaling.
All the drawing and measuring inside your control must take this into account. The final Rect result must already take this scaling into account, so that parent controls may depend on it. All descendants, like TUIControlSizeable, provide a Rect implementation that does what is necessary.
|
Properties
 |
property Controls [Index:Integer]: TUIControl read GetControls write SetControls; |
|
 |
property RenderStyle: TRenderStyle read FRenderStyle write FRenderStyle default rs2D; deprecated 'do not use this to control front-back UI controls order, better to use controls order and TUIControl.KeepInFront'; |
Warning: this symbol is deprecated: do not use this to control front-back UI controls order, better to use controls order and TUIControl.KeepInFront
Determines the rendering order. All controls with RenderStyle = rs3D are drawn first. Then all the controls with RenderStyle = rs2D are drawn. Among the controls with equal RenderStyle , their order on TUIContainer.Controls list determines the rendering order.
|
 |
property GLInitialized: boolean read FGLInitialized default false; |
|
 |
property DisableContextOpenClose: Cardinal
read FDisableContextOpenClose write FDisableContextOpenClose; |
When non-zero, control will not receive GLContextOpen and GLContextClose events when it is added/removed from the TUIContainer.Controls list.
This can be useful as an optimization, to keep the OpenGL resources created even for controls that are not present on the TUIContainer.Controls list. This must used very, very carefully, as bad things will happen if the actual OpenGL context will be destroyed while the control keeps the OpenGL resources (because it had DisableContextOpenClose > 0). The control will then remain having incorrect OpenGL resource handles, and will try to use them, causing OpenGL errors or at least weird display artifacts.
Most of the time, when you think of using this, you should instead use the TUIControl.Exists property. This allows you to keep the control of the TUIContainer.Controls list, and it will be receive GLContextOpen and GLContextClose events as usual, but will not exist for all other purposes.
Using this mechanism is only sensible if you want to reliably hide a control, but also allow readding it to the TUIContainer.Controls list, and then you want to show it again. This is useful for CastleWindowModes, that must push (and then pop) the controls, but then allows the caller to modify the controls list. And some games, e.g. castle1, add back some (but not all) of the just-hidden controls. For example the TCastleNotifications instance is added back, to be visible even in the menu mode. This means that CastleWindowModes cannot just modify the TUIContainer.Exists value, leaving the control on the TUIContainer.Controls list: it would leave the TUIControl existing many times on the TUIContainer.Controls list, with the undefined TUIContainer.Exists value.
|
 |
property Focused: boolean read FFocused write SetFocused; |
|
 |
property Exists: boolean read FExists write SetExists default true; |
Not existing control is not visible, it doesn't receive input and generally doesn't exist from the point of view of user. You can also remove this from controls list (like TCastleWindowCustom.Controls), but often it's more comfortable to set this property to false.
|
 |
property Left: Integer read FLeft write SetLeft stored false default 0; |
|
 |
property Bottom: Integer read FBottom write SetBottom default 0; |
|
 |
property HasHorizontalAnchor: boolean
read FHasHorizontalAnchor write SetHasHorizontalAnchor default false; |
Automatically adjust horizontal position to align us to the parent horizontally. Note that the value of Left remains unchanged (it is just ignored), using the anchors only modifies the output of the ScreenRect value that should be used for rendering/physics.
Anchor distance is automatically affected by TUIContainer.UIScaling.
|
 |
property HorizontalAnchorDelta: Integer
read FHorizontalAnchorDelta write SetHorizontalAnchorDelta default 0; |
Delta between our border and parent, only used if HasHorizontalAnchor.
|
 |
property HasVerticalAnchor: boolean
read FHasVerticalAnchor write SetHasVerticalAnchor default false; |
Automatically adjust vertical position to align us to the parent vertically. Note that the value of Bottom remains unchanged (it is tjust ignored), using the anchors only modifies the output of the ScreenRect value that should be used for rendering/physics.
Anchor distance is automatically affected by TUIContainer.UIScaling.
|
 |
property VerticalAnchorDelta: Integer
read FVerticalAnchorDelta write SetVerticalAnchorDelta default 0; |
Delta between our border and parent, only used if HasVerticalAnchor.
|
 |
property EnableUIScaling: boolean
read FEnableUIScaling write SetEnableUIScaling default true; |
Enable or disable UI scaling for this particular control. See more about UI scaling on TUIContainer.UIScaling and TUIControl.UIScale. Setting this to False forces TUIControl.UIScale to always return 1.0.
Note that this does not work recursively, i.e. it does not affect the children of this control. Setting this to False does not prevent UI scaling on children (you have to turn it off explicitly for children too, if you need to disable UI scaling recursively).
|
 |
property KeepInFront: boolean read FKeepInFront write FKeepInFront
default false; |
Keep the control in front of other controls (with KeepInFront =False ) when inserting.
TODO: Do not change this propertyu while the control is already a children of something.
|
 |
property CapturesEvents: boolean read FCapturesEvents write FCapturesEvents
default true; |
|
Generated by PasDoc 0.15.0.
|