Add MainMenu, PopupMenu, MenuItem, and RadioGroup control types
Menus use 0 0 0 0 geometry (non-visual) with Parent property for hierarchy. TFormCtrlRec.Control widened from TControl to TComponent to support non-visual menu components. RadioGroup auto-wires Click with ItemIndex data. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2d5ed2a3b1
commit
03d44440fd
4 changed files with 362 additions and 108 deletions
|
|
@ -322,6 +322,10 @@ messages are available, dispatching each command as it arrives.
|
|||
| `Panel` | TPanel | Cosmetic container panel |
|
||||
| `ScrollBar` | TScrollBar | Horizontal or vertical scrollbar|
|
||||
| `MediaPlayer` | TMediaPlayer | MCI media player control |
|
||||
| `MainMenu` | TMainMenu | Form main menu bar |
|
||||
| `PopupMenu` | TPopupMenu | Context (right-click) menu |
|
||||
| `MenuItem` | TMenuItem | Menu item (child of menu) |
|
||||
| `RadioGroup` | TRadioGroup | Grouped radio buttons |
|
||||
|
||||
### Creating Controls
|
||||
|
||||
|
|
@ -359,12 +363,12 @@ CTRL.SET 1 3 Text="world" Enabled=0
|
|||
|
||||
### Caption
|
||||
|
||||
- **Applies to:** Label, Button, CheckBox, GroupBox, RadioButton, Panel
|
||||
- **Applies to:** Label, Button, CheckBox, GroupBox, RadioButton, Panel, MenuItem, RadioGroup
|
||||
- **Format:** Quoted string
|
||||
- **Example:** `Caption="Submit"`
|
||||
|
||||
The display text for labels, buttons, check boxes, group boxes, radio
|
||||
buttons, and panels.
|
||||
buttons, panels, menu items, and radio groups.
|
||||
|
||||
### Text
|
||||
|
||||
|
|
@ -381,7 +385,7 @@ CTRL.SET 1 5 Text="Line one\nLine two\nLine three"
|
|||
|
||||
### Items
|
||||
|
||||
- **Applies to:** ListBox, ComboBox
|
||||
- **Applies to:** ListBox, ComboBox, RadioGroup
|
||||
- **Format:** Quoted string, items separated by `\n`
|
||||
- **Example:** `Items="Red\nGreen\nBlue"`
|
||||
|
||||
|
|
@ -390,7 +394,7 @@ new items are added.
|
|||
|
||||
### Checked
|
||||
|
||||
- **Applies to:** CheckBox, RadioButton
|
||||
- **Applies to:** CheckBox, RadioButton, MenuItem
|
||||
- **Format:** `0` (unchecked) or `1` (checked)
|
||||
- **Example:** `Checked=1`
|
||||
|
||||
|
|
@ -433,7 +437,7 @@ Maximum number of characters the user can type.
|
|||
|
||||
### ItemIndex
|
||||
|
||||
- **Applies to:** ListBox, ComboBox
|
||||
- **Applies to:** ListBox, ComboBox, RadioGroup
|
||||
- **Format:** Integer (-1 = no selection)
|
||||
- **Example:** `ItemIndex=2`
|
||||
|
||||
|
|
@ -588,6 +592,41 @@ Pseudo-property that triggers a method call instead of setting a
|
|||
value. Valid commands: `Open`, `Play`, `Stop`, `Close`, `Pause`,
|
||||
`Resume`, `Rewind`, `Next`, `Previous`.
|
||||
|
||||
### Parent
|
||||
|
||||
- **Applies to:** MenuItem
|
||||
- **Format:** Integer (ctrlId of parent menu or menu item)
|
||||
- **Example:** `Parent=1`
|
||||
|
||||
Specifies the parent for a menu item. The parent can be a MainMenu,
|
||||
PopupMenu, or another MenuItem (for submenus).
|
||||
|
||||
### Columns
|
||||
|
||||
- **Applies to:** RadioGroup
|
||||
- **Format:** Integer
|
||||
- **Example:** `Columns=2`
|
||||
|
||||
Number of columns for the radio button layout.
|
||||
|
||||
### ShortCut
|
||||
|
||||
- **Applies to:** MenuItem
|
||||
- **Format:** Integer (Delphi ShortCut value)
|
||||
- **Example:** `ShortCut=16467`
|
||||
|
||||
Keyboard accelerator for the menu item. Uses Delphi's ShortCut
|
||||
encoding (virtual key + modifier flags).
|
||||
|
||||
### PopupMenu
|
||||
|
||||
- **Applies to:** Any visual control
|
||||
- **Format:** Integer (ctrlId of a PopupMenu)
|
||||
- **Example:** `PopupMenu=2`
|
||||
|
||||
Associates a PopupMenu with a control. When the user right-clicks
|
||||
the control, the popup menu is displayed.
|
||||
|
||||
### BasePath
|
||||
|
||||
`BasePath` is a property on `TFormClient` (not a protocol property).
|
||||
|
|
@ -619,6 +658,8 @@ No `EVENT.BIND` command is needed.
|
|||
| ListBox | Select | `<index> "selected text"` |
|
||||
| ComboBox | Select | `<index> "selected text"` |
|
||||
| ComboBox | Change | `"new text"` |
|
||||
| MenuItem | Click | (none) |
|
||||
| RadioGroup | Click | `<itemIndex>` |
|
||||
|
||||
### Opt-in Events
|
||||
|
||||
|
|
@ -666,6 +707,25 @@ EVENT 1 3 KeyDown 13 (client sends back when Enter pressed)
|
|||
EVENT.UNBIND 1 3 KeyDown (server disconnects)
|
||||
```
|
||||
|
||||
### Menu Hierarchy Example
|
||||
|
||||
Menus are built using flat CTRL.CREATE commands with `Parent` properties
|
||||
to establish the hierarchy:
|
||||
|
||||
```
|
||||
CTRL.CREATE 1 1 MainMenu 0 0 0 0
|
||||
CTRL.CREATE 1 2 MenuItem 0 0 0 0 Caption="&File" Parent=1
|
||||
CTRL.CREATE 1 3 MenuItem 0 0 0 0 Caption="&Open" Parent=2 ShortCut=16463
|
||||
CTRL.CREATE 1 4 MenuItem 0 0 0 0 Caption="&Save" Parent=2 ShortCut=16467
|
||||
CTRL.CREATE 1 5 MenuItem 0 0 0 0 Caption="E&xit" Parent=2
|
||||
CTRL.CREATE 1 6 MenuItem 0 0 0 0 Caption="&Help" Parent=1
|
||||
CTRL.CREATE 1 7 MenuItem 0 0 0 0 Caption="&About" Parent=6
|
||||
```
|
||||
|
||||
This creates a menu bar with File (Open, Save, Exit) and Help (About).
|
||||
MenuItem ctrl 2 is a child of MainMenu ctrl 1; ctrl 3-5 are children of
|
||||
the File item (ctrl 2); ctrl 7 is a child of the Help item (ctrl 6).
|
||||
|
||||
## String Encoding
|
||||
|
||||
All strings in the protocol are double-quoted. The following escape
|
||||
|
|
@ -697,9 +757,8 @@ any protocol or application code.
|
|||
## Limitations
|
||||
|
||||
- **RadioButton grouping:** All RadioButtons on a form belong to one
|
||||
group. There is no support for multiple independent radio groups
|
||||
per form (the protocol has a flat parent model with no child
|
||||
containment).
|
||||
group. Use RadioGroup for multiple independent radio groups per
|
||||
form.
|
||||
- **Image format:** Only BMP files are supported for the Picture
|
||||
property.
|
||||
- **dfm2form and Picture:** The converter cannot extract image
|
||||
|
|
|
|||
|
|
@ -32,7 +32,11 @@ typedef enum {
|
|||
ctRadioButton,
|
||||
ctPanel,
|
||||
ctScrollBar,
|
||||
ctMediaPlayer
|
||||
ctMediaPlayer,
|
||||
ctMainMenu,
|
||||
ctPopupMenu,
|
||||
ctMenuItem,
|
||||
ctRadioGroup
|
||||
} CtrlTypeE;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -103,6 +107,11 @@ typedef struct {
|
|||
bool hasAutoOpen;
|
||||
bool hasFileName;
|
||||
bool hasDeviceType;
|
||||
int32_t parentCtrlIdx;
|
||||
int32_t columns;
|
||||
int32_t shortCut;
|
||||
bool hasColumns;
|
||||
bool hasShortCut;
|
||||
} DfmCtrlT;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -143,7 +152,7 @@ static void escapeStr(const char *src, char *dst, int32_t dstSize);
|
|||
static void initCtrl(DfmCtrlT *ctrl);
|
||||
static void initForm(DfmFormT *form);
|
||||
static CtrlTypeE mapClassName(const char *className);
|
||||
static bool parseComponent(const uint8_t *data, int32_t size, int32_t *pos, DfmFormT *form, bool isRoot);
|
||||
static bool parseComponent(const uint8_t *data, int32_t size, int32_t *pos, DfmFormT *form, bool isRoot, int32_t parentIdx);
|
||||
static void parseProperties(const uint8_t *data, int32_t size, int32_t *pos, DfmFormT *form, DfmCtrlT *ctrl, bool isForm);
|
||||
static int32_t readByte(const uint8_t *data, int32_t size, int32_t *pos);
|
||||
static int32_t readInt16LE(const uint8_t *data, int32_t size, int32_t *pos);
|
||||
|
|
@ -360,6 +369,18 @@ static CtrlTypeE mapClassName(const char *className) {
|
|||
if (stricmp_local(className, "TMediaPlayer") == 0) {
|
||||
return ctMediaPlayer;
|
||||
}
|
||||
if (stricmp_local(className, "TMainMenu") == 0) {
|
||||
return ctMainMenu;
|
||||
}
|
||||
if (stricmp_local(className, "TPopupMenu") == 0) {
|
||||
return ctPopupMenu;
|
||||
}
|
||||
if (stricmp_local(className, "TMenuItem") == 0) {
|
||||
return ctMenuItem;
|
||||
}
|
||||
if (stricmp_local(className, "TRadioGroup") == 0) {
|
||||
return ctRadioGroup;
|
||||
}
|
||||
return ctUnknown;
|
||||
}
|
||||
|
||||
|
|
@ -370,13 +391,14 @@ static CtrlTypeE mapClassName(const char *className) {
|
|||
|
||||
static void initCtrl(DfmCtrlT *ctrl) {
|
||||
memset(ctrl, 0, sizeof(DfmCtrlT));
|
||||
ctrl->enabled = 1;
|
||||
ctrl->visible = 1;
|
||||
ctrl->itemIndex = -1;
|
||||
ctrl->tabOrder = -1;
|
||||
ctrl->bevelOuter = 1; // bvRaised
|
||||
ctrl->largeChange = 1;
|
||||
ctrl->smallChange = 1;
|
||||
ctrl->enabled = 1;
|
||||
ctrl->visible = 1;
|
||||
ctrl->itemIndex = -1;
|
||||
ctrl->tabOrder = -1;
|
||||
ctrl->bevelOuter = 1; // bvRaised
|
||||
ctrl->largeChange = 1;
|
||||
ctrl->smallChange = 1;
|
||||
ctrl->parentCtrlIdx = -1;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -790,6 +812,12 @@ static void parseProperties(const uint8_t *data, int32_t size, int32_t *pos, Dfm
|
|||
ctrl->autoOpen = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasAutoOpen = true;
|
||||
} else if (!isForm && stricmp_local(propName, "Columns") == 0) {
|
||||
ctrl->columns = readIntValue(data, size, pos, tag);
|
||||
ctrl->hasColumns = true;
|
||||
} else if (!isForm && stricmp_local(propName, "ShortCut") == 0) {
|
||||
ctrl->shortCut = readIntValue(data, size, pos, tag);
|
||||
ctrl->hasShortCut = true;
|
||||
} else {
|
||||
skipValue(data, size, pos, tag);
|
||||
}
|
||||
|
|
@ -801,7 +829,7 @@ static void parseProperties(const uint8_t *data, int32_t size, int32_t *pos, Dfm
|
|||
// Parse a component (form or child control) recursively
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static bool parseComponent(const uint8_t *data, int32_t size, int32_t *pos, DfmFormT *form, bool isRoot) {
|
||||
static bool parseComponent(const uint8_t *data, int32_t size, int32_t *pos, DfmFormT *form, bool isRoot, int32_t parentIdx) {
|
||||
// Check for flags byte (Delphi 1.0 rarely uses this but handle it)
|
||||
uint8_t peek = data[*pos];
|
||||
if ((peek & 0xF0) == 0xF0) {
|
||||
|
|
@ -833,7 +861,7 @@ static bool parseComponent(const uint8_t *data, int32_t size, int32_t *pos, DfmF
|
|||
(*pos)++; // consume terminator
|
||||
break;
|
||||
}
|
||||
parseComponent(data, size, pos, form, false);
|
||||
parseComponent(data, size, pos, form, false, -1);
|
||||
}
|
||||
} else {
|
||||
// Child control
|
||||
|
|
@ -851,7 +879,7 @@ static bool parseComponent(const uint8_t *data, int32_t size, int32_t *pos, DfmF
|
|||
(*pos)++;
|
||||
break;
|
||||
}
|
||||
parseComponent(data, size, pos, form, false);
|
||||
parseComponent(data, size, pos, form, false, -1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -861,22 +889,24 @@ static bool parseComponent(const uint8_t *data, int32_t size, int32_t *pos, DfmF
|
|||
exit(1);
|
||||
}
|
||||
|
||||
DfmCtrlT *ctrl = &form->ctrls[form->ctrlCount];
|
||||
int32_t myIdx = form->ctrlCount;
|
||||
DfmCtrlT *ctrl = &form->ctrls[myIdx];
|
||||
initCtrl(ctrl);
|
||||
ctrl->type = type;
|
||||
ctrl->type = type;
|
||||
ctrl->parentCtrlIdx = parentIdx;
|
||||
snprintf(ctrl->name, sizeof(ctrl->name), "%s", instName);
|
||||
|
||||
parseProperties(data, size, pos, form, ctrl, false);
|
||||
form->ctrlCount++;
|
||||
|
||||
// Skip nested children (controls within controls, e.g., panels)
|
||||
// Recurse into children (menu items, panels, etc.)
|
||||
while (*pos < size) {
|
||||
peek = data[*pos];
|
||||
if (peek == 0x00) {
|
||||
(*pos)++;
|
||||
break;
|
||||
}
|
||||
parseComponent(data, size, pos, form, false);
|
||||
parseComponent(data, size, pos, form, false, myIdx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -931,13 +961,16 @@ static void emitCtrl(FILE *out, int32_t formId, int32_t ctrlId, DfmCtrlT *ctrl)
|
|||
"Unknown", "Label", "Edit", "Button",
|
||||
"CheckBox", "ListBox", "ComboBox", "Memo",
|
||||
"Image", "GroupBox", "RadioButton", "Panel",
|
||||
"ScrollBar", "MediaPlayer"
|
||||
"ScrollBar", "MediaPlayer",
|
||||
"MainMenu", "PopupMenu", "MenuItem", "RadioGroup"
|
||||
};
|
||||
char escaped[8192];
|
||||
|
||||
fprintf(out, "CTRL.CREATE %d %d %s %d %d %d %d",
|
||||
formId, ctrlId, typeNames[ctrl->type],
|
||||
ctrl->left, ctrl->top, ctrl->width, ctrl->height);
|
||||
if (ctrl->type == ctMainMenu || ctrl->type == ctPopupMenu || ctrl->type == ctMenuItem) {
|
||||
fprintf(out, "CTRL.CREATE %d %d %s 0 0 0 0", formId, ctrlId, typeNames[ctrl->type]);
|
||||
} else {
|
||||
fprintf(out, "CTRL.CREATE %d %d %s %d %d %d %d", formId, ctrlId, typeNames[ctrl->type], ctrl->left, ctrl->top, ctrl->width, ctrl->height);
|
||||
}
|
||||
|
||||
// Inline properties
|
||||
if (ctrl->hasCaption) {
|
||||
|
|
@ -1023,6 +1056,15 @@ static void emitCtrl(FILE *out, int32_t formId, int32_t ctrlId, DfmCtrlT *ctrl)
|
|||
if (ctrl->hasAutoOpen && ctrl->autoOpen) {
|
||||
fprintf(out, " AutoOpen=1");
|
||||
}
|
||||
if (ctrl->type == ctMenuItem && ctrl->parentCtrlIdx >= 0) {
|
||||
fprintf(out, " Parent=%d", ctrl->parentCtrlIdx + 1);
|
||||
}
|
||||
if (ctrl->hasColumns && ctrl->columns != 0) {
|
||||
fprintf(out, " Columns=%d", ctrl->columns);
|
||||
}
|
||||
if (ctrl->hasShortCut && ctrl->shortCut != 0) {
|
||||
fprintf(out, " ShortCut=%d", ctrl->shortCut);
|
||||
}
|
||||
|
||||
fprintf(out, "\n");
|
||||
|
||||
|
|
@ -1030,7 +1072,7 @@ static void emitCtrl(FILE *out, int32_t formId, int32_t ctrlId, DfmCtrlT *ctrl)
|
|||
// Auto-wired: Button/CheckBox→Click, Edit→Change, ListBox→Select,
|
||||
// ComboBox→Select+Change, Memo→Change
|
||||
|
||||
bool autoClick = (ctrl->type == ctButton || ctrl->type == ctCheckBox || ctrl->type == ctRadioButton);
|
||||
bool autoClick = (ctrl->type == ctButton || ctrl->type == ctCheckBox || ctrl->type == ctRadioButton || ctrl->type == ctMenuItem || ctrl->type == ctRadioGroup);
|
||||
bool autoChange = (ctrl->type == ctEdit || ctrl->type == ctComboBox || ctrl->type == ctMemo || ctrl->type == ctScrollBar);
|
||||
bool autoSelect = (ctrl->type == ctListBox || ctrl->type == ctComboBox);
|
||||
|
||||
|
|
@ -1160,7 +1202,7 @@ int main(int argc, char *argv[]) {
|
|||
DfmFormT form;
|
||||
initForm(&form);
|
||||
int32_t pos = 4; // skip TPF0
|
||||
parseComponent(data, (int32_t)fileSize, &pos, &form, true);
|
||||
parseComponent(data, (int32_t)fileSize, &pos, &form, true, -1);
|
||||
|
||||
// Default caption if empty
|
||||
if (form.caption[0] == '\0') {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ unit FormCli;
|
|||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, MPlayer, WinTypes, WinProcs;
|
||||
SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, Menus, MPlayer, WinTypes, WinProcs;
|
||||
|
||||
const
|
||||
MaxMsgLen = 4096;
|
||||
|
|
@ -29,7 +29,8 @@ type
|
|||
TCtrlTypeE = (ctUnknown, ctLabel, ctEdit, ctButton,
|
||||
ctCheckBox, ctListBox, ctComboBox, ctMemo,
|
||||
ctImage, ctGroupBox, ctRadioButton, ctPanel,
|
||||
ctScrollBar, ctMediaPlayer);
|
||||
ctScrollBar, ctMediaPlayer,
|
||||
ctMainMenu, ctPopupMenu, ctMenuItem, ctRadioGroup);
|
||||
|
||||
{ Bound event flags }
|
||||
TBoundEvent = (beDblClick, beKeyDown, beKeyUp,
|
||||
|
|
@ -42,7 +43,7 @@ type
|
|||
TFormCtrlRec = record
|
||||
CtrlId: Integer;
|
||||
CtrlType: TCtrlTypeE;
|
||||
Control: TControl;
|
||||
Control: TComponent;
|
||||
Bound: TBoundEvents;
|
||||
end;
|
||||
|
||||
|
|
@ -81,8 +82,8 @@ type
|
|||
procedure FreeCtrlRec(CR: PFormCtrlRec);
|
||||
|
||||
{ Property application }
|
||||
procedure ApplyProp(CR: PFormCtrlRec; Key, Value: PChar);
|
||||
procedure ApplyInlineProps(CR: PFormCtrlRec; P: PChar);
|
||||
procedure ApplyProp(FR: PFormRec; CR: PFormCtrlRec; Key, Value: PChar);
|
||||
procedure ApplyInlineProps(FR: PFormRec; CR: PFormCtrlRec; P: PChar);
|
||||
|
||||
{ Event wiring }
|
||||
procedure WireAutoEvents(CR: PFormCtrlRec);
|
||||
|
|
@ -109,7 +110,9 @@ type
|
|||
procedure HandleClick(Sender: TObject);
|
||||
procedure HandleRadioButtonClick(Sender: TObject);
|
||||
procedure HandleScrollBarChange(Sender: TObject);
|
||||
procedure HandleMenuItemClick(Sender: TObject);
|
||||
procedure HandleMediaPlayerNotify(Sender: TObject);
|
||||
procedure HandleRadioGroupClick(Sender: TObject);
|
||||
|
||||
{ Outgoing event helpers }
|
||||
procedure SendEvent(FormId, CtrlId: Integer; const EventName: string; const Data: string);
|
||||
|
|
@ -333,8 +336,12 @@ end;
|
|||
|
||||
procedure TFormClient.FreeCtrlRec(CR: PFormCtrlRec);
|
||||
begin
|
||||
{ Menu items are owned by their parent menu and freed automatically }
|
||||
if CR^.Control <> nil then
|
||||
CR^.Control.Free;
|
||||
begin
|
||||
if not (CR^.Control is TMenuItem) then
|
||||
CR^.Control.Free;
|
||||
end;
|
||||
Dispose(CR);
|
||||
end;
|
||||
|
||||
|
|
@ -403,7 +410,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', '');
|
||||
|
|
@ -416,7 +423,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', '');
|
||||
|
|
@ -431,7 +438,7 @@ var
|
|||
Escaped: array[0..4095] of Char;
|
||||
Txt: string;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
Txt := (Sender as TEdit).Text;
|
||||
|
|
@ -449,7 +456,7 @@ var
|
|||
Escaped: array[0..4095] of Char;
|
||||
Txt: string;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
Txt := (Sender as TMemo).Text;
|
||||
|
|
@ -467,7 +474,7 @@ var
|
|||
Escaped: array[0..4095] of Char;
|
||||
Txt: string;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
Txt := (Sender as TComboBox).Text;
|
||||
|
|
@ -486,7 +493,7 @@ var
|
|||
Escaped: array[0..4095] of Char;
|
||||
Txt: string;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
Idx := (Sender as TListBox).ItemIndex;
|
||||
|
|
@ -510,7 +517,7 @@ var
|
|||
Escaped: array[0..4095] of Char;
|
||||
Txt: string;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
Idx := (Sender as TComboBox).ItemIndex;
|
||||
|
|
@ -531,7 +538,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'DblClick', '');
|
||||
|
|
@ -544,7 +551,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Enter', '');
|
||||
|
|
@ -557,7 +564,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Exit', '');
|
||||
|
|
@ -571,7 +578,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'KeyDown', IntToStr(Key));
|
||||
|
|
@ -585,7 +592,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'KeyUp', IntToStr(Key));
|
||||
|
|
@ -600,7 +607,7 @@ var
|
|||
CtrlId: Integer;
|
||||
Btn: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
Btn := Ord(Button);
|
||||
|
|
@ -617,7 +624,7 @@ var
|
|||
CtrlId: Integer;
|
||||
Btn: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
Btn := Ord(Button);
|
||||
|
|
@ -633,7 +640,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'MouseMove',
|
||||
|
|
@ -647,7 +654,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', '');
|
||||
|
|
@ -660,7 +667,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', '');
|
||||
|
|
@ -673,7 +680,7 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Change', IntToStr((Sender as TScrollBar).Position));
|
||||
|
|
@ -686,13 +693,39 @@ var
|
|||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Notify', '');
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleMenuItemClick(Sender: TObject);
|
||||
var
|
||||
Tag: Longint;
|
||||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', '');
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleRadioGroupClick(Sender: TObject);
|
||||
var
|
||||
Tag: Longint;
|
||||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TComponent).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', IntToStr((Sender as TRadioGroup).ItemIndex));
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleFormClose(Sender: TObject;
|
||||
var Action: TCloseAction);
|
||||
var
|
||||
|
|
@ -730,6 +763,10 @@ begin
|
|||
(CR^.Control as TRadioButton).OnClick := HandleRadioButtonClick;
|
||||
ctScrollBar:
|
||||
(CR^.Control as TScrollBar).OnChange := HandleScrollBarChange;
|
||||
ctMenuItem:
|
||||
(CR^.Control as TMenuItem).OnClick := HandleMenuItemClick;
|
||||
ctRadioGroup:
|
||||
(CR^.Control as TRadioGroup).OnClick := HandleRadioGroupClick;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -738,7 +775,8 @@ procedure TFormClient.WireOptEvent(CR: PFormCtrlRec; const EventName: string);
|
|||
begin
|
||||
if EventName = 'DblClick' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnDblClick := HandleDblClick;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnDblClick := HandleDblClick;
|
||||
CR^.Bound := CR^.Bound + [beDblClick];
|
||||
end
|
||||
else if EventName = 'Enter' then
|
||||
|
|
@ -767,17 +805,20 @@ begin
|
|||
end
|
||||
else if EventName = 'MouseDown' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnMouseDown := HandleMouseDown;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnMouseDown := HandleMouseDown;
|
||||
CR^.Bound := CR^.Bound + [beMouseDown];
|
||||
end
|
||||
else if EventName = 'MouseUp' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnMouseUp := HandleMouseUp;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnMouseUp := HandleMouseUp;
|
||||
CR^.Bound := CR^.Bound + [beMouseUp];
|
||||
end
|
||||
else if EventName = 'MouseMove' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnMouseMove := HandleMouseMove;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnMouseMove := HandleMouseMove;
|
||||
CR^.Bound := CR^.Bound + [beMouseMove];
|
||||
end
|
||||
else if EventName = 'Click' then
|
||||
|
|
@ -803,7 +844,8 @@ procedure TFormClient.UnwireOptEvent(CR: PFormCtrlRec; const EventName: string);
|
|||
begin
|
||||
if EventName = 'DblClick' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnDblClick := nil;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnDblClick := nil;
|
||||
CR^.Bound := CR^.Bound - [beDblClick];
|
||||
end
|
||||
else if EventName = 'Enter' then
|
||||
|
|
@ -832,17 +874,20 @@ begin
|
|||
end
|
||||
else if EventName = 'MouseDown' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnMouseDown := nil;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnMouseDown := nil;
|
||||
CR^.Bound := CR^.Bound - [beMouseDown];
|
||||
end
|
||||
else if EventName = 'MouseUp' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnMouseUp := nil;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnMouseUp := nil;
|
||||
CR^.Bound := CR^.Bound - [beMouseUp];
|
||||
end
|
||||
else if EventName = 'MouseMove' then
|
||||
begin
|
||||
(CR^.Control as TControl).OnMouseMove := nil;
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).OnMouseMove := nil;
|
||||
CR^.Bound := CR^.Bound - [beMouseMove];
|
||||
end
|
||||
else if EventName = 'Click' then
|
||||
|
|
@ -866,7 +911,7 @@ end;
|
|||
|
||||
{ ----- Property application ----------------------------------------------- }
|
||||
|
||||
procedure TFormClient.ApplyProp(CR: PFormCtrlRec; Key, Value: PChar);
|
||||
procedure TFormClient.ApplyProp(FR: PFormRec; CR: PFormCtrlRec; Key, Value: PChar);
|
||||
var
|
||||
S: string;
|
||||
Unesc: array[0..4095] of Char;
|
||||
|
|
@ -874,6 +919,7 @@ var
|
|||
Lines: TStringList;
|
||||
P: PChar;
|
||||
Start: PChar;
|
||||
PCR: PFormCtrlRec;
|
||||
begin
|
||||
S := StrPas(Key);
|
||||
|
||||
|
|
@ -887,6 +933,8 @@ begin
|
|||
ctGroupBox: (CR^.Control as TGroupBox).Caption := StrPas(Unesc);
|
||||
ctRadioButton: (CR^.Control as TRadioButton).Caption := StrPas(Unesc);
|
||||
ctPanel: (CR^.Control as TPanel).Caption := StrPas(Unesc);
|
||||
ctMenuItem: (CR^.Control as TMenuItem).Caption := StrPas(Unesc);
|
||||
ctRadioGroup: (CR^.Control as TRadioGroup).Caption := StrPas(Unesc);
|
||||
end;
|
||||
end
|
||||
else if S = 'Text' then
|
||||
|
|
@ -975,6 +1023,26 @@ begin
|
|||
if Start^ <> #0 then
|
||||
(CR^.Control as TComboBox).Items.Add(StrPas(Start));
|
||||
end;
|
||||
ctRadioGroup:
|
||||
begin
|
||||
(CR^.Control as TRadioGroup).Items.Clear;
|
||||
P := Unesc;
|
||||
Start := P;
|
||||
while P^ <> #0 do
|
||||
begin
|
||||
if P^ = #10 then
|
||||
begin
|
||||
P^ := #0;
|
||||
(CR^.Control as TRadioGroup).Items.Add(StrPas(Start));
|
||||
Inc(P);
|
||||
Start := P;
|
||||
end
|
||||
else
|
||||
Inc(P);
|
||||
end;
|
||||
if Start^ <> #0 then
|
||||
(CR^.Control as TRadioGroup).Items.Add(StrPas(Start));
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if S = 'Checked' then
|
||||
|
|
@ -983,17 +1051,25 @@ begin
|
|||
if CR^.CtrlType = ctCheckBox then
|
||||
(CR^.Control as TCheckBox).Checked := (N <> 0)
|
||||
else if CR^.CtrlType = ctRadioButton then
|
||||
(CR^.Control as TRadioButton).Checked := (N <> 0);
|
||||
(CR^.Control as TRadioButton).Checked := (N <> 0)
|
||||
else if CR^.CtrlType = ctMenuItem then
|
||||
(CR^.Control as TMenuItem).Checked := (N <> 0);
|
||||
end
|
||||
else if S = 'Enabled' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 1);
|
||||
CR^.Control.Enabled := (N <> 0);
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).Enabled := (N <> 0)
|
||||
else if CR^.Control is TMenuItem then
|
||||
(CR^.Control as TMenuItem).Enabled := (N <> 0);
|
||||
end
|
||||
else if S = 'Visible' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 1);
|
||||
CR^.Control.Visible := (N <> 0);
|
||||
if CR^.Control is TControl then
|
||||
(CR^.Control as TControl).Visible := (N <> 0)
|
||||
else if CR^.Control is TMenuItem then
|
||||
(CR^.Control as TMenuItem).Visible := (N <> 0);
|
||||
end
|
||||
else if S = 'MaxLength' then
|
||||
begin
|
||||
|
|
@ -1025,8 +1101,9 @@ begin
|
|||
begin
|
||||
N := StrToIntDef(StrPas(Value), -1);
|
||||
case CR^.CtrlType of
|
||||
ctListBox: (CR^.Control as TListBox).ItemIndex := N;
|
||||
ctComboBox: (CR^.Control as TComboBox).ItemIndex := N;
|
||||
ctListBox: (CR^.Control as TListBox).ItemIndex := N;
|
||||
ctComboBox: (CR^.Control as TComboBox).ItemIndex := N;
|
||||
ctRadioGroup: (CR^.Control as TRadioGroup).ItemIndex := N;
|
||||
end;
|
||||
end
|
||||
else if S = 'Stretch' then
|
||||
|
|
@ -1196,11 +1273,45 @@ begin
|
|||
except
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if S = 'Parent' then
|
||||
begin
|
||||
if CR^.CtrlType = ctMenuItem then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
PCR := FindCtrl(FR, N);
|
||||
if PCR <> nil then
|
||||
begin
|
||||
if PCR^.Control is TMenu then
|
||||
(PCR^.Control as TMenu).Items.Add(CR^.Control as TMenuItem)
|
||||
else if PCR^.Control is TMenuItem then
|
||||
(PCR^.Control as TMenuItem).Add(CR^.Control as TMenuItem);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if S = 'Columns' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 1);
|
||||
if CR^.CtrlType = ctRadioGroup then
|
||||
(CR^.Control as TRadioGroup).Columns := N;
|
||||
end
|
||||
else if S = 'ShortCut' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctMenuItem then
|
||||
(CR^.Control as TMenuItem).ShortCut := N;
|
||||
end
|
||||
else if S = 'PopupMenu' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
PCR := FindCtrl(FR, N);
|
||||
if (PCR <> nil) and (PCR^.Control is TPopupMenu) and (CR^.Control is TControl) then
|
||||
(CR^.Control as TControl).PopupMenu := PCR^.Control as TPopupMenu;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.ApplyInlineProps(CR: PFormCtrlRec; P: PChar);
|
||||
procedure TFormClient.ApplyInlineProps(FR: PFormRec; CR: PFormCtrlRec; P: PChar);
|
||||
var
|
||||
Token: array[0..4095] of Char;
|
||||
Key: array[0..63] of Char;
|
||||
|
|
@ -1248,7 +1359,7 @@ begin
|
|||
StrCopy(Value, Eq);
|
||||
end;
|
||||
|
||||
ApplyProp(CR, Key, Value);
|
||||
ApplyProp(FR, CR, Key, Value);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -1286,6 +1397,14 @@ begin
|
|||
Result := ctScrollBar
|
||||
else if S = 'MediaPlayer' then
|
||||
Result := ctMediaPlayer
|
||||
else if S = 'MainMenu' then
|
||||
Result := ctMainMenu
|
||||
else if S = 'PopupMenu' then
|
||||
Result := ctPopupMenu
|
||||
else if S = 'MenuItem' then
|
||||
Result := ctMenuItem
|
||||
else if S = 'RadioGroup' then
|
||||
Result := ctRadioGroup
|
||||
else
|
||||
Result := ctUnknown;
|
||||
end;
|
||||
|
|
@ -1378,7 +1497,7 @@ var
|
|||
FR: PFormRec;
|
||||
CR: PFormCtrlRec;
|
||||
CType: TCtrlTypeE;
|
||||
Ctrl: TControl;
|
||||
Comp: TComponent;
|
||||
begin
|
||||
FormId := ParseInt(P);
|
||||
CtrlId := ParseInt(P);
|
||||
|
|
@ -1398,62 +1517,82 @@ begin
|
|||
Exit;
|
||||
|
||||
{ Create the control }
|
||||
Ctrl := nil;
|
||||
Comp := nil;
|
||||
case CType of
|
||||
ctLabel:
|
||||
begin
|
||||
Ctrl := TLabel.Create(FR^.Form);
|
||||
(Ctrl as TLabel).AutoSize := False;
|
||||
Comp := TLabel.Create(FR^.Form);
|
||||
(Comp as TLabel).AutoSize := False;
|
||||
end;
|
||||
ctEdit:
|
||||
Ctrl := TEdit.Create(FR^.Form);
|
||||
Comp := TEdit.Create(FR^.Form);
|
||||
ctButton:
|
||||
Ctrl := TButton.Create(FR^.Form);
|
||||
Comp := TButton.Create(FR^.Form);
|
||||
ctCheckBox:
|
||||
Ctrl := TCheckBox.Create(FR^.Form);
|
||||
Comp := TCheckBox.Create(FR^.Form);
|
||||
ctListBox:
|
||||
Ctrl := TListBox.Create(FR^.Form);
|
||||
Comp := TListBox.Create(FR^.Form);
|
||||
ctComboBox:
|
||||
Ctrl := TComboBox.Create(FR^.Form);
|
||||
Comp := TComboBox.Create(FR^.Form);
|
||||
ctMemo:
|
||||
Ctrl := TMemo.Create(FR^.Form);
|
||||
Comp := TMemo.Create(FR^.Form);
|
||||
ctImage:
|
||||
begin
|
||||
Ctrl := TImage.Create(FR^.Form);
|
||||
(Ctrl as TImage).AutoSize := False;
|
||||
Comp := TImage.Create(FR^.Form);
|
||||
(Comp as TImage).AutoSize := False;
|
||||
end;
|
||||
ctGroupBox:
|
||||
Ctrl := TGroupBox.Create(FR^.Form);
|
||||
Comp := TGroupBox.Create(FR^.Form);
|
||||
ctRadioButton:
|
||||
Ctrl := TRadioButton.Create(FR^.Form);
|
||||
Comp := TRadioButton.Create(FR^.Form);
|
||||
ctPanel:
|
||||
Ctrl := TPanel.Create(FR^.Form);
|
||||
Comp := TPanel.Create(FR^.Form);
|
||||
ctScrollBar:
|
||||
Ctrl := TScrollBar.Create(FR^.Form);
|
||||
Comp := TScrollBar.Create(FR^.Form);
|
||||
ctMediaPlayer:
|
||||
Ctrl := TMediaPlayer.Create(FR^.Form);
|
||||
Comp := TMediaPlayer.Create(FR^.Form);
|
||||
ctMainMenu:
|
||||
begin
|
||||
Comp := TMainMenu.Create(FR^.Form);
|
||||
FR^.Form.Menu := Comp as TMainMenu;
|
||||
end;
|
||||
ctPopupMenu:
|
||||
Comp := TPopupMenu.Create(FR^.Form);
|
||||
ctMenuItem:
|
||||
Comp := TMenuItem.Create(FR^.Form);
|
||||
ctRadioGroup:
|
||||
Comp := TRadioGroup.Create(FR^.Form);
|
||||
end;
|
||||
|
||||
if Ctrl = nil then
|
||||
if Comp = nil then
|
||||
Exit;
|
||||
|
||||
{ Set parent and geometry }
|
||||
if Ctrl is TWinControl then
|
||||
(Ctrl as TWinControl).Parent := FR^.Form
|
||||
else
|
||||
Ctrl.Parent := FR^.Form;
|
||||
{ Set parent and geometry for visual controls }
|
||||
if Comp is TWinControl then
|
||||
begin
|
||||
(Comp as TWinControl).Parent := FR^.Form;
|
||||
(Comp as TControl).Left := Left;
|
||||
(Comp as TControl).Top := Top;
|
||||
(Comp as TControl).Width := Width;
|
||||
(Comp as TControl).Height := Height;
|
||||
end
|
||||
else if Comp is TControl then
|
||||
begin
|
||||
(Comp as TControl).Parent := FR^.Form;
|
||||
(Comp as TControl).Left := Left;
|
||||
(Comp as TControl).Top := Top;
|
||||
(Comp as TControl).Width := Width;
|
||||
(Comp as TControl).Height := Height;
|
||||
end;
|
||||
{ else: non-visual (menus, menu items) — no parent or geometry }
|
||||
|
||||
Ctrl.Left := Left;
|
||||
Ctrl.Top := Top;
|
||||
Ctrl.Width := Width;
|
||||
Ctrl.Height := Height;
|
||||
Ctrl.Tag := (Longint(FormId) shl 16) or CtrlId;
|
||||
Comp.Tag := (Longint(FormId) shl 16) or CtrlId;
|
||||
|
||||
{ Create control record }
|
||||
New(CR);
|
||||
CR^.CtrlId := CtrlId;
|
||||
CR^.CtrlType := CType;
|
||||
CR^.Control := Ctrl;
|
||||
CR^.Control := Comp;
|
||||
CR^.Bound := [];
|
||||
|
||||
FR^.Ctrls.Add(CR);
|
||||
|
|
@ -1462,7 +1601,7 @@ begin
|
|||
WireAutoEvents(CR);
|
||||
|
||||
{ Apply inline properties }
|
||||
ApplyInlineProps(CR, P);
|
||||
ApplyInlineProps(FR, CR, P);
|
||||
end;
|
||||
|
||||
|
||||
|
|
@ -1484,7 +1623,7 @@ begin
|
|||
if CR = nil then
|
||||
Exit;
|
||||
|
||||
ApplyInlineProps(CR, P);
|
||||
ApplyInlineProps(FR, CR, P);
|
||||
end;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ Event data varies by event type:
|
|||
|
||||
| Event | Data |
|
||||
|-----------|-------------------------------|
|
||||
| Click | (none) |
|
||||
| Click | (none), or `<itemIndex>` (RadioGroup) |
|
||||
| DblClick | (none) |
|
||||
| Change | `"new text"` or `<position>` (ScrollBar) |
|
||||
| Select | `<index> "selected text"` |
|
||||
|
|
@ -101,28 +101,38 @@ Event data varies by event type:
|
|||
| Panel | TPanel | (none) |
|
||||
| ScrollBar | TScrollBar | Change |
|
||||
| MediaPlayer | TMediaPlayer | (none) |
|
||||
| MainMenu | TMainMenu | (none) |
|
||||
| PopupMenu | TPopupMenu | (none) |
|
||||
| MenuItem | TMenuItem | Click |
|
||||
| RadioGroup | TRadioGroup | Click |
|
||||
|
||||
MainMenu and PopupMenu use `0 0 0 0` geometry (non-visual). MenuItem
|
||||
uses `0 0 0 0` geometry and requires a `Parent` property to specify its
|
||||
parent menu or menu item. One MainMenu per form (auto-attached).
|
||||
PopupMenu is associated with any control via the `PopupMenu` property.
|
||||
|
||||
GroupBox and Panel are cosmetic containers (flat parent model — no child
|
||||
containment in the protocol). RadioButtons are all in one group per form.
|
||||
|
||||
Opt-in events (require EVENT.BIND): Click (Image, GroupBox, Panel),
|
||||
Notify (MediaPlayer), DblClick, KeyDown, KeyUp, Enter, Exit,
|
||||
MouseDown, MouseUp, MouseMove.
|
||||
MouseDown, MouseUp, MouseMove. Menu and RadioGroup components do
|
||||
not support opt-in events.
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Applies To | Value Format |
|
||||
|-------------|---------------------------------------------|-------------------------------------------|
|
||||
| Caption | Label, Button, CheckBox, GroupBox, RadioButton, Panel | Quoted string |
|
||||
| Caption | Label, Button, CheckBox, GroupBox, RadioButton, Panel, MenuItem, RadioGroup | Quoted string |
|
||||
| Text | Edit, ComboBox, Memo | Quoted string (`\n` for line breaks) |
|
||||
| Items | ListBox, ComboBox | Quoted string (`\n`-delimited) |
|
||||
| Checked | CheckBox, RadioButton | 0 or 1 |
|
||||
| Items | ListBox, ComboBox, RadioGroup | Quoted string (`\n`-delimited) |
|
||||
| Checked | CheckBox, RadioButton, MenuItem | 0 or 1 |
|
||||
| Enabled | All | 0 or 1 |
|
||||
| Visible | All | 0 or 1 |
|
||||
| MaxLength | Edit | Integer |
|
||||
| ReadOnly | Edit, Memo | 0 or 1 |
|
||||
| ScrollBars | Memo | 0-3 (ssNone..ssBoth) |
|
||||
| ItemIndex | ListBox, ComboBox | Integer (-1 = none) |
|
||||
| ItemIndex | ListBox, ComboBox, RadioGroup | Integer (-1 = none) |
|
||||
| TabOrder | All windowed controls | Integer |
|
||||
| Stretch | Image | 0 or 1 |
|
||||
| Center | Image | 0 or 1 |
|
||||
|
|
@ -141,6 +151,10 @@ MouseDown, MouseUp, MouseMove.
|
|||
| DeviceType | MediaPlayer | Quoted string (e.g., `dtWaveAudio`) |
|
||||
| AutoOpen | MediaPlayer | 0 or 1 |
|
||||
| Command | MediaPlayer | Quoted string (pseudo-property, see below)|
|
||||
| Parent | MenuItem | Integer (ctrlId of parent menu/item) |
|
||||
| Columns | RadioGroup | Integer (number of columns) |
|
||||
| ShortCut | MenuItem | Integer (Delphi ShortCut value) |
|
||||
| PopupMenu | Any TControl | Integer (ctrlId of PopupMenu) |
|
||||
|
||||
File path properties (Picture, FileName) are resolved relative to the
|
||||
client's `BasePath` setting. Subdirectories are allowed (e.g.,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue