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
|
## Supported Controls
|
||||||
|
|
||||||
| Type | Delphi Class | Description |
|
| Type | Delphi Class | Description |
|
||||||
|------------|-------------|--------------------------------|
|
|---------------|--------------|--------------------------------|
|
||||||
| `Label` | TLabel | Static text label |
|
| `Label` | TLabel | Static text label |
|
||||||
| `Edit` | TEdit | Single-line text input |
|
| `Edit` | TEdit | Single-line text input |
|
||||||
| `Button` | TButton | Push button |
|
| `Button` | TButton | Push button |
|
||||||
|
|
@ -316,6 +316,12 @@ messages are available, dispatching each command as it arrives.
|
||||||
| `ListBox` | TListBox | Scrollable list of items |
|
| `ListBox` | TListBox | Scrollable list of items |
|
||||||
| `ComboBox` | TComboBox | Drop-down list with text input |
|
| `ComboBox` | TComboBox | Drop-down list with text input |
|
||||||
| `Memo` | TMemo | Multi-line 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
|
### Creating Controls
|
||||||
|
|
||||||
|
|
@ -353,11 +359,12 @@ CTRL.SET 1 3 Text="world" Enabled=0
|
||||||
|
|
||||||
### Caption
|
### Caption
|
||||||
|
|
||||||
- **Applies to:** Label, Button, CheckBox
|
- **Applies to:** Label, Button, CheckBox, GroupBox, RadioButton, Panel
|
||||||
- **Format:** Quoted string
|
- **Format:** Quoted string
|
||||||
- **Example:** `Caption="Submit"`
|
- **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
|
### Text
|
||||||
|
|
||||||
|
|
@ -383,7 +390,7 @@ new items are added.
|
||||||
|
|
||||||
### Checked
|
### Checked
|
||||||
|
|
||||||
- **Applies to:** CheckBox
|
- **Applies to:** CheckBox, RadioButton
|
||||||
- **Format:** `0` (unchecked) or `1` (checked)
|
- **Format:** `0` (unchecked) or `1` (checked)
|
||||||
- **Example:** `Checked=1`
|
- **Example:** `Checked=1`
|
||||||
|
|
||||||
|
|
@ -432,12 +439,168 @@ Maximum number of characters the user can type.
|
||||||
|
|
||||||
### TabOrder
|
### TabOrder
|
||||||
|
|
||||||
- **Applies to:** All windowed controls (all types except Label)
|
- **Applies to:** All windowed controls (all types except Label and Image)
|
||||||
- **Format:** Integer
|
- **Format:** Integer
|
||||||
- **Example:** `TabOrder=3`
|
- **Example:** `TabOrder=3`
|
||||||
|
|
||||||
Controls the keyboard tab navigation order within the form.
|
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
|
## Events
|
||||||
|
|
||||||
### Auto-wired Events
|
### Auto-wired Events
|
||||||
|
|
@ -449,8 +612,10 @@ No `EVENT.BIND` command is needed.
|
||||||
|-------------|---------|-------------------------------|
|
|-------------|---------|-------------------------------|
|
||||||
| Button | Click | (none) |
|
| Button | Click | (none) |
|
||||||
| CheckBox | Click | (none) |
|
| CheckBox | Click | (none) |
|
||||||
|
| RadioButton | Click | (none) |
|
||||||
| Edit | Change | `"new text"` |
|
| Edit | Change | `"new text"` |
|
||||||
| Memo | Change | `"new text"` |
|
| Memo | Change | `"new text"` |
|
||||||
|
| ScrollBar | Change | `<position>` |
|
||||||
| ListBox | Select | `<index> "selected text"` |
|
| ListBox | Select | `<index> "selected text"` |
|
||||||
| ComboBox | Select | `<index> "selected text"` |
|
| ComboBox | Select | `<index> "selected text"` |
|
||||||
| ComboBox | Change | `"new 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.
|
client will send them. Use `EVENT.UNBIND` to disconnect.
|
||||||
|
|
||||||
| Event | Data Sent | Notes |
|
| Event | Data Sent | Notes |
|
||||||
|-----------|-----------------------|---------------------------------|
|
|-----------|-----------------------|-----------------------------------|
|
||||||
|
| Click | (none) | Image, GroupBox, Panel only |
|
||||||
| DblClick | (none) | Double-click on any control |
|
| DblClick | (none) | Double-click on any control |
|
||||||
|
| Notify | (none) | MediaPlayer playback notification |
|
||||||
| KeyDown | `<vkCode>` | Windows virtual key code |
|
| KeyDown | `<vkCode>` | Windows virtual key code |
|
||||||
| KeyUp | `<vkCode>` | Windows virtual key code |
|
| KeyUp | `<vkCode>` | Windows virtual key code |
|
||||||
| Enter | (none) | Control received focus |
|
| Enter | (none) | Control received focus |
|
||||||
|
|
@ -527,6 +694,22 @@ any protocol or application code.
|
||||||
- Transport handles framing — the protocol layer never sees
|
- Transport handles framing — the protocol layer never sees
|
||||||
delimiters.
|
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
|
## Limits
|
||||||
|
|
||||||
| Limit | Value |
|
| Limit | Value |
|
||||||
|
|
|
||||||
253
forms/dfm2form.c
253
forms/dfm2form.c
|
|
@ -26,7 +26,13 @@ typedef enum {
|
||||||
ctCheckBox,
|
ctCheckBox,
|
||||||
ctListBox,
|
ctListBox,
|
||||||
ctComboBox,
|
ctComboBox,
|
||||||
ctMemo
|
ctMemo,
|
||||||
|
ctImage,
|
||||||
|
ctGroupBox,
|
||||||
|
ctRadioButton,
|
||||||
|
ctPanel,
|
||||||
|
ctScrollBar,
|
||||||
|
ctMediaPlayer
|
||||||
} CtrlTypeE;
|
} CtrlTypeE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -67,6 +73,36 @@ typedef struct {
|
||||||
bool hasOnKeyUp;
|
bool hasOnKeyUp;
|
||||||
bool hasOnMouseDown;
|
bool hasOnMouseDown;
|
||||||
bool hasOnMouseUp;
|
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;
|
} DfmCtrlT;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -306,6 +342,24 @@ static CtrlTypeE mapClassName(const char *className) {
|
||||||
if (stricmp_local(className, "TMemo") == 0) {
|
if (stricmp_local(className, "TMemo") == 0) {
|
||||||
return ctMemo;
|
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;
|
return ctUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,6 +374,9 @@ static void initCtrl(DfmCtrlT *ctrl) {
|
||||||
ctrl->visible = 1;
|
ctrl->visible = 1;
|
||||||
ctrl->itemIndex = -1;
|
ctrl->itemIndex = -1;
|
||||||
ctrl->tabOrder = -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) {
|
if (!isForm) {
|
||||||
ctrl->hasOnMouseUp = true;
|
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 {
|
} else {
|
||||||
skipValue(data, size, pos, tag);
|
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 void emitCtrl(FILE *out, int32_t formId, int32_t ctrlId, DfmCtrlT *ctrl) {
|
||||||
static const char *typeNames[] = {
|
static const char *typeNames[] = {
|
||||||
"Unknown", "Label", "Edit", "Button",
|
"Unknown", "Label", "Edit", "Button",
|
||||||
"CheckBox", "ListBox", "ComboBox", "Memo"
|
"CheckBox", "ListBox", "ComboBox", "Memo",
|
||||||
|
"Image", "GroupBox", "RadioButton", "Panel",
|
||||||
|
"ScrollBar", "MediaPlayer"
|
||||||
};
|
};
|
||||||
char escaped[8192];
|
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) {
|
if (ctrl->hasItemIndex && ctrl->itemIndex >= 0) {
|
||||||
fprintf(out, " ItemIndex=%d", ctrl->itemIndex);
|
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");
|
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,
|
// Auto-wired: Button/CheckBox→Click, Edit→Change, ListBox→Select,
|
||||||
// ComboBox→Select+Change, Memo→Change
|
// ComboBox→Select+Change, Memo→Change
|
||||||
|
|
||||||
bool autoClick = (ctrl->type == ctButton || ctrl->type == ctCheckBox);
|
bool autoClick = (ctrl->type == ctButton || ctrl->type == ctCheckBox || ctrl->type == ctRadioButton);
|
||||||
bool autoChange = (ctrl->type == ctEdit || ctrl->type == ctComboBox || ctrl->type == ctMemo);
|
bool autoChange = (ctrl->type == ctEdit || ctrl->type == ctComboBox || ctrl->type == ctMemo || ctrl->type == ctScrollBar);
|
||||||
bool autoSelect = (ctrl->type == ctListBox || ctrl->type == ctComboBox);
|
bool autoSelect = (ctrl->type == ctListBox || ctrl->type == ctComboBox);
|
||||||
|
|
||||||
if (ctrl->hasOnClick && !autoClick) {
|
if (ctrl->hasOnClick && !autoClick) {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ unit FormCli;
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
SysUtils, Classes, Controls, Forms, StdCtrls, WinTypes, WinProcs;
|
SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, MPlayer, WinTypes, WinProcs;
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxMsgLen = 4096;
|
MaxMsgLen = 4096;
|
||||||
|
|
@ -27,11 +27,14 @@ type
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TCtrlTypeE = (ctUnknown, ctLabel, ctEdit, ctButton,
|
TCtrlTypeE = (ctUnknown, ctLabel, ctEdit, ctButton,
|
||||||
ctCheckBox, ctListBox, ctComboBox, ctMemo);
|
ctCheckBox, ctListBox, ctComboBox, ctMemo,
|
||||||
|
ctImage, ctGroupBox, ctRadioButton, ctPanel,
|
||||||
|
ctScrollBar, ctMediaPlayer);
|
||||||
|
|
||||||
{ Bound event flags }
|
{ Bound event flags }
|
||||||
TBoundEvent = (beDblClick, beKeyDown, beKeyUp,
|
TBoundEvent = (beDblClick, beKeyDown, beKeyUp,
|
||||||
beEnter, beExit, beMouseDown, beMouseUp, beMouseMove);
|
beEnter, beExit, beMouseDown, beMouseUp, beMouseMove,
|
||||||
|
beClick, beNotify);
|
||||||
TBoundEvents = set of TBoundEvent;
|
TBoundEvents = set of TBoundEvent;
|
||||||
|
|
||||||
{ Per-control record }
|
{ Per-control record }
|
||||||
|
|
@ -58,6 +61,7 @@ type
|
||||||
FForms: TList; { of PFormRec }
|
FForms: TList; { of PFormRec }
|
||||||
FMsgBuf: PChar; { read buffer }
|
FMsgBuf: PChar; { read buffer }
|
||||||
FTmpBuf: PChar; { scratch buffer for outgoing messages }
|
FTmpBuf: PChar; { scratch buffer for outgoing messages }
|
||||||
|
FBasePath: string;
|
||||||
|
|
||||||
{ Command dispatch }
|
{ Command dispatch }
|
||||||
procedure DoCtrlCreate(P: PChar);
|
procedure DoCtrlCreate(P: PChar);
|
||||||
|
|
@ -102,6 +106,10 @@ type
|
||||||
procedure HandleMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
procedure HandleMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
||||||
procedure HandleMouseMove(Sender: TObject; 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 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 }
|
{ Outgoing event helpers }
|
||||||
procedure SendEvent(FormId, CtrlId: Integer; const EventName: string; const Data: string);
|
procedure SendEvent(FormId, CtrlId: Integer; const EventName: string; const Data: string);
|
||||||
|
|
@ -116,6 +124,7 @@ type
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
procedure ProcessMessages;
|
procedure ProcessMessages;
|
||||||
property Transport: TFormTransport read FTransport;
|
property Transport: TFormTransport read FTransport;
|
||||||
|
property BasePath: string read FBasePath write FBasePath;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
@ -632,6 +641,58 @@ begin
|
||||||
end;
|
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;
|
procedure TFormClient.HandleFormClose(Sender: TObject;
|
||||||
var Action: TCloseAction);
|
var Action: TCloseAction);
|
||||||
var
|
var
|
||||||
|
|
@ -665,6 +726,10 @@ begin
|
||||||
(CR^.Control as TComboBox).OnClick := HandleComboBoxSelect;
|
(CR^.Control as TComboBox).OnClick := HandleComboBoxSelect;
|
||||||
(CR^.Control as TComboBox).OnChange := HandleComboBoxChange;
|
(CR^.Control as TComboBox).OnChange := HandleComboBoxChange;
|
||||||
end;
|
end;
|
||||||
|
ctRadioButton:
|
||||||
|
(CR^.Control as TRadioButton).OnClick := HandleRadioButtonClick;
|
||||||
|
ctScrollBar:
|
||||||
|
(CR^.Control as TScrollBar).OnChange := HandleScrollBarChange;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -714,6 +779,22 @@ begin
|
||||||
begin
|
begin
|
||||||
(CR^.Control as TControl).OnMouseMove := HandleMouseMove;
|
(CR^.Control as TControl).OnMouseMove := HandleMouseMove;
|
||||||
CR^.Bound := CR^.Bound + [beMouseMove];
|
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;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -763,6 +844,22 @@ begin
|
||||||
begin
|
begin
|
||||||
(CR^.Control as TControl).OnMouseMove := nil;
|
(CR^.Control as TControl).OnMouseMove := nil;
|
||||||
CR^.Bound := CR^.Bound - [beMouseMove];
|
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;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -787,6 +884,9 @@ begin
|
||||||
ctLabel: (CR^.Control as TLabel).Caption := StrPas(Unesc);
|
ctLabel: (CR^.Control as TLabel).Caption := StrPas(Unesc);
|
||||||
ctButton: (CR^.Control as TButton).Caption := StrPas(Unesc);
|
ctButton: (CR^.Control as TButton).Caption := StrPas(Unesc);
|
||||||
ctCheckBox: (CR^.Control as TCheckBox).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;
|
||||||
end
|
end
|
||||||
else if S = 'Text' then
|
else if S = 'Text' then
|
||||||
|
|
@ -881,7 +981,9 @@ begin
|
||||||
begin
|
begin
|
||||||
N := StrToIntDef(StrPas(Value), 0);
|
N := StrToIntDef(StrPas(Value), 0);
|
||||||
if CR^.CtrlType = ctCheckBox then
|
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
|
end
|
||||||
else if S = 'Enabled' then
|
else if S = 'Enabled' then
|
||||||
begin
|
begin
|
||||||
|
|
@ -926,6 +1028,174 @@ begin
|
||||||
ctListBox: (CR^.Control as TListBox).ItemIndex := N;
|
ctListBox: (CR^.Control as TListBox).ItemIndex := N;
|
||||||
ctComboBox: (CR^.Control as TComboBox).ItemIndex := N;
|
ctComboBox: (CR^.Control as TComboBox).ItemIndex := N;
|
||||||
end;
|
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;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
@ -1004,6 +1274,18 @@ begin
|
||||||
Result := ctComboBox
|
Result := ctComboBox
|
||||||
else if S = 'Memo' then
|
else if S = 'Memo' then
|
||||||
Result := ctMemo
|
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
|
else
|
||||||
Result := ctUnknown;
|
Result := ctUnknown;
|
||||||
end;
|
end;
|
||||||
|
|
@ -1135,6 +1417,21 @@ begin
|
||||||
Ctrl := TComboBox.Create(FR^.Form);
|
Ctrl := TComboBox.Create(FR^.Form);
|
||||||
ctMemo:
|
ctMemo:
|
||||||
Ctrl := TMemo.Create(FR^.Form);
|
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;
|
end;
|
||||||
|
|
||||||
if Ctrl = nil then
|
if Ctrl = nil then
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ Event data varies by event type:
|
||||||
|-----------|-------------------------------|
|
|-----------|-------------------------------|
|
||||||
| Click | (none) |
|
| Click | (none) |
|
||||||
| DblClick | (none) |
|
| DblClick | (none) |
|
||||||
| Change | `"new text"` |
|
| Change | `"new text"` or `<position>` (ScrollBar) |
|
||||||
| Select | `<index> "selected text"` |
|
| Select | `<index> "selected text"` |
|
||||||
| KeyDown | `<vkCode>` |
|
| KeyDown | `<vkCode>` |
|
||||||
| KeyUp | `<vkCode>` |
|
| KeyUp | `<vkCode>` |
|
||||||
|
|
@ -82,11 +82,12 @@ Event data varies by event type:
|
||||||
| Enter | (none) |
|
| Enter | (none) |
|
||||||
| Exit | (none) |
|
| Exit | (none) |
|
||||||
| Close | (none) |
|
| Close | (none) |
|
||||||
|
| Notify | (none) |
|
||||||
|
|
||||||
## Control Types
|
## Control Types
|
||||||
|
|
||||||
| Type | Delphi Class | Auto-wired Events |
|
| Type | Delphi Class | Auto-wired Events |
|
||||||
|----------|-------------|-------------------|
|
|-------------|--------------|-------------------|
|
||||||
| Label | TLabel | (none) |
|
| Label | TLabel | (none) |
|
||||||
| Edit | TEdit | Change |
|
| Edit | TEdit | Change |
|
||||||
| Button | TButton | Click |
|
| Button | TButton | Click |
|
||||||
|
|
@ -94,18 +95,28 @@ Event data varies by event type:
|
||||||
| ListBox | TListBox | Select |
|
| ListBox | TListBox | Select |
|
||||||
| ComboBox | TComboBox | Select, Change |
|
| ComboBox | TComboBox | Select, Change |
|
||||||
| Memo | TMemo | 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.
|
MouseDown, MouseUp, MouseMove.
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
| Property | Applies To | Value Format |
|
| 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) |
|
| Text | Edit, ComboBox, Memo | Quoted string (`\n` for line breaks) |
|
||||||
| Items | ListBox, ComboBox | Quoted string (`\n`-delimited) |
|
| Items | ListBox, ComboBox | Quoted string (`\n`-delimited) |
|
||||||
| Checked | CheckBox | 0 or 1 |
|
| Checked | CheckBox, RadioButton | 0 or 1 |
|
||||||
| Enabled | All | 0 or 1 |
|
| Enabled | All | 0 or 1 |
|
||||||
| Visible | All | 0 or 1 |
|
| Visible | All | 0 or 1 |
|
||||||
| MaxLength | Edit | Integer |
|
| MaxLength | Edit | Integer |
|
||||||
|
|
@ -113,6 +124,33 @@ MouseDown, MouseUp, MouseMove.
|
||||||
| ScrollBars | Memo | 0-3 (ssNone..ssBoth) |
|
| ScrollBars | Memo | 0-3 (ssNone..ssBoth) |
|
||||||
| ItemIndex | ListBox, ComboBox | Integer (-1 = none) |
|
| ItemIndex | ListBox, ComboBox | Integer (-1 = none) |
|
||||||
| TabOrder | All windowed controls | Integer |
|
| 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
|
## String Encoding
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue