====== Razvoj kontrolnikov ======
Potek dela za ustvarjanje novih UI kontrolnikov za WvdS FPC RAD Suite.
Kontrolniki morajo delovati tako v **načrtovalnem času** (VS Code Designer) kot v **izvajalnem času** (Desktop/TUI/Web).
===== Pregled =====
Kontrolnik sestoji iz več plasti:
^ Plast ^ Namen ^ Pot ^
| Runtime Model | Cilju nevtralna logika | ''~/sources/common/ui/controls/{category}/'' |
| Target Renderer | Cilju specifična predstavitev | ''~/sources/common/ui/targets/{target}/renderers/'' |
| Pack Manifest | PXAML oznaka → Preslikava razreda | ''~/packs/controls/{control_id}/'' |
| Designer Metadata | Orodjarna, lastnosti, dogodki | ''~/sources/extensions/wvds.vscode.ui.meta/'' |
===== Spremenljivke =====
Pri ustvarjanju kontrolnika določite te spremenljivke:
^ Spremenljivka ^ Primer ^ Opis ^
| ''{CONTROL_ID}'' | ''dateedit'' | Enolični identifikator (male črke) |
| ''{CONTROL_CLASS}'' | ''TWvdSDateEdit'' | Ime Pascal razreda |
| ''{PXAML_TAG}'' | ''DateEdit'' | Ime oznake v PXAML |
| ''{PXAML_NS}'' | ''wvds'' | Imenski prostor (wvds za notranje kontrolnike) |
| ''{TARGETS}'' | ''tui,desktop,web'' | Podprti cilji |
===== Potek dela (7 korakov) =====
==== Korak 1: Zamrznitev pogodbe ====
Definirajte javni API kontrolnika:
**Lastnosti:**
(* Minimalni nabor javnih lastnosti *)
property Value: TDateTime read FValue write SetValue;
property Format: string read FFormat write SetFormat;
property MinDate: TDateTime read FMinDate write FMinDate;
property MaxDate: TDateTime read FMaxDate write FMaxDate;
property ReadOnly: Boolean read FReadOnly write FReadOnly;
**Dogodki:**
(* Zahtevani dogodki *)
property OnValueChanged: TWvdSNotifyEvent read FOnValueChanged write FOnValueChanged;
property OnValidating: TWvdSValidateEvent read FOnValidating write FOnValidating;
**TargetCaps:**
^ Zmožnost ^ TUI ^ Desktop ^ Web ^
| Tipkovnica | Zahtevano | Zahtevano | Zahtevano |
| Miška | Opcijsko | Zahtevano | Zahtevano |
| Dotik | N/A | Opcijsko | Opcijsko |
| Pojavno okno | Opcijsko | Zahtevano | Zahtevano |
==== Korak 2: Enota izvajalnega modela ====
Ustvarite cilju nevtralno enoto modela:
**Pot:** ''~/sources/common/ui/controls/{category}/WvdS.UI.Controls.{Category}.{ControlId}.pas''
unit WvdS.UI.Controls.Editors.DateEdit;
{$mode objfpc}{$H+}
interface
uses
WvdS.UI.Core.Base,
WvdS.UI.Core.Events;
type
(*
@abstract(Polje za vnos datuma s pojavnim koledarjem)
Cilju nevtralen model za DateEdit.
Ne vsebuje NOBENIH odvisnosti od upodabljanja ali gostitelja.
*)
TWvdSDateEdit = class(TWvdSControl)
private
FValue: TDateTime;
FFormat: string;
FOnValueChanged: TWvdSNotifyEvent;
procedure SetValue(AValue: TDateTime);
protected
procedure DoValueChanged; virtual;
public
constructor Create(AOwner: TWvdSComponent); override;
property Value: TDateTime read FValue write SetValue;
property Format: string read FFormat write FFormat;
property OnValueChanged: TWvdSNotifyEvent read FOnValueChanged write FOnValueChanged;
end;
implementation
(* Implementacija brez cilju specifične kode *)
end.
**Brez cilju specifičnih odvisnosti!** Brez DOM, brez terminalskih I/O, brez LCL enot.
==== Korak 3: Enote ciljnih upodabljalnikov ====
Za vsak cilj v ''{TARGETS}'' ustvarite upodabljalnik:
=== TUI upodabljalnik ===
**Pot:** ''~/sources/common/ui/targets/tui/renderers/WvdS.UI.TUI.Renderers.DateEdit.pas''
unit WvdS.UI.TUI.Renderers.DateEdit;
{$mode objfpc}{$H+}
interface
uses
WvdS.UI.TUI.Renderer.Base,
WvdS.UI.Controls.Editors.DateEdit;
type
TWvdSTUIDateEditRenderer = class(TWvdSTUIRenderer)
public
procedure Measure(AControl: TWvdSControl; out AWidth, AHeight: Integer); override;
procedure Paint(AControl: TWvdSControl; ACanvas: TWvdSTUICanvas); override;
procedure HandleInput(AControl: TWvdSControl; AEvent: TWvdSInputEvent); override;
end;
implementation
procedure TWvdSTUIDateEditRenderer.Measure(AControl: TWvdSControl; out AWidth, AHeight: Integer);
begin
AWidth := 12; (* [YYYY-MM-DD] *)
AHeight := 1;
end;
procedure TWvdSTUIDateEditRenderer.Paint(AControl: TWvdSControl; ACanvas: TWvdSTUICanvas);
var
DateEdit: TWvdSDateEdit;
begin
DateEdit := AControl as TWvdSDateEdit;
ACanvas.DrawText(0, 0, FormatDateTime(DateEdit.Format, DateEdit.Value));
end;
procedure TWvdSTUIDateEditRenderer.HandleInput(AControl: TWvdSControl; AEvent: TWvdSInputEvent);
begin
(* Obravnava tipkovnice za spremembo datuma *)
end;
end.
=== Desktop upodabljalnik ===
**Pot:** ''~/sources/common/ui/targets/gui/renderers/WvdS.UI.Desktop.Renderers.DateEdit.pas''
=== Web upodabljalnik ===
**Pot:** ''~/sources/common/ui/targets/web/renderers/WvdS.UI.Web.Renderers.DateEdit.pas''
==== Korak 4: Pack manifest ====
Ustvarite Pack manifest za PXAML razreševalnik:
**Pot:** ''~/packs/controls/{control_id}/pack.wvds.json''
{
"id": "dateedit",
"vendor": "wvds",
"version": "0.1.0",
"xml": {
"namespace": "wvds",
"tag": "DateEdit"
},
"model": {
"unit": "WvdS.UI.Controls.Editors.DateEdit",
"class": "TWvdSDateEdit"
},
"renderers": {
"tui": {
"unit": "WvdS.UI.TUI.Renderers.DateEdit",
"class": "TWvdSTUIDateEditRenderer"
},
"desktop": {
"unit": "WvdS.UI.Desktop.Renderers.DateEdit",
"class": "TWvdSDesktopDateEditRenderer"
},
"web": {
"unit": "WvdS.UI.Web.Renderers.DateEdit",
"class": "TWvdSWebDateEditRenderer"
}
},
"targetCaps": {
"requires": ["keyboard"],
"optional": ["mouse", "popup"]
}
}
==== Korak 5: Metapodatki načrtovalnika ====
Ustvarite metapodatke načrtovalnika za orodjarno in lastnosti:
**Dodajte deskriptor v:** ''~/sources/common/core/meta/WvdS.Meta.Controls.Editors.pas''
procedure RegisterDateEditMeta(ARegistry: TMetaRegistry);
var
TypeMeta: TTypeMeta;
begin
TypeMeta := CreateTypeMeta('DateEdit', 'TWvdSDateEdit', 'Editors');
TypeMeta.Description := 'Polje za vnos datuma s pojavnim koledarjem';
TypeMeta.Icon := 'calendar';
(* Lastnosti *)
TypeMeta.AddProperty(CreatePropertyMeta('Value', pkDateTime, 'Trenutna vrednost datuma'));
TypeMeta.AddProperty(CreatePropertyMeta('Format', pkString, 'Format prikaza (npr. yyyy-mm-dd)'));
TypeMeta.AddProperty(CreatePropertyMeta('MinDate', pkDateTime, 'Najzgodnejši dovoljeni datum'));
TypeMeta.AddProperty(CreatePropertyMeta('MaxDate', pkDateTime, 'Najpoznejši dovoljeni datum'));
TypeMeta.AddProperty(CreatePropertyMeta('ReadOnly', pkBoolean, 'Način samo za branje'));
(* Dogodki *)
TypeMeta.AddEvent(CreateEventMeta('OnValueChanged', 'Sproži se ob spremembi Value'));
TypeMeta.AddEvent(CreateEventMeta('OnValidating', 'Sproži se pred spremembo vrednosti'));
ARegistry.RegisterType(TypeMeta);
end;
==== Korak 6: Registracija v registru ====
Registrirajte kontrolnik v izvajalnih registrih:
=== PXAML razreševalnik ===
''pxamlc'' prevajalnik samodejno bere ''pack.wvds.json'' iz ''~/packs/''.
=== Register izvajalnika ciljev ===
Za vsak cilj posodobite register upodabljalnikov:
(* V WvdS.UI.TUI.Render.Registry.pas *)
procedure RegisterTUIRenderers;
begin
(* ... drugi upodabljalniki ... *)
RegisterRenderer(TWvdSDateEdit, TWvdSTUIDateEditRenderer);
end;
==== Korak 7: Dokumentacija ====
Ustvarite API dokumentacijo za kontrolnik:
**Pot:** ''~/docs/api/controls/dateedit.md''
# TWvdSDateEdit
Polje za vnos datuma z opcijskim pojavnim koledarjem.
## Kdaj uporabiti
- Uporabnik mora vnesti datum
- Omejitev datumskega razpona (MinDate/MaxDate)
- Potreben formatiran prikaz datuma
## Lastnosti
| Lastnost | Tip | Opis |
|----------|-----|------|
| Value | TDateTime | Trenutna vrednost datuma |
| Format | string | Format prikaza |
| MinDate | TDateTime | Najzgodnejši dovoljeni datum |
| MaxDate | TDateTime | Najpoznejši dovoljeni datum |
| ReadOnly | Boolean | Način samo za branje |
## Dogodki
| Dogodek | Opis |
|---------|------|
| OnValueChanged | Sproži se ob spremembi Value |
| OnValidating | Omogoča validacijo pred spremembo vrednosti |
## Primer
```xml
```
===== Merila za dokončanje =====
Kontrolnik je dokončan, ko:
[ ] VS Code Designer lahko postavi {PXAML_NS}:{PXAML_TAG}
[ ] Lastnosti so urejalne v načrtovalniku
[ ] Predogled v načrtovalniku deluje
[ ] Ciljna gradnja (tui/desktop/web) se uspešno prevede
[ ] Pack manifest je prisoten in razreševalnik ga prepozna
[ ] API dokumentacija je napisana
===== Glejte tudi =====
* [[.:pxaml-pipeline|PXAML cevovod]]
* [[.:pack-struktur|Struktura paketov]]
* [[.:targets|Cilji gradnje]]
* [[.:meta-api|Meta API]]