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

KeyValue typeDescription
paddingBoxSizeLayout: padding
spacingBoxSizeLayout: spacing
sizeBoxSizeLayout: explicit widget size
backgroundColorColorThe background color of the widget
foregroundColorColorText color in a label or editable field; icon color for FontAwesome icons
cornerStylesquare or roundedThe widget's corner style. Defaults to square
cornerRadiusnumberThe widget's corner radius (where cornerStyle is rounded), measured in points
interactivebooleanIf true, enables touch and click events
namestringSets the Morphic "name" for the widget

Icon attributes

KeyValue typeDescription
iconsymbolThe FontAwesome icon name for icons
icon-stylesymbolThe FontAwesome icon style name for icons

Slider attributes

KeyValue typeDescription
maxnumberMaximum value
minnumberMinimum value
valuenumberInitial value
orientationvertical or horizontalOrientation

Text attributes

KeyValue typeDescription
fontSizenumberThe font size, measured in points
readOnlybooleanIf true or absent, a label; if false, an editable text field
valuestringInitial value

Row and column attributes

KeyValue typeDescription
cellsintegerNumber of cells per row (column) in a grid; if absent, just one row (column)
scrollablebooleanWhether 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> .