[Editor's note: this document is an HTML version of notes written by Emden Gansner on the new widget set.]
The eXene widget set has undergone major changes. Although the new set is largely upward compatible with the old (version 0.4) in terms of function and use, the new set has new widgets, old widgets have new features, the widgets have a Motif-like 3D look, and the widgets use X resources to allow customization, especially of such visual aspects as color and font.
The use of resources allows us to make the creation of widgets more uniform. By convention, the creation function for a widget will have the form
val gadget : (Widget.root * Widget.view * Widget.arg list)The root argument, as before, corresponds to a screen in X terminology. The view argument provides a "view" of the widget as parameterized by X resources. At present, a view is the pair
[ -> optional additional arguments ] -> gadget
type view = Styles.style_view * Styles.style
The style component can be viewed as a database of string values keyed by regular expressions, following the conventions of standard X resource files. Thus, a typical entry might be
plotos*TextEntry.background: red
The style_view component corresponds to a collection of names and aliases the widget will use for itself when it looks up resources in the style. If widgetB is to be a child of widgetA, a programmer will typically make a style_view for widgetB by extending the style_view of widgetA (using Styles.extendView and Styles.extendName) with some specific name for widgetB. In addition, if widgetB belongs to some logical class, names for the logical class can be added to widgetB's style_view as aliases.
For example, suppose we have a pair widget (we don't) that takes two child widgets and displays them next to each other.
val pair : (Widget.root * Widget.view * Widget.arg list)and suppose we have a style and have constructed a style_view for the pair widget:
-> (Widget.widget * Widget.widget) -> pair
val style : styleWe want to create two text buttons that will be put into the pair widget. We will name one button "leftButton" and the other "rightButton". In addition, for our application, the left button will belong to a special class of alarm buttons. We would then do the following:
val pairName : style_view
structure S = StylesConcerning the style, usually a single style is created for an application and is passed unchanged to all the widgets. At present, a style can be created from a list of strings using Widget.styleFromStrings. In the near future, we will provide functions for creating styles using user and application default resource files, the X resource database and command line arguments.
structure B = Button
val rightButtonName = S.extendView (pairName, "rightButton")
val leftButtonName =
S.prependAlias (S.extendView (pairName, "leftButton"), "Alarm")
val leftButton = B.widgetOf (B.textBtn (root, (leftButtonName,style), []))
val rightButton = B.widgetOf (B.textBtn (root, (rightButtonName,style), []))
val pair = pair (root, (pairName,style), []) (leftButton, rightButton)
As noted above, the first argument used to create a widget is the triple
(Widget.root * Widget.view * Widget.arg list)We've discussed the first two components. The argument list allows the programmer to have specific control over the resources of a widget. Normally, a widget uses the style in the view to find its resources. The end user determines the style by altering her X resource database. However, for a given application, certain parameters of a widget might be critical enough that the user should not be able to affect them. In these cases, the programmer can specify these parameters using the argument list. The attributes specified in the argument list override the style provided in the view.
At present, an arg is a name-value pair
type arg = Attrs.attr_name * Attrs.attr_valueObviously, attr_name corresponds to the name of the resource and attr_value corresponds to its value. (The Attrs structure provides internal representation of the names and values used in styles. In addition, it provides a collection of common attr_names.) Thus, if a programmer insists that a button have a red background, she can use
structure Attrs = AFor further information on the creation of styles and style_views, see the styles directory.
val bttn = B.textBtn (root,view,[(A.attr_background, A.AV_Str "red")])
To simplify the startup of an eXene application, there is a new module RunEXene that provides a function that takes an argument of type Widget.root -> unit, looks for the shell environment variable DISPLAY to specify the display, starts CML, creates a root, and then calls the function provided.
Below is a sketch of a typical eXene application called "draw":
structure S = Styles
val defaults = [
"draw*background: gray80",
"draw*foreground: black",
"draw*selectColor: yellow",
"draw*Button.background: gray70",
"draw*font: -Adobe-Helvetica-Bold-R-Normal--*-120-*"
]
fun main root = let
val style = Widget.styleFromStrings (root, defaults)
val name = S.mkView {name = S.styleName ["draw"], aliases = []}
(* make widget name hierarchy *)
(* create widgets button up *)
val layout = ... (* top-level widget *)
val shellArgs = [
(Attrs.attr_title, Attrs.AV_Str "draw")),
(Attrs.attr_iconName, Attrs.AV_Str "draw")
]
val shell = Shell.shell (root,(name,style),shellArgs) layout
in
Shell.init shell
end
fun doit () = RunEXene.run main
This version of the eXene widgets represents the widgets as they are right now. There are many bugs; many of the widgets have not been converted to a 3D look or to use resources; there will probably be additional changes in the design.
The use of resources is neither complete nor uniform. There will probably be some convention by which a widget will automatically add some class name to its style_view. Widgets that create internal subwidgets (e.g., scrollPorts) do not as yet provide them with new style_views.
The idea of the argument list used at widget creation is right, but its
form is not. A flat name-value list does not allow a programmer to
control the resources of specific internal widgets. The name component
of an argument needs to reflect the hierarchy. This suggests replacing
the type of name with a list of names, a list of strings or perhaps
strings following the conventions of resource databases, i.e.,
"plotos*TextEntry.background"
There is no new documentation reflecting the new interfaces and features. At this point, even comments are minimal. If a widget supports resources, these can be deduced from a list of attribute names and default values found in the source file.