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