Design Issues for the Athena Tools Library ------------------------------------------ 1. Dialog management 2. Appropriate Granularity for Ease of Use 3. Interface Builder 4. Tools for Groupware 5. Multi-media/Hypertext 6. Postscript Output 7. Data/view separation 8. Inter-object/widget communication 9. Cut-and-paste 1. Dialog Management ----------------------- We'd like some easy way to create and deal with non-trivial dialog boxes. "deal with" means put initial values in, let the user mess with the values, maybe do some sanity checking on the user's values, then return the user-modified values to the programmer. The approach I've taken in my testplotter program is to initailize a static array of structures with information about each element (widget) in my dialog box. Each structure indicates the type of the widget, the name of the widget, where the dialog should get the initial value and what it should do with the modified value, etc. It is designed to work only for user editing of values in an Xt Object -- each dialog element modifies a single resource of the Xt object. All layout of the dialog box is done from resource files, which currently still proves fairly tedious. This scheme seems like a fairly good one. By adding more fields to the structure used in the static array describing the dialog, more features could be added. Another approach would be to have an AtDialog widget which had a string resource which encoded all this stuff. This is the approach MuMenubar took. One of the hard questions about dialog managament is deciding what quantities are to be edited in the dialog. The scheme described above uses resource names. The AtParameterBox (a "dialog box" in the sense that its contents are automatically generated, and somewhat automatically managed) simpifies the problem by only allowing numbers to be edited, and only one type of widget to be used to do that editing. Another approach might be to have the app programmer give names (char *'s) to each value that is going to be subject to dialog and then use those names when constructing the dialog boxes. Or each value could have a integer handle associated with it (using a header file of #define's) and these handles used to refer to the quantity. This is like the approach the Mac takes to resource management -- each "resource" has a number. It cuts down on flexiblilty somewhat, but probably results in a system that is easier for programmers to understand and therefore easier to use. In this example, any quantity subject to dialog in the application would get a "resource number" This "resource number" concept might also be useful elsewhere. In the MuMenubar widget for example -- one resource number for each entry in the menubar. The other hard problem of dialog management is laying out the dialog box so that it looks nice. In my testplotter program, I put the dialog in a form widget and do all the layout from a (very long) resource file. That approach works, but it means that the dialog facility I use really isn't "automatic", because it takes about an hour to write the "code" that lays it out. An interface builder would solve this problem, perhaps. Also helpful though would be an alternate sort of layout widget. Marc Horowitz (I think it was him) has a good idea about a composite widget that lays things out in TeX like hboxes and vboxes. It has a single string resource that sets up the "boxes" and indicates where each child goes. The layout algorithm would also understand the TeX concepts of hspace and vspace. I imagine a resource specification looking something like this: dialog1.layout: column[row(space, title, space),\ row(list),\ space,\ row(okay, help, cancel)] The names ("title", "list", "help", etc.) are names of the children of the composite widget. This would simplify layout alot, I think. 2. Appropriate Granularity for Ease of Use ------------------------------------------ It is interesting to consider the "granularity" of the widgets we produce. Simple, widgets, while general purpose and elegant, can be a pain to compose up with other into a useful form. Widgets that are already highly composite lose the general-purpose nature and become less useful. We've got to find the right balance: what tools are the most useful building blocks we can provide? Some tools that seem to me to be at the right level of abstraction: MuMenubar (renamed At?) AtDialog (as described above) AtCli (command line interface, xterm like) AtMessageLine AtFileViewer AtParameterBox (already being designed) AtRadioBox (creates its own toggle button children, remembers which is selected) MuOptionMenu (creates its own chidren, remebers which is selected) XmMainWindow XmFileSelectionBox AtPalette (bitmap buttons in one or two columns) AtDrawingArea (like XmDrawingArea, but w/ more features) etc. Things that are cumbersome to adapt to particular uses: XmList XmOptionMenu XmText It is worth spending time looking through existing applications to see what the major components of the interface are. If we can supply widgets so that a programmer can choose 5 or 6, one for each major component of the application, we'll have done well. Just because application don't commonly use a particular component doesn't mean its not useful. Maybe it just wasn't available (pull down menus, for example). So we need to think about the application development process and common components. 3. Interface Builder --------------------- It would be real nice to have one of these. There's no good definition of just what an "interface builder" is, though. It could just be something that allowed a programmer to graphically lay out widgets, or it could go further and take on some dialog management type features -- helping the programmer to set up the computer/user interactions. We could buy one. It would have to be flexible enough to work with all of the objects in the Athena Tools library, though. We could wait and see what the CDS people come up with. We could write our own. Writing one wouldn't be that hard if we constrained the problem to graphical composition of the components discussed in the last section. The output of an interface builder could be code + a resource file, or depending on how sophisticated our automatic dialog creation routines became, possibly only a resource file. 4. Tools for Groupware ----------------------- Don Davis and I had a very fruitful discussion about "groupware" on Project Athena. By groupware, we mean (approximately) applications that allow for some degree of colloboration between students, or perhaps more generally simply applications that take good advantage of the network. The concept of groupware is an up-and-coming one, and its potentials are not well understood yet (at least not by Don and I). Our discussion centered around the questions "What can be done with groupware?/What forms might a colloborative appolication take?", and "what sort of tools can Athena provide to support the use of the network in faculty courseware?" I've written a separate document detailing my ideas on the subject. Below are the things most directly related to the At library. - "Talk widget". A compound widget that is essentially a zephyrgram browser. It would automatically subscribe to a particular class (based on the application name) of zephyrgrams. Another text widget and a "Send" button would allow each user to compose and send their own messages. Maybe it should also display a list of other users currently running the application, and perhaps the establisment of a private conversation between some subset of those users (eg. a group of lab partners). - "Discuss widget" A compound widget for reading discuss meetings. It should emphasize the use of messages chains to the extent that each chain looks like a separate meeting. It needn't support all the acces control features of the text-based discuss. - "Show Me" support in Athena Tools widgets. The major widgets (plotter, stripchart, spreadsheet, etc.) under development in the Athena tools library should support a "show me" facility for displaying themselves in another instance of an application. This is probably best done by making a copy of the widget's resources, sending those over the net and re-creating the widget on the other end. It has to be done in an architecture independant way. If we have a good data/view separation, then it is only necessary to send the data objects over the wire. - A simple inter-application messaging scheme. A simple call for an application to send a message (integer message id + a string of bytes) to another instance of itself, and a simple call for an application to register a callback to be invoked on receipt of a message. This could serve as the basis for a simple cycle service scheme. This would not be user visible, but the application developer would have to use it. 5. Multi-media/hypertext ------------------------ This would also be something that would be "real nice" to have. I've become more and more convinced that we need something like this. We should really have multi-font formatted text and equations for the AtHelp widget as well as for a "discuss widget". The ability to include drawings and window dumps in the text would also be a big win. Annotations in the text would also be valuable. A well done "hypercard stack" often makes a good piece of courseware just by itself, even though it is not an "application" in a traditional sense. The CDS project is headed in this direction, and may come up with a useful hypercard system. The andrew tookit also has good multi-media capabliity. It may be possible to turn the guts of the Atk objects into widgets. Allowing mult-media editing is not as important as allowing the display of multi-media. We may be able to get away with just static display of text with pictures and equations. The current AtText implementation is set up with short (multi-line) strings of text in mind. It may not be satisfactory for the display (and scrolling) pages of text. 6. Postscript Output -------------------- Some of our widgets will have to be able to generate high-quality postscript representations of themselves. Certainly the widgets used to display data: AtPlotter AtStripchart AtSpreadsheet and perhaps others. Note that the postscript representation need not look exactly like the screen representation, and in fact, in the case of the stripchart, for example, they may look very different. Writing good postscript takes some work. Read: "the green book" -- Postscript Language Program Design", as well as "Document Structuring Conventions Specification". I found this latter in the NeXT 0.9 Technical Documentation appendicies volume. One of the tricky things is to make sure that the postscipt output conforms to the structuring standards so that it can be included into other docs as an illustration. Since composite widgets can have complicated internal substructures, their postscript may also have substructures. For example to draw a plotter widget, it is necessary to draw axes, a title, a legend, and all the plots. Since the axis and plots are separate objects, they should be responsible for generating their own postscript representations. But the plotter is responsible for taking those represenatations and incorporating them into the larger picture. Object like AtText and AtAxis need to have a bounding box query function that returns how much space they will take up on the page. All widgets and objects need a draw function which is passed a FILE * and a bounding box. If the object can't fit in the passed bounding box, it is okay ot overflow it. A widget like the plotter doesn't need a bounding box query function, because it isn't a component in a larger widget that will want to be displayed, and because no matter what size box is passed, the plotter can fit itself in by shrinking its plotting area. Generating the prolog for postscript output is also a little tricky. Any object that has an "OutputPostscript" function will probably need an "OutputProlog" function, so the postscript code can rely on functions defined in the prolog. The AtPlotterOutputProlog() function would call the AtAxisOutputProlog, AtPlotOutputProlog, and AtTextOutputProlog, for example. But the AtAxisOutputProlog would also call AtTextOutputProlog, and the postscript code would end up with two copies of it. So it would be nice if we had some way of remembering which prologs had been written to a file so that they wouldn't be duplicated. Then writing a prolog would be like registering a converter, or including a file -- it could only be done once, and everything could call the function without worrying about multiple inclusion. It is the fact that the prologs are getting written to a file that makes it difficult to keep track of which have been output, so a better solution might be that each object would have a static string as prolog, and it would return a (constant) pointer to that string when requested. Then code could check that no two pointers to the same object were being passed. Another solution would be to keep the prologs simple enought that they could all just be included at the top of all Athena Tools postscript output. The postscript output itself should be kept as straightforward as possible. There should be no (or few) computations done in the code. All objects should assume that they are being printed at the default scale with no rotation. They should simply draw themselves at the requested location. 7. Data/View Separation ------------------------ A common object oriented programming technique for user interfaces is to enforce a data/view separation. This means that the data being viewed (an array of numbers, or a buffer of text, for example) are kept as separate objects from the viewer objects. This allows the flexiblity to allow multiple views on the same object (two different locations in the buffer for example, or plotted as two different plot styles). It allows the viewer object to easily be "reused" on different data. One of the advantages of a data/view separation for the Athena Tools library is that it would simplify cut-and-paste operations (the data, not the viewer is responsible for data format conversion) and allow data to easily be "bundled up" and passed over the network to another instance of the application. (It is a difficult problem to do the same for the view widgets.) Our current architecture contains a kind of data/view separation. The separation of AtPlot from AtPlotter, of AtTable from AtSpreadshet, and AtTrace from AtStripchart are along the right tracks, but since the "data" object are Xt Objects, things are not quite right. AtPlot and AtTrace objects are children of their viewer objects, which means that there cannot be multiple views on the same object. The AtTable object does not have this problem. It is possible to "clone" an Xt Object and even to pass it over the network, but because of the hierarchial architecture of the X Toolkit, this is not simply a matter of copying the bytes. Currently our AtPlot AtTrace and AtTable objects would have to each have their own Copy function. Perhaps it would be better to consider the AtPlot and AtTrace objects as another kind of view object, and come up with non-Xt pure data objects for each. Then each AtPlot or AtTrace object will have a pointer to one of the pure data objects, allowing multiple views and easy copying. 8. Inter-Object/Widget communication ------------------------------------- There are a variety of ways that communication takes place between objects and widgets in the current Athena Tools library. All the existing techniques are for communication between a view widget and its associated data XtObject. One obvious technique is for the viewer to invoke class methods (draw, resize, etc) of its children. Using XtSetValues or XtGetValues to examine or set resource values is another techinque for communicating. When a child object needs to send its parent a command or a notice, ("redraw me", or "my bounding box has changed"), it can use XtCallCallbacks to invoke procedures its parent has registered, or it can use XtSetValues to set the value of a constraint resource, thereby causing its parent's ConstraintSetValues method to be invoked. A more interesting sort of commnincation is the ability to communicate changes in the values of data objects when there are multiple views on the same object. Consider a parameter to some simulation program. Its value might be displayed in an AtParameter widget or an AtSlider widget, and might also be available for manipulation through an AtScratchpad widget. When the user changes the value in one widget, it must also change in the other. As another example, consider a table of data displayed stored in an AtTable object and displayed in an AtSpreadsheet widget. Two of the columns of data are plotted in an AtPlotter widget, and the user now edits the data in the AtSpreadsheet. An approach to this sort of communication is to give a name to all data objects and register them in an AtSymbolTable or some other sort of "Notificiation Handler". These data objects are the "pure data objects" described in the section on data/view separation above could be simple floating point numbers used as simulation parameters, or entire tables of data being viewed in an AtSpreadsheet through an AtTable object. The symbol table would allow lookup of data by name, and would also maintain a reference count of interested parties for each object. When the value of a data object changed, the symbol table would notify (through what amounts to a callback list) all the interestd parties. Implementing such a notification handler system will probably require enumerating a fixed number of data objects to be used in the Athena Tools architecture. While this may seem like an unreasonable imposition, we can probably manage fine with a moderate number of datatypes (integer, real, complex, rational?, bigint?, date?, time?, boolean?, array, matrix, for example.) We will probably want one AtValue type which is the union of all these primitive types. 9. Cut and Paste ---------------- Cut-and-paste protocols are fairly well supported and defined by X and the Inter-Client Communictions Conventions Manual (ICCCM). The interesting issue is another facet of the inter-object communication problem -- what are the standard data interchange formats? ASCII is the obvious and most important one. All of our objets must be able to read and write an ASCII representation of themselves from and to files and strings. This is useful for saving a table to a file, or pasting an AtPlot into an xterm (formatted as an ASCII table of x,y pairs), but not as appropriate for cutting columns of data from an AtSpreadsheet and pasting them into an AtPlotter to see them graphically. For this sort of data transfer, we'd like a more compact representation that required less conversion time. In its most general form, this seems like a fairly open-ended problem, but if we impose appropriate constraints on it, we can probably come up with a satisfctory solution. If we can (as postulated in the last section) enumerate all the data objects that are used in the Athena Tools library then we can list data exchange formats that will cover all of these cases. (Maybe just a one-to-one mapping from data-type to exchange format, or perhaps something somewhat more complicated.)