[comp.sources.x] v11i033: wcl - Widget Creation Library, Part21/35

david@devvax.Jpl.Nasa.Gov (David E. Smyth) (02/09/91)

Submitted-by: david@devvax.Jpl.Nasa.Gov (David E. Smyth)
Posting-number: Volume 11, Issue 33
Archive-name: wcl/part21

#! /bin/sh

# Make a new directory for the wc sources, cd to it, and run kits 1
# thru 35 through sh.  When all 35 kits have been run, read README.

echo "This is wc 1.05 kit 21 (of 35).  If kit 21 is complete, the line"
echo '"'"End of kit 21 (of 35)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir Xp 2>/dev/null
echo Extracting Xp/Table.c
sed >Xp/Table.c <<'!STUFFY!FUNK!' -e 's/X//'
X/*LINTLIBRARY*/
X/*
X * Table - Forms-based composite widget/geometry manager for the X Toolkit
X *
X * David Harrison
X * University of California, Berkeley
X * 1989
X *
X * This file contains the implementation for the Table widget.
X */
X
X#include "X11/IntrinsicP.h"
X#include "X11/StringDefs.h"
X
X#if defined(XtSpecificationRelease) && XtSpecificationRelease < 4
X#include "X11/Xmu.h"
X#else
X#include "X11/Xmu/Xmu.h"
X#endif
X
X#include "TableP.h"
X
X#define INIT_TBL_SIZE	10
X#define TBL_CLASS_NAME	"Table"
X
Xstatic caddr_t def = (caddr_t) 0;
X
Xstatic XtResource resources[] = {
X    { XtNlayout, XtCLayout, XtRPointer, sizeof(caddr_t),
X	XtOffset(TableWidget, table.init_layout), XtRPointer, (caddr_t) &def },
X    { XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
X	XtOffset(TableWidget, table.int_height), XtRImmediate, (caddr_t) 0 },
X    { XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension),
X	XtOffset(TableWidget, table.int_width), XtRImmediate, (caddr_t) 0 },
X    { XtNcolumnSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
X	XtOffset(TableWidget, table.col_spacing), XtRImmediate, (caddr_t) 0 },
X    { XtNrowSpacing, XtCSpacing, XtRDimension, sizeof(Dimension),
X	XtOffset(TableWidget, table.row_spacing), XtRImmediate, (caddr_t) 0 },
X    { XtNdefaultOptions, XtCOptions, XtROptions, sizeof(XtTblMask),
X	XtOffset(TableWidget, table.def_options), XtRImmediate, (caddr_t) 0 }
X};
X
X/* Forward declarations */
Xstatic void TblClassInitialize();
Xstatic void TblInitialize();
Xstatic void TblResize();
Xstatic XtGeometryResult TblQueryGeometry();
Xstatic void TblPositionChild();
Xstatic Boolean TblSetValues();
Xstatic XtGeometryResult TblGeometryManager();
Xstatic void TblChangeManaged();
Xstatic Boolean TblFindChild();
Xstatic void TblDestroy();
Xstatic XtTblMask ParseOpts();
X
X
X
X/*
X * Local structures
X */
X
Xtypedef struct _TableLoc {
X    Position ax, ay;		/* Position in array       */
X    Dimension h_span, v_span;	/* Span size in array      */
X    XtTblMask options;		/* Widget position options */
X} TableLoc, *TableLocPtr;
X
Xtypedef struct _TableLocEntry {
X    Widget w;
X    TableLoc loc;
X} TableLocEntry, *TableLocEntryPtr;
X
Xstruct _TableLocTbl {
X    Cardinal n_layout;		/* Number of layout widgets */
X    Cardinal a_layout;		/* Allocated space          */
X    TableLocEntryPtr locs;	/* Widget locations         */
X};
X
Xstruct _TableDefLoc {
X    String w_name;		/* Widget name        */
X    TableLoc loc;		/* Widget information */
X};
X
Xtypedef unsigned long TableVecMask;
X#define	VEC_MINIMIZE	0x01
X
Xstruct _TableVector {
X    TableVecMask mask;		/* Option mask  */
X    Cardinal value;		/* Size of item */
X};
X
X
X
XTableClassRec tableClassRec = {
X  { /* core_class fields */
X    /* superclass         */    (WidgetClass) &compositeClassRec,
X    /* class_name         */    TBL_CLASS_NAME,
X    /* widget_size        */    sizeof(TableRec),
X    /* class_initialize   */    TblClassInitialize,
X    /* class_part_init    */    NULL,
X    /* class_inited       */    FALSE,
X    /* initialize         */    TblInitialize,
X    /* initialize_hook    */    NULL,
X    /* realize            */    XtInheritRealize,
X    /* actions            */    NULL,
X    /* num_actions        */    0,
X    /* resources          */    resources,
X    /* num_resources      */    XtNumber(resources),
X    /* xrm_class          */    NULLQUARK,
X    /* compress_motion    */    TRUE,
X    /* compress_exposure  */    TRUE,
X    /* compress_enterleave*/    TRUE,
X    /* visible_interest   */    FALSE,
X    /* destroy            */    TblDestroy,
X    /* resize             */    TblResize,
X    /* expose             */    XtInheritExpose,
X    /* set_values         */    TblSetValues,
X    /* set_values_hook    */    NULL,
X    /* set_values_almost  */    XtInheritSetValuesAlmost,
X    /* get_values_hook    */    NULL,
X    /* accept_focus       */    NULL,
X    /* version            */    XtVersion,
X    /* callback_private   */    NULL,
X    /* tm_table           */    NULL,
X    /* query_geometry     */	TblQueryGeometry,
X    /* display_accelerator*/	XtInheritDisplayAccelerator,
X    /* extension          */	NULL
X  },
X  { /* composite_class fields */
X    /* geometry_manager   */   TblGeometryManager,
X    /* change_managed     */   TblChangeManaged,
X    /* insert_child       */   XtInheritInsertChild,
X    /* delete_child       */   XtInheritDeleteChild,
X    /* extension          */   NULL
X  },
X  { /* table_class fields */
X    /* position_child	  */	TblPositionChild,
X    /* find_child	  */	TblFindChild,
X  }
X};
X
XWidgetClass tableWidgetClass = (WidgetClass) &tableClassRec;
X
X
X
X/*ARGSUSED*/
Xstatic void cvtStrToDefLoc(args, num_args, from, to)
XXrmValue *args;			/* Arguments to converter */
XCardinal *num_args;		/* Number of arguments    */
XXrmValue *from;			/* From type              */
XXrmValue *to;			/* To type                */
X/*
X * Converts a string representation into an array of TableDefLoc
X * structures.
X */
X{
X    static caddr_t ptr;
X    String layout_spec;
X
X    if (*num_args != 0) {
X	XtErrorMsg("cvtStrToDefLoc", "wrongParameters", "XtToolkitError",
X		   "String to layout takes no additional arguments",
X		   (String *) NULL, (Cardinal *) NULL);
X    }
X
X    layout_spec = (String) from->addr;
X    to->size = sizeof(caddr_t);
X    ptr = XtTblParseLayout(layout_spec);
X    to->addr = (caddr_t) &ptr;
X}
X
X/*ARGSUSED*/
Xstatic void cvtStrToOpts(args, num_args, from, to)
XXrmValue *args;			/* Arguments to converter */
XCardinal *num_args;		/* Number of arguments    */
XXrmValue *from;			/* From type              */
XXrmValue *to;			/* To type                */
X/*
X * Converts a string representation into a default options
X * mask (XtTblMask).
X */
X{
X    static XtTblMask mask;
X    String opt_spec;
X
X    if (*num_args != 0) {
X	XtErrorMsg("cvtStrToOpts", "wrongParameters", "XtToolkitError",
X		   "String to options takes no additional arguments",
X		   (String *) NULL, (Cardinal *) NULL);
X    }
X
X    opt_spec = (String) from->addr;
X    to->size = sizeof(int);
X    mask = ParseOpts(opt_spec);
X    to->addr = (caddr_t) &mask;
X}
X
X
Xstatic void TblClassInitialize()
X/*
X * Adds an appropriate string-to-default widget location table
X * converter.
X */
X{
X    XtAddConverter(XtRString, XtRPointer, cvtStrToDefLoc, NULL, 0);
X    XtAddConverter(XtRString, XtROptions, cvtStrToOpts, NULL, 0);
X}
X
X
X
X/* 
X * Table Management Functions
X *
X * Default table is a linear null terminated array,  the location
X * array is a linear dynamic array.  Both should be replaced
X * with hash tables.
X */
X
Xstatic Cardinal LenDefLoc(ptr)
XTableDefLocPtr ptr;
X/*
X * Returns the length of a DefLoc list.
X */
X{
X    Cardinal i;
X
X    for (i = 0;  ptr && ptr[i].w_name;  i++) {
X	/* Null body */
X    }
X    return i;
X}
X
Xstatic TableDefLocPtr CopyDefLoc(ptr)
XTableDefLocPtr ptr;
X/*
X * Makes a dynamically allocated copy of `ptr'.
X */
X{
X    TableDefLocPtr copy;
X    Cardinal i, len;
X
X    len = LenDefLoc(ptr);
X    if (len) {
X	copy = (TableDefLocPtr) XtCalloc(len+1, sizeof(struct _TableDefLoc));
X	for (i = 0;  i < len;  i++) {
X	    copy[i] = ptr[i];
X	}
X	copy[i].w_name = (String) 0;
X    } else {
X	copy = (TableDefLocPtr) 0;
X    }
X    return copy;
X}
X
Xstatic TableDefLocPtr FindDefLoc(tbl, name)
XTableDefLocPtr tbl;		/* Table to examine */
XString name;			/* Widget name      */
X/*
X * Scans through `tbl' looking for the name `name'.  Returns
X * a pointer to the found value or NULL if not found.
X */
X{
X    TableDefLocPtr idx;
X
X    for (idx = tbl;  idx && idx->w_name;  idx++) {
X	if (strcmp(idx->w_name, name) == 0) return idx;
X    }
X    return (TableDefLocPtr) 0;
X}
X
Xstatic TableDefLocPtr MergeDefLoc(source, dest)
XTableDefLocPtr source;		/* Original table     */
XTableDefLocPtr dest;		/* Additional entries */
X/*
X * Returns a table where the entries in `dest' have been
X * merged with those in `source'.  Similar entries in
X * `dest' override those in `source'.  The returned
X * table is allocated.
X */
X{
X    TableDefLocPtr result, update;
X    Cardinal s_len, d_len;
X    Cardinal i, j;
X
X    s_len = LenDefLoc(source);
X    d_len = LenDefLoc(dest);
X    result = (TableDefLocPtr)
X      XtCalloc(s_len + d_len + 1, sizeof(struct _TableDefLoc));
X    for (i = 0;  i < s_len;  i++) {
X	result[i] = source[i];
X    }
X    /* Add null termination */
X    result[i].w_name = (String) 0;
X    /* Now merge the results */
X    for (j = 0;  j < d_len;  j++) {
X	if (update = FindDefLoc(result, dest[j].w_name)) {
X	    update->loc = dest[j].loc;
X	} else {
X	    /* Add to end */
X	    result[i].w_name = dest[j].w_name;
X	    result[i].loc = dest[j].loc;
X	    i += 1;
X	    result[i].w_name = (String) 0;
X	}
X    }
X    return result;
X}
X
X
X
Xstatic TableLocTblPtr TblInitLocTbl()
X/*
X * Returns a newly allocated location table.  This is implemented
X * at the moment as dynamic array.  Eventually,  a hash table
X * will be used.
X */
X{
X    TableLocTblPtr rtn;
X
X    rtn = (TableLocTblPtr) XtMalloc(sizeof(struct _TableLocTbl));
X    rtn->n_layout = 0;
X    rtn->a_layout = INIT_TBL_SIZE;
X    rtn->locs = (TableLocEntryPtr)
X      XtCalloc(INIT_TBL_SIZE, sizeof(TableLocEntry));
X    return rtn;
X}
X
Xstatic void TblInsertLoc(tbl, w, locp)
XTableLocTblPtr tbl;		/* Table for insertion             */
XWidget w;			/* Subwidget to place              */
XTableLocPtr locp;		/* Widget location information     */
X/*
X * Inserts an item into the location table.  If there is already
X * an entry for the widget,  it is replaced by this one.  If there
X * is no room,  additional room is allocated.
X */
X{
X    int i;
X
X    for (i = 0;  i < tbl->n_layout;  i++) {
X	if (tbl->locs[i].w == w) {
X	    tbl->locs[i].loc = *locp;
X	    return;
X	}
X    }
X    /* Not in the table */
X    if (tbl->n_layout >= tbl->a_layout) {
X	/* Make more space */
X	tbl->a_layout += tbl->a_layout;
X	tbl->locs = (TableLocEntryPtr)
X	  XtRealloc(tbl->locs, tbl->a_layout * sizeof(TableLocEntry));
X    }
X    tbl->locs[tbl->n_layout].w = w;
X    tbl->locs[tbl->n_layout].loc = *locp;
X    tbl->n_layout += 1;
X}
X
Xstatic TableLocPtr TblLocLookup(tbl, w)
XTableLocTblPtr tbl;		/* Table for lookup      */
XWidget w;			/* What widget to lookup */
X/*
X * Looks up widget `w' in the hard widget position table.
X * Returns NULL if it can't find the widget.
X */
X{
X    int i;
X
X    for (i = 0;  i < tbl->n_layout;  i++) {
X	if (tbl->locs[i].w == w) {
X	    return &(tbl->locs[i].loc);
X	}
X    }
X    return (TableLocPtr) 0;
X}
X
Xstatic void TblFreeLocTbl(tbl)
XTableLocTblPtr tbl;		/* Table to free */
X/*
X * Frees memory resources of `tbl'.
X */
X{
X    XtFree((char *) (tbl->locs));
X    XtFree((char *) tbl);
X}
X
X
X
Xstatic void TblInitialize(request, new)
XWidget request;			/* Values from resources */
XWidget new;			/* Actual widget         */
X/*
X * Intializes appropriate fields in instance record.
X */
X{
X    TableWidget old = (TableWidget) request;
X    TableWidget tw = (TableWidget) new;
X
X    tw->table.init_layout = CopyDefLoc(old->table.init_layout);
X    tw->table.layout_db = (TableDefLocPtr) 0;
X    tw->table.real_layout = TblInitLocTbl();
X    tw->table.vec_state = INVALID;
X    tw->table.num_rows = tw->table.num_cols = 0;
X    tw->table.rows = (TableVecPtr) 0;
X    tw->table.cols = (TableVecPtr) 0;
X    tw->table.vec_height = 0;
X    tw->table.vec_width = 0;
X}
X
X
X
Xstatic TableLocTblPtr GetManaged(nw, wl)
XCardinal nw;			/* Number of widgets */
XWidgetList wl;			/* Widget list       */
X/*
X * Returns those widgets in `wl' that are managed and looks
X * up their table postions.  If no table position is found,
X * the widget is placed at 0,0 with a span of 1 with no options.
X */
X{
X    TableLocTblPtr result;
X    Cardinal i;
X
X    result = TblInitLocTbl();
X    for (i = 0;  i < nw;  i++) {
X	if (XtIsManaged(wl[i])) {
X	    if (result->n_layout >= result->a_layout) {
X		/* Make more space */
X		result->a_layout += result->a_layout;
X		result->locs = (TableLocEntryPtr)
X		  XtRealloc(result->locs,
X			    result->a_layout * sizeof(TableLocEntry));
X	    }
X	    result->locs[result->n_layout].w = wl[i];
X	    if (!TblFindChild(wl[i],
X			      &(result->locs[result->n_layout].loc.ax),
X			      &(result->locs[result->n_layout].loc.ay),
X			      &(result->locs[result->n_layout].loc.h_span),
X			      &(result->locs[result->n_layout].loc.v_span),
X			      &(result->locs[result->n_layout].loc.options))) {
X		/* Can't find location -- make one up */
X		result->locs[result->n_layout].loc.ax = 0;
X		result->locs[result->n_layout].loc.ay = 0;
X		result->locs[result->n_layout].loc.h_span = 1;
X		result->locs[result->n_layout].loc.v_span = 1;
X		result->locs[result->n_layout].loc.options = 0;
X	    }
X	    result->n_layout += 1;
X	}
X    }
X    return result;
X}
X
X
Xstatic Cardinal VecSize(mw, val_func)
XTableLocTblPtr mw;		/* List of managed widgets           */
Xvoid (*val_func)();		/* Returns either row or column info */
X/*
X * Determines the vector size by examining locations of all
X * widgets in `mw'.  Basically determines the maximum of loc+span.
X */
X{
X    Cardinal i, loc, span;
X    Cardinal result = 0;
X    Boolean small_flag;
X
X    for (i = 0;  i < mw->n_layout;  i++) {
X	(*val_func)(&(mw->locs[i]), &loc, &span, &small_flag);
X	if (result < loc+span) {
X	    result = loc+span;
X	}
X    }
X    return result;
X}
X
X
X
Xstatic void SetVecOptions(mw, val_func, vec)
XTableLocTblPtr mw;		/* Managed widget list */
Xvoid (*val_func)();		/* Row or col info     */
XTableVecPtr vec;		/* Spacing vector      */
X/*
X * Steps through the list of widgets.  If the widget is marked
X * as having the small flag set,  it sets all corresponding
X * options in `vec'.
X */
X{
X    Cardinal i, j;
X    Cardinal loc, span;
X    Boolean small_flag;
X
X    for (i = 0;  i < mw->n_layout;  i++) {
X	(*val_func)(&(mw->locs[i]), &loc, &span, &small_flag);
X	if (small_flag) {
X	    for (j = loc;  j < loc+span;  j++) {
X		vec[j].mask = VEC_MINIMIZE;
X	    }
X	}
X    }
X}
X
X
X/* Must be set before span_cmp works */
Xstatic void (*span_cmp_val_func)();
X
Xstatic int span_cmp(a, b)
Xchar *a, *b;
X/*
X * Compares items based on span.
X */
X{
X    Cardinal loc_a, loc_b;
X    Cardinal span_a, span_b;
X    Boolean small_flag;
X
X    (*span_cmp_val_func)((TableLocEntryPtr) a, &loc_a, &span_a, &small_flag);
X    (*span_cmp_val_func)((TableLocEntryPtr) b, &loc_b, &span_b, &small_flag);
X    return span_a - span_b;
X}
X
X
Xstatic Cardinal FindDistrib(loc, span, vec, result)
XCardinal loc, span;		/* Widget loc and span */
XTableVecPtr vec;		/* Spacing vector     */
XCardinal *result;		/* Result array       */
X/*
X * This routine fills in `result' with a list of indices
X * into the spacing vector suitable for distributing required
X * space.  Normally,  it skips those items marked as
X * VEC_MINIMIZE.  However,  if there aren't any non-VEC_MINIMIZE
X * spaces,  all of them become candidates.
X */
X{
X    Cardinal i, count;
X
X    count = 0;
X    for (i = loc;  i < loc+span;  i++) {
X	if (vec[i].mask & VEC_MINIMIZE) continue;
X	result[count++] = i;
X    }
X    if (count == 0) {
X	/* Add them all back in */
X	for (i = loc;  i < loc+span;  i++) {
X	    result[count++] = i;
X	}
X    }
X    return count;
X}
X
X
Xstatic void DoDistrib(n_dist, distrib, loc, span, vec, size, inter)
XCardinal n_dist;		/* Number of distribution points */
XCardinal *distrib;		/* Indicies into `vec'           */
XCardinal loc, span;		/* Widget location and span      */
XTableVecPtr vec;		/* Spacing vector                */
XDimension size;			/* Size of widget                */
XDimension inter;		/* inter {col,row} spacing	 */
X/*
X * If `size' is larger than the current sum of space in `vec'
X * specified by `loc' and `span',  the difference in space
X * is evenly added to each vector entry given by `distrib'.
X */
X{
X    Cardinal sum = 0;
X    Cardinal i;
X    int diff, amt;
X
X    for (i = loc;  i < loc+span;  i++) {
X	sum += vec[i].value;
X    }
X    if (span > 1)
X	sum += (span-1) * inter;
X    diff = size - sum;
X    if (diff > 0) {
X	/* Distribution required */
X	amt = diff / n_dist;
X	for (i = 0;  i < n_dist-1;  i++) {
X	    vec[distrib[i]].value += amt;
X	    diff -= amt;
X	}
X	/* Last one deincremented by remaining space */
X	vec[distrib[i]].value += diff;
X    }
X}
X
X
X
X
Xstatic Cardinal CompVector(mw, val_func, size_func, inter, result)
XTableLocTblPtr mw;		/* List of managed widgets with locs */
Xvoid (*val_func)();		/* Returns either row or column info */
XDimension (*size_func)();	/* Returns desired size of subwidget */
XDimension inter;		/* inter {row,col} spacing	     */
XTableVecPtr *result;		/* Result vector                     */
X/*
X * This routine computes the values for either the row or column
X * spacing vector.  The strategy is as follows:
X *   1. Scan mw and determine number of entrys in result and allocate
X *   2. Scan list and set appropriate vector flags.
X *   3. Sort the managed widgets in span order (low to high)
X *   4. For each item in sorted list:
X *      A. Determine distribution locations.
X *      B. Distribute any needed space to locations.
X * There are some inefficiencies here that could be overcome.
X */
X{
X    Cardinal res_num, i;
X    Cardinal n_dist, *distrib;
X    Cardinal loc, span;
X    Boolean small_flag;
X
X    res_num = VecSize(mw, val_func);
X    if (res_num) {
X	*result = (TableVecPtr) XtCalloc(res_num, sizeof(struct _TableVector));
X	for (i = 0;  i < res_num;  i++) {
X	    (*result)[i].mask = 0;
X	    (*result)[i].value = 0;
X	}
X	SetVecOptions(mw, val_func, *result);
X
X	span_cmp_val_func = val_func;
X	qsort((char *) mw->locs, (int) mw->n_layout,
X	      sizeof(TableLocEntry), span_cmp);
X
X	distrib = (Cardinal *) XtCalloc(res_num, sizeof(Cardinal));
X	for (i = 0;  i < mw->n_layout;  i++) {
X	    (*val_func)(&(mw->locs[i]), &loc, &span, &small_flag);
X	    n_dist = FindDistrib(loc, span, *result, distrib);
X	    DoDistrib(n_dist, distrib, loc, span, *result,
X		      (*size_func)(mw->locs[i].w), inter);
X	}
X	return res_num;
X    } else {
X	*result = (TableVecPtr) 0;
X	return 0;
X    }
X    /*NOTREACHED*/
X}
X
X
Xstatic void ColValues(oneloc, loc, span, small_flag)
XTableLocEntryPtr oneloc;	/* Widget data       */
XCardinal *loc;			/* Location in array */
XCardinal *span;			/* Spanning distance */
XBoolean *small_flag;		/* Whether locked    */
X/*
X * This routine returns column data from `oneloc'.  It is
X * passed to CompVector when computing the column spacing vector.
X */
X{
X    *loc = oneloc->loc.ax;
X    *span = oneloc->loc.h_span;
X    *small_flag = oneloc->loc.options & TBL_SM_WIDTH;
X}
X
Xstatic void RowValues(oneloc, loc, span, small_flag)
XTableLocEntryPtr oneloc;	/* Widget data       */
XCardinal *loc;			/* Location in array */
XCardinal *span;			/* Spanning distance */
XBoolean *small_flag;		/* Whether locked    */
X/*
X * This routine returns row data from `oneloc'.  It is
X * passed to CompVector when computing the row spacing vector.
X */
X{
X    *loc = oneloc->loc.ay;
X    *span = oneloc->loc.v_span;
X    *small_flag = oneloc->loc.options & TBL_SM_HEIGHT;
X}
X
Xstatic Dimension ColSize(w)
XWidget w;			/* Child widget */
X/*
X * This routine returns the desired width of the widget `w'.
X * It is used by CompVector when computing the column vector.
X */
X{
X    Dimension r_size, r_border;
X    XtWidgetGeometry child;
X
X    r_size = w->core.width;
X    r_border = w->core.border_width;
X    (void) XtQueryGeometry(w, (XtWidgetGeometry *) 0, &child);
X    if (child.request_mode & CWWidth) r_size = child.width;
X    if (child.request_mode & CWBorderWidth) r_border = child.border_width;
X    return r_size + r_border + r_border;
X}
X
Xstatic Dimension RowSize(w)
XWidget w;			/* Child widget */
X/*
X * This routine returns the desired width of the widget `w'.
X * It is used by CompVector when computing the column vector.
X */
X{
X    Dimension r_size, r_border;
X    XtWidgetGeometry child;
X
X    r_size = w->core.height;
X    r_border = w->core.border_width;
X    (void) XtQueryGeometry(w, (XtWidgetGeometry *) 0, &child);
X    if (child.request_mode & CWHeight) r_size = child.height;
X    if (child.request_mode & CWBorderWidth) r_border = child.border_width;
X    return r_size + r_border + r_border;
X}
X
X
X
X/*ARGSUSED*/
Xstatic void TblRecompVectors(tw)
XTableWidget tw;			/* Table widget */
X/*
X * Recomputes the size vectors in the table widget by
X * examining the preferred sizes of subwidgets.  The
X * following fields are modified: num_rows, num_cols,
X * rows, cols, vec_height, and vec_width.
X */
X{
X    TableLocTblPtr managed;
X    Cardinal i;
X
X    /* Free existing vectors */
X    if (tw->table.cols) XtFree((char *) (tw->table.cols));
X    tw->table.num_cols = 0;
X    if (tw->table.rows) XtFree((char *) (tw->table.rows));
X    tw->table.num_rows = 0;
X    tw->table.vec_width = tw->table.vec_height = 0;
X
X    /* Generate list of managed widgets with locations */
X    managed = GetManaged(tw->composite.num_children, tw->composite.children);
X    
X    /* Handle columns */
X    tw->table.num_cols = CompVector(managed, ColValues, ColSize,
X				    tw->table.col_spacing, &(tw->table.cols));
X    for (i = 0;  i < tw->table.num_cols;  i++) {
X	tw->table.vec_width += tw->table.cols[i].value;
X    }
X      
X
X    /* Handle rows */
X    tw->table.num_rows = CompVector(managed, RowValues, RowSize,
X				    tw->table.row_spacing, &(tw->table.rows));
X    for (i = 0;  i < tw->table.num_rows;  i++) {
X	tw->table.vec_height += tw->table.rows[i].value;
X    }
X
X    TblFreeLocTbl(managed);
X}
X
X
Xstatic void TblRequestResize(tw)
XTableWidget tw;			/* Table widget */
X/*
X * Asks the parent to become the size given by the row and
X * column vectors.  Precondition: vec_state must be MINIMUM.
X */
X{
X    XtGeometryResult rtn;
X    Dimension act_width, act_height;
X    Dimension r_width, r_height;
X
X    act_width = tw->table.vec_width + 2*tw->table.int_width +
X      (tw->table.num_cols-1)*tw->table.col_spacing;
X    act_height = tw->table.vec_height + 2*tw->table.int_height +
X      (tw->table.num_rows-1)*tw->table.row_spacing;
X    rtn = XtMakeResizeRequest((Widget) tw, act_width, act_height,
X			      &r_width, &r_height);
X    switch (rtn) {
X    case XtGeometryYes:
X    case XtGeometryNo:
X	/* Either case -- no action required */
X	break;
X    case XtGeometryAlmost:
X	if ((r_width >= act_width) &&
X	    (r_height >= act_height)) {
X	    (void) XtMakeResizeRequest((Widget) tw, r_width, r_height,
X				       (Dimension *) 0, (Dimension *) 0);
X	}
X	break;
X    }
X}
X
X
X
Xstatic void ExtraSpace(num, vec, size)
XCardinal num;			/* Length of `vec' */
XTableVecPtr vec;		/* Spacing vector  */
XDimension size;			/* Overall size    */
X/*
X * If `size' is larger than the sum of all widths in `vec',
X * the extra space is distributed evenly among appropriate
X * candidates of `vec'.
X */
X{
X    Cardinal i, ndist, sum = 0;
X    Cardinal *dist;
X    int diff, amt;
X
X    for (i = 0;  i < num;  i++) sum += vec[i].value;
X    diff = size - sum;
X    if (diff > 0) {
X	/* Have to distribute space */
X	dist = (Cardinal *) XtCalloc(num, sizeof(Cardinal));
X	ndist = FindDistrib(0, num, vec, dist);
X	amt = diff/ndist;
X	for (i = 0;  i < ndist-1;  i++) {
X	    vec[dist[i]].value += amt;
X	    diff -= amt;
X	}
X	vec[dist[i]].value += diff;
X	XtFree((char *) dist);
X    }
X}
X
X
Xstatic Dimension SumVec(loc, span, vec, start, inter, end)
XPosition loc, span;		/* Start and length      */
XTableVecPtr vec;		/* Spacing vector        */
XDimension start;		/* Added before sum      */
XDimension inter;		/* Added between items   */
XDimension end;			/* Added after sum       */
X/*
X * Returns the sum of the space in `vec' from `loc' for length `span'.
X * Adds in the appropriate padding given by `start', `inter' and `end'.
X */
X{
X    Position i;
X    Dimension sum = 0;
X
X    for (i = loc;  i < loc+span;  i++) sum += vec[i].value;
X    return sum + start + end + ((span >= 0) ? span*inter : 0);
X}
X
Xstatic void PlaceWidget(w, x, y, width, height, rw, rh, opt)
XWidget w;			/* What widget to place  */
XPosition x, y;			/* Location of space     */
XDimension width, height;	/* Size of space         */
XDimension rw, rh;		/* Actual size           */
XXtTblMask opt;			/* Justification options */
X/*
X * This routine moves the widget `w' inside the space given
X * by x, y, width, height.  Its location in this space
X * is determined by looking at the justification options of 
X * `opt'.
X */
X{
X    Position rx, ry;
X
X    if (opt & TBL_LEFT) rx = x;
X    else if (opt & TBL_RIGHT) rx = x + width - rw;
X    else rx = x + (width-rw)/2;
X    if (opt & TBL_TOP) ry = y;
X    else if (opt & TBL_BOTTOM) ry = y + height - rh;
X    else ry = y + (height-rh)/2;
X#ifdef NOTDEF
X    rx += w->core.border_width;
X    ry += w->core.border_width;
X#endif
X    
X    XtMoveWidget(w, rx, ry);
X}
X
X
Xstatic void DoPlace(managed, cvec, rvec, vp, hp, rs, cs)
XTableLocTblPtr managed;		/* List of managed widgets with locs */
XTableVecPtr cvec, rvec;		/* Column and row spacing vector     */
XDimension vp, hp;		/* Vertical and horizontal padding   */
XDimension rs, cs;		/* Row and column interspace         */
X/*
X * This routine places each widget in `managed' according to the
X * spacing vectors `cvec' and `rvec' and the widget placement
X * options (justification and resizing).  First,  if allowed,
X * the routine will resize the widget to fit its allocated
X * space.  Then it will place the widget paying attention
X * to the justification.
X */
X{
X    Cardinal i;
X    Position ax, ay;
X    Dimension aw, ah;
X    Dimension nw, nh;
X
X    for (i = 0;  i < managed->n_layout;  i++) {
X	ax = SumVec(0, managed->locs[i].loc.ax, cvec, hp, cs, 0);
X	ay = SumVec(0, managed->locs[i].loc.ay, rvec, vp, rs, 0);
X	aw = SumVec(managed->locs[i].loc.ax,
X		    (Position) managed->locs[i].loc.h_span, cvec, 0, cs, -cs);
X	ah = SumVec(managed->locs[i].loc.ay,
X		    (Position) managed->locs[i].loc.v_span, rvec, 0, rs, -rs);
X	nw = aw - 2*managed->locs[i].w->core.border_width;
X	nh = ah - 2*managed->locs[i].w->core.border_width;
X	if (managed->locs[i].loc.options & TBL_LK_WIDTH) {
X	    nw = managed->locs[i].w->core.width;
X	}
X	if (managed->locs[i].loc.options & TBL_LK_HEIGHT) {
X	    nh = managed->locs[i].w->core.height;
X	}
X	if (((nw != managed->locs[i].w->core.width) ||
X	     (nh != managed->locs[i].w->core.height)) &&
X	    (nw > 0) && (nh > 0)) {
X	    /* Resize widget */
X	    XtResizeWidget(managed->locs[i].w, nw, nh,
X			   managed->locs[i].w->core.border_width);
X	}
X	/* Now place */
X	nw = managed->locs[i].w->core.width +
X	  2*managed->locs[i].w->core.border_width;;
X	nh = managed->locs[i].w->core.height +
X	  2*managed->locs[i].w->core.border_width;;
X	PlaceWidget(managed->locs[i].w, ax, ay, aw, ah, nw, nh,
X		    managed->locs[i].loc.options);
X    }
X}
X
X
X
X/*ARGSUSED*/
Xstatic void TblPlacement(tw)
XTableWidget tw;			/* Table widget */
X/*
X * Places the children of the table widget.  There are several steps:
X *   1.  Distribute any extra space into local copies of spacing vectors.
X *   2.  If the option is set,  any extra space is offered to each widget.
X *   3.  The final placement is done according to the actual size of
X *       each widget and the space allocated for it.
X */
X{
X    Cardinal i;
X    TableVecPtr lrows, lcols;
X    TableLocTblPtr managed;
X    Dimension real_width, real_height;
X
X    if (tw->table.num_rows && tw->table.num_cols) {
X	/* Make local copies of vectors */
X	lrows = (TableVecPtr)
X	  XtCalloc(tw->table.num_rows, sizeof(struct _TableVector));
X	for (i = 0;  i < tw->table.num_rows;  i++) {
X	    lrows[i] = tw->table.rows[i];
X	}
X	lcols = (TableVecPtr)
X	  XtCalloc(tw->table.num_cols, sizeof(struct _TableVector));
X	for (i = 0;  i < tw->table.num_cols;  i++) {
X	    lcols[i] = tw->table.cols[i];
X	}
X
X	/* Add extra space to vector */
X	real_width = tw->core.width - 2*tw->table.int_width -
X	  (tw->table.num_cols-1)*tw->table.col_spacing;
X	real_height = tw->core.height - 2*tw->table.int_height -
X	  (tw->table.num_rows-1)*tw->table.row_spacing;
X	ExtraSpace(tw->table.num_cols, lcols, real_width);
X	ExtraSpace(tw->table.num_rows, lrows, real_height);
X
X	/* Get list of managed widgets with locations */
X	managed = GetManaged(tw->composite.num_children, tw->composite.children);
X	DoPlace(managed, lcols, lrows, tw->table.int_height, tw->table.int_width,
X		tw->table.row_spacing, tw->table.col_spacing);
X
X	/* Free up resources */
X	XtFree((char *) lcols);
X	XtFree((char *) lrows);
X	TblFreeLocTbl(managed);
X    }
X}
X
X
X
X
Xstatic void TblResize(w)
XWidget w;			/* Table widget */
X/*
X * This routine is called when the table widget itself is
X * resized.  If needed,  the vectors are recomputed and
X * placement is done.
X */
X{
X    TableWidget tw = (TableWidget) w;
X
X    if ((tw->core.width < tw->table.vec_width) ||
X	(tw->core.height < tw->table.vec_height)) {
X	TblRequestResize(tw);
X    }
X    if (tw->table.vec_state == INVALID) {
X	TblRecompVectors(tw);
X	tw->table.vec_state = MINIMUM;
X    }
X    TblPlacement(tw);
X}
X
X
X
Xstatic XtGeometryResult ExamineRequest(request)
XXtWidgetGeometry *request;
X/*
X * Examines the bits set in `request' and returns an appropriate
X * geometry manager result.  Pure size changes are accepted
X * (XtGeometryYes),  pure position changes are rejected
X * (XtGeometryNo),  and combinations are conditionally
X * accepted (XtGeometryAlmost).
X */
X{
X    if (request->request_mode & (CWWidth|CWHeight|CWBorderWidth)) {
X	if (request->request_mode & (CWX|CWY|CWSibling|CWStackMode)) {
X	    return XtGeometryAlmost;
X	} else {
X	    return XtGeometryYes;
X	}
X    } else {
X	return XtGeometryNo;
X    }
X}
X
X
X
Xstatic XtGeometryResult TblGeometryManager(w, request, reply)
XWidget w;			/* Widget                    */
XXtWidgetGeometry *request;	/* Requested geometry change */
XXtWidgetGeometry *reply;	/* Actual reply to request   */
X/*
X * This routine handles geometry requests from children.  Width
X * and height changes are always accepted.  Position changes
X * are always rejected.  Combinations result in XtGeometryAlmost
X * with the requested widths filled in.  Accepted changes cause
X * an immediate XtResizeWidget followed by a new placement.
X */
X{
X    Widget parent;
X    TableWidget tw = (TableWidget) w->core.parent;
X    XtGeometryResult result;
X    Dimension width, height, bdr;
X    Dimension ow, oh;
X
X    parent = w->core.parent;
X    if (parent &&
X	(strcmp(parent->core.widget_class->core_class.class_name,
X		TBL_CLASS_NAME) == 0)) {
X	tw = (TableWidget) parent;
X	result = ExamineRequest(request);
X	switch (result) {
X	case XtGeometryYes:
X	    if (request->request_mode & XtCWQueryOnly) {
X		return XtGeometryYes;
X	    }
X	    if (request->request_mode & CWWidth) {
X		width = request->width;
X	    } else {
X		width = w->core.width;
X	    }
X	    if (request->request_mode & CWHeight) {
X		height = request->height;
X	    } else {
X		height = w->core.height;
X	    }
X	    bdr = w->core.border_width;
X	    if ((width > 0) && (height > 0)) {
X		XtResizeWidget(w, width, height, bdr);
X	    }
X	    ow = tw->table.vec_width;
X	    oh = tw->table.vec_height;
X	    TblRecompVectors(tw);
X	    tw->table.vec_state = MINIMUM;
X	    if ((ow != tw->table.vec_width) || (oh != tw->table.vec_height)) {
X		TblRequestResize(tw);
X	    }
X	    TblPlacement(tw);
X	    return XtGeometryDone;
X	    /*NOTREACHED*/
X	case XtGeometryNo:
X	    return result;
X	case XtGeometryAlmost:
X	    *reply = *request;
X	    /* Turn off all but the size changes */
X	    reply->request_mode &= (CWWidth|CWHeight|CWBorderWidth);
X	    return XtGeometryAlmost;
X	}
X	/*NOTREACHED*/
X    } else {
X	XtErrorMsg("TblGeometryManager", "badParent", "XtToolkitError",
X		   "Parent of widget is not a tableClassWidget",
X		   (String *) NULL, (Cardinal *) NULL);
X    }
X    /*NOTREACHED*/
X}
X
X
X
X/*ARGSUSED*/
Xstatic Boolean TblSetValues(current, request, new)
XWidget current;			/* Before call to XtSetValues */
XWidget request;			/* After call to XtSetValues  */
XWidget new;			/* Final version of widget    */
X/*
X * Checks for changes to `init_table'.  If so,  a recomputation
X * and replacement occurs.  Always returns false.
X */
X{
X    TableWidget old = (TableWidget) current;
X    TableWidget tw = (TableWidget) new;
X    Boolean recomp = False;
X
X    if ((tw->table.init_layout) ||
X	(old->table.int_width != tw->table.int_width) ||
X	(old->table.int_height != tw->table.int_height) ||
X	(old->table.row_spacing != tw->table.row_spacing) ||
X	(old->table.col_spacing != tw->table.col_spacing)) {
X	recomp = True;
X    }
X    if (recomp) {
X	/* Causes complete recomputation and placement */
X	TblRecompVectors(tw);
X	tw->table.vec_state = MINIMUM;
X	TblRequestResize(tw);
X	TblPlacement(tw);
X    }
X    return FALSE;
X}
X
X
X
X
Xstatic void TblChangeManaged(w)
XWidget w;			/* Table widget */
X/*
X * This routine is called when a change to the managed set of
X * children occurs.  The current implementation simply refigures
X * the widget and repositions all widgets.  Better implementations
X * may be able to examine the change and react accordingly.
X */
X{
X    TableWidget tw = (TableWidget) w;
X
X    TblRecompVectors(tw);
X    tw->table.vec_state = MINIMUM;
X    TblRequestResize(tw);
X    TblPlacement(tw);
X}
X
X
X
Xstatic XtGeometryResult TblQueryGeometry(w, request, geo_return)
XWidget w;			/* Table widget         */
XXtWidgetGeometry *request;	/* Parent intended size */
XXtWidgetGeometry *geo_return;   /* This widget's size   */
X/*
X * This routine is called by a parent that wants a preferred
X * size for the widget.  The `request' is the size (and/or position) 
X * the parent intends to make the widget.  The `geo_return' is the
X * preferred size of the widget.  The preferred size of the
X * table widget is its vector size.
X */
X{
X    TableWidget tw = (TableWidget) w;
X
X    if (tw->table.vec_state == INVALID) {
X	TblRecompVectors(tw);
X	tw->table.vec_state = MINIMUM;
X    }
X    geo_return->request_mode = CWWidth|CWHeight;
X    geo_return->width = tw->table.vec_width + 2*tw->table.int_width +
X      (tw->table.num_cols-1)*tw->table.col_spacing;
X    geo_return->height = tw->table.vec_height + 2*tw->table.int_height +
X      (tw->table.num_rows-1)*tw->table.row_spacing;
X
X    /* Now determine return code */
X    if (((geo_return->request_mode & request->request_mode) !=
X	 geo_return->request_mode) ||
X	(request->width < geo_return->width) ||
X	(request->height < geo_return->height)) {
X	return XtGeometryAlmost;
X    } else if ((request->width == geo_return->width) &&
X	       (request->height == geo_return->height)) {
X	return XtGeometryNo;
X    } else {
X	return XtGeometryYes;
X    }
X    /*NOTREACHED*/
X}
X
X
X
Xstatic void TblPositionChild(w, c, r, hspan, vspan, options)
XWidget w;			/* Subwidget to place              */
XPosition c, r;			/* Position in array (column, row) */
XDimension hspan, vspan;		/* Horizontal and vertical span    */
XXtTblMask options;		/* Widget placement options        */
X/*
X * This routine registers the position of Widget w.  The widget
X * must be a sub-widget of a Table class widget.  The row and
X * column must be non-negative.  The horizontal and vertical
X * span must be positive.  The options are as follows:
X *   TBL_LEFT		Horizontally left justified.
X *   TBL_RIGHT		Horizontally right justified.
X *   TBL_TOP		Vertically top justified.
X *   TBL_BOTTOM 	Vertically bottom justified.
X *   TBL_SM_WIDTH	Force the width to be as small as possible.
X *   TBL_SM_HEIGHT	Force the height to be as small as possible.
X *   TBL_LK_WIDTH	Don't try to expand the widget horizontally.
X *   TBL_LK_HEIGHT	Don't try to expand the widget vertically.
X * If `options' is equal to TBL_DEF_OPT,  it is filled with 
X * the default value for the table widget. The routine adds the 
X * information into a table and recomputes position information.
X */
X{
X    Widget parent;
X    TableWidget tw;
X    TableLoc loc;
X
X    if ((c < 0) || (r < 0) || (hspan == 0) || (vspan == 0)) {
X	/* Bad arguments */
X	XtErrorMsg("TblPositionChild", "wrongParameters", "XtToolkitError",
X		   "Bad value for row, column, hspan, or vspan",
X		   (String *) NULL, (Cardinal *) NULL);
X    }
X    parent = w->core.parent;
X    if (parent &&
X	(strcmp(parent->core.widget_class->core_class.class_name,
X		TBL_CLASS_NAME)==0)){
X	/* The parent exists and is a TableWidget */
X	tw = (TableWidget) parent;
X	loc.ax = c;
X	loc.ay = r;
X	loc.h_span = hspan;
X	loc.v_span = vspan;
X	if (options == TBL_DEF_OPT) {
X	    loc.options = tw->table.def_options;
X	} else {
X	    loc.options = options;
X	}
X	TblInsertLoc(tw->table.real_layout, w, &loc);
X	tw->table.vec_state = INVALID;
X	/* Full recomputation if realized */
X	if (XtIsRealized(parent)) TblResize(parent);
X    } else {
X	XtErrorMsg("TblPositionChild", "badParent", "XtToolkitError",
X		   "Parent of widget is not a tableClassWidget",
X		   (String *) NULL, (Cardinal *) NULL);
X    }
X}
X
X
X
Xstatic Boolean TblFindChild(w, c_r, r_r, hspan_r, vspan_r, opt_r)
XWidget w;			/* Widget to locate  */
XPosition *c_r, *r_r;		/* Returned position */
XDimension *hspan_r, *vspan_r;	/* Returned span     */
XXtTblMask *opt_r;		/* Returned options  */
X/*
X * This routine looks up a child widget's location and span.  The
X * parent must be a table widget.  Only non-zero fields are filled
X * in.  If the widget cannot be found,  the routine returns False
X * and does not modify any of the passed in pointers.  The routine
X * first looks in a table of widget positions defined by the
X * `position_child' class procedure.  If not found there,  it
X * searches the default table using the widget name.  These
X * defaults are set by resources or XtSetValues().
X */
X{
X    Widget parent;
X    TableWidget tw;
X    TableLocPtr locp;
X    TableDefLocPtr temp;
X
X    parent = w->core.parent;
X    if (parent &&
X	(strcmp(parent->core.widget_class->core_class.class_name,
X		TBL_CLASS_NAME)==0)) {
X	tw = (TableWidget) parent;
X	if (locp = TblLocLookup(tw->table.real_layout, w)) {
X	    if (c_r) *c_r = locp->ax;
X	    if (r_r) *r_r = locp->ay;
X	    if (hspan_r) *hspan_r = locp->h_span;
X	    if (vspan_r) *vspan_r = locp->v_span;
X	    if (opt_r) *opt_r = locp->options;
X	    return True;
X	} else {
X	    if (tw->table.init_layout) {
X		temp = MergeDefLoc(tw->table.layout_db, tw->table.init_layout);
X		XtFree((char *) (tw->table.init_layout));
X		tw->table.init_layout = (TableDefLocPtr) 0;
X		XtFree((char *) (tw->table.layout_db));
X		tw->table.layout_db = temp;
X	    }
X	    /* Attempt to look it up */
X	    if (temp = FindDefLoc(tw->table.layout_db, w->core.name)) {
X		if (c_r) *c_r = temp->loc.ax;
X		if (r_r) *r_r = temp->loc.ay;
X		if (hspan_r) *hspan_r = temp->loc.h_span;
X		if (vspan_r) *vspan_r = temp->loc.v_span;
X		if (opt_r) *opt_r = temp->loc.options;
X		return True;
X	    } else {
X		return False;
X	    }
X	}
X    } else {
X	XtErrorMsg("TblFindChild", "badParent", "XtToolkitError",
X		   "Parent of widget is not a tableClassWidget",
X		   (String *) NULL, (Cardinal *) NULL);
X    }
X    /*NOTREACHED*/
X}
X
X
X
Xstatic void TblDestroy(w)
XWidget w;			/* Widget to destroy */
X/*
X * Called to free resources consumed by the widget.
X */
X{
X    TableWidget tw = (TableWidget) w;
X
X    XtFree((char *) (tw->table.init_layout));
X    XtFree((char *) (tw->table.layout_db));
X    TblFreeLocTbl(tw->table.real_layout);
X    if (tw->table.rows) XtFree((char *) (tw->table.rows));
X    if (tw->table.cols) XtFree((char *) (tw->table.cols));
X}
X
X
Xstatic Cardinal DefSpecLen(layout)
XString layout;			/* Full layout specification string */
X/*
X * Examines `layout' and determines how many statements there are.
X * Basically counts semi-colons and adds one.
X */
X{
X    extern String strchr();
X    String idx = layout;
X    Cardinal result = 0;
X
X    while (idx && *idx) {
X	idx = strchr(idx, ';');
X	if (idx) {
X	    result++;
X	    idx++;
X	}
X    }
X    return result+1;
X}
X
X#define MAX_FIELD	128
X#define NUM_FIELDS	6
X#define MAX_CHARS	255
X
Xstatic XtTblMask ParseOpts(spec)
XString spec;			/* Option letters */
X/*
X * Parses the null-terminated string of option characters in `spec'.
X * Returns a mask that is the `or' of all options selected.
X */
X{
X    static Boolean init = 0;
X    static XtTblMask all_chars[MAX_CHARS];
X    XtTblMask result = 0;
X    String idx;
X
X    if (!init) {
X	Cardinal i;
X
X	for (i = 0;  i < MAX_CHARS;  i++) all_chars[i] = 0;
X	all_chars['l'] = TBL_LEFT;
X	all_chars['r'] = TBL_RIGHT;
X	all_chars['t'] = TBL_TOP;
X	all_chars['b'] = TBL_BOTTOM;
X	all_chars['w'] = TBL_LK_WIDTH;
X	all_chars['h'] = TBL_LK_HEIGHT;
X	all_chars['W'] = TBL_SM_WIDTH;
X	all_chars['H'] = TBL_SM_HEIGHT;
X    }
X    for (idx = spec;  *idx;  idx++) {
X	result |= all_chars[*idx];
X    }
X    return result;
X}
X
Xstatic void DefParse(spec, loc_spec)
XString spec;			/* One specification statement */
XTableDefLocPtr loc_spec;	/* Result location spec        */
X/*
X * Parses a text specification statement into an internal
X * form given  by `loc_spec'.
X *
X ******************* NOTE ********************
X * Assumes only called from cvtStrToDefLoc() *
X *********************************************
X */
X{
X#ifndef MAX_TABLE_CHILD_WIDGET_NAME_LEN
X#define MAX_TABLE_CHILD_WIDGET_NAME_LEN 128
X#endif
X    static char buf[MAX_TABLE_CHILD_WIDGET_NAME_LEN];
X    int         i  = 0;
X    char*       cp = spec;
X
X    /* initial values, NOT the defaults */
X    loc_spec->loc.ax = loc_spec->loc.ay = 0;
X    loc_spec->loc.h_span = loc_spec->loc.v_span = 0;
X
X    /* Now attempt to parse the string */
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while (' ' < *cp && i < MAX_TABLE_CHILD_WIDGET_NAME_LEN)
X	buf[i++] = *cp++;
X    buf[i] = '\0';
X    if ( i )
X	loc_spec->w_name = XtNewString(buf);	/* widget name */
X    else
X	loc_spec->w_name = "No Name";		/* default name */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.ax = loc_spec->loc.ax * 10 + *cp++ - '0';
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.ay = loc_spec->loc.ay * 10 + *cp++ - '0';
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.h_span = loc_spec->loc.h_span * 10 + *cp++ - '0';
X    if (loc_spec->loc.h_span == 0)
X	loc_spec->loc.h_span = 1;		/* default span */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.v_span = loc_spec->loc.v_span * 10 + *cp++ - '0';
X    if (loc_spec->loc.v_span == 0)
X	loc_spec->loc.v_span = 1;		/* default span */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    i = 0;
X    while (*cp && i < MAX_TABLE_CHILD_WIDGET_NAME_LEN &&
X	*cp == 'l' || *cp == 'r' || *cp == 't' || *cp == 'b' ||
X	*cp == 'w' || *cp == 'h' || *cp == 'W' || *cp == 'H' )
X	buf[i++] = *cp++;
X    buf[i] = '\0';
X    if ( i )
X	loc_spec->loc.options = ParseOpts(buf);
X    else
X	loc_spec->loc.options = 0;		/* default */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    if (*cp )
X	XtStringConversionWarning( spec, 
X	    "layout component: name [col] [row] [h_span] [v_span] [lrtbwhWH]");
X}
X
Xstatic String GetSpec(spec_ptr)
XString *spec_ptr;		/* Specification pointer */
X/*
X * This routine gets the next specification from the string
X * `spec_ptr' and updates the pointer appropriately.
X */
X{
X    extern String strchr();
X    String result;
X    String semi;
X
X    if (*spec_ptr && **spec_ptr) {
X	semi = strchr(*spec_ptr, ';');
X	if (semi) {
X	    *semi = '\0';
X	    result = *spec_ptr;
X	    *spec_ptr = semi+1;
X	    return result;
X	} else {
X	    result = *spec_ptr;
X	    *spec_ptr += strlen(*spec_ptr);
X	    return result;
X	}
X    } else {
X	return (String) 0;
X    }
X}
X
X
X
X/**********************************************************************
X *
X * Public routines
X *
X **********************************************************************/
X
X
X/*ARGSUSED*/
Xcaddr_t XtTblParseLayout(layout)
XString layout;			/* String layout specification */
X/*
X * Parses a string layout specification into an internal form
X * suitable for use in a call to XtSetValues().  The form is
X * a list of statements separated by semicolons.  Each statement
X * has the form:
X *   widget_name column row horizontal_span vertical_span opt_list
X * where the meaning of each field is:
X *   widget_name	Name of the widget as given to XtCreateWidget().
X *   column		Integer >= 0 descibing column in array
X *   row		Row >= 0 describing row in array
X *   horizontal_span	Integer >= 1 describing horizontal widget span
X *   vertical_span	Integer >= 1 describing vertical widget span
X *   opt_list		Series of characters each representing an option:
X *	l:  TBL_LEFT
X *	r:  TBL_RIGHT
X *      t:  TBL_TOP
X *      b:  TBL_BOTTOM
X *      w:  TBL_LK_WIDTH
X *      h:  TBL_LK_HEIGHT
X *      W:  TBL_SM_WIDTH
X *      H:  TBL_SM_HEIGHT
X * The options are as described in TblPostionChild().  The horizontal_span,
X * vertical_span, and opt_list are optional and will default to reasonable
X * values.
X */
X{
X    TableDefLocPtr result, idx;
X    Cardinal len;
X    String spec;
X    String orig;
X
X    /* Make a copy for safety */
X    if (layout && ((len = DefSpecLen(layout)) > 0)) {
X	orig = layout = XtNewString(layout);
X	result = (TableDefLocPtr) XtCalloc(len+1, sizeof(struct _TableDefLoc));
X	idx = result;
X	while (spec = GetSpec(&layout)) {
X	    DefParse(spec, idx);
X	    idx++;
X	}
X	/* null terminate */
X	idx->w_name = (String) 0;
X	XtFree(orig);
X	return (caddr_t) result;
X    } else {
X	return (caddr_t) 0;
X    }
X    /*NOTREACHED*/
X}
X
Xvoid XtTblPosition(w, col, row)
XWidget w;			/* Widget to position */
XPosition col, row;		/* Position in array  */
X/*
X * This routine positions a widget that has been created
X * under a widget of class tableWidgetClass.  The widget
X * will be placed at column `col' and row `row'.  If
X * the widget has never been placed before,  it will
X * span only one space in each direction and its
X * options will be the defaults for the table widget.
X */
X{
X    Position old_row, old_col;
X    Dimension old_hspan, old_vspan;
X    XtTblMask old_opts;
X
X    if (TblFindChild(w, &old_col, &old_row, &old_hspan, &old_vspan, &old_opts)) {
X	TblPositionChild(w, col, row, old_hspan, old_vspan, old_opts);
X    } else {
X	TblPositionChild(w, col, row, 1, 1, TBL_DEF_OPT);
X    }
X}
X
Xvoid XtTblResize(w, h_span, v_span)
XWidget w;			/* Widget to resize            */
XDimension h_span, v_span;	/* New widget span             */
X/*
X * This routine changes the span of widget `w' to (`h_span', `v_span').
X * If the widget has never been placed before,  it will be located
X * at (0,0) and its options will be the defaults for its
X * parent table widget.
X */
X{
X    Position old_row, old_col;
X    Dimension old_hspan, old_vspan;
X    XtTblMask old_opts;
X
X    if (TblFindChild(w, &old_col, &old_row, &old_hspan, &old_vspan, &old_opts)) {
X	TblPositionChild(w, old_col, old_row, h_span, v_span, old_opts);
X    } else {
X	TblPositionChild(w, 0, 0, h_span, v_span, TBL_DEF_OPT);
X    }
X}
X
Xvoid XtTblOptions(w, opt)
XWidget w;			/* Widget to change */
XXtTblMask opt;			/* New option mask  */
X/*
X * This routine changes the options of widget `w' to `opt'.  If
X * the widget has never been placed before,  it will be located
X * and (0,0) with a span of (1,1) and its options will be the
X * default options for its parent table widget.  The option
X * mask is as described for TblPositionChild.
X */
X{
X    Position old_row, old_col;
X    Dimension old_hspan, old_vspan;
X    XtTblMask old_opts;
X
X    if (TblFindChild(w, &old_col, &old_row, &old_hspan, &old_vspan, &old_opts)) {
X	TblPositionChild(w, old_col, old_row, old_hspan, old_vspan, opt);
X    } else {
X	TblPositionChild(w, 0, 0, 1, 1, opt);
X    }
X}
X
Xvoid XtTblConfig(w, col, row, h_span, v_span, opt)
XWidget w;			/* Widget to position          */
XPosition col, row;		/* Position in array           */
XDimension h_span, v_span;	/* Horizonal and vertical span */
XXtTblMask opt;			/* Widget placement options    */
X/*
X * This routine positions a widget that has been created
X * under a widget of class tableWidgetClass.  The widget
X * will be placed at column `col' and row `row'.  The
X * widget will span the distances given by `h_span' and `v_span'.
X * The options argument is as described for TblPositionChild.
X */
X{
X    TblPositionChild(w, col, row, h_span, v_span, opt);
X}
X
!STUFFY!FUNK!
echo " "
echo "End of kit 21 (of 35)"
cat /dev/null >kit21isdone
run=''
config=''
for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35; do
    if test -f kit${iskit}isdone; then
	run="$run $iskit"
    else
	todo="$todo $iskit"
    fi
done
case $todo in
    '')
	echo "You have run all your kits.  Please read README."
	for combo in `find . -name '*:AA' -print`; do
	    if test -f "$combo"; then
		realfile=`echo $combo | sed 's/:AA$//'`
		cat $realfile:[A-Z][A-Z] >$realfile
		rm -rf $realfile:[A-Z][A-Z]
	    fi
	done
	rm -rf kit*isdone
	chmod ugo+x test*
	;;
    *)  echo "You have run$run."
	echo "You still need to run$todo."
	;;
esac
: Someone might mail this, so...
exit

--
dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.