v08i033: wcl - Widget Creation Library, Part03/06

David E. Smyth david at devvax.Jpl.Nasa.Gov
Fri Jul 6 17:40:47 AEST 1990


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

# to unbundle, "sh" this file -- DO NOT use csh
#  SHAR archive format.  Archive created Tue Jul 3 16:49:00 PDT 1990
echo x - Table.c
sed 's/^X//' > Table.c <<'+FUNKY+STUFF+'
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#ifdef X11R4
X#include "X11/Xmu/Xmu.h"
X#else
X#include "X11/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{
X    static String def_name = "No Name";
X    char fields[NUM_FIELDS][MAX_FIELD];
X    Cardinal num;
X
X    /* First, set up defaults */
X    loc_spec->w_name = def_name;
X    loc_spec->loc.ax = loc_spec->loc.ay = 0;
X    loc_spec->loc.h_span = loc_spec->loc.v_span = 1;
X    loc_spec->loc.options = 0;
X
X    /* Now attempt to parse the string */
X    num = sscanf(spec, "%s %s %s %s %s %s",
X		 fields[0], fields[1], fields[2], fields[3], fields[4], fields[5]);
X    if (num >= 1) {
X	loc_spec->w_name = XtNewString(fields[0]);
X    }
X    if (num >= 2) {
X	loc_spec->loc.ax = atoi(fields[1]);
X    }
X    if (num >= 3) {
X	loc_spec->loc.ay = atoi(fields[2]);
X    }
X    if (num >= 4) {
X	loc_spec->loc.h_span = atoi(fields[3]);
X    }
X    if (num >= 5) {
X	loc_spec->loc.v_span = atoi(fields[4]);
X    }
X    if (num >= 6) {
X	loc_spec->loc.options = ParseOpts(fields[5]);
X    }
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
X    /* Make a copy for safety */
X    if (layout && ((len = DefSpecLen(layout)) > 0)) {
X	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(layout);
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
+FUNKY+STUFF+
echo '-rw-r--r--  1 david       45961 Jul  3 13:48 Table.c    (as sent)'
chmod u=rw,g=r,o=r Table.c
ls -l Table.c
echo x - Table.doc
sed 's/^X//' > Table.doc <<'+FUNKY+STUFF+'
X
XTable - Geometry Management Widget for the X Toolkit
X
XDavid Harrison
XUC Berkeley Electronics Research Lab
X(davidh at ic.Berkeley.EDU, ...!ucbvax!ucbcad!davidh)
X
XTable is a composite widget designed to manage the size and location
Xof its children.  The widget uses an array model to simplify the
Xarrangement of child widgets.  The widget is directly derived from the
Xcore and composite widgets provided by the X Toolkit and can be used
Xwith any widget set.  It has been tested using the Athena widget set.
XBelow is a short summary on the operation and use of the Table widget.
XIt assumes a working knowledge of the X Toolkit Intrinsics.
X
XThe Table widget addresses formatting for dialog boxes.  Dialog boxes
Xare rectangular windows that contain a wide variety of widgets.  Most
Xdialog boxes are arranged with widgets aligned in a way similar to the
Xlayout found in business forms.  The Table widget is designed to make
Xsuch layouts easy to specify.
X
XWhen designing dialog boxes that resemble business forms, the primary
Xproblem is specifying the alignment between widgets.  The Table widget
Xaddresses this problem by adopting an array model.  Under this model,
Xwidgets are placed at row and column locations in a variable sized
Xarray.  Widgets may span more than one row or column.  The array can
Xexpand or contract in size as needed.  There are options to control
Xjustification and place size restrictions on rows and columns of
Xwidgets.
X
XThe Table widget can contain any number and type of sub-widgets
X(including other Table widgets).  XtCreateWidget() is used to create
Xnew Table widgets using the class variable tableWidgetClass.  The
Xresources listed below are retrieved from the argument list or from
Xthe resource database:
X
X			tableWidgetClass
X
XName		Type		Default			Description
X--------------------------------------------------------------------------------
XXtNbackground	Pixel		XtDefaultBackground	Window background
XXtNborder	Pixel		XtDefaultForeground	Window border
XXtNborderWidth	Dimension	0			Width of border
XXtNx		Position	0			X position of table
XXtNy		Position	0			Y position of table
XXtNwidth	Dimension	(computed at realize)	Width of form
XXtNheight	Dimension	(computed at realize)	Height of form
XXtNmappedWhenManaged Boolean	True			XtMapWidget is automatic
XXtNsensitive	Boolean		True			Widget receives input
XXtNlayout	Layout		None			See text
XXtNinternalHeight Dimension	0			Int. horizontal padding
XXtNinternalWidth Dimension	0			Int. vertical padding
XXtNcolumnSpacing Dimension	0			Inter-column padding
XXtNrowSpacing	Dimension	0			Inter-row padding
XXtNdefaultOptions Options	None			See text
X
X
XWidgets are added to a Table by specifying a Table widget as the
Xparent widget when the widget is created.  Once a widget is added to a
Xtable, it can be assigned a row and column position, a horizontal
Xand vertical span, and justification options.  This information can be
Xspecified in two ways: using public access functions or using the
Xresource database.
X
XPublic access functions allow the programmer to dynamically alter the
Xformatting of children of a Table widget.  One can alter the position,
Xspan, or options of a widget using XtTblConfig:
X
Xvoid XtTblConfig(
X     Widget w,		/* Subwidget to modify          */
X     Position col,	/* Column position (horizontal) */
X     Position row,	/* Row position (vertical)      */
X     Dimension h_span,	/* How many columns to span     */
X     Dimension v_span,	/* How many rows to span        */
X     XtTblMask opt	/* Justification options        */
X);
X
XThe specified widget (which must be a child of a Table widget) will be
Xplaced at column `col' and row `row'.  The widget will span `h_span'
Xcolumns to the right of `col' and `v_span' rows below `row'.  The
Xarray for the table will expand as necessary.  Options are specified
Xby `or'ing together the following option bits: 
X
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_LK_WIDTH		Don't try to expand the widget horizontally.
X   TBL_LK_HEIGHT	Don't try to expand the widget vertically.
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
XAlternatively,  if `options' is equal to TBL_DEF_OPT,  the options are
Xset to the default options for the Table widget.  The default options
Xfor the Table widget are set using the XtNdefaultOptions resource (see
Xresource specifications below).  The routine changes the formatting
Xinformation in its internal table.  If the Table widget is realized,
Xthe positions of all child widgets are recomputed and the change on
Xthe screen will be immediate.
X
X
XThe Table widget computes the size of a widget based on the minimum
Xsize required for the row(s) and column(s) it occupies.  However, some
Xwidgets may require less space than that computed by the Table widget.
XIn this case, the widget is aligned in the larger space according to
Xthe bits TBL_LEFT, TBL_RIGHT, TBL_TOP, and TBL_BOTTOM.  These bits may
Xbe combined (i.e. TBL_RIGHT|TBL_TOP specifies upper right hand corner
Xjustification). If no justification bits are specified, the widget is
Xcentered.
X
XSome widgets may be amenable to growing to any size specified by the
XTable widget.  Often, it may be desirable to force these widgets to
Xremain at their optimal size for asthetic or operational convenience.
XIf the TBL_LK_WIDTH bit is specified, the Table widget will not make
Xthe widget any wider than it's original desired size.  Similarly, if
Xthe TBL_LK_HEIGHT bit is specified, the Table widget will not make the
Xwidget any taller than it's original size.  Note this may bring widget
Xjustification into play.
X
XWhen a Table widget is resized, it automatically recomputes the sizes
Xof the rows and columns of an array and distributes extra space evenly
Xamong the rows and columns.  Often, it may be useful to control this
Xdistribution of space so that some rows or columns are not resized
Xwhen extra space becomes available.  If the TBL_SM_WIDTH bit is
Xspecified, the entire column(s) containing the widget are excluded
Xfrom the excess space distribution algorithm.  Thus, the column(s) are
Xforced to remain as small as possible.  The TBL_SM_HEIGHT bit works
Xthe same way with respect to the row(s) containing the widget. A title
Xbar is a good example of this concept. When a dialog is resized, any
Xexcess vertical space should be given to the body of the dialog not to
Xthe title bar.  Thus, TBL_SM_HEIGHT would be specified for a title bar
Xwidget.
X
X
XIn most applications, the programmer will not set all of the above
Xinformation for all widgets.  The following convenience functions have
Xbeen defined for use in these cases:
X
Xvoid XtTblPosition(
X     Widget w,		/* Child of table widget        */
X     Position col,	/* Column position (horizontal) */
X     Position row	/* Row position (vertical)      */
X);
X
XThe specified widget (which must be a child of a Table widget) will be
Xplaced at column `col' and row `row'.  The vertical and horizontal
Xspan of the widget will remain unchanged.  If the span of the widget
Xwas not set, it will default to one row and one column.  The
Xjustification options of the widget will remain unchanged.  If the
Xjustification options of the widget were not set, it will default to
XTBL_DEF_OPT (see XtTblConfig).
X
Xvoid XtTblResize(
X     Widget w,		/* Child of table widget        */
X     Dimension h_span,	/* How many columns to span     */
X     Dimention v_span	/* How many rows to span        */
X);
X
XThis routine changes the span of widget `w' (which must be a child of
Xa Table widget) to span `h_span' columns and `v_span' rows.  Any
Xprevious position or options assigned to the widget will be preserved.
XIf no position is associated with the widget,  it will be placed at
X(0,0).  If no options are associated with the widget, its options will
Xbe the defaults for the parent table widget.
X
Xvoid XtTblOptions(
X     Widget w,		/* Child of table widget */
X     XtTblMask opt	/* Option mask           */
X);
X
XThis routine changes the option bits of widget `w' (which must be a
Xchild of a Table widget) to `opt'.  The options are as described for
XXtTblConfig().  Any associated position and span of the widget remains
Xunchanged.  If the widget hasn't been placed, it will be located at
X(0,0) and given a span of (1,1).
X
X
XLayout information may also be specified using XtSetValues() or using
Xthe resource database.  The resources XtNlayout and XtNdefaultOptions
Xmay both be set in this fashion.
X
XThe XtNlayout resource allows the user to specify the row, column,
Xvertical span, horizontal span, and options for a set of widgets
Xstatically through the resource database or dynamically using
XXtSetValues().  The type of this resource is private to the Table
Xwidget.  However, the widget automatically registers a type converter
Xthat converts between a string layout format and the internal form
Xused by the Table widget.  This form is a list of statements separated
Xby semicolons.  Each statement has the form:
X
X	widget_name column row horizontal_span vertical_span opt_list
X
Xwidget_name	Name of the widget as given to XtCreateWidget().
Xcolumn		Integer >= 0 giving column in array
Xrow		Integer >= 0 giving row in array
Xhorizontal_span	Integer >= 1 giving number of columns to span
Xvertical_span	Integer >= 1 giving number of rows to span
Xopt_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
XThe options are as described for XtTblConfig().  The horizontal_span,
Xvertical_span, and opt_list are optional and may be omitted.  The
Xhorizontal and vertical spans will default to 1.  The option list will
Xdefault to the default options for the Table widget.  A sample layout
Xdescription is given below:
X
X	"Title 0 0 2 1 H; First 0 1; Second 1 1"
X
XWhen using XtSetValues to specify the XtNlayout resource, the caller
Xshould use the following function to parse a textual form into the
Xinternal form used by the Table widget:
X
Xcaddr_t XtTblParseLayout(
X	String layout		/* String layout specification */
X);
X
XThis function parses `layout' into an internal form that can be passed
Xto a Table widget as the XtNlayout resource.  The form of the layout
Xis described above.
X
XUnless otherwise specified, all options for widgets created under a
XTable widget are set based on the default options for the Table
Xwidget.  These default options are set using the XtNdefaultOptions
Xresource.  This resource can be specified in the resource database as
Xa string of option characters.  This string has the same form as the
Xopt_list described above for XtTblParseLayout().
X
X/*
X * Table Widget Example - Using resources
X *
X * Place the following entries in your resources file:
X *   TableExample.table.Layout: title 0 0 2 1 H; bt1 0 1; bt2 1 1
X *   TableExample*title.label: Title Bar
X *   TableExample*bt1.label: Button One
X *   TableExample*bt2.label: Button Two
X */
X
X#include <X11/StringDefs.h>
X#include <X11/Intrinsic.h>
X#include <X11/Shell.h>
X#include <X11/Label.h>
X#include <X11/Command.h>
X
X#include "Table.h"
X
X#define MAX_ARGS	10
X#define APP_NAME	"TableExample"
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    Widget initialize(), top, table, title, bt1, bt2;
X    Arg arg_list[MAX_ARGS];
X    int arg_len;
X
X    top = initialize(&argc, argv);
X    arg_len = 0;
X    table = XtCreateManagedWidget("table", tableWidgetClass,
X				  top, arg_list, arg_len);
X    title = XtCreateManagedWidget("title", labelWidgetClass,
X				  table, arg_list, arg_len);
X    bt1 = XtCreateManagedWidget("bt1", commandWidgetClass,
X				table, arg_list, arg_len);
X    bt2 = XtCreateManagedWidget("bt2", commandWidgetClass,
X				table, arg_list, arg_len);
X    XtRealizeWidget(top);
X    XtMainLoop();
X}
X
XWidget initialize(argc_p, argv)
Xint *argc_p;
Xchar *argv[];
X{
X    Widget top;
X    Display *disp;
X    Arg arg_list[MAX_ARGS];
X    int arg_len;
X
X    XtToolkitInitialize();
X    disp = XtOpenDisplay((XtAppContext) 0, "", argv[0], APP_NAME,
X			 (XrmOptionDescRec *) 0, 0, argc_p, argv);
X    arg_len = 0;
X    XtSetArg(arg_list[arg_len], XtNallowShellResize, True); arg_len++;
X    top = XtAppCreateShell(argv[0], APP_NAME, applicationShellWidgetClass,
X			   disp, arg_list, arg_len);
X    return top;
X}
X
X/*
X * Table Widget Example - Direct specification
X *
X * This program creates one button for each string on the command
X * line.  Try "ex2 *" to see all the files in the directory.
X */
X
X#include <X11/StringDefs.h>
X#include <X11/Intrinsic.h>
X#include <X11/Shell.h>
X#include <X11/Label.h>
X#include <X11/Command.h>
X
X#include "Table.h"
X
X#define MAX_ARGS	10
X#define APP_NAME	"TableExample"
X#define NUM_ROWS	3
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    Widget initialize(), top, table, title, button;
X    Arg arg_list[MAX_ARGS];
X    int arg_len, i, cols;
X
X    top = initialize(&argc, argv);
X    arg_len = 0;
X    table = XtCreateManagedWidget("table", tableWidgetClass,
X				  top, arg_list, arg_len);
X    XtSetArg(arg_list[arg_len], XtNlabel, "Title Bar");  arg_len++;
X    title = XtCreateManagedWidget("title", labelWidgetClass,
X				  table, arg_list, arg_len);
X    /* Each column will have three rows */
X    cols = (argc-1)/NUM_ROWS + 1;
X    XtTblConfig(title, 0, 0, cols, 1, TBL_SM_HEIGHT);
X    for (i = 1;  i < argc;  i++) {
X	arg_len = 0;
X	XtSetArg(arg_list[arg_len], XtNlabel, argv[i]);  arg_len++;
X	button = XtCreateManagedWidget("button", commandWidgetClass,
X				       table, arg_list, arg_len);
X	if (i < argc-1) {
X	    XtTblPosition(button, (i-1)/NUM_ROWS, (i-1)%NUM_ROWS + 1);
X	} else {
X	    /* Last one spans to bottom */
X	    XtTblConfig(button, (i-1)/NUM_ROWS, (i-1)%NUM_ROWS + 1,
X			1, 3 - ((i-1)%NUM_ROWS), TBL_DEF_OPT);
X	}
X    }
X    XtRealizeWidget(top);
X    XtMainLoop();
X}
X
XWidget initialize(argc_p, argv)
Xint *argc_p;
Xchar *argv[];
X{
X    Widget top;
X    Display *disp;
X    Arg arg_list[MAX_ARGS];
X    int arg_len;
X
X    XtToolkitInitialize();
X    disp = XtOpenDisplay((XtAppContext) 0, "", argv[0], APP_NAME,
X			 (XrmOptionDescRec *) 0, 0, argc_p, argv);
X    arg_len = 0;
X    XtSetArg(arg_list[arg_len], XtNallowShellResize, True); arg_len++;
X    top = XtAppCreateShell(argv[0], APP_NAME, applicationShellWidgetClass,
X			   disp, arg_list, arg_len);
X    return top;
X}
+FUNKY+STUFF+
echo '-rw-r--r--  1 david       14285 Jun 28 09:13 Table.doc    (as sent)'
chmod u=rw,g=r,o=r Table.doc
ls -l Table.doc
echo x - Table.h
sed 's/^X//' > Table.h <<'+FUNKY+STUFF+'
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 Table public declarations.
X */
X 
X#ifndef _Table_h
X#define _Table_h
X
X/*
X * Table Widget Parameters
X *
X * Name			Class		RepType		Default Value
X *
X * background		Background	Pixel		XtDefaultBackground
X * border		BorderColor	Pixel		XtDefaultForeground
X * borderWidth		BorderWidth	Dimension	0
X * x			Position	Position	0
X * y			Position	Position	0
X * width		Width		Dimension	(computed)
X * height		Height		Dimension	(computed)
X * mappedWhenManaged	MappedWhenManaged Boolean	True
X * sensitive		Sensitive	Boolean		True
X * layout		Layout		String		NULL
X * internalHeight	Height		Dimension	0
X * internalWidth	Width		Dimension	0
X * columnSpacing	Spacing		Dimension	0
X * rowSpacing		Spacing		Dimension	0
X */
X
X#define XtNlayout		"layout"
X#define XtNcolumnSpacing        "columnSpacing"
X#define XtNrowSpacing           "rowSpacing"
X#define XtNdefaultOptions	"defaultOptions"
X
X#define XtCLayout		"Layout"
X#ifndef XtCSpacing
X#define XtCSpacing		"Spacing"
X#endif
X#define XtCOptions		"Options"
X
X#define XtROptions		"Options"
X
X/*
X * Option masks
X */
X#define TBL_LEFT	(1<<0)
X#define TBL_RIGHT	(1<<1)
X#define TBL_TOP		(1<<2)
X#define TBL_BOTTOM	(1<<3)
X#define TBL_SM_WIDTH	(1<<4)
X#define TBL_SM_HEIGHT	(1<<5)	
X#define TBL_LK_WIDTH	(1<<6)
X#define TBL_LK_HEIGHT	(1<<7)
X
X#define TBL_DEF_OPT	-1
X
Xtypedef int XtTblMask;
X
X/*
X * Opaque class and instance records
X */
X
Xtypedef struct _TableClassRec	*TableWidgetClass;
Xtypedef struct _TableRec	*TableWidget;
X
Xextern WidgetClass tableWidgetClass;
X
X/*
X * Public access routines
X */
X
Xextern caddr_t XtTblParseLayout();
X  /* String layout; */
X
Xextern void XtTblPosition();
X  /* 
X   * Widget w;
X   * Position col, row;
X   */
X
Xextern void XtTblResize();
X  /*
X   * Widget w;
X   * Dimension h_span, v_span;
X   */
X
Xextern void XtTblOptions();
X  /*
X   * Widget w;
X   * XtTblMask opt;
X   */
X
Xextern void XtTblConfig();
X  /* 
X   * Widget w;
X   * Position col, row;
X   * Dimension h_span, v_span;
X   * XtTblMask opt;
X   */
X 
X#endif /* _Table_h */
X
+FUNKY+STUFF+
echo '-rw-r--r--  1 david        2125 Jun 28 09:13 Table.h    (as sent)'
chmod u=rw,g=r,o=r Table.h
ls -l Table.h
echo x - TableP.h
sed 's/^X//' > TableP.h <<'+FUNKY+STUFF+'
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 Table private declarations.
X */
X
X#ifndef _TableP_h
X#define _TableP_h
X
X#include "Table.h"
X
X/*
X * Local definitions
X */
X
Xtypedef void (*XtTblRProc)();
X  /*
X   * Widget table;
X   * Widget subwidget;
X   * Position r, c;
X   * Dimension hspan, vspan;
X   * XtTblMask options;
X   */
X
Xtypedef Boolean (*XtTblLProc)();
X   /*
X    * Widget w;
X    * Position *r, *c;
X    * Dimension *hspan, *vspan;
X    * XtTblMask *options;
X    */
X
Xtypedef struct _TableLocTbl *TableLocTblPtr;
X   /*
X    * Opaque reference to actual widget location table
X    * defined in Table.c
X    */
X
Xtypedef struct _TableDefLoc *TableDefLocPtr;
X   /*
X    * Opaque reference to default widget location table defined
X    * in Table.c.
X    */    
X
Xtypedef struct _TableVector *TableVecPtr;
X   /*
X    * Opaque reference to vectors used for giving size of
X    * each row and column.
X    */
X
Xtypedef enum _TableVecState { INVALID, MINIMUM } TableVecState;
X
X/*
X * Information kept in class record
X */
X
Xtypedef struct {
X    XtTblRProc position_child;	/* Register location of some child widget  */
X    XtTblLProc find_child;	/* Return information about a child widget */
X} TableClassPart;
X
X/*
X * Class hierarchy
X */
X
Xtypedef struct _TableClassRec {
X    CoreClassPart	core_class;
X    CompositeClassPart	composite_class;
X    TableClassPart	table_class;
X} TableClassRec;
X
Xextern TableClassRec tableClassRec;
X
X/*
X * Information in instance record
X */
X
Xtypedef struct _TablePart {
X    Dimension		int_width;   /* Inner horizontal padding          */
X    Dimension		int_height;  /* Inner vertical padding            */
X    Dimension		row_spacing; /* Space between rows                */
X    Dimension		col_spacing; /* Space between columns             */
X    XtTblMask		def_options; /* Default layout options            */
X    TableDefLocPtr	init_layout; /* Initial layout spec from resource */
X    TableDefLocPtr	layout_db;   /* Merged table                      */
X    TableLocTblPtr	real_layout; /* Actual current layout information */
X    TableVecState	vec_state;   /* Current state of vectors          */
X    Cardinal		num_rows;    /* Number of rows                    */
X    TableVecPtr		rows;	     /* Heights of each row               */
X    Cardinal		num_cols;    /* Number of columns                 */
X    TableVecPtr		cols;	     /* Widths of each column             */
X    Cardinal		vec_height;  /* Sum of current rows               */
X    Cardinal		vec_width;   /* Sum of current columns            */
X} TablePart;
X
X/*
X * Instance hierarchy
X */
X
Xtypedef struct _TableRec {
X    CorePart		core;
X    CompositePart	composite;
X    TablePart		table;
X} TableRec;
X
X#endif /* _TableP_h */
+FUNKY+STUFF+
echo '-rw-r--r--  1 david        2809 Jun 28 09:13 TableP.h    (as sent)'
chmod u=rw,g=r,o=r TableP.h
ls -l TableP.h
echo x - TableREADME.ANNOUNCE
sed 's/^X//' > TableREADME.ANNOUNCE <<'+FUNKY+STUFF+'
X
XRecently, some notes were posted to this newsgroup about the lack of
Xalternate geometry managers for the Athena Widget set.  I have written
Xa row/column based geometry management widget that I have used
Xextensively in my toolkit applications.  A short description is given
Xbelow:
X
XTable - Geometry Management Widget for the X Toolkit
X
XTable is a composite widget designed to manage the size and location
Xof its children.  The widget uses an array model to simplify the
Xarrangement of child widgets.  Widgets are placed at row and column
Xlocations in a variable sized array.  Widgets may span more than one
Xrow or column.  The array automatically expands or contracts as
Xneeded.  There are options to control justification and place size
Xrestrictions on rows or columns in the array.  The widget is directly
Xderived from the core and composite widgets provided by the X Toolkit
Xand can be used with any widget set.  It has been tested using the
XAthena widget set.
X
XSource for the Table widget is available through anonymous ftp to
Xshambhala.Berkeley.EDU (128.32.132.54).  Instructions are given below:
X
X	% ftp shambhala.Berkeley.EDU
X	Name: anonymous
X	Password: <anything non-null>
X	ftp> cd pub
X	ftp> binary
X	ftp> get Table.tar.Z
X	ftp> quit
X	% uncompress Table.tar.Z
X	% tar xf Table.tar
X
XThose without ftp access can obtain the source for the Table widget
Xusing a mail archive system I have installed on dent.Berkeley.EDU
X(courtesy of Brian Reid at Digital).  An example is given below:
X
X	To: ucbvax!dent!archive-server
X	Subject: send programs Table.shar.01 Table.shar.02
X
XThe archive server will send you these files as time and load
Xpermits.  They are standard shell archives that can be unpacked
Xby running them through /bin/sh (in order).  If you would like
Xto know more about the mail server, send a message with a subject
Xof "help".
X
XAfter unpacking the files, you will find a README file in the directory
Xthat contains installation instructions.
X
X			David Harrison
X			UC Berkeley Electronics Research Lab
X			(davidh at ic.Berkeley.EDU, ...!ucbvax!ucbcad!davidh)
X
X
X
+FUNKY+STUFF+
echo '-rw-r--r--  1 david        2068 Jun 28 09:13 TableREADME.ANNOUNCE    (as sent)'
chmod u=rw,g=r,o=r TableREADME.ANNOUNCE
ls -l TableREADME.ANNOUNCE
echo x - TableREADME.FIRST
sed 's/^X//' > TableREADME.FIRST <<'+FUNKY+STUFF+'
X
XTable - Geometry Management Widget for the X Toolkit
X
XTable is a composite widget designed to manage the size and location
Xof its children.  The widget uses an array model to simplify the
Xarrangement of child widgets.  The widget is directly derived from the
Xcore and composite widgets provided by the X Toolkit and can be used
Xwith any widget set.  It has been tested using the Athena widget set.
X
XInstallation instructions are found in the file INSTALL.  Programming 
Xdocumentation can be found in Table.doc.  Two example programs
Xare provided: ex1, and ex2.  These can all be made using the
Xprovided Makefile.  Comments and suggestions should be sent the
Xaddress below:
X
X			David Harrison
X			UC Berkeley Electronics Research Lab
X			(davidh at ic.Berkeley.EDU, ...!ucbvax!ucbcad!davidh)
X
+FUNKY+STUFF+
echo '-rw-r--r--  1 david         788 Jun 28 09:13 TableREADME.FIRST    (as sent)'
chmod u=rw,g=r,o=r TableREADME.FIRST
ls -l TableREADME.FIRST
echo x - TableREADME.INSTALL
sed 's/^X//' > TableREADME.INSTALL <<'+FUNKY+STUFF+'
X
XThis file contains instructions for building the Table widget.
XIf you have X11R4 libraries installed on your machine, you should
Xbe able to type "make" and libTable.a will be built for you.  If
Xyou are running an earlier version of X11, use the old Makefile
Xby typing "make -f Makefile.old" instead of just make.
X
XOnce the library is made, you can make the example programs by
Xtyping:
X
X	% make ex1
X	% make ex2
X
XAgain, if you are using an older version of X, replace make with
X"make -f Makefile.old".  See the comment at the top of the corresponding 
X.c files for instructions on how to run these programs.
X
X			David Harrison
X			UC Berkeley Electronics Research Lab
X			(davidh at ic.Berkeley.EDU, ...!ucbvax!ucbcad!davidh)
X
+FUNKY+STUFF+
echo '-rw-r--r--  1 david         721 Jun 28 09:13 TableREADME.INSTALL    (as sent)'
chmod u=rw,g=r,o=r TableREADME.INSTALL
ls -l TableREADME.INSTALL
exit 0

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



More information about the Comp.sources.x mailing list