[PEAK] Generalizing interaction and presentation components
Phillip J. Eby
pje at telecommunity.com
Wed Nov 7 19:42:46 EST 2007
So, after thinking some more about the menu/toolbar stuff, and
talking it over with Grant, I've come up with a refinement of how
PEAK's coming UI framework should handle interaction and presentation
Scopes and Features
The basic idea is that there are two basic kinds of interaction
components: "scopes" and "features". A scope is some
application-specific object representing an ongoing interaction
between the user and some application state.
For example, if one were making a calendar application, one might
have a scope that included a "current day" cell, and a trellisized
list of events for the current day. It might even include discrete
event cells that trigger "next day" or "previous day" actions, etc.
In contrast, "features" are usually *not* application-specific, at
least in the sense that they conform to standardized interfaces, even
if their implementation includes application-specific details.
The most basic kind of feature would simply know its ID (a unique
string), human-readable (and localized) title, a help string (also
localized), and have cells for its visibility and enabled/disabled
status. It would also be able to have tags associated with it.
More specific types of features would represent generalized
interaction concepts like Text (i.e. a type-in field), Choice,
Toggle, Command, and so on.
Features are still interaction-layer components, however, not
presentation layer. A set of "Choices", for example, could be
represented as a submenu (or pop-up menu) with checkable items, a
dropdown box, or a set of radio buttons (including toolbar
buttons). The specific presentation chosen is sensitive to the usage
context and tags. Ordering, as well as menu placement, nesting,
hierarchy, etc., can all be done with tagging.
A Scope is responsible for keeping track of its Features, so that
when one attempts to create a presentation component for a Scope, it
should be possible to assemble and render the relevant Features automatically.
So, our hypothetical calendar scope would need to be able to
instantiate Features to represent the "current day", "current day's
events", "next day action", and so on. In addition, extensible
scopes would need to allow plugins to add Features on-the-fly.
Questions So Far
At this point, some of the remaining open questions are:
* Are Scopes themselves Features? It seems that sometimes the
features provided to a sub-scope need to be seen at a parent
scope. For example, if our calendar scope is displayed as a small
part of a larger window, we may want its next/previous day actions to
show up in the window's menus or toolbar. However, this doesn't
automatically mean Scopes are features, just that Scopes need to know
about sub-scopes and include their Features when queried.
* How, precisely, do we implement key tag-based features
(menu/toolbar paths, ordering, custom widget factories,
enable/disable rules, etc.)?
To answer these questions, it's probably going to be best to try to
develop some presentation components, in order to see what sort of
API they will "naturally want" to query features by. For example, a
window will want to query its scope for features tagged as relevant
to its menu, a toolbar will want to query for toolbar-capable
features, and so on.
And virtually every sort of presentation will involve some kind of
ordering and nesting, so there probably needs to be a generic
implementation there. At the same time, it needs to be set up such
that each presentation has its own ordering and nesting information,
since the same feature may appear in a menu, toolbar, and dialog --
each with its own sequence and grouping. (Indeed, it's possible that
the tab order of controls in a dialog might also be different from
the dialog's visual appearance order.)
Besides the ordering and nesting, however, relatively little tagging
information seems likely to be GUI framework neutral or
application-neutral. It's possible that we could include generic
symbols that could be interpreted in framework-specific ways, and we
can likely include some general purpose "toolbar" and "top-level
menu" tagging structures. But applications with specialized needs
(like Eclipse's views with their individual toolbars and pull-down
menus) will almost certainly need to build on these things a bit.
In order to keep from talking about "menus, toolbars, etc."
indefinitely, I think I'm going to refer to "composite affordances"
instead. An affordance is something like a button or menu item or
field, and a composite affordance is thus a group of affordances
that's rendered automatically from a scope's features. Let's call it
a CA for short.
In essence, there will be generic CA types like toolbar and menu,
with specializations for context menus, dockable toolbars, and
whatnot. In addition, applications could further specialize these CA
types for e.g. Eclipse-style view-specific pulldowns.
The CA types need not depend on a specific GUI framework, as the
mechanical presentation aspects can be handled via other tags. The
main purpose of CA types is to select, group, nest, and order a
subset of available features.
At this point, it's not entirely clear to me where or how CA
instances are created, or how they link to features. One likely
method would be to make them AddOns to the Scope, initialized by the
Scope's __init__ and load_extension() methods. That is, plugins
would just refer to them as add-ons and go from there.
The API for this needs to gel a bit. Well, more than a bit! It's
going to be interesting/tricky to do it in such a way that there's
minimal redundancy and maximum error checking at definition
time. The "strings as IDs" thing needs to trade off against ease of
reference, for example, as hinted at in my last missive.
So I think my next step is going to be to start doing some API
sketches, like the ones I did for the Trellis a few months ago, to
look at some alternatives for how to spell and link things together.
More information about the PEAK