====== Arhitektura kontrol ======
Arhitektura in vzorci za WvdS UI kontrole.
===== Pregled =====
Vse WvdS kontrole sledijo vzorcu **Properties/ViewInfo/Control Pattern** (navdahnjeno z WPF):
TWvdSDependencyObject
+-- TWvdSFrameworkElement
+-- TWvdSControl
+-- TWvdS{ControlName}
===== Hierarhija razredov =====
==== TWvdSDependencyObject ====
Osnova za vse objekte z 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 ====
Razširjeno s postavitvijo in vizualnimi lastnostmi.
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 ====
Osnova za vse 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 =====
==== Triplastna arhitektura ====
+-------------------------------------------------+
| Plast Properties |
| - Javni API (Properties, Events) |
| - Dependency Properties |
| - Možnost vezave, PXAML-združljivo |
+-------------------------------------------------+
| Plast ViewInfo |
| - Izračunane vizualne informacije |
| - Predpomnilnik za upodabljanje |
| - Bounds, Rects, izračunane vrednosti |
+-------------------------------------------------+
| Plast Control |
| - Logika upodabljanja |
| - Obdelava vnosa |
| - Specifično za cilj (TUI/GUI/Web) |
+-------------------------------------------------+
==== Primer: TWvdSButton ====
(* Plast Properties *)
TWvdSButtonProperties = class(TWvdSControlProperties)
published
property Caption: string;
property ImageSource: TWvdSImageSource;
property IsDefault: Boolean;
property IsCancel: Boolean;
property Command: IWvdSCommand;
end;
(* Plast ViewInfo *)
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;
(* Plast Control *)
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 =====
Vsaka kontrola ima specializiran upodabljalnik za vsak cilj.
==== Vmesnik upodabljalnika ====
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;
==== Implementacije specifične za cilj ====
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
+-- ...
==== Primer TUI upodabljalnika ====
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);
(* Izbira sloga glede na stanje *)
if not Btn.IsEnabled then
Style := Theme.ButtonDisabled
else if Btn.IsFocused then
Style := Theme.ButtonFocused
else
Style := Theme.ButtonDefault;
(* Risanje obrobe *)
ASurface.DrawBorder(Btn.Bounds, bsSingle, Style);
(* Risanje sredinske oznake *)
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', (* Ime *)
TypeInfo(string), (* Tip *)
TWvdSButton, (* Lastnik *)
'', (* Privzeto *)
@OnCaptionChanged (* Povratni klic *)
);
end;
**pas2js-združljivost:** ''class var'' ne deluje v pas2js. Namesto tega uporabite spremenljivke na ravni enote.
==== pas2js-združljiva alternativa ====
var
GButtonCaptionProperty: TWvdSDependencyProperty = nil;
function ButtonCaptionProperty: TWvdSDependencyProperty;
begin
if GButtonCaptionProperty = nil then
GButtonCaptionProperty := TWvdSDependencyProperty.Register(...);
Result := GButtonCaptionProperty;
end;
===== Visual States =====
Obvezna stanja:
+-- Normal (* Privzeto stanje *)
+-- Focused (* Ima fokus tipkovnice *)
+-- Disabled (* IsEnabled = False *)
+-- Invalid (* Napaka validacije *)
Izbirna stanja:
+-- MouseOver (* Miška nad *)
+-- Pressed (* Aktivno pritisnjen *)
+-- Selected (* Izbrano *)
===== Obdelava vnosa =====
==== Vrstni red dogodkov ====
1. PreviewKeyDown (Tunneling)
2. KeyDown (Bubbling)
3. Obdelava specifična za kontrolo
4. Izvajanje ukaza (če je vezan)
==== Upravljanje fokusa ====
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 =====
==== Sintaksa vezave v PXAML ====
==== Načini vezave ====
| Način | Opis |
^ OneTime | Enkratno ob inicializaciji |
^ OneWay | Vir -> Cilj |
^ TwoWay | Vir <-> Cilj |
^ OneWayToSource | Cilj -> Vir |
===== Življenjski cikel kontrole =====
1. Konstruktor
+-- Inicializacija lastnosti
2. Uporaba predloge
+-- Nalaganje in uporaba ControlTemplate
3. Measure
+-- Izračun želene velikosti
4. Arrange
+-- Končna pozicija in velikost
5. Render
+-- Risanje v RenderSurface
6. Dogodki vnosa
+-- Tipkovnica, miška, dotik
7. Destruktor
+-- Sprostitev virov
===== Struktura datotek =====
sources/common/ui/
+-- framework/ # Osnovno ogrodje (42 enot)
| +-- WvdS.UI.DependencyObject.pas
| +-- WvdS.UI.FrameworkElement.pas
| +-- WvdS.UI.Control.pas
| +-- WvdS.UI.ViewInfo.pas
| +-- ...
|
+-- controls/ # Implementacije kontrol
| +-- basic/
| | +-- WvdS.UI.Controls.Button.pas
| | +-- WvdS.UI.Controls.Label.pas
| | +-- ...
| +-- editors/
| +-- data/
| +-- ...
|
+-- targets/ # Upodabljalniki specifični za cilj
| +-- tui/
| +-- gui/
| +-- web/
|
+-- themes/ # Definicije tem
+-- WvdS.UI.Themes.Default.pas
+-- WvdS.UI.Themes.Dark.pas
===== Glejte tudi =====
* [[.:control-bibliothek|Knjižnica kontrol]]
* [[.:control-entwicklung|Razvoj kontrol (7 korakov)]]
* [[.:tui-controls|TUI kontrole]]
* [[.:pxaml-pipeline|PXAML-Pipeline]]