Inhaltsverzeichnis

Arhitektura kontrola

Arhitektura i obrasci za WvdS UI Controls.

Pregled

Sve WvdS Controls prate Properties/ViewInfo/Control Pattern (WPF-inspiriran):

TWvdSDependencyObject
    └── TWvdSFrameworkElement
            └── TWvdSControl
                    └── TWvdS{ControlName}

Hijerarhija klasa

TWvdSDependencyObject

Baza za sve objekte s 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

Proširuje s layoutom i vizualnim svojstvima.

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

Baza za sve interaktivne kontrole.

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

Troslojna arhitektura

┌─────────────────────────────────────────────────┐
│  Properties Layer                               │
│  - Javni API (Properties, Events)               │
│  - Dependency Properties                        │
│  - Bindable, PXAML-kompatibilno                 │
├─────────────────────────────────────────────────┤
│  ViewInfo Layer                                 │
│  - Izračunate vizualne informacije              │
│  - Cache za rendering                           │
│  - Bounds, Rects, izračunate vrijednosti        │
├─────────────────────────────────────────────────┤
│  Control Layer                                  │
│  - Rendering-logika                             │
│  - Input-Handling                               │
│  - Target-specifično (TUI/GUI/Web)              │
└─────────────────────────────────────────────────┘

Primjer: 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

Svaka kontrola ima specijalizirani renderer po targetu.

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-specifične implementacije

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 Primjer

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);
 
  (* Odabir stila na temelju stanja *)
  if not Btn.IsEnabled then
    Style := Theme.ButtonDisabled
  else if Btn.IsFocused then
    Style := Theme.ButtonFocused
  else
    Style := Theme.ButtonDefault;
 
  (* Crtanje obruba *)
  ASurface.DrawBorder(Btn.Bounds, bsSingle, Style);
 
  (* Centrirano crtanje Caption *)
  ASurface.DrawTextCentered(Btn.ViewInfo.ContentBounds,
    Btn.Caption, Style);
end;

Dependency Properties

Definicija

class var
  CaptionProperty: TWvdSDependencyProperty;
 
class constructor TWvdSButton.Create;
begin
  CaptionProperty := TWvdSDependencyProperty.Register(
    'Caption',                    (* Naziv *)
    TypeInfo(string),             (* Tip *)
    TWvdSButton,                  (* Owner *)
    '',                           (* Default *)
    @OnCaptionChanged             (* Callback *)
  );
end;
pas2js-kompatibilnost: class var ne radi u pas2js. Koristi Unit-Level varijable umjesto toga.

pas2js-kompatibilna alternativa

var
  GButtonCaptionProperty: TWvdSDependencyProperty = nil;
 
function ButtonCaptionProperty: TWvdSDependencyProperty;
begin
  if GButtonCaptionProperty = nil then
    GButtonCaptionProperty := TWvdSDependencyProperty.Register(...);
  Result := GButtonCaptionProperty;
end;

Visual States

Obvezna stanja:
├─ Normal       (* Zadano stanje *)
├─ Focused      (* Ima tipkovnički fokus *)
├─ Disabled     (* IsEnabled = False *)
└─ Invalid      (* Validacijska greška *)

Opcionalna stanja:
├─ MouseOver    (* Miš iznad *)
├─ Pressed      (* Aktivno pritisnuto *)
└─ Selected     (* Odabrano *)

Input-Handling

Redoslijed događaja

1. PreviewKeyDown (Tunneling)
2. KeyDown (Bubbling)
3. Kontrola-specifična obrada
4. Izvršavanje Command (ako je povezan)

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-sintaksa u PXAML

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

Binding-Modes

Mode Opis
OneTime Jednom kod inicijalizacije
OneWay Source → Target
TwoWay Source ↔ Target
OneWayToSource Target → Source

Životni ciklus kontrole

1. Konstruktor
   └─ Inicijalizacija svojstava

2. Primjena predloška
   └─ Učitavanje i primjena ControlTemplate

3. Measure
   └─ Izračun željene veličine

4. Arrange
   └─ Finalna pozicija i veličina

5. Render
   └─ Crtanje u RenderSurface

6. Input-Events
   └─ Tipkovnica, miš, dodir

7. Destruktor
   └─ Oslobađanje resursa

Struktura datoteka

sources/common/ui/
├── framework/                    # Bazni Framework (42 Unit-a)
│   ├── WvdS.UI.DependencyObject.pas
│   ├── WvdS.UI.FrameworkElement.pas
│   ├── WvdS.UI.Control.pas
│   ├── WvdS.UI.ViewInfo.pas
│   └── ...
│
├── controls/                     # Implementacije kontrola
│   ├── basic/
│   │   ├── WvdS.UI.Controls.Button.pas
│   │   ├── WvdS.UI.Controls.Label.pas
│   │   └── ...
│   ├── editors/
│   ├── data/
│   └── ...
│
├── targets/                      # Target-specifični Rendereri
│   ├── tui/
│   ├── gui/
│   └── web/
│
└── themes/                       # Definicije tema
    ├── WvdS.UI.Themes.Default.pas
    └── WvdS.UI.Themes.Dark.pas

Vidi također