Getting Started Documentation Glish Learn More Programming Contact Us
Version 1.9 Build 1556
News FAQ
Search Home


next up previous contents
Up: NOTE 231 - All About the AIPS++ Display Previous: The Glish Connection

Subsections


Programming Practicalities

Implementing a new PixelCanvas

To support a new output device for AIPS++ display applications or tools, it will be necessary to implement a new PixelCanvas and PixelCanvasColorTable pair. At the time of writing, two major PixelCanvas implementations exist: the X11PixelCanvas for display to X Windows devices, and the PSPixelCanvas for hardcopy output using PostScript. A slightly specialised version of the X11PixelCanvas -- TclTkPixelCanvas/GTkPixelCanvas -- exists to facilitate the implementation of the Display Library interface in gDisplay.so. New PixelCanvases are envisaged for OpenGL and Java devices in the future, but are not yet included in planning documents.

Development of a new PixelCanvas should begin with the design of a PixelCanvasColorTable which manages color allocation strategies on the new device. The PixelCanvasColorTable class is quite sophisticated, but should be adaptable to most display device allocation schemes in the near future. The most important facilities of the PixelCanvasColorTable to implement for new devices are the capability to dynamically resize the entire ColorTable itself, and to dynamically extend and reduce the color usage of the various Colormaps registered on the ColorTable. Of high importance also is the facility to provide multichannel visuals even on devices whose intrinsic software or hardware does not provide such. For example, the X11PCColorTable provides HSV and RGB facilities even for native X PseudoColor visuals.

With the PixelCanvasColorTable in hand for the new device, attention can turn to the PixelCanvas itself. From the outset, a decision should be made on whether a display list caching facility will be provided. This is highly recommended for interactive devices, such as OpenGL, but is seen as less important for non-interactive devices, such as the existing PSPixelCanvas which has no great need to offer caching services. For interactive devices, code to turn native events (such as mouse movement and key presses) into PC{Motion,Position}Event objects as appropriate must be implemented, and finally the graphics primitives must be implemented to a high level of quality and trustworthiness. Ultimately, it is the intention to provide full test wrappers for all classes in the Display Library, and PixelCanvases being one of the fundamental classes should receive such attention early on in the development process.

Writing new Tools

The first decision to make when writing a new tool (control) for the Display Library is whether the tool needs to detect events on the PixelCanvas, or instead on the WorldCanvas. Events on the PixelCanvas are appropriate, for example, when the user is going to modify a parameter which might be applied to objects which are not necessarily specific to a WorldCanvas, eg. a Colormap. Events on the WorldCanvas are appropriate when the tool will need real world coordinates to accomplish its task, as is the case for example in zooming. Having made this choice, the programmer should then derive from either WCTool or PCTool in the DisplayEvents module of the display package. In certain cases, deriving from existing higher-level classes such as WCRectTool will be good practise and buy the developer and user significant common ground. There are sufficient tools now implemented to give good example code on how to extend the tool beyond the derived capabilities. The majority of this code can be found in trialdisplay/implement/DisplayEvents.

Writing a DisplayData

Writing a new DisplayData still remains the most complex task in developing the Display Library, and no doubt it would be worth spending a considerable amount of time on improving the programmability of DisplayDatas. This complexity is primarily because the DisplayData object is expected to do a lot of work, both in accessing and extracting data from storage, and actually drawing the data to the screen. The complexity also arises from the fraction of development time spent on DisplayDatas to date, compared to the magnitude of the work they are ultimately expected to do. There is no doubt that parts of the DisplayData class interfaces need further work, and this work will need to be carefully coordinated in the future amongst the various Display Library developers. Anyway, on with the show ...Start by examining the code available in trialdisplay/implement/DisplayDatas: the primary interfaces that must be understood are the DisplayData and DisplayMethod classes. These two classes define the interface for the entire DisplayData class hierarchy, and are therefore of utmost importance.

After digesting these two classes, attention should be given to the immediately derived classes CachingDisplayData and CachingDisplayMethod. These two classes add to the base class interfaces to implement ``automagic'' caching facilities for DisplayDatas. The idea is that if a DisplayData has previously drawn itself on a WorldCanvas, with a set of given options or attributes or characteristics, then if requested to do so again, and the conditions have not changed, or at least have reverted to the state they were in, then a cached drawing should be available to place rapidly on the viewing surface (ie. the WorldCanvas). The main trick to using these classes correctly is to properly implement the optionsAsAttributes function, and to correctly manage the set of Attributes on the DisplayData itself. If this is done correctly, as described in the class documentation, then classes derived from CachingDisplayData and CachingDisplayMethod need never worry about implementing the refreshEH method of the base DisplayData class.4It is the humble suggestion of the author that all future implementations of DisplayDatas be made by deriving ultimately from the CachingDisplay classes.

Other than actually accessing data and drawing it to a WorldCanvas, one very important task still not implemented at the level of the CachingDisplayData class is DisplayData::sizeControl. The job of this method is -- on request from a WorldCanvas -- to set up the linear coordinate system (LCS) of that WorldCanvas. Very roughly, two types of DisplayData exist: those that do implement sizeControl and can therefore set up the WorldCanvas LCS, and those that leave a null implementation and return False to the caller. The latter type can be termed passive DisplayDatas, and they can only ever draw once another DisplayData's sizeControl method has been called for the WorldCanvas/Holder on which they are registered. As such, they are pretty easy to write, but only suitable for use as overlays on other DisplayDatas.

The former type, the active DisplayDatas, must have the sizeControl function implemented in a non-trivial way, and return a True value to indicate to the caller that indeed they did perform a ``sizeControl'' action. The sizeControl function is expected to set up the LCS of a specified WorldCanvas. It must honour any zoom level that is presently set, and then satisfy any settings on the DisplayData itself regarding the coordinate system. While the sizeControl function is quite complex, it ultimately provides tremendous freedom in terms of the types of DisplayData that can be implemented. For example, in the sizeControl function, a DisplayData could actually modify its data based on geometry of the WorldCanvas. A specific example of where this could be used is in some application where the user is allowed to drag a WorldCanvas around a PixelCanvas, and the WorldCanvas acts as a ``window'' to some larger dataset beneath it -- just an idea!

Of course the final task of a DisplayData is to actually draw data to the WorldCanvas upon request. In the CachingDisplayData branch, this is handled by the (already implemented) refresEH function constructing a new DisplayMethod if necessary, and then calling the draw method within

Adding Agents to the GlishTk Interface

Adding new proxy agents to the GlishTk interface is a fiddly procedure. Aside from making decisions about whether the new agent maps exactly to an existing Display Library class, or instead makes use of multiple classes, there is a moderate amount of coding to be done. Design decisions aside, let us concentrate on the GTkColormap class, which contains a Display Library Colormap object. This class is an implementation of a GTkDisplayProxy, and makes use of some services from the DisplayOptions class. A cursory examination of GTkColormap.h will reveal that this class mostly provides a brief interface to access the facilities of the Colormap class, eg. char *GTkColormap::setoptions(Value *); is provided to allow a number of settings to be made from Glish. In the way of private data, GTkColormap simply stores a pointer to a Colormap.

Turning now to the implementation file, GTkColormap.cc, most of the interface work is done in the constructor. Each proxy agent must have a unique agent_ID, and this tag can be used by other agents to check that a provided agent for some operation is of the correct type, before casting. The contained Colormap is constructed, and then a couple of widget commands are installed. Just follow the existing code, which simply sets up a small map of Strings to functions (actually offsets into the class object). At the end of the constructor it is very important to mark the agent as valid, so that destruction can be handled properly.

The next function is a global C-style function, GTkColormap_Create. This is actually the function which is registered with Tcl to create colormap proxy agents, and after parsing the arguments (Value *args), explicitly constructs a GTkColormap object. Many things can go wrong here, so a fair component of the code is actually error checking code. This global function is actually registered to create colormap proxy agents by code in the Gdisplay_Init function implemented in gDisplay.cc. Destruction of the GTkColormap agent is straightforward. There follows a simple implementation of the required IsValid function, whose return value is examined when the destructor of the base class is called.

Finally, in GTkColormap.cc, implementations of the widget commands themselves (in this case setoptions and getoptions are given. Most of their work is involved in turning arguments coming in to the function in the Value *args style into useable data for native Display Library class functions.

Let's now look at the gDisplay.h and gDisplay.cc files. To ``export'' the GTkColormap class to Glish, it is necessary to add protected data to the TkDisplayProc class which can store the offset of a widget command in the GTkColormap class, and provide a constructor which can set up this protected data member when necessary. In gDisplay.cc the operator()(...) must be extended to handle the case where the stored offset is one into a GTkColormap, and call the method at the stored offset. Additionally, the global functionGTkColormap_Create must be declared in this file, and then registered with a call to GlishTk_Register in the implementation of Gdisplay_Init.

It is worth pointing out that the function Gdisplay_Init also does a very important thing regarding PGPLOT. It initialises the global pointer display_library_pgplot_driver to point to the global external function wcdriv_, in order that PGPLOT be able to draw on Display Library WorldCanvases. Gdisplay_Init is called when the Display Library module gDisplay.so is loaded, and so if the Display Library is not loaded, the global pointer display_library_pgplot_driver remains zero, and is (correctly) never available for use.

The last link in the chain to get colormap agents working from Glish is to add appropriate code to the Glish script gdisplay.g. This script actually provides the mechanism from Glish for loading the gDisplay.so module, and thereby installs global symbols in Glish for constructing the various proxy agents. Simply follow the existing code to add a new agent.


next up previous contents
Up: NOTE 231 - All About the AIPS++ Display Previous: The Glish Connection   Contents
Please send questions or comments about AIPS++ to aips2-request@nrao.edu.
Copyright © 1995-2000 Associated Universities Inc., Washington, D.C.

Return to AIPS++ Home Page
2006-10-15