draft April 1989 Panel Library Programmer's Manual Version 9 David A. Tristram National Aeronautics and Space Administration Ames Research Center Moffett Field, California 94035 Pamela P. Walatka Sterling Software Contract 2-11555 Ames Research Center Moffett Field, California 94035 NASA Ames Research Center Numerical Aerodynamic Simulation Systems Division 1989 TABLE OF CONTENTS Introduction Initialization Scripting Script Files Some Sample Code Action Functions Behavior Functions PROGRAMMER FUNCTIONS.........................................Section 2 g_gets-- get string from user without textport g_getstring -- get string from user without textport pnl_addact -- add an actuator to a panel pnl_addpanel -- add a panel to a running application pnl_addsubact -- add subactuator to actuator pnl_alloc -- allocate storage pnl_delact -- delete an actuator and its subactuators pnl_delpanel -- delete a panel and its actuators pnl_dopanel -- initialize and update panels pnl_drawpanel -- draw all panels pnl_dumppanel -- create file defining current panel configuration pnl_endgroup -- signal end of group of actuators pnl_fixact -- update actuator pnl_fixpanel -- update panel pnl_mkact -- create actuator descriptor pnl_mkpanel -- create panel descriptor pnl_mkuseract -- create actuator with extra storage for user data PNL_MKUSERACT -- create actuator with extra storage for user data pnl_needredraw -- save data window redraw events pnl_userredraw -- save data window redraw events initscriptfile -- create panel with actuators for scripting functions pnl_beginreadscript -- control creation and use of script files pnl_beginwritescript -- control creation and use of script files pnl_beginappendscript -- control creation and use of script files pnl_endreadscript -- control creation and use of script files pnl_endwritescript -- control creation and use of script files pnl_dumpstate -- control creation and use of script files pnl_strwidth -- return width of string in panel coordinates ACTUATORS ..................................................Section 3 Overview of Actuator Types Actuator Descriptions PANEL AND ACTUATOR STRUCTURES ..............................Section 4 Panel fields list Actuator fields list Field descriptions GLOBAL VARIABLES ...........................................Section 5 Colors Fill patterns Panel and actuator structure pointers Positions and dimensions Scripting Library state Introduction The panel library provides a user-interface toolkit for the Silicon Graphics IRIS workstation family. It is used by programmers writing applications for the IRIS. User-interfaces built using the panel library consist of actuators and panels. Actuators are dials, sliders, or other mouse-sensitive glyphs. Panels are groups of actuators that appear as separate windows on the Silicon Graphics IRIS Workstations. The panel library offers a number of programmer functions that access two data structures: 1) the descriptor of panels, and 2) the descriptor of actuators. This reference manual is in a draft stage. It provides documentation of the library's functional interface, the actuator types, the use and meaning of the structure fields, and the global variables used to control the library. In this section it also gives some words on some basic concepts and design philosophy. However, it does not provide much high-level help for the new user of the library. New users are directed to the 47 demonstration programs provided with the source code. Each demo illustrates a new feature of the library, and, incidently, the order of the demos reflects its development history. The Panel Library is an extremely powerful and flexible toolkit, and there are usually a couple of ways to do what you want to do, so take some time when developing your application to consider the solution best for you. Initialization The function pnl_dopanel() expects that the application has already initialized its own graphics window for data output if there is to be one. The first time pnl_dopanel() is called, these initialization steps are performed: 1) The panel library sets the RGB color stored in nine locations of the colormap. The indices used can be changed by setting the panels color variables before pnl_dopanel() is called. The application programmer can change the color of control panels by setting the RGB colors stored in these locations or by changing the indices in the color variables after initialization has been performed. 2) Each panel created previously with pnl_mkpanel() is then initialized. The limits (minx, maxx, miny, maxy) of the world space coordinates are calculated. This is the bounding box of all actuators in the panel, plus a small border value. 3) If the application programmer has not set the height or width (h and w) of the panel (in screen space), the library determines the panel's size based on the world space limits and the panel's scalefactor (ppu or pixels per unit). 4) If the programmer has not set the panel's screen space origin (x and y), the library places the panel to the right and aligned at the top of the application's data window, or below and aligned on the left of the previous panel if there is one. If a panel would extend off the screen on the bottom, the library attempts to place it to the right of the topmost, rightmost panel. If a panel extends off the right of the screen, the library offsets it down and to the right 20 pixels from the upper right of the data window. 5) A window for this panel is then created and constrained to maintain its aspect ratio. On Iris 4D's, the window is placed in doublebuffered colormap mode. An orthographic viewing transformation mapping the panel's world space limits to the edges of its window is created and saved in vobj. 6) After all panels are initialized, the library queues the LEFTMOUSE, LEFTSHIFTKEY, RIGHTSHIFTKEY,CTRLKEY, (LEFTCTRLKEY and RIGHTCTRLKEY on the Iris 4D's) devices and ties the MOUSEX and MOUSEY devices to the LEFTMOUSE device. If the workstation is running the NeWS (4sight) window manager, the WINFREEZE and WINTHAW devices are queued to allow the application to continue running when a panel has been iconified. Scripting The Panel Library has the capability to save user interactions to a script file on disk for later replay. In all but a few cases, when reading from a script file, the user interface will behave exactly as though the user were operating the mouse. Scripting is controlled by five functions, pnl_beginreadscript(), pnl_beginwritescript(), pnl_beginappendscript(), pnl_endreadscript(), and pnl_endwritescript(). A predefined panel providing buttons activating these functions is provided by the library and may be added to any application by calling initscriptpanel() when defining the application's panels. Scripts may be interpreted in a human readable form by using the stoa utility. Script Files Script files consist of three types of packets: mouse, delay, and state, which are identified by reserved tokens, followed by binary data. Mouse packets are generated whenever an actuator is 'active', which usually means that the user has selected an actuator with the mouse button, and is still holding the button down. Mouse packets consist of the PNL_MT_MOUSE token, the id's of the current panel and actuator, the current world coordinates of the mouse in the current panel, and five bits of key state information, the values of pnl_justup, pnl_justdown, pnl_mousedown, pnl_shiftkey, and pnl_controlkey. Delay packets are generated when a number of frames, or calls to pnl_dopanel() have occurred without writing a mouse or state packet. This allows the Panel Library to wait while reading a script until the specified number of frames have gone by, keeping playback of scripts roughly time-synchronous with the recorded version. Delay packets consist of the PNL_MT_DELAY token and the number of fames since the last mouse or state packet. State packets attempt to save all information regarding an actuator. A state packet consists of the PNL_MT_STATE token followed by a dump of an actuator descriptor. If there is actuator-specific data associated with the actuator, it follows. Some Sample Code The following is a code fragment that allocates two global variables to hold pointers to actuators, and defines a function that, when called, creates a panel, creates two sliders with specified labels, positions, initial values, and value ranges, adds the sliders to the panel, and returns a pointer to the panel. #include /* globally accessable pointers to actuators */ Actuator *slider1, *slider2; /* call defpanel() before pnl_dopanel() to create a panel */ /* containing two sliders. */ Panel *defpanel() { Panel *panel; panel=pnl_mkpanel(); /* create a panel structure */ panel->label="position control"; /* give it a title bar string */ slider1=pnl_mkact(pnl_hslider); /* create a horizontal slider */ slider1->label="x position"; /* assign some of its properties */ slider1->x=1.0; slider1->y=0.0; slider1->val=0.0; slider1->minval= -1.0; slider1->maxval=1.0; pnl_addact(slider1, panel); /* place the slider on the panel */ slider2=pnl_mkact(pnl_vslider); /* create a vertical slider */ slider2->label="y position"; /* assign some of its properties */ slider2->x=0.0; slider2->y=0.0; slider2->val=0.0; slider2->minval= -1.0; slider2->maxval=1.0; pnl_addact(slider2, panel); /* place the slider on the panel */ return panel; } Action Functions Panel Library actuators and panels have three pointers to functions that are called when the user operates the mouse. These are called the action function pointers and are named downfunc, activefunc, and upfunc. The application programmer assigns the addresses of user defined functions to these pointers. Two of them are called when the mouse button makes the transition from up to down or down to up, and the third is called whenever the mouse button is down. The action functions are called after execution of the newvalfunc for the actuator and its subactuators. Panels may have action functions associated with themselves also. Assuming that an actuator A has been added to a panel P, and has in turn had a subactuator SA added to it, and SA, A, and P have a full complement (all three) of action functions, the following indicates what order the functions are called. event action ========================= mouse down pnl_dopanel() A->newvalfunc(A) SA->newvalfunc(SA) SA->downfunc(SA) SA->activefunc(SA) A->downfunc(A) A->activefunc(A) P->downfunc(P) P->activefunc(P) pnl_dopanel() A->newvalfunc(A) SA->newvalfunc(SA) SA->activefunc(SA) A->activefunc(A) P->activefunc(P) . . . continues while mouse button is down . . . pnl_dopanel() A->newvalfunc(A) SA->newvalfunc(SA) SA->activefunc(SA) A->activefunc(A) P->activefunc(P) mouse up pnl_dopanel() A->newvalfunc(A) SA->newvalfunc(SA) SA->upfunc(SA) A->upfunc(A) P->upfunc(P) Behavior Functions initfunc, pickfunc, newvalfunc, addfunc, addsubfunc, fixfunc, drawfunc, dumpfunc, loadfunc, delfunc. A design concept of the panel library is the use of indirect functions to provide behavior that is specific to an particular type of actuator, while letting static code in the library perform generic functions. For example, when calling pnl_addact(), generic modification of the panel library data structures containing actuators is performed, followed by execution of the actuator's addfunc. For some behavior functions almost all the processing is performed by the behavior function itself, while for others, almost all is done by the library. The following lists the behavior functions, and gives a brief description of their use and responsibilities. This information is intended to guide the programmer in the development of new actuators. initfunc Initfunc takes an Actuator structure that has had its fields initialized to standard values, and customizes it to reflect the properties of a particular type of actuator. The standard initfuncs are declared globally and are used by application developers as the argument to pnl_mkact() to specify which type of actuator to instantiate. responsibilities Initfunc is responsible to set the TYPE, W and H fields of the actuator. Initfunc sets the value of the behavior function fields to point to functions to implement the behaviors. Behavior functions fields left unassigned are ignored by the library. The initfunc allocates space for actuator-specific data structures and initializes the fields in it. DATA holds the pointer to this space, and DATASIZE its size. Some compound actuators create subactuators and add them to one another using pnl_addsubact(). These subactuators are also positioned within the actuator and initialized. pickfunc The pickfunc examines the mouse position within the panel or parent actuator and determines whether the mouse currently "selects" the actuator. Most actuators use the _hitact() function provided by the library which simply compares the mouse position against the actuator's bounding rectangle. newvalfunc Each actuator is expected to provide a function for determining the value of its VAL field. This function is given the address of the actuator being processed, the active panel, and the mouse x and y values. By using this information and the values of global variables describing mouse state, the newvalfunc determines its actuator's new value. responsibilities Newvalfunc is responsible to behave nicely if called with ACTIVE false. This is to give actuators a chance to change their value when the mouse has been released. In compound actuators: Newvalfunc usually calculates x and y coordinates relative to its own origin to determine which subactuator is selected and to propagate to its subactuators' newvalfuncs. If the actuator is not active, any current subactuator is set inactive and its newvalfunc is called. Newvalfunc usually returns with no further processing at this point. The actuator then determines which subactuator, if any, is active. The subactuator's SELECTABLE and VISIBLE fields are usually required to be TRUE, and the subactuator's pickfunc may be used. The actuator's CA field is usually set to the active subactuator. If a subactuator is active, its newvalfunc is called, using the internal x and y coordinates mentioned above. Some newvalfuncs calculate the subactuator's EXTVAL, or value in the context of the enclosing actuator, at this time. The value for the actuator itself is detemined, usually duplicating or otherwise derived from the active subactuator's value, and is stored in the actuator's VAL field. addfunc Addfunc is called when the actuator is added to a panel or to another actuator as a subactuator. Addfunc usually performs further initialization that could not be done by initfunc because it requires knowlege of values assigned to the actuator's fields by the application developer. For example, addfunc for multislider looks at its actuator-specific N field to determine how many sliderbars to add to itself. addsubfunc Addsubfunc is called when a subactuator is added to the actuator, it is therefore only used in compound actuators. Its purpose is to link the new subactuator into the actuator structure properly, and update any actuator internal state to accomodate the new subactuator. responsibilities If the subactuator is going to be a direct child of the actuator, addsubfunc is expected to increment the actuator's NA, or number of actuator field. Addsubfunc is expected to set the subactuator's PA, or parent actuator field to something reasonable, usually the actuator. If the subactuator is going to be a direct child of the actuator, addsubfunc inserts the subactuator into the actuator's actuator list (AL). Usually this is done at the head of the list, but some actuators enforce a specific order in the actuator list, and insertion may be elsewhere. Addsubfunc then updates the subactuator if necessary to reflect its role in the actuator, for example, menu's addsubfunc sets the y position of the subactuator to reflect the order in which it was added to the actuator. It is possible that the new subactuator will have implications for previously added subactuators, and addsubfunc may modify them also. fixfunc Fixfunc re-calculates an actuator's internal data state values to incorporate any changes that have been made by the programmer. For example, the fixfunc for wide buttons recalulates the width of the button to accomodate any change made in the length of the label string. Pnl_fixact(), which calls fixfunc, calls itself recursively on each of the actuator's subactuators before calling the actuator's fixfunc. Therefore, a fixfunc may reliably expect that its subactuators have self-consistant internal data state. drawfunc Drawfunc calls Iris graphics library drawing routines to paint a visible repsentation of the actuator into the bitplanes. In most cases the appearance of the actuator is a function of its value, and occasionally, the mouse state. responsibilities For simple actuators, drawfunc should perform drawing only if DIRTYCNT is non-zero. Compound actuators should set the DIRTYCNT of each subactuator to the maximum of the subactuator's DIRTYCNT and the actuator's DIRTYCNT, and then call the drawfunc of each subactuator. This causes all subactuators to be drawn when a higher level actuator is marked dirty. Drawfuncs draw themselves in the context of a surrounding rectangle, so that usually the first graphics operation they perform is a pushmatrix followed by a translation to their x and y position in that rectangle. Colors are sometimes selected based on the selection status of the actuator. dumpfunc loadfunc Dumpfunc and loadfunc write and read the actuator's internal state to and from a disk file during scripting operations. Most actuators use _dumpact() and _loadact() which are provided by the library. These functions transfer the data in the Actuator structure, followed by the data in the actuator-specific structure (pointed to by the DATA field). If the actuator-specific structure contains any pointers to other memory areas, these must be transferred in addition to the other two areas, and require a special dumpfunc and loadfunc. NOTE: scripts with pointers to actual memory locations usually will not work over separate invocations of the program; for this reason, use of pnl_dumpstate(), loadfunc and dumpfunc is not recommended. delfunc Delfunc frees memory allocated to the actuator when the actuator is being deleted by pnl_delact(). Most actuators use pnl_delact() provided by the library which simply frees the memory pointed to by DATA, if DATA is non-NULL. Since _delact() recursively deletes all subactuators of the actuator, only memory referenced by pointers in the actuator-specific data structure that do not point to subactuators need be freed by a special purpose delfunc. PROGRAMMER FUNCTIONS NAME g_gets; g_getstring -- get string from user without textport SYNOPSIS char *g_gets(stringcolor, backcolor, cursorcolor) Colorindex stringcolor, backcolor, cursorcolor; char *g_getstring(stringcolor, backcolor, cursorcolor, protostring, maxstringlen) Colorindex stringcolor, backcolor, cursorcolor; char *protostring; int maxstringlen; DESCRIPTION G_gets() and g_getstring() are used to get a string from the user without using a textport. They temporarily queue the entire keyboard and read events until RETURN is typed. Control is then returned to the calling routine. G_gets() and g_getstring() return a pointer to the string. Both routines take parameters indicating the color indices to be used when drawing text, background and cursor. G_getstring() takes additional arguments of: 1) a prototype string which appears as a default and may be edited by the user, and 2) a length, specifying the maximum length of the entered string. For g_gets(), these are the null string and 80, respectively. The user may edit the string while it is being typed using BACKSPACE or DELETE to delete the previously typed character, or CONTROL-U to delete the entire string. Both routines are entirely independent of the Panel Library and may be used without creating actuators or panels. RETURN VALUE both functions return a pointer to the acquired string NAME pnl_addact -- add an actuator to a panel SYNOPSIS void pnl_addact(a,p) Actuator *a; Panel *p; DESCRIPTION Pnl_addact() adds an actuator to a particular panel, in these steps: 1) The pointer to the Actuator is saved in pnl_table, allowing subsequent reference to the actuator by its id. 2) The actuator is placed at the head of the panel p's actuator list (al). 3) The current value of a's val field is saved as its initval for subsequent reset operations. 4) The dimensions and offsets of a's label are calculated, based on the panel's scalefactor (ppu, i.e., pixels per unit). 5) The actuator's addfunc is called to perform any actuator- specific initialization. 6) If a is an automatic actuator, it is placed on the panel's autolist. 7) If a has a key equivalent, it is placed on the Panel Library's key list (pnl_kl) and its key device is queued. 8) The actuator is marked as needing to be redrawn. SEE ALSO pnl_addsubact() NAME pnl_addpanel -- add a panel to a running application SYNOPSIS void pnl_addpanel(p) Panel *p; DESCRIPTION Pnl_addpanel() is used to add a panel created with pnl_mkpanel() to the library's list of active panels. Panels that are created before the first call to pnl_dopanel() need not be explicitly added with pnl_addpanel(). Pnl_addpanel() is used to add panels that are created after the first call to pnl_dopanel(). NAME pnl_addsubact -- add subactuator to actuator SYNOPSIS void pnl_addsubact(sa,a) Actuator *sa; Actuator *a; DESCRIPTION Pnl_addsubact() adds a subactuator,sa, to an actuator,a. Potentially, any actuator may be a subactuator of any other, but in practice certain actuators like menus, icons, and frames, are expected to have certain other actuators, like buttons and submenus, added to them. The Actuator to which the Subactuator is being added should already have been added to a Panel with pnl_addact(), or to another actuator with pnl_addsubact (). A subactuator, once added to another actuator, is not to be added to a panel with pnl_addact(), or vice versa. Pnl_addsubact() performs these steps: 1) Pnl_addsubact() saves a pointer to the Subactuator in pnl_table, allowing subsequent access to the Subactuator via its id. 2) The Subactuator is placed at the head of the Actuator's actuator list (al). 3) The value of sa's val field is stored as initval for subsequent resets. 4) The dimensions and offsets of the Subactuator's label are calculated based on the actuator's enclosing Panel's scalefactor (ppu). 5) The Subactuator's addfunc is called to perform any actuator- specific initialization. 6) The actuator's addsubfunc is then called to update any actuator-specific data structures it may have. 7) Pnl_fixact() is then called to allow the actuator to adjust its appearance (or other internal data structures) based on its new addition. 8) If sa is an automatic actuator it is placed on a's panel's autolist. 9) If sa has a key equivalent, it is placed on the Panel Library's key list (pnl_kl) and its key device is queued. DIAGNOSTICS pnl_addsubact() prints a warning and exits if a has not been added to a panel or another actuator. SEE ALSO pnl_addact() NAME pnl_alloc -- allocate storage SYNOPSIS char *pnl_alloc(size) int size; DESCRIPTION Pnl_alloc() is a simple front end to the UNIX calloc(3) call. It returns a pointer to size number of bytes of storage. If calloc(3) generates an error, pnl_alloc() prints the perror error message before returning. RETURN VALUE returns a pointer to the allocated storage or NULL if error occurred. NAME pnl_delact() -- delete an actuator and its subactuators SYNOPSIS void pnl_delact(a) Actuator *a; DESCRIPTION Pnl_delact removes an actuator A and all its subactuators (as found in its AL) from the panel library's data structures. The actuator's entry in pnl_table is set to NULL, and then pnl_delact() is called for each of the subactuators in AL. If A is a top-level actuator (originally added to a panel with pnl_addact()), it is removed from its panel's AL. If A is a subactuator of some other actuator, it is removed from that actuator's AL if it appears there. If A is a member of a group it is removed from it. If A has a delfunc it is then called. The default delfunc free's storage used for the actuator-specific data structure. A is deleted from its panel's autolist if it is there, and deleted from the libraries list of actuators with key equivalents (pnl_kl), unqueueing its associated key device if it appears there. Finally, the space referenced by A is freed. DIAGNOSTICS warning: wanky group ring for act