====== Control-Architektur ======
Architektur und Patterns für WvdS UI Controls.
===== Übersicht =====
Alle WvdS Controls folgen dem **Properties/ViewInfo/Control Pattern** (WPF-inspiriert):
TWvdSDependencyObject
└── TWvdSFrameworkElement
└── TWvdSControl
└── TWvdS{ControlName}
===== Klassenhierarchie =====
==== TWvdSDependencyObject ====
Basis für alle Objekte mit 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 ====
Erweitert um Layout und visuelle Eigenschaften.
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 ====
Basis für alle interaktiven 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 =====
==== Drei-Schichten-Architektur ====
┌─────────────────────────────────────────────────┐
│ Properties Layer │
│ - Öffentliche API (Properties, Events) │
│ - Dependency Properties │
│ - Bindungsfähig, PXAML-kompatibel │
├─────────────────────────────────────────────────┤
│ ViewInfo Layer │
│ - Berechnete visuelle Informationen │
│ - Cache für Rendering │
│ - Bounds, Rects, berechnete Werte │
├─────────────────────────────────────────────────┤
│ Control Layer │
│ - Rendering-Logik │
│ - Input-Handling │
│ - Target-spezifisch (TUI/GUI/Web) │
└─────────────────────────────────────────────────┘
==== Beispiel: 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-Renderer =====
Jedes Control hat pro Target einen spezialisierten Renderer.
==== 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-spezifische Implementierungen ====
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 Beispiel ====
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-basierte Style-Auswahl *)
if not Btn.IsEnabled then
Style := Theme.ButtonDisabled
else if Btn.IsFocused then
Style := Theme.ButtonFocused
else
Style := Theme.ButtonDefault;
(* Border zeichnen *)
ASurface.DrawBorder(Btn.Bounds, bsSingle, Style);
(* Caption zentriert zeichnen *)
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), (* Typ *)
TWvdSButton, (* Owner *)
'', (* Default *)
@OnCaptionChanged (* Callback *)
);
end;
**pas2js-Kompatibilität:** ''class var'' funktioniert nicht in pas2js. Verwende stattdessen Unit-Level Variablen.
==== pas2js-kompatible Alternative ====
var
GButtonCaptionProperty: TWvdSDependencyProperty = nil;
function ButtonCaptionProperty: TWvdSDependencyProperty;
begin
if GButtonCaptionProperty = nil then
GButtonCaptionProperty := TWvdSDependencyProperty.Register(...);
Result := GButtonCaptionProperty;
end;
===== Visual States =====
Pflicht-States:
├─ Normal (* Default-Zustand *)
├─ Focused (* Hat Tastatur-Fokus *)
├─ Disabled (* IsEnabled = False *)
└─ Invalid (* Validierungsfehler *)
Optional-States:
├─ MouseOver (* Maus darüber *)
├─ Pressed (* Aktiv gedrückt *)
└─ Selected (* Ausgewählt *)
===== Input-Handling =====
==== Event-Reihenfolge ====
1. PreviewKeyDown (Tunneling)
2. KeyDown (Bubbling)
3. Control-spezifische Verarbeitung
4. Command-Ausführung (wenn gebunden)
==== 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 | Beschreibung |
^ OneTime | Einmalig bei Initialisierung |
^ OneWay | Source → Target |
^ TwoWay | Source ↔ Target |
^ OneWayToSource | Target → Source |
===== Control-Lebenszyklus =====
1. Konstruktor
└─ Properties initialisieren
2. Template anwenden
└─ ControlTemplate laden und anwenden
3. Measure
└─ Gewünschte Größe berechnen
4. Arrange
└─ Finale Position und Größe
5. Render
└─ In RenderSurface zeichnen
6. Input-Events
└─ Tastatur, Maus, Touch
7. Destruktor
└─ Ressourcen freigeben
===== Dateistruktur =====
sources/common/ui/
├── framework/ # Basis-Framework (42 Units)
│ ├── WvdS.UI.DependencyObject.pas
│ ├── WvdS.UI.FrameworkElement.pas
│ ├── WvdS.UI.Control.pas
│ ├── WvdS.UI.ViewInfo.pas
│ └── ...
│
├── controls/ # Control-Implementierungen
│ ├── basic/
│ │ ├── WvdS.UI.Controls.Button.pas
│ │ ├── WvdS.UI.Controls.Label.pas
│ │ └── ...
│ ├── editors/
│ ├── data/
│ └── ...
│
├── targets/ # Target-spezifische Renderer
│ ├── tui/
│ ├── gui/
│ └── web/
│
└── themes/ # Theme-Definitionen
├── WvdS.UI.Themes.Default.pas
└── WvdS.UI.Themes.Dark.pas
===== Siehe auch =====
* [[.:control-bibliothek|Control-Bibliothek]]
* [[.:control-entwicklung|Control-Entwicklung (7-Schritte)]]
* [[.:tui-controls|TUI Controls]]
* [[.:pxaml-pipeline|PXAML-Pipeline]]