Class TUIControl

Unit

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 T3D 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

Protected procedure DefineProperties(Filer: TFiler); override;
Protected procedure SetContainer(const Value: TUIContainer); override;
Protected function LeftBottomScaled: TVector2Integer;
Protected procedure UIScaleChanged; virtual;
Public constructor Create(AOwner: TComponent); override;
Public destructor Destroy; override;
Public function ControlsCount: Integer;
Public procedure InsertFront(const NewItem: TUIControl);
Public procedure InsertFrontIfNotExists(const NewItem: TUIControl);
Public procedure InsertFront(const NewItems: TUIControlList);
Public procedure InsertBack(const NewItem: TUIControl);
Public procedure InsertBackIfNotExists(const NewItem: TUIControl);
Public procedure InsertBack(const NewItems: TUIControlList);
Public procedure RemoveControl(Item: TUIControl);
Public procedure ClearControls;
Public function GetExists: boolean; virtual;
Public function CapturesEventsAtPosition(const Position: TVector2Single): boolean; virtual;
Public procedure BeforeRender; virtual;
Public procedure Render; virtual;
Public procedure RenderOverChildren; virtual;
Public function TooltipStyle: TRenderStyle; virtual; deprecated 'do not use this to control front-back UI controls order, better to use controls order and TUIControl.KeepInFront';
Public function TooltipExists: boolean; virtual;
Public procedure TooltipRender; virtual;
Public procedure GLContextOpen; virtual;
Public procedure GLContextClose; virtual;
Public procedure SetFocused(const Value: boolean); virtual;
Public function Rect: TRectangle; virtual;
Public function CalculatedRect: TRectangle;
Public function CalculatedWidth: Cardinal;
Public function CalculatedHeight: Cardinal;
Public function ScreenRect: TRectangle;
Public function LocalToScreenTranslation: TVector2Integer;
Public function ParentRect: TRectangle;
Public procedure Anchor(const AHorizontalAnchor: THorizontalPosition; const AHorizontalAnchorDelta: Integer = 0);
Public procedure Anchor( const AHorizontalAnchorSelf, AHorizontalAnchorParent: THorizontalPosition; const AHorizontalAnchorDelta: Integer = 0);
Public procedure Anchor(const AVerticalAnchor: TVerticalPosition; const AVerticalAnchorDelta: Integer = 0);
Public procedure Anchor( const AVerticalAnchorSelf, AVerticalAnchorParent: TVerticalPosition; const AVerticalAnchorDelta: Integer = 0);
Public procedure AlignHorizontal( const ControlPosition: TPositionRelative = prMiddle; const ContainerPosition: TPositionRelative = prMiddle; const X: Integer = 0); deprecated 'use Align or Anchor';
Public procedure Align( const ControlPosition: THorizontalPosition; const ContainerPosition: THorizontalPosition; const X: Integer = 0);
Public procedure AlignVertical( const ControlPosition: TPositionRelative = prMiddle; const ContainerPosition: TPositionRelative = prMiddle; const Y: Integer = 0); deprecated 'use Align or Anchor';
Public procedure Align( const ControlPosition: TVerticalPosition; const ContainerPosition: TVerticalPosition; const Y: Integer = 0);
Public procedure Center;
Public function UIScale: Single;

Properties

Public property Controls [Index:Integer]: TUIControl read GetControls write SetControls;
Public 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';
Public property GLInitialized: boolean read FGLInitialized default false;
Public property DisableContextOpenClose: Cardinal read FDisableContextOpenClose write FDisableContextOpenClose;
Public property Focused: boolean read FFocused write SetFocused;
Public property Parent: TUIControl read FParent;
Published property Exists: boolean read FExists write SetExists default true;
Published property Left: Integer read FLeft write SetLeft stored false default 0;
Published property Bottom: Integer read FBottom write SetBottom default 0;
Published property HasHorizontalAnchor: boolean read FHasHorizontalAnchor write SetHasHorizontalAnchor default false;
Published property HorizontalAnchorSelf: THorizontalPosition read FHorizontalAnchorSelf write SetHorizontalAnchorSelf default hpLeft;
Published property HorizontalAnchorParent: THorizontalPosition read FHorizontalAnchorParent write SetHorizontalAnchorParent default hpLeft;
Published property HorizontalAnchorDelta: Integer read FHorizontalAnchorDelta write SetHorizontalAnchorDelta default 0;
Published property HasVerticalAnchor: boolean read FHasVerticalAnchor write SetHasVerticalAnchor default false;
Published property VerticalAnchorSelf: TVerticalPosition read FVerticalAnchorSelf write SetVerticalAnchorSelf default vpBottom;
Published property VerticalAnchorParent: TVerticalPosition read FVerticalAnchorParent write SetVerticalAnchorParent default vpBottom;
Published property VerticalAnchorDelta: Integer read FVerticalAnchorDelta write SetVerticalAnchorDelta default 0;
Published property EnableUIScaling: boolean read FEnableUIScaling write SetEnableUIScaling default true;
Published property KeepInFront: boolean read FKeepInFront write FKeepInFront default false;

Description

Methods

Protected procedure DefineProperties(Filer: TFiler); override;
 
Protected procedure SetContainer(const Value: TUIContainer); override;
 
Protected function LeftBottomScaled: TVector2Integer;

The left-bottom corner scaled by UIScale, useful for implementing overridden Rect methods.

Protected procedure UIScaleChanged; virtual;
 
Public constructor Create(AOwner: TComponent); override;

procedure DoCursorChange; override;

Public destructor Destroy; override;
 
Public function ControlsCount: Integer;
 
Public procedure InsertFront(const NewItem: TUIControl);

Add child control, at the front of other children.

Public procedure InsertFrontIfNotExists(const NewItem: TUIControl);
 
Public procedure InsertFront(const NewItems: TUIControlList);
 
Public procedure InsertBack(const NewItem: TUIControl);

Add child control, at the back of other children.

Public procedure InsertBackIfNotExists(const NewItem: TUIControl);
 
Public procedure InsertBack(const NewItems: TUIControlList);
 
Public procedure RemoveControl(Item: TUIControl);

Remove control added by InsertFront or InsertBack.

Public procedure ClearControls;

Remove all child controls added by InsertFront or InsertBack.

Public 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;

Public function CapturesEventsAtPosition(const Position: TVector2Single): boolean; virtual;

Does this control capture events under this screen position. The default implementation simply checks whether Position is inside ScreenRect now.

Always treated like False when GetExists returns False, so the implementation of this method only needs to make checks assuming that GetExists = True.

Public procedure BeforeRender; virtual;

Prepare your resources, right before drawing. Called only when GetExists and GLInitialized.

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.

Public 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.

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). (In Castle Game Engine < 5.1.0, the rules were more complicated and depending on RenderStyle. This is no longer the case, RenderStyle now determines only the render order, allowing TCastleSceneManager to be used in the middle of 2D controls.)

OpenGL state always set:

  • (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.

  • glViewport is set to include whole container.

  • (For fixed-function pipeline.) The modelview matrix is set to identity. The matrix mode is always modelview.

  • The raster position (for fixed-function pipeline) is set to (0,0). The (deprecated) WindowPos is also set to (0,0).

  • Depth test is off.

  • (For fixed-function pipeline.) Texturing, lighting, fog is off.

Beware that GLSL CurrentProgram 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).

Public procedure RenderOverChildren; virtual;
 
Public 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.

Public function TooltipExists: boolean; virtual;
 
Public procedure TooltipRender; virtual;
 
Public 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.

Public 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.

Public 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.

Public 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.
Public 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:

  • This takes into account the anchors.

  • This ignores the UI scaling.

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).
Public 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.
Public 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.
Public function ScreenRect: TRectangle;

Position and size of this control, assuming it exists, in screen (container) coordinates.

Public function LocalToScreenTranslation: TVector2Integer;

How to translate local coords to screen.

Public 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.

Public procedure Anchor(const AHorizontalAnchor: THorizontalPosition; const AHorizontalAnchorDelta: Integer = 0);

Quick way to enable horizontal anchor, to automatically keep this control aligned to parent. Sets HasHorizontalAnchor, HorizontalAnchorSelf, HorizontalAnchorParent, HorizontalAnchorDelta.

Public procedure Anchor( const AHorizontalAnchorSelf, AHorizontalAnchorParent: THorizontalPosition; const AHorizontalAnchorDelta: Integer = 0);

Quick way to enable horizontal anchor, to automatically keep this control aligned to parent. Sets HasHorizontalAnchor, HorizontalAnchorSelf, HorizontalAnchorParent, HorizontalAnchorDelta.

Public procedure Anchor(const AVerticalAnchor: TVerticalPosition; const AVerticalAnchorDelta: Integer = 0);

Quick way to enable vertical anchor, to automatically keep this control aligned to parent. Sets HasVerticalAnchor, VerticalAnchorSelf, VerticalAnchorParent, VerticalAnchorDelta.

Public procedure Anchor( const AVerticalAnchorSelf, AVerticalAnchorParent: TVerticalPosition; const AVerticalAnchorDelta: Integer = 0);

Quick way to enable vertical anchor, to automatically keep this control aligned to parent. Sets HasVerticalAnchor, VerticalAnchorSelf, VerticalAnchorParent, VerticalAnchorDelta.

Public procedure AlignHorizontal( const ControlPosition: TPositionRelative = prMiddle; const ContainerPosition: TPositionRelative = prMiddle; const X: Integer = 0); deprecated 'use Align or Anchor';

Warning: this symbol is deprecated: use Align or Anchor

Immediately position the control with respect to the parent by adjusting Left. Deprecated, use Align with THorizontalPosition.

Public procedure Align( const ControlPosition: THorizontalPosition; const ContainerPosition: THorizontalPosition; const X: Integer = 0);

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.

Public procedure AlignVertical( const ControlPosition: TPositionRelative = prMiddle; const ContainerPosition: TPositionRelative = prMiddle; const Y: Integer = 0); deprecated 'use Align or Anchor';

Warning: this symbol is deprecated: use Align or Anchor

Immediately position the control with respect to the parent by adjusting Bottom. Deprecated, use Align with TVerticalPosition.

Public procedure Align( const ControlPosition: TVerticalPosition; const ContainerPosition: TVerticalPosition; const Y: Integer = 0);

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.

Public 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.

Public 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

Public property Controls [Index:Integer]: TUIControl read GetControls write SetControls;
 
Public 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.

Public property GLInitialized: boolean read FGLInitialized default false;
 
Public 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.

Public property Focused: boolean read FFocused write SetFocused;
 
Public property Parent: TUIControl read FParent;
 
Published 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.

Published property Left: Integer read FLeft write SetLeft stored false default 0;
 
Published property Bottom: Integer read FBottom write SetBottom default 0;
 
Published 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.

Published property HorizontalAnchorSelf: THorizontalPosition read FHorizontalAnchorSelf write SetHorizontalAnchorSelf default hpLeft;

Which our border to align (it's aligned to parent HorizontalAnchorParent border), only used if HasHorizontalAnchor.

Published property HorizontalAnchorParent: THorizontalPosition read FHorizontalAnchorParent write SetHorizontalAnchorParent default hpLeft;

Which parent border is aligned to our HorizontalAnchorSelf border, only used if HasHorizontalAnchor.

Published property HorizontalAnchorDelta: Integer read FHorizontalAnchorDelta write SetHorizontalAnchorDelta default 0;

Delta between our border and parent, only used if HasHorizontalAnchor.

Published 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.

Published property VerticalAnchorSelf: TVerticalPosition read FVerticalAnchorSelf write SetVerticalAnchorSelf default vpBottom;

Which our border to align (it's aligned to parent VerticalAnchorParent border), only used if HasVerticalAnchor.

Published property VerticalAnchorParent: TVerticalPosition read FVerticalAnchorParent write SetVerticalAnchorParent default vpBottom;

Which parent border is aligned to our VerticalAnchorSelf border, only used if HasVerticalAnchor.

Published property VerticalAnchorDelta: Integer read FVerticalAnchorDelta write SetVerticalAnchorDelta default 0;

Delta between our border and parent, only used if HasVerticalAnchor.

Published 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).

Published 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.


Generated by PasDoc 0.14.0.