====== Control Architecture ======
Architecture and patterns for WvdS UI Controls.
===== Overview =====
All WvdS Controls follow the **Properties/ViewInfo/Control Pattern** (WPF-inspired):
TWvdSDependencyObject
└── TWvdSFrameworkElement
└── TWvdSControl
└── TWvdS{ControlName}
===== Class Hierarchy =====
==== TWvdSDependencyObject ====
Base for all objects with Dependency Properties.
TWvdSDependencyObject = class
private
FPropertyValues: TDictionary;
public
function GetValue(AProperty: TWvdSDependencyProperty): TValue;
procedure SetValue(AProperty: TWvdSDependencyProperty; AValue: TValue);
procedure ClearValue(AProperty: TWvdSDependencyProperty);
end;
==== TWvdSFrameworkElement ====
Extended with layout and visual properties.
TWvdSFrameworkElement = class(TWvdSDependencyObject)
private
FWidth, FHeight: Double;
FMinWidth, FMinHeight: Double;
FMaxWidth, FMaxHeight: Double;
FMargin, FPadding: TWvdSThickness;
FHorizontalAlignment: TWvdSHorizontalAlignment;
FVerticalAlignment: TWvdSVerticalAlignment;
public
function MeasureOverride(AAvailableSize: TWvdSSize): TWvdSSize; virtual;
function ArrangeOverride(AFinalSize: TWvdSSize): TWvdSSize; virtual;
procedure Render(ASurface: TWvdSRenderSurface); virtual; abstract;
end;
==== TWvdSControl ====
Base for all interactive controls.
TWvdSControl = class(TWvdSFrameworkElement)
private
FIsEnabled: Boolean;
FIsFocused: Boolean;
FTabIndex: Integer;
FTemplate: TWvdSControlTemplate;
FViewInfo: TWvdSViewInfo;
public
property IsEnabled: Boolean read FIsEnabled write SetIsEnabled;
property IsFocused: Boolean read FIsFocused;
property TabIndex: Integer read FTabIndex write FTabIndex;
property Template: TWvdSControlTemplate read FTemplate write FTemplate;
property ViewInfo: TWvdSViewInfo read FViewInfo;
procedure OnGotFocus; virtual;
procedure OnLostFocus; virtual;
procedure OnKeyDown(AEvent: TWvdSKeyEventArgs); virtual;
procedure OnMouseDown(AEvent: TWvdSMouseEventArgs); virtual;
end;
===== Properties/ViewInfo/Control Pattern =====
==== Three-Layer Architecture ====
┌─────────────────────────────────────────────────┐
│ Properties Layer │
│ - Public API (Properties, Events) │
│ - Dependency Properties │
│ - Bindable, PXAML-compatible │
├─────────────────────────────────────────────────┤
│ ViewInfo Layer │
│ - Calculated visual information │
│ - Cache for rendering │
│ - Bounds, Rects, calculated values │
├─────────────────────────────────────────────────┤
│ Control Layer │
│ - Rendering logic │
│ - Input handling │
│ - Target-specific (TUI/GUI/Web) │
└─────────────────────────────────────────────────┘
==== Example: TWvdSButton ====
(* Properties Layer *)
TWvdSButtonProperties = class(TWvdSControlProperties)
published
property Caption: string;
property ImageSource: TWvdSImageSource;
property IsDefault: Boolean;
property IsCancel: Boolean;
property Command: IWvdSCommand;
end;
(* ViewInfo Layer *)
TWvdSButtonViewInfo = class(TWvdSViewInfo)
private
FCaptionBounds: TRect;
FImageBounds: TRect;
FContentBounds: TRect;
public
procedure Calculate(AAvailableRect: TRect); override;
property CaptionBounds: TRect read FCaptionBounds;
property ImageBounds: TRect read FImageBounds;
end;
(* Control Layer *)
TWvdSButton = class(TWvdSControl)
private
FProperties: TWvdSButtonProperties;
FViewInfo: TWvdSButtonViewInfo;
public
constructor Create;
procedure Render(ASurface: TWvdSRenderSurface); override;
procedure OnClick; virtual;
published
property Caption: string read GetCaption write SetCaption;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
end;
===== Target Renderers =====
Each control has a specialized renderer per target.
==== Renderer Interface ====
IWvdSControlRenderer = interface
function Measure(AControl: TWvdSControl; AAvailable: TWvdSSize): TWvdSSize;
procedure Arrange(AControl: TWvdSControl; ARect: TRect);
procedure Paint(AControl: TWvdSControl; ASurface: TWvdSRenderSurface);
function HandleInput(AControl: TWvdSControl; AEvent: TWvdSInputEvent): Boolean;
end;
==== Target-Specific Implementations ====
sources/common/ui/targets/
├── tui/
│ ├── WvdS.UI.TUI.ButtonRenderer.pas
│ ├── WvdS.UI.TUI.TextEditRenderer.pas
│ └── ...
├── gui/
│ ├── WvdS.UI.GUI.ButtonRenderer.pas
│ └── ...
└── web/
├── WvdS.UI.Web.ButtonRenderer.pas
└── ...
==== TUI Renderer Example ====
TWvdSButtonTUIRenderer = class(TInterfacedObject, IWvdSControlRenderer)
public
function Measure(AControl: TWvdSControl; AAvailable: TWvdSSize): TWvdSSize;
procedure Arrange(AControl: TWvdSControl; ARect: TRect);
procedure Paint(AControl: TWvdSControl; ASurface: TWvdSRenderSurface);
function HandleInput(AControl: TWvdSControl; AEvent: TWvdSInputEvent): Boolean;
end;
procedure TWvdSButtonTUIRenderer.Paint(AControl: TWvdSControl;
ASurface: TWvdSRenderSurface);
var
Btn: TWvdSButton;
Style: TWvdSStyle;
begin
Btn := TWvdSButton(AControl);
(* State-based style selection *)
if not Btn.IsEnabled then
Style := Theme.ButtonDisabled
else if Btn.IsFocused then
Style := Theme.ButtonFocused
else
Style := Theme.ButtonDefault;
(* Draw border *)
ASurface.DrawBorder(Btn.Bounds, bsSingle, Style);
(* Draw caption centered *)
ASurface.DrawTextCentered(Btn.ViewInfo.ContentBounds,
Btn.Caption, Style);
end;
===== Dependency Properties =====
==== Definition ====
class var
CaptionProperty: TWvdSDependencyProperty;
class constructor TWvdSButton.Create;
begin
CaptionProperty := TWvdSDependencyProperty.Register(
'Caption', (* Name *)
TypeInfo(string), (* Type *)
TWvdSButton, (* Owner *)
'', (* Default *)
@OnCaptionChanged (* Callback *)
);
end;
**pas2js Compatibility:** ''class var'' does not work in pas2js. Use Unit-Level Variables instead.
==== pas2js-Compatible Alternative ====
var
GButtonCaptionProperty: TWvdSDependencyProperty = nil;
function ButtonCaptionProperty: TWvdSDependencyProperty;
begin
if GButtonCaptionProperty = nil then
GButtonCaptionProperty := TWvdSDependencyProperty.Register(...);
Result := GButtonCaptionProperty;
end;
===== Visual States =====
Required States:
├─ Normal (* Default state *)
├─ Focused (* Has keyboard focus *)
├─ Disabled (* IsEnabled = False *)
└─ Invalid (* Validation error *)
Optional States:
├─ MouseOver (* Mouse hovering *)
├─ Pressed (* Actively pressed *)
└─ Selected (* Selected *)
===== Input Handling =====
==== Event Order ====
1. PreviewKeyDown (Tunneling)
2. KeyDown (Bubbling)
3. Control-specific processing
4. Command execution (when bound)
==== Focus Management ====
TWvdSFocusManager = class
public
class function GetFocusedElement: TWvdSFrameworkElement;
class procedure SetFocus(AElement: TWvdSFrameworkElement);
class procedure MoveFocus(ADirection: TWvdSFocusNavigationDirection);
end;
TWvdSFocusNavigationDirection = (
fndNext, (* Tab *)
fndPrevious, (* Shift+Tab *)
fndUp,
fndDown,
fndLeft,
fndRight
);
===== Data Binding =====
==== Binding Syntax in PXAML ====
==== Binding Modes ====
| Mode | Description |
^ OneTime | Once at initialization |
^ OneWay | Source → Target |
^ TwoWay | Source ↔ Target |
^ OneWayToSource | Target → Source |
===== Control Lifecycle =====
1. Constructor
└─ Initialize properties
2. Apply template
└─ Load and apply ControlTemplate
3. Measure
└─ Calculate desired size
4. Arrange
└─ Final position and size
5. Render
└─ Draw to RenderSurface
6. Input events
└─ Keyboard, mouse, touch
7. Destructor
└─ Release resources
===== File Structure =====
sources/common/ui/
├── framework/ # Base framework (42 units)
│ ├── WvdS.UI.DependencyObject.pas
│ ├── WvdS.UI.FrameworkElement.pas
│ ├── WvdS.UI.Control.pas
│ ├── WvdS.UI.ViewInfo.pas
│ └── ...
│
├── controls/ # Control implementations
│ ├── basic/
│ │ ├── WvdS.UI.Controls.Button.pas
│ │ ├── WvdS.UI.Controls.Label.pas
│ │ └── ...
│ ├── editors/
│ ├── data/
│ └── ...
│
├── targets/ # Target-specific renderers
│ ├── tui/
│ ├── gui/
│ └── web/
│
└── themes/ # Theme definitions
├── WvdS.UI.Themes.Default.pas
└── WvdS.UI.Themes.Dark.pas
===== See Also =====
* [[.:control-bibliothek|Control Library]]
* [[.:control-entwicklung|Control Development (7 Steps)]]
* [[.:tui-controls|TUI Controls]]
* [[.:pxaml-pipeline|PXAML Pipeline]]