You may answer that you see an applet or application, or
more specifically the user interface to an application. However
'user interface' can refer to anything from a functional and
aesthetic design to a particular arrangement of platform widgets.
Superficial gives a more definite answer to this question:
- You the user are on the outside of an application.
- You need to interact with content that is inside the application.
- The element that enables interaction between the inside
and outside of an application is most helpfully described
as its surface.
The metaphor of surface leaves open the exact means by which
a surface manages interaction between user and application,
but it is easy to decide whether an application has a surface.
A GUI is evidently a surface, but so is a command-line interface
or even a teletype.
Defining a GUI surface - facets
How does the surface metaphor help
with the practicalities of developing GUI applications?
Superficial views a GUI surface as composed primarily not
of its low-level widgets, but of facets that expose
elements within the application. Each facet creates
and manages a a group (usually) of widgets, updating their
state as required to match the application element the facet
exposes, and relaying input from the widgets to the application.
By mediating between the GUI widgets and
the application, facets make possible the key Superficial
mechanism of retargeting. They
also greatly reduce the number of GUI elements that need to
be specified by application code. Even the simple GUI surface
of the spike applet
comprises nearly 140 Swing components, but these are built
and managed by only around 50 facets. For instance:
- a textual facet uses a text field
to expose the text of the currently selected text line object
- a toggling facet uses a Font
sub-menu
to expose text line style flags, while activating the Font
tool panel reveals another that does the same using a checkbox
panel
- a trigger facet in the tool panel
exposes line selection with a pair of buttons ,
while another does the same with a pair of Line menu
items
- indexing facets use Font
sub-menus to expose the font face
,
size
and shade ;
while in the tool panel others expose the same values using
a radio-button panel ,
a drop-down list
combined with indexing buttons ,
and a list box
- a single numeric facet in the
Position tool panel manages sliders and associated
text fields for both the X and Y positions of the selected
text line,
while another exposes the same values using a button panel
that has its counterpart in Line menu items
The fact that facets usually manage more than one widget
is a major benefit of the Superficial approach - developing
a GUI is much easier if you don't have to specify each and
every button, label and menu item.
Behind the facets - targets
Developing a GUI surface with Superficial
is easier in another way.
Superficial defines each facet as exposing
a target in the application. Targets may represent
a simple data value, an action, a complete content structure,
or even an element of the surface itself such as a viewer
or window. The retargeting mechanism
described below transparently connects facets to targets both
during construction of the GUI and in response to events such
as change in selection
Each target in the application may be exposed by any number
of facets in the surface. This means that many fewer targets
are required than facets, while each facet may bind several
widgets to the data represented by its target.
In the spike applet
and spike application the ratios
of targets, facets and widgets are as shown below:
|
|
|
Targets |
|
Facets |
|
Widgets |
Spike applet |
|
22 |
|
54 |
|
137 |
Spike application |
|
70 |
|
114 |
|
321 |
Both facets and their targets can be defined semi-declaratively,
allowing Superficial GUIs to be defined with the same simplicity
as JavaFX
Script but with the advantages of
- GUI definition within Java - no special language
- conciseness - each facet manages a complete group of widgets
Manipulating content - the viewer facet and its targets
To see how Superficial makes it much easier to define the
interactions that make for a rich, responsive GUI, let's look
at how the spike applet
responds to user interaction with its viewer.
Superficial regards the viewer as being a facet that exposes
a viewable target acting as a frame for application
content, here an array of three text line objects; it also
has a view target defining graphical avatars
for the content.
When the spike applet
opens, none of the text line avatars is selected and most
of the tools and menu items are disabled. Click on the avatar
for a text line and a bar appears beneath it.
The avatar now depicts a selection target within the
viewable target of the whole viewer. At the same time the
tools panel and menu items respond by becoming enabled and
exposing the values for the same selection target.
Drag the selected text line to a new position,
and the Position facets in the tools panel are updated
to match the new values.
Drag the far end of the text line avatar to change its angle,
and the tool panel switches to the Angle tools, which
are updated with the angle of the selected text line.
As you change the selection target by clicking on another
avatar or a Line iteration button, the tool panel and
menu items are updated to match the newly selected text line.
And if you change the properties of a text line using the
tools panel or menus, its avatar in the viewer is updated
to match.
This responsive behaviour is intuitive in user terms, but
far from straightforward to code:
- Tool panel and menu widgets must always display the properties
of the selected text line.
- User input via tool panel or menu widgets must result
in corresponding updates to the viewer, and vice-versa.
- The GUI as a whole must respond to interaction in the
viewer by switching tool panel widgets etc.
To put the problem in general terms, a GUI application has
to ensure that it maintains view consistency at all times.
Coding a GUI using conventional methods that meets this requirement
can be a struggle; Superficial's concepts of surface,
facet and target
make possible the retargeting
mechanism that makes it almost a pleasure.
Oh, and it's a reasonable guess that the cow jumped over
the moon.
Retargeting - the key Superficial mechanism
Superficial maintains view consistency (as demonstrated
in the spike applet
and spike application) by treating
the complete GUI surface as an integrated
view of the application and its content. Refreshing this view
to match the state of the application is achieved by retargeting.
The facets that create and manage GUI
widgets are connected to their targets
in the application via a targeter tree created by the
surface (and visible in the debug pane).
After any significant application event all facets are retargeted
via the targeter tree on appropriate targets, thus synchronising
all widgets with the latest application state. Each facet
uses the event handling of the GUI toolkit to listen for input
on its widget(s) and interpret this input in relation to its
current target.
Application events that trigger a retargeting include the
initial construction of the GUI surface, and any action by
a facet on its target in response to GUI events.
Retargeting is largely transparent to client code, enabling
you the developer to let Superficial take care of the two
major issues of GUI development: binding widgets to data and
listening on events.
- Data binding is automatic - when retargeted initially
or in response to an application event, each facet updates
its widgets to match its current target, and thus to the
content or other application object represented by that
target.
- Event handling is hidden - each widget need only communicate
with its managing facet, which will relay input from the
widget to the facet's current target in the application.
Given the update speeds of modern GUI toolkits, retargeting
has minimal impact on the latency of an application surface:
in the spike applet
a full retargeting takes place every time you pause a drag
or slider movement.
Construction of the targeter tree is handled transparently
by Superficial. Each contenter in
a Superficial application need only define target and facet
trees for its content, and its containing surface constructs
a suitable targeter tree to connect them.
Defining the surface - contenters
The transparency to client code of retargeting
makes it possible to encapsulate the definition of surfaces
and thus of complete applications.
Take a look at the code in the code
viewer applet, and you will find that surface elements
are always defined by contenters that wrap the application
content. A contenter defines
- targets representing both its content and surface elements
such as panes and windows
- facets defining GUI widgets for viewers, menus and tool
areas that expose these targets to the user
Simple applications such as those in the tutorial
can be constructed using specialised contenters, while even
a multi-viewer, multi-content type application such as the
spike application
is surprisingly easy to define.
Retargeting in action
You can view retargeting in the
spike applet and
code viewer using
two different debug options.
Toggle the Graph checkbox below the spike applet
and
the viewer pane splits into two.
In the left-hand pane you can still interact with the viewable
content, while in the right-hand pane you can monitor the
state of the targeter tree.
Expand the bottom, 'selection' node of the targeter tree
far enough,
and for each property of the currently selected text line
you will find
- the targeter for the property
- its current target representing the property
- the property value itself
- the facets attached to the targeter, exposing the target
and thus the property
Change or move the text line and the targeter tree adjusts
to match.
The other debug option allows you to watch the retargeting
sequence that updates the targeter tree and the facets attached
to it.
Open the Java console for your browser and toggle the Trace
checkbox below the spike applet. The applet reopens and you
can watch the targeter tree being created, then the retargeting
that takes place after each input to the surface.
The power of Superficial - separation of concerns
Because a Superficial surface is defined
purely in terms of facets, targets
and the targeter tree that mediates
between them, interactions between application elements are
very clearly defined.
- A GUI widget interacts with its managing facet only to
notify user input.
- While viewer facets interact directly with the domain
content framed by their viewable targets, simple facets
interact only with their targets.
- The targeter tree interacts with both facets and targets
through very narrow interfaces.
- A target interacts actively only with the application
element it represents.
- Application content has no knowledge of the surface that
enables the user to interact with it.
This strong separation of concerns ensures that Superficial
applications are inherently easy to develop, debug and maintain.
© 2007 David M Wright
|