201 lines
8.8 KiB
Markdown
201 lines
8.8 KiB
Markdown
# User interface definitions and interaction
|
|
|
|
- [`[synit]/protocols/schemas/ui.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/ui.prs)
|
|
|
|
The user interface protocol is perhaps the most subject-to-change part of the whole system. It
|
|
is a client-server protocol, similar in spirit to X-Windows, where *clients* request display
|
|
and input services from a *server*, to which is attached a display and input devices.
|
|
|
|
At present, it is a simple system with a fixed set of widget types, a TeX-inspired box-and-glue
|
|
layout model, and a very limited set of event types. In future, a
|
|
NeWS/Display-PostScript-inspired model could dovetail very nicely with the capability and
|
|
dataspace features of Syndicate.
|
|
|
|
**Implementation.** The SqueakPhone Smalltalk image includes the initial implementation of the
|
|
protocol, in classes `WidgetDaemon`, `WidgetBuilder`, `WidgetWindow`, and so on.
|
|
|
|
## Creating a window
|
|
|
|
A client *observes* `Window` assertions with an `id` of its choice. The server notices the
|
|
client's interest, and in response, creates a fresh dataspace for configuration and interaction
|
|
relating to the new window, and asserts a `Window` record mapping the `id` to the new `space`.
|
|
|
|
```
|
|
Window = <window @id WidgetId @space #!any> .
|
|
WidgetId = any .
|
|
```
|
|
|
|
## Configuring a window
|
|
|
|
Within the dataspace referred to by a `Window` assertion—henceforth the *window dataspace*—the
|
|
client may assert `WindowCloseable` to add a close button to the window decoration, and may
|
|
assert `WindowTitle` to give the window a name.
|
|
|
|
```
|
|
WindowCloseable = <window-closeable> .
|
|
WindowTitle = <window-title @title string> .
|
|
```
|
|
|
|
## Creating widget trees
|
|
|
|
The client may place `Widget` assertions within the window dataspace to create new widgets
|
|
within the window. The window is hidden until the first `Widget` is asserted.
|
|
|
|
`Root` and `Parent` assertions connect new widgets to the overall window layout tree. A `Root`
|
|
assertion places the widget directly in the containing window, while a `Parent` assertion marks
|
|
a widget as child of another widget. In both cases, the `order` sort key is used when multiple
|
|
children are present within a container that supports widget ordering.
|
|
|
|
```
|
|
Widget = <widget @id WidgetId @type WidgetType> .
|
|
|
|
Parent = <parent @id WidgetId @parentId WidgetId @order SortKey> .
|
|
Root = <root @id WidgetId @order SortKey> .
|
|
|
|
SortKey = @double double / @string string .
|
|
```
|
|
|
|
## Widget Types
|
|
|
|
Widgets acting as containers for other widgets may be of either `column` or `row` type. Leaf
|
|
widgets may be `blank` (for spacing/padding/layout), `text` (a label or editable field), a
|
|
`slider`, or a [FontAwesome](https://fontawesome.com/) `icon`.
|
|
|
|
```
|
|
WidgetType = NodeType / LeafType .
|
|
NodeType = =column / =row .
|
|
LeafType = =blank / =text / =slider / =icon .
|
|
```
|
|
|
|
## Configuring widgets
|
|
|
|
Widgets have *attributes* attached to them. An attribute is a pair of a symbol `key` and a
|
|
`value` (of `key`-specific type) attached to a particular widget. Most attribute keys are
|
|
expected to have either zero or one `Attribute` records for any given widget, but the
|
|
Syndicated Actor Model naturally supports *multiple* values for a given attribute, and some
|
|
attribute keys take advantage of this. See [below](#attribute-keys) for more on the available
|
|
attribute keys.
|
|
|
|
```
|
|
Attribute = <attribute @id WidgetId @key symbol @value any> .
|
|
```
|
|
|
|
## Events and Widget State
|
|
|
|
Widgets marked with the [`interactive` attribute](#interactive) generate events in response to
|
|
user interaction.
|
|
|
|
Clients can observe `Touch` assertions to receive information about when the user has a finger
|
|
touching the displayed widget on a touchscreen. The assertion for a given widget will appear
|
|
when the touch starts, and disappear when the touch ends. Multiple touches, uniquely
|
|
identified, may be active simultaneously.
|
|
|
|
```
|
|
Touch = <touch @widget WidgetId @touchId any> .
|
|
```
|
|
|
|
Clients can observe `Click` messages to receive information about when the user removes a
|
|
touching finger from a widget while the finger is within the widget's bounds.
|
|
|
|
```
|
|
Click = <click @widget WidgetId> .
|
|
```
|
|
|
|
Finally, whether a widget is marked interactive or not, the UI server actor asserts `State`
|
|
assertions containing facts about a given widget's state. For example, a text widget asserts a
|
|
`State` assertion with the symbol `text` as its `key` and a string as its `value`; a slider
|
|
asserts a `value`-keyed `State`; and a scrollable widget asserts a `visible-scroll-range`-keyed
|
|
`State` with a `VisibleScrollRange` value.
|
|
|
|
```
|
|
State = <state @widget WidgetId @key any @value any> .
|
|
|
|
VisibleScrollRange =
|
|
/ =none
|
|
/ @visibleScrollRange <visible-scroll-range
|
|
<min @minId WidgetId @minSortKey SortKey>
|
|
<max @maxId WidgetId @maxSortKey SortKey>>
|
|
.
|
|
```
|
|
|
|
## Accessing widget instances
|
|
|
|
Within the current implementation, access to the raw
|
|
[Morphic](http://wiki.squeak.org/squeak/morphic) object representing the widget can be gained
|
|
by monitoring `WidgetInstance` assertions. (This is not a sustainable technique, and it will be
|
|
replaced in future by an entity-reference-based system.)
|
|
|
|
```
|
|
WidgetInstance = <widget-instance @id WidgetId @instance #!any> .
|
|
```
|
|
|
|
## <span id="attribute-keys"></span>Widget attributes
|
|
|
|
### General attributes, for any widget type
|
|
|
|
| Key | Value type | Description |
|
|
|-----------------|-----------------------|-----------------------------------------------------------------------------------|
|
|
| padding | `BoxSize` | Layout: padding |
|
|
| spacing | `BoxSize` | Layout: spacing |
|
|
| size | `BoxSize` | Layout: explicit widget size |
|
|
| backgroundColor | `Color` | The background color of the widget |
|
|
| foregroundColor | `Color` | Text color in a label or editable field; icon color for FontAwesome icons |
|
|
| cornerStyle | `square` or `rounded` | The widget's corner style. Defaults to `square` |
|
|
| cornerRadius | number | The widget's corner radius (where `cornerStyle` is `rounded`), measured in points |
|
|
| interactive | boolean | If true, enables touch and click events |
|
|
| name | string | Sets the Morphic "name" for the widget |
|
|
|
|
### Icon attributes
|
|
|
|
| Key | Value type | Description |
|
|
|------------|------------|-------------------------------------------|
|
|
| icon | symbol | The FontAwesome icon name for icons |
|
|
| icon-style | symbol | The FontAwesome icon style name for icons |
|
|
|
|
### Slider attributes
|
|
|
|
| Key | Value type | Description |
|
|
|-------------|----------------------------|---------------|
|
|
| max | number | Maximum value |
|
|
| min | number | Minimum value |
|
|
| value | number | Initial value |
|
|
| orientation | `vertical` or `horizontal` | Orientation |
|
|
|
|
### Text attributes
|
|
|
|
| Key | Value type | Description |
|
|
|----------|------------|--------------------------------------------------------------|
|
|
| fontSize | number | The font size, measured in points |
|
|
| readOnly | boolean | If true or absent, a label; if false, an editable text field |
|
|
| value | string | Initial value |
|
|
|
|
### Row and column attributes
|
|
|
|
| Key | Value type | Description |
|
|
|------------|------------|------------------------------------------------------------------------------|
|
|
| cells | integer | Number of cells per row (column) in a grid; if absent, just one row (column) |
|
|
| scrollable | boolean | Whether the container is a scrollable viewport or fixed-size |
|
|
|
|
## Widget value types
|
|
|
|
### Color values
|
|
|
|
The `Color` type describes an RGBA color value where the components are `double`s in the range
|
|
`0.0` to `1.0` (inclusive).
|
|
|
|
```
|
|
Color = <rgba @red double @green double @blue double @alpha double> .
|
|
```
|
|
|
|
### `BoxSize`: layout sizes
|
|
|
|
The `BoxSize` type is a pair of `Sizing`s, one for the horizontal and one for the vertical
|
|
dimension. Each `Sizing` describes an *ideal* size, measured in points, plus a "stretch" and a
|
|
"shrink" specification of `Fill` type, loosely modelled on the TeX concept of "boxes and glue".
|
|
|
|
```
|
|
Fill = @fixed double / <fill @weight int @rank int> .
|
|
Sizing = <sizing @ideal double @stretch Fill @shrink Fill> .
|
|
BoxSize = <box-size @horizontal Sizing @vertical Sizing> .
|
|
```
|