[comp.sources.x] v11i026: wcl - Widget Creation Library, Part14/35

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

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

#! /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 14 (of 35).  If kit 14 is complete, the line"
echo '"'"End of kit 14 (of 35)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir Xmp 2>/dev/null
echo Extracting Xmp/Table.c:AA
sed >Xmp/Table.c:AA <<'!STUFFY!FUNK!' -e 's/X//'
X/*LINTLIBRARY*/ /* -*-C++-*- */
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/* Edit History
X
X11/25/90  12 nazgul	Better handling of geometry
X11/08/90   2 schulert	remove include of Xmu.h
X10/31/90   1 schulert	change w->xrm_name to x->core.xrm_name
X10/31/90  10 nazgul	Handle gadgets when formatting is done by name
X09/30/90   9 nazgul	Try not to change the widget if we are going to return
X			XtGeometryAlmost
X09/13/90   7 nazgul	Added #ifdefs so it works with Motif 1.1 as well as 1.0
X08/07/90   5 nazgul	Mon Aug  6 09:41:11 1990 patches from david@jpl-devvax.jpl.nasa.gov
X07/26/90   4 nazgul	Removal of Xmu.h reference (Niels Mayer)
X07/25/90   3 nazgul	Merged in latest patches from the net
X07/15/90   2 nazgul	Now deal with XmText widgets reasonably
X
X*/
X
X#include "X11/IntrinsicP.h"
X#include "X11/StringDefs.h"
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
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/* If we want it more motif-like
X    { XmNverticalSpacing, XmCSpacing, XtRDimension, sizeof(Dimension),
X	XtOffset(TableWidget, table.col_spacing), XtRImmediate, (caddr_t) 0 },
X    { XmNhorizontalSpacing, XmCSpacing, XtRDimension, sizeof(Dimension),
X	XtOffset(TableWidget, table.row_spacing), XtRImmediate, (caddr_t) 0 },
X*/
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 TblExposeProc();
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#if XmVersion > 1000
Xstatic XtActionsRec actionsList[] =
X{
X	{ "Enter",	(XtActionProc)	_XmManagerEnter },
X	{ "FocusIn",	(XtActionProc)	_XmManagerFocusIn },
X	{ "Arm",	(XtActionProc)	_XmGadgetArm  },
X	{ "Activate",	(XtActionProc)	_XmGadgetActivate },
X	{ "Help",	(XtActionProc)	_XmManagerHelp },
X	{ "Return",	(XtActionProc)	_XmBulletinBoardReturn },
X	{ "BulletinBoardReturn", (XtActionProc)	_XmBulletinBoardReturn },
X        { "BulletinBoardCancel", (XtActionProc)	_XmBulletinBoardCancel },
X};
X#else
Xstatic XtActionsRec actionsList[] =
X{
X	{ "Enter",	(XtActionProc)	_XmManagerEnter },
X	{ "FocusIn",	(XtActionProc)	_XmBulletinBoardFocus },
X	{ "Arm",	(XtActionProc)	_XmBulletinBoardArm  },
X	{ "Activate",	(XtActionProc)	_XmBulletinBoardActivate },
X	{ "Help",	(XtActionProc)	_XmBulletinBoardHelp },
X	{ "Return",	(XtActionProc)	_XmBulletinBoardReturn },
X};
X#endif
X
XTableClassRec tableClassRec = {
X  { /* core_class fields */
X#ifdef OLDLEVEL
X    /* superclass	  */    (WidgetClass) &compositeClassRec,
X#else
X    /* superclass         */    (WidgetClass) &xmBulletinBoardClassRec,
X#endif
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            */    actionsList,
X    /* num_actions        */    XtNumber(actionsList),
X    /* resources          */    resources,
X    /* num_resources      */    XtNumber(resources),
X    /* xrm_class          */    NULLQUARK,
X    /* compress_motion    */    False,
X    /* compress_exposure  */    TRUE,
X    /* compress_enterleave*/    False,
X    /* visible_interest   */    FALSE,
X    /* destroy            */    TblDestroy,
X    /* resize             */    TblResize,
X    /* expose             */    _XmRedisplayGadgets,
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           */    XtInheritTranslations,
X    /* query_geometry     */	TblQueryGeometry,
X    /* display_accelerator*/	/*XtInheritDisplayAccelerator,*/ NULL,
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#ifndef OLDLEVEL
X{ /* constraint_class fields */
X    /* resource list 	*/ NULL,
X    /* num resources	*/ 0,
X    /* constraint size  */ 0,
X    /* init proc	*/ NULL,
X    /* destroy proc     */ NULL,
X    /* set values proc  */ NULL,
X    /* extension 	*/   NULL
X  },
X  { /* manager_class	  */
X#if XmVersion > 1000
X    /* translations 	  */	XtInheritTranslations,
X    /* syn_resources	  */	NULL,
X    /* num_syn_resources  */	0,
X    /* syn_cont_resources */	NULL,
X    /* num_syn_cont_resources */ 0,
X    /* parent_process     */    NULL,
X    /* extension	  */	NULL
X#else
X    /* translations 	  */	(XtTranslations) _XtInherit,
X    /* get_resources	  */	NULL,
X    /* num_get_resources  */	0,
X    /* get_constraint_resources */	NULL,
X    /* num_get_constraint_resources */	0,
X    /* extension	  */	NULL
X#endif
X  },
X{ /* Bulletin Board */
X    /* always_install_accelerators */	False,
X#if XmVersion > 1000
X    /* geo_matrix_create */	NULL,
X    /* focus_moved_proc */	XtInheritFocusMovedProc,
X#endif
X    /* extension	*/  NULL,
X  },
X#endif
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/* 
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    if (!name) return (TableDefLocPtr) 0;
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    _XmMoveObject((RectObj) 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#ifdef sizing
X	    Widget w = managed->locs[i].w;
X	    printf("Resizing %s(%X) -> %d, %d, %d\n", (XtIsWidget(w)?w->core.name:
X						       XrmQuarkToString(w->core.xrm_name)),
X		   w, nw, nh,
X		   w->core.border_width);
X#endif
X	    _XmResizeObject((RectObj) managed->locs[i].w, nw, nh,
X			    managed->locs[i].w->core.border_width);
X	}
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, tmp;
X    float	offset;
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
X#ifdef sizing
X	/* Worry about the case where we couldn't grow enough */
X	/* This is a real hack.  If there is one item which seems to be the
X         * trouble maker, then we shrink it, otherwise we shrink everyone
X	 * proportionately.  We can still truncate here, but only when things
X	 * start getting around 10 pixels.
X         */
X	if (real_width < tw->table.vec_width) {
X	    printf("Too wide! (%d < %d)\n", real_width, tw->table.vec_width);
X	    for (i = 0; i < tw->table.num_rows; ++i) {
X		if (lrows[i].value > real_width) {
X		    printf("shrunk item %d from %d", i, lrows[i].value);
X		    tmp = lrows[i].value;
X		    lrows[i].value = real_width - (tw->table.vec_width - tmp);
X		    if (lrows[i].value < 10) lrows[i].value = 10;
X		    tw->table.vec_width -= (tmp - lrows[i].value);
X		    printf(" to %d\n", lrows[i].value);
X		}
X	    }
X	    if (real_width < tw->table.vec_width) {
X		offset = tw->table.vec_width - real_width;
X		offset /= tw->table.vec_width;
X		for (i = 0; i < tw->table.num_rows; ++i) {
X		    if (lrows[i].value > 10) {
X			lrows[i].value *= offset;
X			if (lrows[i].value < 10) lrows[i].value = 10;
X		    } else printf("won't shrink %d\n", i);
X		}
X		printf("shrunk by %f\n", offset);
X	    }
X	}
X	if (real_height < tw->table.vec_height) {
X	    printf("Too tall! (%d < %d)\n", real_height, tw->table.vec_height);
X	    for (i = 0; i < tw->table.num_cols; ++i) {
X		if (lcols[i].value > real_height) {
X		    printf("shrunk item %d from %d", i, lcols[i].value);
X		    tmp = lcols[i].value;
X		    lcols[i].value = real_height - (tw->table.vec_height - tmp);
X		    if (lcols[i].value < 10) lcols[i].value = 10;
X		    tw->table.vec_height -= (tmp - lcols[i].value);
X		    printf(" to %d\n", lcols[i].value);
X		}
X	    }
X	    if (real_height < tw->table.vec_height) {
X		offset = tw->table.vec_height - real_height;
X		offset /= tw->table.vec_height;
X		for (i = 0; i < tw->table.num_cols; ++i) {
X		    if (lcols[i].value > 10) {
X			lcols[i].value *= offset;
X			if (lcols[i].value < 10) lcols[i].value = 10;
X		    } else printf("won't shrink %d\n", i);
X		}
X		printf("shrunk by %f\n", offset);
X	    }
X	}
X#endif
X	      
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 owidth, oheight, obdr;
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
X	tw = (TableWidget) parent;
X	result = ExamineRequest(request);
X	switch (result) {
X	  case XtGeometryYes:
X	  case XtGeometryAlmost:
X	    if (request->request_mode & CWWidth) width = request->width;
X	    else width = w->core.width;
X	    if (request->request_mode & CWHeight) height = request->height;
X	    else height = w->core.height;
X	    if (request->request_mode & CWBorderWidth) bdr = request->height;
X	    else bdr = w->core.border_width;
X
X	    oheight = w->core.height;
X	    owidth = w->core.width;
X	    obdr = w->core.border_width;
X	    w->core.width = width;
X	    w->core.height = height;
X	    w->core.border_width = bdr;
X
X	    ow = tw->table.vec_width;
X	    oh = tw->table.vec_height;
X	    TblRecompVectors(tw);
X	    w->core.width = owidth;
X	    w->core.height = oheight;
X	    w->core.border_width = obdr;
X	    
X	    if ((ow != tw->table.vec_width) || (oh != tw->table.vec_height)) {
X		tw->table.vec_state = MINIMUM;
X		TblRequestResize(tw);
X	    }
X
X	  {
X	      Position		x, y;
X	      Dimension		h, v;
X	      XtTblMask 	options;
X	      Position 		ax, ay;
X	      Dimension 	aw, ah;
X	      Dimension 	nw, nh;
X	      TableVecPtr	lcols, lrows;
X	      Cardinal		i;
X	      XtGeometryResult	gres;
X	      char		*name;
X	      Dimension		real_width, real_height;
X    
X	      if (!XtIsWidget(w)) name = XrmQuarkToString(w->core.xrm_name);
X	      else name = w->core.name;
X
X#ifdef sizing
X	      printf("Positioning %s (%X)\n", name, w);
X#endif
X	      
X	      if (!TblFindChild(w, &x, &y, &h, &v, &options)) return XtGeometryNo;
X
X	      lrows = (TableVecPtr)  XtCalloc(tw->table.num_rows, sizeof(struct _TableVector));
X	      for (i = 0;  i < tw->table.num_rows;  i++) lrows[i] = tw->table.rows[i];
X	      lcols = (TableVecPtr) XtCalloc(tw->table.num_cols, sizeof(struct _TableVector));
X	      for (i = 0;  i < tw->table.num_cols;  i++) lcols[i] = tw->table.cols[i];
X
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	      ax = SumVec(0, x, lcols, tw->table.int_width, tw->table.col_spacing, 0);
X	      ay = SumVec(0, y, lrows, tw->table.int_height, tw->table.row_spacing, 0);
X	      aw = SumVec(x, (Position) h, lcols, 0, tw->table.col_spacing, -tw->table.col_spacing);
X	      ah = SumVec(y, (Position) v, lrows, 0, tw->table.row_spacing, -tw->table.row_spacing);
X	      nw = aw - 2*w->core.border_width;
X	      nh = ah - 2*w->core.border_width;
X	      if (options & TBL_LK_WIDTH) nw = w->core.width;
X	      if (options & TBL_LK_HEIGHT) nh = w->core.height;
X	      XtFree(lcols);
X	      XtFree(lrows);
X
X	      /* Worry about the case where we couldn't grow enough */
X	      /* Note, we may need a border here or something! */
X	      if (real_width < tw->table.vec_width) {
X#ifdef sizing
X		  printf("%s: Too wide! (%d < %d)\n", name, real_width, tw->table.vec_width);
X#endif
X		  nw -= (tw->table.vec_width - real_width);
X		  if (nw <= 0) {
X#ifdef sizing
X		      printf("%s: Give up!\n", name);
X#endif
X		      return XtGeometryNo;
X		  }
X	      }
X	      if (real_height < tw->table.vec_height) {
X#ifdef sizing
X		  printf("%s: Too tall! (%d < %d)\n", name, real_height, tw->table.vec_height);
X#endif
X		  nh -= (tw->table.vec_height - real_height);
X		  if (nh <= 0) {
X#ifdef sizing
X		      printf("%s: Give up!\n", name);
X#endif
X		      return XtGeometryNo;
X		  }
X	      }
X	      
X
X	      *reply = *request;
X	      reply->request_mode &= (CWWidth|CWHeight|CWBorderWidth);
X	      reply->width = nw;
X	      reply->height = nh;
X
X#ifdef sizing
X	      printf("%s: w=o%d,r%d,a%d,t%d h=o%d,r%d,a%d,t%d\n", name,
X		     owidth, width, w->core.width, nw, oheight, height, w->core.height, nh);
X#endif
X
X	      /* Return No if there is no change */
X	      if (w->core.width == nw && w->core.height == nh) {
X		  if (request->request_mode & CWBorderWidth) {
X		      if (w->core.border_width == request->border_width) {
X#ifdef sizing
X			  printf("%s: No change\n", name);
X#endif
X			  return XtGeometryNo;
X		      }
X#ifdef sizing
X		      printf("%s: Almost border\n", name);
X#endif
X		      reply->request_mode = CWBorderWidth;
X		      return XtGeometryAlmost;
X		  }
X	      }
X		      
X	      gres = XtGeometryDone;
X	      if (((request->request_mode & CWWidth) && nw != width) ||
X		  ((request->request_mode & CWHeight) && nh != height)) {
X		  gres = XtGeometryAlmost;
X	      }
X
X	      if (request->request_mode & (~CWWidth&~CWHeight&~CWBorderWidth&~XtCWQueryOnly))
X		gres = XtGeometryAlmost;
X
X	      if (request->request_mode & XtCWQueryOnly) {
X		  if (gres == XtGeometryDone) return XtGeometryYes;
X#ifdef sizing
X		  printf("%s: It was a query (%d)\n", name, gres);
X#endif
X		  return gres;
X	      }
X
X	      if (gres == XtGeometryAlmost) {
X#ifdef sizing
X		  printf("%s: Almost fits (Request=%d Reply=%d)\n", name,
X			 request->request_mode, reply->request_mode);
X#endif
X		  return gres;
X	      }
X
X	      w->core.border_width = bdr;
X	      TblPlacement(tw);
X
X#ifdef sizing
X	      printf("%s: w=o%d,r%d,a%d,t%d h=o%d,r%d,a%d,t%d (%X)\n", name,
X		     owidth, width, w->core.width, nw, oheight, height, w->core.height, nh, w);
X#endif
X	  }
X
X	    return XtGeometryDone;
X	    /*NOTREACHED*/
X	case XtGeometryNo:
X	    return result;
X#ifdef never
X	    /* This isn't right, since if you return almost you must promise
X	     * to honor the same request next time, and we haven't really checked
X	     * here.
X             */
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#endif
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    XtWidgetGeometry	g;
X
X/*    if (_XmMakeGeometryRequest(tw, &g) == XtGeometryYes && XtIsRealized(tw)) 
X    {
X*/
X	TblRecompVectors(tw);
X	tw->table.vec_state = MINIMUM;
X	TblRequestResize(tw);
X	TblPlacement(tw);
X/*    }*/
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    char	*name;
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 (!XtIsWidget(w)) name = XrmQuarkToString(w->core.xrm_name);
X	    else name = w->core.name;
!STUFFY!FUNK!
echo " "
echo "End of kit 14 (of 35)"
cat /dev/null >kit14isdone
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.