Add Image, GroupBox, RadioButton, Panel, ScrollBar, and MediaPlayer control types
Extends the remote forms system from 7 to 13 control types across dfm2form converter, formcli client engine, and documentation. Image and MediaPlayer support file paths resolved via BasePath. MediaPlayer adds a Command pseudo-property for method calls. RadioButton auto-wires Click; ScrollBar auto-wires Change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e45d72588a
commit
2d5ed2a3b1
4 changed files with 825 additions and 62 deletions
195
forms/README.md
195
forms/README.md
|
|
@ -308,7 +308,7 @@ messages are available, dispatching each command as it arrives.
|
|||
## Supported Controls
|
||||
|
||||
| Type | Delphi Class | Description |
|
||||
|------------|-------------|--------------------------------|
|
||||
|---------------|--------------|--------------------------------|
|
||||
| `Label` | TLabel | Static text label |
|
||||
| `Edit` | TEdit | Single-line text input |
|
||||
| `Button` | TButton | Push button |
|
||||
|
|
@ -316,6 +316,12 @@ messages are available, dispatching each command as it arrives.
|
|||
| `ListBox` | TListBox | Scrollable list of items |
|
||||
| `ComboBox` | TComboBox | Drop-down list with text input |
|
||||
| `Memo` | TMemo | Multi-line text input |
|
||||
| `Image` | TImage | Bitmap image display (BMP only)|
|
||||
| `GroupBox` | TGroupBox | Cosmetic grouping frame |
|
||||
| `RadioButton` | TRadioButton | Radio button (one group/form) |
|
||||
| `Panel` | TPanel | Cosmetic container panel |
|
||||
| `ScrollBar` | TScrollBar | Horizontal or vertical scrollbar|
|
||||
| `MediaPlayer` | TMediaPlayer | MCI media player control |
|
||||
|
||||
### Creating Controls
|
||||
|
||||
|
|
@ -353,11 +359,12 @@ CTRL.SET 1 3 Text="world" Enabled=0
|
|||
|
||||
### Caption
|
||||
|
||||
- **Applies to:** Label, Button, CheckBox
|
||||
- **Applies to:** Label, Button, CheckBox, GroupBox, RadioButton, Panel
|
||||
- **Format:** Quoted string
|
||||
- **Example:** `Caption="Submit"`
|
||||
|
||||
The display text for labels, buttons, and check boxes.
|
||||
The display text for labels, buttons, check boxes, group boxes, radio
|
||||
buttons, and panels.
|
||||
|
||||
### Text
|
||||
|
||||
|
|
@ -383,7 +390,7 @@ new items are added.
|
|||
|
||||
### Checked
|
||||
|
||||
- **Applies to:** CheckBox
|
||||
- **Applies to:** CheckBox, RadioButton
|
||||
- **Format:** `0` (unchecked) or `1` (checked)
|
||||
- **Example:** `Checked=1`
|
||||
|
||||
|
|
@ -432,12 +439,168 @@ Maximum number of characters the user can type.
|
|||
|
||||
### TabOrder
|
||||
|
||||
- **Applies to:** All windowed controls (all types except Label)
|
||||
- **Applies to:** All windowed controls (all types except Label and Image)
|
||||
- **Format:** Integer
|
||||
- **Example:** `TabOrder=3`
|
||||
|
||||
Controls the keyboard tab navigation order within the form.
|
||||
|
||||
### Stretch
|
||||
|
||||
- **Applies to:** Image
|
||||
- **Format:** `0` (off) or `1` (on)
|
||||
- **Example:** `Stretch=1`
|
||||
|
||||
When enabled, the image is stretched to fill the control bounds.
|
||||
|
||||
### Center
|
||||
|
||||
- **Applies to:** Image
|
||||
- **Format:** `0` (off) or `1` (on)
|
||||
- **Example:** `Center=1`
|
||||
|
||||
When enabled, the image is centered within the control bounds.
|
||||
|
||||
### Transparent
|
||||
|
||||
- **Applies to:** Image
|
||||
- **Format:** `0` (off) or `1` (on)
|
||||
- **Example:** `Transparent=1`
|
||||
|
||||
When enabled, the image background is transparent.
|
||||
|
||||
### Picture
|
||||
|
||||
- **Applies to:** Image
|
||||
- **Format:** Quoted string (filename)
|
||||
- **Example:** `Picture="images\logo.bmp"`
|
||||
|
||||
BMP file to display. The path is resolved relative to the client's
|
||||
`BasePath` setting. Subdirectories are allowed.
|
||||
|
||||
**Note:** `dfm2form` does not emit Picture from DFM files because
|
||||
image data is stored as a binary blob in the DFM. Set Picture at
|
||||
runtime via `CTRL.SET` or by manually editing the `.form` file.
|
||||
|
||||
### BevelOuter
|
||||
|
||||
- **Applies to:** Panel
|
||||
- **Format:** Integer 0-2
|
||||
- **Values:**
|
||||
- `0` — bvNone
|
||||
- `1` — bvLowered
|
||||
- `2` — bvRaised
|
||||
- **Example:** `BevelOuter=2`
|
||||
|
||||
### BevelInner
|
||||
|
||||
- **Applies to:** Panel
|
||||
- **Format:** Integer 0-2
|
||||
- **Values:**
|
||||
- `0` — bvNone
|
||||
- `1` — bvLowered
|
||||
- `2` — bvRaised
|
||||
- **Example:** `BevelInner=1`
|
||||
|
||||
### BorderStyle (Panel)
|
||||
|
||||
- **Applies to:** Panel
|
||||
- **Format:** `0` (bsNone) or `1` (bsSingle)
|
||||
- **Example:** `BorderStyle=1`
|
||||
|
||||
### Kind
|
||||
|
||||
- **Applies to:** ScrollBar
|
||||
- **Format:** `0` (sbHorizontal) or `1` (sbVertical)
|
||||
- **Example:** `Kind=1`
|
||||
|
||||
### Min
|
||||
|
||||
- **Applies to:** ScrollBar
|
||||
- **Format:** Integer
|
||||
- **Example:** `Min=0`
|
||||
|
||||
### Max
|
||||
|
||||
- **Applies to:** ScrollBar
|
||||
- **Format:** Integer
|
||||
- **Example:** `Max=100`
|
||||
|
||||
### Position
|
||||
|
||||
- **Applies to:** ScrollBar
|
||||
- **Format:** Integer
|
||||
- **Example:** `Position=50`
|
||||
|
||||
### LargeChange
|
||||
|
||||
- **Applies to:** ScrollBar
|
||||
- **Format:** Integer
|
||||
- **Example:** `LargeChange=10`
|
||||
|
||||
The amount the position changes when the user clicks the scroll bar
|
||||
track.
|
||||
|
||||
### SmallChange
|
||||
|
||||
- **Applies to:** ScrollBar
|
||||
- **Format:** Integer
|
||||
- **Example:** `SmallChange=1`
|
||||
|
||||
The amount the position changes when the user clicks an arrow button.
|
||||
|
||||
### FileName
|
||||
|
||||
- **Applies to:** MediaPlayer
|
||||
- **Format:** Quoted string (file path)
|
||||
- **Example:** `FileName="sounds\intro.wav"`
|
||||
|
||||
Media file to open. The path is resolved relative to the client's
|
||||
`BasePath` setting.
|
||||
|
||||
### DeviceType
|
||||
|
||||
- **Applies to:** MediaPlayer
|
||||
- **Format:** Quoted string
|
||||
- **Example:** `DeviceType="dtWaveAudio"`
|
||||
|
||||
MCI device type. Valid values: `dtAutoSelect`, `dtAVIVideo`,
|
||||
`dtCDAudio`, `dtDAT`, `dtDigitalVideo`, `dtMMMovie`, `dtOther`,
|
||||
`dtOverlay`, `dtScanner`, `dtSequencer`, `dtVCR`, `dtVideodisc`,
|
||||
`dtWaveAudio`.
|
||||
|
||||
### AutoOpen
|
||||
|
||||
- **Applies to:** MediaPlayer
|
||||
- **Format:** `0` (off) or `1` (on)
|
||||
- **Example:** `AutoOpen=1`
|
||||
|
||||
When enabled, the media file is opened automatically when FileName
|
||||
is set.
|
||||
|
||||
### Command
|
||||
|
||||
- **Applies to:** MediaPlayer
|
||||
- **Format:** Quoted string
|
||||
- **Example:** `Command="Play"`
|
||||
|
||||
Pseudo-property that triggers a method call instead of setting a
|
||||
value. Valid commands: `Open`, `Play`, `Stop`, `Close`, `Pause`,
|
||||
`Resume`, `Rewind`, `Next`, `Previous`.
|
||||
|
||||
### BasePath
|
||||
|
||||
`BasePath` is a property on `TFormClient` (not a protocol property).
|
||||
Set it before loading forms to specify where file-based properties
|
||||
(Picture, FileName) resolve relative paths. Example:
|
||||
|
||||
```pascal
|
||||
Client.BasePath := 'C:\MYAPP';
|
||||
```
|
||||
|
||||
A Picture value of `"images\logo.bmp"` then resolves to
|
||||
`C:\MYAPP\images\logo.bmp`.
|
||||
|
||||
## Events
|
||||
|
||||
### Auto-wired Events
|
||||
|
|
@ -449,8 +612,10 @@ No `EVENT.BIND` command is needed.
|
|||
|-------------|---------|-------------------------------|
|
||||
| Button | Click | (none) |
|
||||
| CheckBox | Click | (none) |
|
||||
| RadioButton | Click | (none) |
|
||||
| Edit | Change | `"new text"` |
|
||||
| Memo | Change | `"new text"` |
|
||||
| ScrollBar | Change | `<position>` |
|
||||
| ListBox | Select | `<index> "selected text"` |
|
||||
| ComboBox | Select | `<index> "selected text"` |
|
||||
| ComboBox | Change | `"new text"` |
|
||||
|
|
@ -461,8 +626,10 @@ These events require an explicit `EVENT.BIND` command before the
|
|||
client will send them. Use `EVENT.UNBIND` to disconnect.
|
||||
|
||||
| Event | Data Sent | Notes |
|
||||
|-----------|-----------------------|---------------------------------|
|
||||
|-----------|-----------------------|-----------------------------------|
|
||||
| Click | (none) | Image, GroupBox, Panel only |
|
||||
| DblClick | (none) | Double-click on any control |
|
||||
| Notify | (none) | MediaPlayer playback notification |
|
||||
| KeyDown | `<vkCode>` | Windows virtual key code |
|
||||
| KeyUp | `<vkCode>` | Windows virtual key code |
|
||||
| Enter | (none) | Control received focus |
|
||||
|
|
@ -527,6 +694,22 @@ any protocol or application code.
|
|||
- Transport handles framing — the protocol layer never sees
|
||||
delimiters.
|
||||
|
||||
## 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).
|
||||
- **Image format:** Only BMP files are supported for the Picture
|
||||
property.
|
||||
- **dfm2form and Picture:** The converter cannot extract image
|
||||
filenames from DFM files (image data is stored as a binary blob).
|
||||
Set Picture at runtime via `CTRL.SET` or by manually editing the
|
||||
`.form` file.
|
||||
- **GroupBox and Panel:** These are cosmetic-only containers. The
|
||||
protocol has no child containment — all controls are direct
|
||||
children of the form.
|
||||
|
||||
## Limits
|
||||
|
||||
| Limit | Value |
|
||||
|
|
|
|||
253
forms/dfm2form.c
253
forms/dfm2form.c
|
|
@ -26,7 +26,13 @@ typedef enum {
|
|||
ctCheckBox,
|
||||
ctListBox,
|
||||
ctComboBox,
|
||||
ctMemo
|
||||
ctMemo,
|
||||
ctImage,
|
||||
ctGroupBox,
|
||||
ctRadioButton,
|
||||
ctPanel,
|
||||
ctScrollBar,
|
||||
ctMediaPlayer
|
||||
} CtrlTypeE;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -67,6 +73,36 @@ typedef struct {
|
|||
bool hasOnKeyUp;
|
||||
bool hasOnMouseDown;
|
||||
bool hasOnMouseUp;
|
||||
int32_t stretch;
|
||||
int32_t center;
|
||||
int32_t transparent;
|
||||
int32_t bevelOuter;
|
||||
int32_t bevelInner;
|
||||
int32_t borderStyle;
|
||||
int32_t kind;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t position;
|
||||
int32_t largeChange;
|
||||
int32_t smallChange;
|
||||
int32_t autoOpen;
|
||||
char fileName[256];
|
||||
char deviceType[64];
|
||||
bool hasStretch;
|
||||
bool hasCenter;
|
||||
bool hasTransparent;
|
||||
bool hasBevelOuter;
|
||||
bool hasBevelInner;
|
||||
bool hasBorderStyle;
|
||||
bool hasKind;
|
||||
bool hasMin;
|
||||
bool hasMax;
|
||||
bool hasPosition;
|
||||
bool hasLargeChange;
|
||||
bool hasSmallChange;
|
||||
bool hasAutoOpen;
|
||||
bool hasFileName;
|
||||
bool hasDeviceType;
|
||||
} DfmCtrlT;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -306,6 +342,24 @@ static CtrlTypeE mapClassName(const char *className) {
|
|||
if (stricmp_local(className, "TMemo") == 0) {
|
||||
return ctMemo;
|
||||
}
|
||||
if (stricmp_local(className, "TImage") == 0) {
|
||||
return ctImage;
|
||||
}
|
||||
if (stricmp_local(className, "TGroupBox") == 0) {
|
||||
return ctGroupBox;
|
||||
}
|
||||
if (stricmp_local(className, "TRadioButton") == 0) {
|
||||
return ctRadioButton;
|
||||
}
|
||||
if (stricmp_local(className, "TPanel") == 0) {
|
||||
return ctPanel;
|
||||
}
|
||||
if (stricmp_local(className, "TScrollBar") == 0) {
|
||||
return ctScrollBar;
|
||||
}
|
||||
if (stricmp_local(className, "TMediaPlayer") == 0) {
|
||||
return ctMediaPlayer;
|
||||
}
|
||||
return ctUnknown;
|
||||
}
|
||||
|
||||
|
|
@ -320,6 +374,9 @@ static void initCtrl(DfmCtrlT *ctrl) {
|
|||
ctrl->visible = 1;
|
||||
ctrl->itemIndex = -1;
|
||||
ctrl->tabOrder = -1;
|
||||
ctrl->bevelOuter = 1; // bvRaised
|
||||
ctrl->largeChange = 1;
|
||||
ctrl->smallChange = 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -594,6 +651,145 @@ static void parseProperties(const uint8_t *data, int32_t size, int32_t *pos, Dfm
|
|||
if (!isForm) {
|
||||
ctrl->hasOnMouseUp = true;
|
||||
}
|
||||
} else if (!isForm && stricmp_local(propName, "Stretch") == 0) {
|
||||
if (tag == vaTrue) {
|
||||
ctrl->stretch = 1;
|
||||
} else if (tag == vaFalse) {
|
||||
ctrl->stretch = 0;
|
||||
} else {
|
||||
ctrl->stretch = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasStretch = true;
|
||||
} else if (!isForm && stricmp_local(propName, "Center") == 0) {
|
||||
if (tag == vaTrue) {
|
||||
ctrl->center = 1;
|
||||
} else if (tag == vaFalse) {
|
||||
ctrl->center = 0;
|
||||
} else {
|
||||
ctrl->center = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasCenter = true;
|
||||
} else if (!isForm && stricmp_local(propName, "Transparent") == 0) {
|
||||
if (tag == vaTrue) {
|
||||
ctrl->transparent = 1;
|
||||
} else if (tag == vaFalse) {
|
||||
ctrl->transparent = 0;
|
||||
} else {
|
||||
ctrl->transparent = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasTransparent = true;
|
||||
} else if (!isForm && stricmp_local(propName, "BevelOuter") == 0) {
|
||||
if (tag == vaIdent) {
|
||||
readStr(data, size, pos, strBuf, sizeof(strBuf));
|
||||
if (stricmp_local(strBuf, "bvNone") == 0) {
|
||||
ctrl->bevelOuter = 0;
|
||||
} else if (stricmp_local(strBuf, "bvLowered") == 0) {
|
||||
ctrl->bevelOuter = 1;
|
||||
} else if (stricmp_local(strBuf, "bvRaised") == 0) {
|
||||
ctrl->bevelOuter = 2;
|
||||
} else {
|
||||
ctrl->bevelOuter = 0;
|
||||
}
|
||||
} else {
|
||||
ctrl->bevelOuter = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasBevelOuter = true;
|
||||
} else if (!isForm && stricmp_local(propName, "BevelInner") == 0) {
|
||||
if (tag == vaIdent) {
|
||||
readStr(data, size, pos, strBuf, sizeof(strBuf));
|
||||
if (stricmp_local(strBuf, "bvNone") == 0) {
|
||||
ctrl->bevelInner = 0;
|
||||
} else if (stricmp_local(strBuf, "bvLowered") == 0) {
|
||||
ctrl->bevelInner = 1;
|
||||
} else if (stricmp_local(strBuf, "bvRaised") == 0) {
|
||||
ctrl->bevelInner = 2;
|
||||
} else {
|
||||
ctrl->bevelInner = 0;
|
||||
}
|
||||
} else {
|
||||
ctrl->bevelInner = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasBevelInner = true;
|
||||
} else if (!isForm && stricmp_local(propName, "BorderStyle") == 0) {
|
||||
if (tag == vaIdent) {
|
||||
readStr(data, size, pos, strBuf, sizeof(strBuf));
|
||||
if (stricmp_local(strBuf, "bsNone") == 0) {
|
||||
ctrl->borderStyle = 0;
|
||||
} else if (stricmp_local(strBuf, "bsSingle") == 0) {
|
||||
ctrl->borderStyle = 1;
|
||||
} else {
|
||||
ctrl->borderStyle = 0;
|
||||
}
|
||||
} else {
|
||||
ctrl->borderStyle = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasBorderStyle = true;
|
||||
} else if (!isForm && stricmp_local(propName, "Kind") == 0) {
|
||||
if (tag == vaIdent) {
|
||||
readStr(data, size, pos, strBuf, sizeof(strBuf));
|
||||
if (stricmp_local(strBuf, "sbHorizontal") == 0) {
|
||||
ctrl->kind = 0;
|
||||
} else if (stricmp_local(strBuf, "sbVertical") == 0) {
|
||||
ctrl->kind = 1;
|
||||
} else {
|
||||
ctrl->kind = 0;
|
||||
}
|
||||
} else {
|
||||
ctrl->kind = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasKind = true;
|
||||
} else if (!isForm && stricmp_local(propName, "Min") == 0) {
|
||||
ctrl->min = readIntValue(data, size, pos, tag);
|
||||
ctrl->hasMin = true;
|
||||
} else if (!isForm && stricmp_local(propName, "Max") == 0) {
|
||||
ctrl->max = readIntValue(data, size, pos, tag);
|
||||
ctrl->hasMax = true;
|
||||
} else if (!isForm && stricmp_local(propName, "Position") == 0) {
|
||||
ctrl->position = readIntValue(data, size, pos, tag);
|
||||
ctrl->hasPosition = true;
|
||||
} else if (!isForm && stricmp_local(propName, "LargeChange") == 0) {
|
||||
ctrl->largeChange = readIntValue(data, size, pos, tag);
|
||||
ctrl->hasLargeChange = true;
|
||||
} else if (!isForm && stricmp_local(propName, "SmallChange") == 0) {
|
||||
ctrl->smallChange = readIntValue(data, size, pos, tag);
|
||||
ctrl->hasSmallChange = true;
|
||||
} else if (!isForm && stricmp_local(propName, "FileName") == 0) {
|
||||
if (tag == vaString) {
|
||||
readStr(data, size, pos, ctrl->fileName, sizeof(ctrl->fileName));
|
||||
} else if (tag == vaLString) {
|
||||
int32_t len = readInt32LE(data, size, pos);
|
||||
int32_t copyLen = (len < (int32_t)sizeof(ctrl->fileName) - 1) ? len : (int32_t)sizeof(ctrl->fileName) - 1;
|
||||
memcpy(ctrl->fileName, data + *pos, copyLen);
|
||||
ctrl->fileName[copyLen] = '\0';
|
||||
*pos += len;
|
||||
} else {
|
||||
skipValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasFileName = true;
|
||||
} else if (!isForm && stricmp_local(propName, "DeviceType") == 0) {
|
||||
if (tag == vaIdent) {
|
||||
readStr(data, size, pos, ctrl->deviceType, sizeof(ctrl->deviceType));
|
||||
} else if (tag == vaString) {
|
||||
readStr(data, size, pos, ctrl->deviceType, sizeof(ctrl->deviceType));
|
||||
} else if (tag == vaLString) {
|
||||
int32_t len = readInt32LE(data, size, pos);
|
||||
int32_t copyLen = (len < (int32_t)sizeof(ctrl->deviceType) - 1) ? len : (int32_t)sizeof(ctrl->deviceType) - 1;
|
||||
memcpy(ctrl->deviceType, data + *pos, copyLen);
|
||||
ctrl->deviceType[copyLen] = '\0';
|
||||
*pos += len;
|
||||
} else {
|
||||
skipValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasDeviceType = true;
|
||||
} else if (!isForm && stricmp_local(propName, "AutoOpen") == 0) {
|
||||
if (tag == vaTrue) {
|
||||
ctrl->autoOpen = 1;
|
||||
} else if (tag == vaFalse) {
|
||||
ctrl->autoOpen = 0;
|
||||
} else {
|
||||
ctrl->autoOpen = readIntValue(data, size, pos, tag);
|
||||
}
|
||||
ctrl->hasAutoOpen = true;
|
||||
} else {
|
||||
skipValue(data, size, pos, tag);
|
||||
}
|
||||
|
|
@ -733,7 +929,9 @@ static void escapeStr(const char *src, char *dst, int32_t dstSize) {
|
|||
static void emitCtrl(FILE *out, int32_t formId, int32_t ctrlId, DfmCtrlT *ctrl) {
|
||||
static const char *typeNames[] = {
|
||||
"Unknown", "Label", "Edit", "Button",
|
||||
"CheckBox", "ListBox", "ComboBox", "Memo"
|
||||
"CheckBox", "ListBox", "ComboBox", "Memo",
|
||||
"Image", "GroupBox", "RadioButton", "Panel",
|
||||
"ScrollBar", "MediaPlayer"
|
||||
};
|
||||
char escaped[8192];
|
||||
|
||||
|
|
@ -778,6 +976,53 @@ static void emitCtrl(FILE *out, int32_t formId, int32_t ctrlId, DfmCtrlT *ctrl)
|
|||
if (ctrl->hasItemIndex && ctrl->itemIndex >= 0) {
|
||||
fprintf(out, " ItemIndex=%d", ctrl->itemIndex);
|
||||
}
|
||||
if (ctrl->hasStretch && ctrl->stretch) {
|
||||
fprintf(out, " Stretch=1");
|
||||
}
|
||||
if (ctrl->hasCenter && ctrl->center) {
|
||||
fprintf(out, " Center=1");
|
||||
}
|
||||
if (ctrl->hasTransparent && ctrl->transparent) {
|
||||
fprintf(out, " Transparent=1");
|
||||
}
|
||||
if (ctrl->hasBevelOuter) {
|
||||
fprintf(out, " BevelOuter=%d", ctrl->bevelOuter);
|
||||
}
|
||||
if (ctrl->hasBevelInner && ctrl->bevelInner != 0) {
|
||||
fprintf(out, " BevelInner=%d", ctrl->bevelInner);
|
||||
}
|
||||
if (ctrl->hasBorderStyle && ctrl->borderStyle != 0) {
|
||||
fprintf(out, " BorderStyle=%d", ctrl->borderStyle);
|
||||
}
|
||||
if (ctrl->hasKind && ctrl->kind != 0) {
|
||||
fprintf(out, " Kind=%d", ctrl->kind);
|
||||
}
|
||||
if (ctrl->hasMin) {
|
||||
fprintf(out, " Min=%d", ctrl->min);
|
||||
}
|
||||
if (ctrl->hasMax) {
|
||||
fprintf(out, " Max=%d", ctrl->max);
|
||||
}
|
||||
if (ctrl->hasPosition && ctrl->position != 0) {
|
||||
fprintf(out, " Position=%d", ctrl->position);
|
||||
}
|
||||
if (ctrl->hasLargeChange && ctrl->largeChange != 1) {
|
||||
fprintf(out, " LargeChange=%d", ctrl->largeChange);
|
||||
}
|
||||
if (ctrl->hasSmallChange && ctrl->smallChange != 1) {
|
||||
fprintf(out, " SmallChange=%d", ctrl->smallChange);
|
||||
}
|
||||
if (ctrl->hasFileName) {
|
||||
escapeStr(ctrl->fileName, escaped, sizeof(escaped));
|
||||
fprintf(out, " FileName=\"%s\"", escaped);
|
||||
}
|
||||
if (ctrl->hasDeviceType) {
|
||||
escapeStr(ctrl->deviceType, escaped, sizeof(escaped));
|
||||
fprintf(out, " DeviceType=\"%s\"", escaped);
|
||||
}
|
||||
if (ctrl->hasAutoOpen && ctrl->autoOpen) {
|
||||
fprintf(out, " AutoOpen=1");
|
||||
}
|
||||
|
||||
fprintf(out, "\n");
|
||||
|
||||
|
|
@ -785,8 +1030,8 @@ 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);
|
||||
bool autoChange = (ctrl->type == ctEdit || ctrl->type == ctComboBox || ctrl->type == ctMemo);
|
||||
bool autoClick = (ctrl->type == ctButton || ctrl->type == ctCheckBox || ctrl->type == ctRadioButton);
|
||||
bool autoChange = (ctrl->type == ctEdit || ctrl->type == ctComboBox || ctrl->type == ctMemo || ctrl->type == ctScrollBar);
|
||||
bool autoSelect = (ctrl->type == ctListBox || ctrl->type == ctComboBox);
|
||||
|
||||
if (ctrl->hasOnClick && !autoClick) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ unit FormCli;
|
|||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Classes, Controls, Forms, StdCtrls, WinTypes, WinProcs;
|
||||
SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, MPlayer, WinTypes, WinProcs;
|
||||
|
||||
const
|
||||
MaxMsgLen = 4096;
|
||||
|
|
@ -27,11 +27,14 @@ type
|
|||
end;
|
||||
|
||||
TCtrlTypeE = (ctUnknown, ctLabel, ctEdit, ctButton,
|
||||
ctCheckBox, ctListBox, ctComboBox, ctMemo);
|
||||
ctCheckBox, ctListBox, ctComboBox, ctMemo,
|
||||
ctImage, ctGroupBox, ctRadioButton, ctPanel,
|
||||
ctScrollBar, ctMediaPlayer);
|
||||
|
||||
{ Bound event flags }
|
||||
TBoundEvent = (beDblClick, beKeyDown, beKeyUp,
|
||||
beEnter, beExit, beMouseDown, beMouseUp, beMouseMove);
|
||||
beEnter, beExit, beMouseDown, beMouseUp, beMouseMove,
|
||||
beClick, beNotify);
|
||||
TBoundEvents = set of TBoundEvent;
|
||||
|
||||
{ Per-control record }
|
||||
|
|
@ -58,6 +61,7 @@ type
|
|||
FForms: TList; { of PFormRec }
|
||||
FMsgBuf: PChar; { read buffer }
|
||||
FTmpBuf: PChar; { scratch buffer for outgoing messages }
|
||||
FBasePath: string;
|
||||
|
||||
{ Command dispatch }
|
||||
procedure DoCtrlCreate(P: PChar);
|
||||
|
|
@ -102,6 +106,10 @@ type
|
|||
procedure HandleMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
||||
procedure HandleMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
||||
procedure HandleMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
||||
procedure HandleClick(Sender: TObject);
|
||||
procedure HandleRadioButtonClick(Sender: TObject);
|
||||
procedure HandleScrollBarChange(Sender: TObject);
|
||||
procedure HandleMediaPlayerNotify(Sender: TObject);
|
||||
|
||||
{ Outgoing event helpers }
|
||||
procedure SendEvent(FormId, CtrlId: Integer; const EventName: string; const Data: string);
|
||||
|
|
@ -116,6 +124,7 @@ type
|
|||
destructor Destroy; override;
|
||||
procedure ProcessMessages;
|
||||
property Transport: TFormTransport read FTransport;
|
||||
property BasePath: string read FBasePath write FBasePath;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
@ -632,6 +641,58 @@ begin
|
|||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleClick(Sender: TObject);
|
||||
var
|
||||
Tag: Longint;
|
||||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', '');
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleRadioButtonClick(Sender: TObject);
|
||||
var
|
||||
Tag: Longint;
|
||||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Click', '');
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleScrollBarChange(Sender: TObject);
|
||||
var
|
||||
Tag: Longint;
|
||||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Change', IntToStr((Sender as TScrollBar).Position));
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleMediaPlayerNotify(Sender: TObject);
|
||||
var
|
||||
Tag: Longint;
|
||||
FormId: Integer;
|
||||
CtrlId: Integer;
|
||||
begin
|
||||
Tag := (Sender as TControl).Tag;
|
||||
FormId := Tag shr 16;
|
||||
CtrlId := Tag and $FFFF;
|
||||
SendEvent(FormId, CtrlId, 'Notify', '');
|
||||
end;
|
||||
|
||||
|
||||
procedure TFormClient.HandleFormClose(Sender: TObject;
|
||||
var Action: TCloseAction);
|
||||
var
|
||||
|
|
@ -665,6 +726,10 @@ begin
|
|||
(CR^.Control as TComboBox).OnClick := HandleComboBoxSelect;
|
||||
(CR^.Control as TComboBox).OnChange := HandleComboBoxChange;
|
||||
end;
|
||||
ctRadioButton:
|
||||
(CR^.Control as TRadioButton).OnClick := HandleRadioButtonClick;
|
||||
ctScrollBar:
|
||||
(CR^.Control as TScrollBar).OnChange := HandleScrollBarChange;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -714,6 +779,22 @@ begin
|
|||
begin
|
||||
(CR^.Control as TControl).OnMouseMove := HandleMouseMove;
|
||||
CR^.Bound := CR^.Bound + [beMouseMove];
|
||||
end
|
||||
else if EventName = 'Click' then
|
||||
begin
|
||||
if CR^.Control is TImage then
|
||||
(CR^.Control as TImage).OnClick := HandleClick
|
||||
else if CR^.Control is TPanel then
|
||||
(CR^.Control as TPanel).OnClick := HandleClick
|
||||
else if CR^.Control is TGroupBox then
|
||||
(CR^.Control as TGroupBox).OnClick := HandleClick;
|
||||
CR^.Bound := CR^.Bound + [beClick];
|
||||
end
|
||||
else if EventName = 'Notify' then
|
||||
begin
|
||||
if CR^.Control is TMediaPlayer then
|
||||
(CR^.Control as TMediaPlayer).OnNotify := HandleMediaPlayerNotify;
|
||||
CR^.Bound := CR^.Bound + [beNotify];
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -763,6 +844,22 @@ begin
|
|||
begin
|
||||
(CR^.Control as TControl).OnMouseMove := nil;
|
||||
CR^.Bound := CR^.Bound - [beMouseMove];
|
||||
end
|
||||
else if EventName = 'Click' then
|
||||
begin
|
||||
if CR^.Control is TImage then
|
||||
(CR^.Control as TImage).OnClick := nil
|
||||
else if CR^.Control is TPanel then
|
||||
(CR^.Control as TPanel).OnClick := nil
|
||||
else if CR^.Control is TGroupBox then
|
||||
(CR^.Control as TGroupBox).OnClick := nil;
|
||||
CR^.Bound := CR^.Bound - [beClick];
|
||||
end
|
||||
else if EventName = 'Notify' then
|
||||
begin
|
||||
if CR^.Control is TMediaPlayer then
|
||||
(CR^.Control as TMediaPlayer).OnNotify := nil;
|
||||
CR^.Bound := CR^.Bound - [beNotify];
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -787,6 +884,9 @@ begin
|
|||
ctLabel: (CR^.Control as TLabel).Caption := StrPas(Unesc);
|
||||
ctButton: (CR^.Control as TButton).Caption := StrPas(Unesc);
|
||||
ctCheckBox: (CR^.Control as TCheckBox).Caption := StrPas(Unesc);
|
||||
ctGroupBox: (CR^.Control as TGroupBox).Caption := StrPas(Unesc);
|
||||
ctRadioButton: (CR^.Control as TRadioButton).Caption := StrPas(Unesc);
|
||||
ctPanel: (CR^.Control as TPanel).Caption := StrPas(Unesc);
|
||||
end;
|
||||
end
|
||||
else if S = 'Text' then
|
||||
|
|
@ -881,7 +981,9 @@ begin
|
|||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctCheckBox then
|
||||
(CR^.Control as TCheckBox).Checked := (N <> 0);
|
||||
(CR^.Control as TCheckBox).Checked := (N <> 0)
|
||||
else if CR^.CtrlType = ctRadioButton then
|
||||
(CR^.Control as TRadioButton).Checked := (N <> 0);
|
||||
end
|
||||
else if S = 'Enabled' then
|
||||
begin
|
||||
|
|
@ -926,6 +1028,174 @@ begin
|
|||
ctListBox: (CR^.Control as TListBox).ItemIndex := N;
|
||||
ctComboBox: (CR^.Control as TComboBox).ItemIndex := N;
|
||||
end;
|
||||
end
|
||||
else if S = 'Stretch' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctImage then
|
||||
(CR^.Control as TImage).Stretch := (N <> 0);
|
||||
end
|
||||
else if S = 'Center' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctImage then
|
||||
(CR^.Control as TImage).Center := (N <> 0);
|
||||
end
|
||||
else if S = 'Transparent' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctImage then
|
||||
(CR^.Control as TImage).Transparent := (N <> 0);
|
||||
end
|
||||
else if S = 'Picture' then
|
||||
begin
|
||||
if CR^.CtrlType = ctImage then
|
||||
begin
|
||||
UnescapeString(Value, Unesc, SizeOf(Unesc));
|
||||
try
|
||||
if FBasePath <> '' then
|
||||
(CR^.Control as TImage).Picture.LoadFromFile(FBasePath + '\' + StrPas(Unesc))
|
||||
else
|
||||
(CR^.Control as TImage).Picture.LoadFromFile(StrPas(Unesc));
|
||||
except
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if S = 'BevelOuter' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 1);
|
||||
if CR^.CtrlType = ctPanel then
|
||||
(CR^.Control as TPanel).BevelOuter := TBevelCut(N);
|
||||
end
|
||||
else if S = 'BevelInner' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctPanel then
|
||||
(CR^.Control as TPanel).BevelInner := TBevelCut(N);
|
||||
end
|
||||
else if S = 'BorderStyle' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctPanel then
|
||||
(CR^.Control as TPanel).BorderStyle := TBorderStyle(N);
|
||||
end
|
||||
else if S = 'Kind' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctScrollBar then
|
||||
(CR^.Control as TScrollBar).Kind := TScrollBarKind(N);
|
||||
end
|
||||
else if S = 'Min' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctScrollBar then
|
||||
(CR^.Control as TScrollBar).Min := N;
|
||||
end
|
||||
else if S = 'Max' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctScrollBar then
|
||||
(CR^.Control as TScrollBar).Max := N;
|
||||
end
|
||||
else if S = 'Position' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctScrollBar then
|
||||
(CR^.Control as TScrollBar).Position := N;
|
||||
end
|
||||
else if S = 'LargeChange' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 1);
|
||||
if CR^.CtrlType = ctScrollBar then
|
||||
(CR^.Control as TScrollBar).LargeChange := N;
|
||||
end
|
||||
else if S = 'SmallChange' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 1);
|
||||
if CR^.CtrlType = ctScrollBar then
|
||||
(CR^.Control as TScrollBar).SmallChange := N;
|
||||
end
|
||||
else if S = 'FileName' then
|
||||
begin
|
||||
if CR^.CtrlType = ctMediaPlayer then
|
||||
begin
|
||||
UnescapeString(Value, Unesc, SizeOf(Unesc));
|
||||
if FBasePath <> '' then
|
||||
(CR^.Control as TMediaPlayer).FileName := FBasePath + '\' + StrPas(Unesc)
|
||||
else
|
||||
(CR^.Control as TMediaPlayer).FileName := StrPas(Unesc);
|
||||
end;
|
||||
end
|
||||
else if S = 'DeviceType' then
|
||||
begin
|
||||
if CR^.CtrlType = ctMediaPlayer then
|
||||
begin
|
||||
UnescapeString(Value, Unesc, SizeOf(Unesc));
|
||||
S := StrPas(Unesc);
|
||||
if S = 'dtAutoSelect' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtAutoSelect
|
||||
else if S = 'dtAVIVideo' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtAVIVideo
|
||||
else if S = 'dtCDAudio' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtCDAudio
|
||||
else if S = 'dtDAT' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtDAT
|
||||
else if S = 'dtDigitalVideo' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtDigitalVideo
|
||||
else if S = 'dtMMMovie' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtMMMovie
|
||||
else if S = 'dtOther' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtOther
|
||||
else if S = 'dtOverlay' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtOverlay
|
||||
else if S = 'dtScanner' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtScanner
|
||||
else if S = 'dtSequencer' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtSequencer
|
||||
else if S = 'dtVCR' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtVCR
|
||||
else if S = 'dtVideodisc' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtVideodisc
|
||||
else if S = 'dtWaveAudio' then
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtWaveAudio
|
||||
else
|
||||
(CR^.Control as TMediaPlayer).DeviceType := dtAutoSelect;
|
||||
end;
|
||||
end
|
||||
else if S = 'AutoOpen' then
|
||||
begin
|
||||
N := StrToIntDef(StrPas(Value), 0);
|
||||
if CR^.CtrlType = ctMediaPlayer then
|
||||
(CR^.Control as TMediaPlayer).AutoOpen := (N <> 0);
|
||||
end
|
||||
else if S = 'Command' then
|
||||
begin
|
||||
if CR^.CtrlType = ctMediaPlayer then
|
||||
begin
|
||||
UnescapeString(Value, Unesc, SizeOf(Unesc));
|
||||
S := StrPas(Unesc);
|
||||
try
|
||||
if S = 'Open' then
|
||||
(CR^.Control as TMediaPlayer).Open
|
||||
else if S = 'Play' then
|
||||
(CR^.Control as TMediaPlayer).Play
|
||||
else if S = 'Stop' then
|
||||
(CR^.Control as TMediaPlayer).Stop
|
||||
else if S = 'Close' then
|
||||
(CR^.Control as TMediaPlayer).Close
|
||||
else if S = 'Pause' then
|
||||
(CR^.Control as TMediaPlayer).Pause
|
||||
else if S = 'Resume' then
|
||||
(CR^.Control as TMediaPlayer).Resume
|
||||
else if S = 'Rewind' then
|
||||
(CR^.Control as TMediaPlayer).Rewind
|
||||
else if S = 'Next' then
|
||||
(CR^.Control as TMediaPlayer).Next
|
||||
else if S = 'Previous' then
|
||||
(CR^.Control as TMediaPlayer).Previous;
|
||||
except
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -1004,6 +1274,18 @@ begin
|
|||
Result := ctComboBox
|
||||
else if S = 'Memo' then
|
||||
Result := ctMemo
|
||||
else if S = 'Image' then
|
||||
Result := ctImage
|
||||
else if S = 'GroupBox' then
|
||||
Result := ctGroupBox
|
||||
else if S = 'RadioButton' then
|
||||
Result := ctRadioButton
|
||||
else if S = 'Panel' then
|
||||
Result := ctPanel
|
||||
else if S = 'ScrollBar' then
|
||||
Result := ctScrollBar
|
||||
else if S = 'MediaPlayer' then
|
||||
Result := ctMediaPlayer
|
||||
else
|
||||
Result := ctUnknown;
|
||||
end;
|
||||
|
|
@ -1135,6 +1417,21 @@ begin
|
|||
Ctrl := TComboBox.Create(FR^.Form);
|
||||
ctMemo:
|
||||
Ctrl := TMemo.Create(FR^.Form);
|
||||
ctImage:
|
||||
begin
|
||||
Ctrl := TImage.Create(FR^.Form);
|
||||
(Ctrl as TImage).AutoSize := False;
|
||||
end;
|
||||
ctGroupBox:
|
||||
Ctrl := TGroupBox.Create(FR^.Form);
|
||||
ctRadioButton:
|
||||
Ctrl := TRadioButton.Create(FR^.Form);
|
||||
ctPanel:
|
||||
Ctrl := TPanel.Create(FR^.Form);
|
||||
ctScrollBar:
|
||||
Ctrl := TScrollBar.Create(FR^.Form);
|
||||
ctMediaPlayer:
|
||||
Ctrl := TMediaPlayer.Create(FR^.Form);
|
||||
end;
|
||||
|
||||
if Ctrl = nil then
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ Event data varies by event type:
|
|||
|-----------|-------------------------------|
|
||||
| Click | (none) |
|
||||
| DblClick | (none) |
|
||||
| Change | `"new text"` |
|
||||
| Change | `"new text"` or `<position>` (ScrollBar) |
|
||||
| Select | `<index> "selected text"` |
|
||||
| KeyDown | `<vkCode>` |
|
||||
| KeyUp | `<vkCode>` |
|
||||
|
|
@ -82,11 +82,12 @@ Event data varies by event type:
|
|||
| Enter | (none) |
|
||||
| Exit | (none) |
|
||||
| Close | (none) |
|
||||
| Notify | (none) |
|
||||
|
||||
## Control Types
|
||||
|
||||
| Type | Delphi Class | Auto-wired Events |
|
||||
|----------|-------------|-------------------|
|
||||
|-------------|--------------|-------------------|
|
||||
| Label | TLabel | (none) |
|
||||
| Edit | TEdit | Change |
|
||||
| Button | TButton | Click |
|
||||
|
|
@ -94,18 +95,28 @@ Event data varies by event type:
|
|||
| ListBox | TListBox | Select |
|
||||
| ComboBox | TComboBox | Select, Change |
|
||||
| Memo | TMemo | Change |
|
||||
| Image | TImage | (none) |
|
||||
| GroupBox | TGroupBox | (none) |
|
||||
| RadioButton | TRadioButton | Click |
|
||||
| Panel | TPanel | (none) |
|
||||
| ScrollBar | TScrollBar | Change |
|
||||
| MediaPlayer | TMediaPlayer | (none) |
|
||||
|
||||
Opt-in events (require EVENT.BIND): DblClick, KeyDown, KeyUp, Enter, Exit,
|
||||
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.
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Applies To | Value Format |
|
||||
|------------|-------------------------------|-------------------------------------------|
|
||||
| Caption | Label, Button, CheckBox | Quoted string |
|
||||
|-------------|---------------------------------------------|-------------------------------------------|
|
||||
| Caption | Label, Button, CheckBox, GroupBox, RadioButton, Panel | Quoted string |
|
||||
| Text | Edit, ComboBox, Memo | Quoted string (`\n` for line breaks) |
|
||||
| Items | ListBox, ComboBox | Quoted string (`\n`-delimited) |
|
||||
| Checked | CheckBox | 0 or 1 |
|
||||
| Checked | CheckBox, RadioButton | 0 or 1 |
|
||||
| Enabled | All | 0 or 1 |
|
||||
| Visible | All | 0 or 1 |
|
||||
| MaxLength | Edit | Integer |
|
||||
|
|
@ -113,6 +124,33 @@ MouseDown, MouseUp, MouseMove.
|
|||
| ScrollBars | Memo | 0-3 (ssNone..ssBoth) |
|
||||
| ItemIndex | ListBox, ComboBox | Integer (-1 = none) |
|
||||
| TabOrder | All windowed controls | Integer |
|
||||
| Stretch | Image | 0 or 1 |
|
||||
| Center | Image | 0 or 1 |
|
||||
| Transparent | Image | 0 or 1 |
|
||||
| Picture | Image | Quoted string (filename, BMP only) |
|
||||
| BevelOuter | Panel | 0-2 (bvNone, bvLowered, bvRaised) |
|
||||
| BevelInner | Panel | 0-2 (bvNone, bvLowered, bvRaised) |
|
||||
| BorderStyle | Panel | 0-1 (bsNone, bsSingle) |
|
||||
| Kind | ScrollBar | 0-1 (sbHorizontal, sbVertical) |
|
||||
| Min | ScrollBar | Integer |
|
||||
| Max | ScrollBar | Integer |
|
||||
| Position | ScrollBar | Integer |
|
||||
| LargeChange | ScrollBar | Integer |
|
||||
| SmallChange | ScrollBar | Integer |
|
||||
| FileName | MediaPlayer | Quoted string (media file path) |
|
||||
| DeviceType | MediaPlayer | Quoted string (e.g., `dtWaveAudio`) |
|
||||
| AutoOpen | MediaPlayer | 0 or 1 |
|
||||
| Command | MediaPlayer | Quoted string (pseudo-property, see below)|
|
||||
|
||||
File path properties (Picture, FileName) are resolved relative to the
|
||||
client's `BasePath` setting. Subdirectories are allowed (e.g.,
|
||||
`Picture="images\logo.bmp"` with `BasePath=C:\MYAPP` resolves to
|
||||
`C:\MYAPP\images\logo.bmp`).
|
||||
|
||||
Command is a pseudo-property that triggers a method call on the
|
||||
MediaPlayer rather than setting a value. Valid commands: `Open`,
|
||||
`Play`, `Stop`, `Close`, `Pause`, `Resume`, `Rewind`, `Next`,
|
||||
`Previous`.
|
||||
|
||||
## String Encoding
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue