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<string, TValue>;
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

<TextEdit Text="{Binding CustomerName, Mode=TwoWay}" />
<Button Caption="{Binding SaveCommand.Caption}"
        Command="{Binding SaveCommand}" />

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

Zuletzt geändert: on 2026/01/29 at 10:28 PM