This is the panel library, a set of routines used for building "control
panel" interfaces to interactive graphic applications.  These routines
let you assemble "actuators" like sliders, buttons, stripcharts, and 
typeouts into control panels that live on separate mex windows.  As the
user mouses the actuators, values accessable to the applications programmer,
(THAT'S YOU!) appear in predefined structures.  You can also set the values
and watch the positions or states of the actuators change.  You can 
customize the actuators in many ways because alot of their properties are
controlled by indirect functions that you can replace with your own.  In
fact, you can add new actuators without changing any of the panel library
code because the initialization function is one of these indirect guys!
Someday all this will be nicely documented, but until then, hopefully you
can get something out of the 20 or so demo programs.  Try ep, the
psychedelic electro-paint program.  Have fun.

	 David A Tristram
	 NASA  Ames Research Center
	 Numerical Aerodynamic Simulation Systems Division
	 Moffett Field, CA  94035
	 415-694-4404
	 dat@ames-nas.ARPA

ps: g_gets.c is useful in its own right, get strings from a graphics
    program, thanks for preliminary work by Diana Choi.

Operating Notes:

To see the panels, run the sgi utility makemap to load reasonable
values into the color map.  The colors can be changed either by
bashing the entries that are used, or changing the global variables
pnl_normal_color, pnl_highlight_color, pnl_other_color, etc.


Adding Your Own Actuators.

To add your own actuators, you only have to support a couple of
functional interfaces.  The basic functions are drawX and my_X.
DrawX draws the actuator in a standard 2D coordinate system, and my_X
is initialization code.  If your actuator is going to be mouse
sensitive, it also needs a newvalX function.  In this and the
following discussion, X stands for the name of your new actuator, and
my_ is a short prefix intended to help avoid collisions in a user's
name space.

Additional functions you may need for your actuator are addX, which
getes executed when the actuator is added to a panel, ie., after the
user has had an opportunity to customize its properties, and fixX,
which is used to bring an actuator's internal state up-to-date with
respect to its environment.

So, to add an actuator type you would do something like this:

Start a new source file beginning with 

#include <gl.h>
#include <panel.h>

that is called <actuator>.c where <actuator> is the name or some
shortened form of the generic type of actuator you are adding.  For
example, let's say you are adding an actuator called a dial consisting
of a circular pointer that you can turn with the mouse.  Your source
file might be called dial.c

In your source file you need to support the following functions:

void drawdial(a, p)
Actuator *a;
Panel *p;
{
/* The actuator's drawfunc gets called by dopanel() after normal mouse
 * event handling has be performed if the actuators dirtycnt is
 * non-zero.  The dirtycnt gets set automatically whenever an actuator
 * is selected, and may also be set by the user.  Fixact() also sets
 * the dirtycnt. */

/* In drawdial goes code to actually draw the dial.  In the panel
 * library it is assumed that all actuators are rectangular, so you
 * might want to make some kind of background rectangle to indicate
 * the mouseable region.  On the iris it looks better to put an
 * outline around things.  Look at the code for the other actuators
 * for the names of the colors to use.  The actuators that come with
 * the panel library are drawn using a coordinate system that is
 * supposed to make it easier for the user to lay out control
 * panels.  Sliders, for example, are just under one unit wide and six
 * units high.  This allows the user to plunk his sliders down at
 * integer grid points and have the panel look okay.  There are some
 * manifest constants for the dimensions of the little spaces that
 * show up between actuators.  Use the val field of the Actuator
 * structure you get the pointer to when drawdial() is called to
 * determine what position to draw the dial in.  If your actuator
 * allows labels add a line like

    if (a->label) drawlabel(a, p);

 * at the end of the function.
 */
}

void my_dial(a)
Actuator *a;
{
/* this is initialization code that converts a generic actuator
 * structure to one that implements your kind of actuator.  You have
 * to tie all your functions to the actuator here. */

    a->type=MY_DIAL;		/* an integer for your dials > PNL_MAXACT */

    a->w=MY_DIAL_WIDTH;		/* like maybe 2.0-PNL_DIM_1 */
    a->h=MY_DIAL_HEIGHT;	/* these are default dimensions, that
				   the user can bash */

/* you may want to do other initialization here, for example, you can
 * set the labeltype to one of the five predefined types.  If your
 * actuator has a special internal data structure, space for it should
 * be allocated for it here.
 */

/* if you have other functions then they go here. like maybe: */
/*  a->newvalfunc=newvaldial; */
/*  a->addfunc=adddial; */
    a->drawfunc=drawdial;
}


void newvaldial(a,p,sx,sy)
Actuator *a;
Panel *p;
Screencoord sx,sy;
{
/* the newvalfunc for an actuator if first called when the mouse
 * button goes down and the mouse is within the rectangular region
 * defined by the actuator's x, y, w, and h.   It is then called
 * repeatedly while the mouse button remains down.  When the mouse
 * button goes up, the newvalfunc is called once again. */

/* Sx and sy are screen (pixel) coordinates of the mouse relative to
 * the origin of the panel.  To get floating point coordinates
 * relative to the origin of your actuator, use: */

    mapw2(p->vobj,sx,sy,&wx,&wy);
    wx-=a->x;
    wy-=a->y;

/* Now you have to come up with some way to map the wx and wy to a new
 * value for your actuator.  Sliders, for example, take wy and scale
 * it to a fraction of the total height of the slider, and then
 * interpolate minval and maxval to come up with val.  For a dial you
 * might add the step of determining the angular distance from some
 * index mark, and use that as your interpolation fraction.  You will
 * notice that this is the inverse of the mapping that you made for
 * drawdial.
 */

/* some actuators (toggle buttons, for example) have different
 * behavior when first moused.  You can examine the panel library
 * global variables pnl_justup and pnl_justdown to discriminate these
 * states. */
}

void
adddial(a, p)
Actuator *a;
Panel *p;
{
/* Dial actuators don't need an addfunc, but some actuators do special
 * processing when they are added to a panel.  Stripcharts, for
 * example, malloc space to store their histories.  If the user
 * desires, the storage capacity of a stripchart may be increased by
 * bumping the value of one of the fields in the stripchart's data
 * area.  Then, when the stripchart is added to a panel, its addfunc
 * is called which does the malloc.  Another example is the radio
 * button.  When it is added to a panel, its address is added to a
 * list of radio buttons that are forming a group.  The list is a
 * field called group in the actuator structure and you can use that
 * field to provide special interaction among a set of like actuators.
 */
}


To use the new actuator, my_dial has to be declared as an external
reference.  When the user calls mkact() the argument to mkact
is a pointer to this my_dial.  The other functions are all scoped
locally to dial.c and need not appear in the user code.
