WinComm/forms/protocol.md
Scott Duensing dd115d3727 Add BitBtn, SpeedButton, TabSet, Notebook, TabbedNotebook, MaskEdit, Outline, Bevel, Header, and ScrollBox control types
Completes the Delphi 1.0 Standard, Additional, and Win31 component
palettes. DFM parser maps Tabs/Lines/Pages/Sections.Strings to Items
and TabIndex/PageIndex to ItemIndex. Kind extended with bk* idents
for BitBtn.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:13:59 -06:00

206 lines
10 KiB
Markdown

# Remote Forms Protocol
## Overview
Text-based protocol for remote GUI. A C server on Linux sends form/control
commands over a transport layer; a Delphi 1.0 client on Windows 3.1 creates
native controls and sends user events back.
## Message Format
- One command per message.
- Transport delivers whole messages (today: newline-delimited over serial).
- Strings are double-quoted with escapes: `\"` `\\` `\n` `\r` `\t`.
- Bare tokens (IDs, numbers, type names) are whitespace-delimited.
- IDs are positive integers assigned by the server.
## Server → Client Commands
### FORM.CREATE
FORM.CREATE <formId> <width> <height> "<title>"
Create a new form with the given dimensions and title. The form is not
shown until FORM.SHOW is sent.
### FORM.SHOW
FORM.SHOW <formId>
### FORM.HIDE
FORM.HIDE <formId>
### FORM.DESTROY
FORM.DESTROY <formId>
Free the form and all its controls.
### CTRL.CREATE
CTRL.CREATE <formId> <ctrlId> <type> <left> <top> <width> <height> [Key="val" ...]
Create a control on the specified form. Inline key/value properties are
applied immediately after creation. See Control Types and Properties below.
### CTRL.SET
CTRL.SET <formId> <ctrlId> Key="val" [Key="val" ...]
Update one or more properties on an existing control.
### EVENT.BIND
EVENT.BIND <formId> <ctrlId> <eventName>
Wire an opt-in event handler. Auto-wired events do not need explicit binding.
### EVENT.UNBIND
EVENT.UNBIND <formId> <ctrlId> <eventName>
Remove an event handler.
## Client → Server Events
EVENT <formId> <ctrlId> <eventName> [<data>]
Event data varies by event type:
| Event | Data |
|-----------|-------------------------------|
| Click | (none), or `<itemIndex>` (RadioGroup) |
| DblClick | (none) |
| Change | `"new text"`, `<position>` (ScrollBar), or `<index>` (TabSet, TabbedNotebook) |
| Select | `<index> "selected text"` |
| KeyDown | `<vkCode>` |
| KeyUp | `<vkCode>` |
| MouseDown | `<x> <y> <button>` |
| MouseUp | `<x> <y> <button>` |
| MouseMove | `<x> <y> <button>` |
| 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 |
| CheckBox | TCheckBox | Click |
| 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) |
| MainMenu | TMainMenu | (none) |
| PopupMenu | TPopupMenu | (none) |
| MenuItem | TMenuItem | Click |
| RadioGroup | TRadioGroup | Click |
| BitBtn | TBitBtn | Click |
| SpeedButton | TSpeedButton | Click |
| TabSet | TTabSet | Change |
| Notebook | TNotebook | (none) |
| TabbedNotebook | TTabbedNotebook | Change |
| MaskEdit | TMaskEdit | Change |
| Outline | TOutline | (none) |
| Bevel | TBevel | (none) |
| Header | THeader | (none) |
| ScrollBox | TScrollBox | (none) |
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. Menu and RadioGroup components do
not support opt-in events.
## Properties
| Property | Applies To | Value Format |
|-------------|---------------------------------------------|-------------------------------------------|
| Caption | Label, Button, CheckBox, GroupBox, RadioButton, Panel, MenuItem, RadioGroup, BitBtn, SpeedButton | Quoted string |
| Text | Edit, ComboBox, Memo, MaskEdit | Quoted string (`\n` for line breaks) |
| Items | ListBox, ComboBox, RadioGroup, TabSet, Notebook, TabbedNotebook, Outline, Header | Quoted string (`\n`-delimited) |
| Checked | CheckBox, RadioButton, MenuItem | 0 or 1 |
| Enabled | All | 0 or 1 |
| Visible | All | 0 or 1 |
| MaxLength | Edit, MaskEdit | Integer |
| ReadOnly | Edit, Memo | 0 or 1 |
| ScrollBars | Memo | 0-3 (ssNone..ssBoth) |
| ItemIndex | ListBox, ComboBox, RadioGroup, TabSet, Notebook, TabbedNotebook | 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, BitBtn | Integer (see below) |
| 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)|
| 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) |
| Layout | BitBtn, SpeedButton | 0-3 (blGlyphLeft..blGlyphBottom) |
| NumGlyphs | BitBtn, SpeedButton | Integer (1-4) |
| GroupIndex | SpeedButton | Integer (0 = no group) |
| Down | SpeedButton | 0 or 1 |
| AllowAllUp | SpeedButton | 0 or 1 |
| EditMask | MaskEdit | Quoted string |
| OutlineStyle| Outline | 0-6 (osText..osTreePictureText) |
| Shape | Bevel | 0-5 (bsBox..bsRightLine) |
| Style | Bevel | 0-1 (bsLowered, bsRaised) |
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
- Strings in the protocol are always double-quoted.
- Escape sequences: `\"` (literal quote), `\\` (literal backslash),
`\n` (newline), `\r` (carriage return), `\t` (tab).
- Multi-line values (Memo text, ListBox items) use `\n` within a single
quoted string.
## Transport Layer
The protocol is transport-agnostic. Messages are delivered via:
```
int ReadMessage(char *buf, int maxLen); // returns bytes read, 0 = none
void WriteMessage(const char *buf); // sends complete message
```
Current transport: newline-delimited serial (messages terminated by CR+LF).
The transport handles framing; protocol layer never sees delimiters.