book/protocols/synit/ui
User interface definitions and interaction
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 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 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 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 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> .
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 doubles 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 Sizings, 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> .
Copyright © 2021–2023 Tony Garnock-Jones, CC BY 4.0
