v10i055: wcl -- Widget Creation Library, Part07/11

David E. Smyth david at jpl-devvax.jpl.nasa.gov
Tue Dec 18 09:16:18 AEST 1990


Submitted-by: david at jpl-devvax.jpl.nasa.gov (David E. Smyth)
Posting-number: Volume 10, Issue 55
Archive-name: wcl/part07

# to unbundle, "sh" this file -- DO NOT use csh
#  SHAR archive format.  Archive created Fri Oct 19 09:32:58 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#if defined(XtSpecificationRelease) && XtSpecificationRelease >= 4
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 ******************* NOTE ********************
X * Assumes only called from cvtStrToDefLoc() *
X *********************************************
X */
X{
X#ifndef MAX_TABLE_CHILD_WIDGET_NAME_LEN
X#define MAX_TABLE_CHILD_WIDGET_NAME_LEN 128
X#endif
X    static char buf[MAX_TABLE_CHILD_WIDGET_NAME_LEN];
X    int         i  = 0;
X    char*       cp = spec;
X
X    /* initial values, NOT the defaults */
X    loc_spec->loc.ax = loc_spec->loc.ay = 0;
X    loc_spec->loc.h_span = loc_spec->loc.v_span = 0;
X
X    /* Now attempt to parse the string */
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while (' ' < *cp && i < MAX_TABLE_CHILD_WIDGET_NAME_LEN)
X	buf[i++] = *cp++;
X    buf[i] = '\0';
X    if ( i )
X	loc_spec->w_name = XtNewString(buf);	/* widget name */
X    else
X	loc_spec->w_name = "No Name";		/* default name */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.ax = loc_spec->loc.ax * 10 + *cp++ - '0';
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.ay = loc_spec->loc.ay * 10 + *cp++ - '0';
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.h_span = loc_spec->loc.h_span * 10 + *cp++ - '0';
X    if (loc_spec->loc.h_span == 0)
X	loc_spec->loc.h_span = 1;		/* default span */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    while ('0' <= *cp && *cp <= '9')
X	loc_spec->loc.v_span = loc_spec->loc.v_span * 10 + *cp++ - '0';
X    if (loc_spec->loc.v_span == 0)
X	loc_spec->loc.v_span = 1;		/* default span */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    i = 0;
X    while (*cp && i < MAX_TABLE_CHILD_WIDGET_NAME_LEN &&
X	*cp == 'l' || *cp == 'r' || *cp == 't' || *cp == 'b' ||
X	*cp == 'w' || *cp == 'h' || *cp == 'W' || *cp == 'H' )
X	buf[i++] = *cp++;
X    buf[i] = '\0';
X    if ( i )
X	loc_spec->loc.options = ParseOpts(buf);
X    else
X	loc_spec->loc.options = 0;		/* default */
X
X    while (*cp && *cp <= ' ') cp++;		/* eat whitespace */
X
X    if (*cp )
X	XtStringConversionWarning( spec, 
X	    "layout component: name [col] [row] [h_span] [v_span] [lrtbwhWH]");
X}
X
Xstatic String GetSpec(spec_ptr)
XString *spec_ptr;		/* Specification pointer */
X/*
X * This routine gets the next specification from the string
X * `spec_ptr' and updates the pointer appropriately.
X */
X{
X    extern String strchr();
X    String result;
X    String semi;
X
X    if (*spec_ptr && **spec_ptr) {
X	semi = strchr(*spec_ptr, ';');
X	if (semi) {
X	    *semi = '\0';
X	    result = *spec_ptr;
X	    *spec_ptr = semi+1;
X	    return result;
X	} else {
X	    result = *spec_ptr;
X	    *spec_ptr += strlen(*spec_ptr);
X	    return result;
X	}
X    } else {
X	return (String) 0;
X    }
X}
X
X
X
X/**********************************************************************
X *
X * Public routines
X *
X **********************************************************************/
X
X
X/*ARGSUSED*/
Xcaddr_t XtTblParseLayout(layout)
XString layout;			/* String layout specification */
X/*
X * Parses a string layout specification into an internal form
X * suitable for use in a call to XtSetValues().  The form is
X * a list of statements separated by semicolons.  Each statement
X * has the form:
X *   widget_name column row horizontal_span vertical_span opt_list
X * where the meaning of each field is:
X *   widget_name	Name of the widget as given to XtCreateWidget().
X *   column		Integer >= 0 descibing column in array
X *   row		Row >= 0 describing row in array
X *   horizontal_span	Integer >= 1 describing horizontal widget span
X *   vertical_span	Integer >= 1 describing vertical widget span
X *   opt_list		Series of characters each representing an option:
X *	l:  TBL_LEFT
X *	r:  TBL_RIGHT
X *      t:  TBL_TOP
X *      b:  TBL_BOTTOM
X *      w:  TBL_LK_WIDTH
X *      h:  TBL_LK_HEIGHT
X *      W:  TBL_SM_WIDTH
X *      H:  TBL_SM_HEIGHT
X * The options are as described in TblPostionChild().  The horizontal_span,
X * vertical_span, and opt_list are optional and will default to reasonable
X * values.
X */
X{
X    TableDefLocPtr result, idx;
X    Cardinal len;
X    String spec;
X    String orig;
X
X    /* Make a copy for safety */
X    if (layout && ((len = DefSpecLen(layout)) > 0)) {
X	orig = layout = XtNewString(layout);
X	result = (TableDefLocPtr) XtCalloc(len+1, sizeof(struct _TableDefLoc));
X	idx = result;
X	while (spec = GetSpec(&layout)) {
X	    DefParse(spec, idx);
X	    idx++;
X	}
X	/* null terminate */
X	idx->w_name = (String) 0;
X	XtFree(orig);
X	return (caddr_t) result;
X    } else {
X	return (caddr_t) 0;
X    }
X    /*NOTREACHED*/
X}
X
Xvoid XtTblPosition(w, col, row)
XWidget w;			/* Widget to position */
XPosition col, row;		/* Position in array  */
X/*
X * This routine positions a widget that has been created
X * under a widget of class tableWidgetClass.  The widget
X * will be placed at column `col' and row `row'.  If
X * the widget has never been placed before,  it will
X * span only one space in each direction and its
X * options will be the defaults for the table widget.
X */
X{
X    Position old_row, old_col;
X    Dimension old_hspan, old_vspan;
X    XtTblMask old_opts;
X
X    if (TblFindChild(w, &old_col, &old_row, &old_hspan, &old_vspan, &old_opts)) {
X	TblPositionChild(w, col, row, old_hspan, old_vspan, old_opts);
X    } else {
X	TblPositionChild(w, col, row, 1, 1, TBL_DEF_OPT);
X    }
X}
X
Xvoid XtTblResize(w, h_span, v_span)
XWidget w;			/* Widget to resize            */
XDimension h_span, v_span;	/* New widget span             */
X/*
X * This routine changes the span of widget `w' to (`h_span', `v_span').
X * If the widget has never been placed before,  it will be located
X * at (0,0) and its options will be the defaults for its
X * parent table widget.
X */
X{
X    Position old_row, old_col;
X    Dimension old_hspan, old_vspan;
X    XtTblMask old_opts;
X
X    if (TblFindChild(w, &old_col, &old_row, &old_hspan, &old_vspan, &old_opts)) {
X	TblPositionChild(w, old_col, old_row, h_span, v_span, old_opts);
X    } else {
X	TblPositionChild(w, 0, 0, h_span, v_span, TBL_DEF_OPT);
X    }
X}
X
Xvoid XtTblOptions(w, opt)
XWidget w;			/* Widget to change */
XXtTblMask opt;			/* New option mask  */
X/*
X * This routine changes the options of widget `w' to `opt'.  If
X * the widget has never been placed before,  it will be located
X * and (0,0) with a span of (1,1) and its options will be the
X * default options for its parent table widget.  The option
X * mask is as described for TblPositionChild.
X */
X{
X    Position old_row, old_col;
X    Dimension old_hspan, old_vspan;
X    XtTblMask old_opts;
X
X    if (TblFindChild(w, &old_col, &old_row, &old_hspan, &old_vspan, &old_opts)) {
X	TblPositionChild(w, old_col, old_row, old_hspan, old_vspan, opt);
X    } else {
X	TblPositionChild(w, 0, 0, 1, 1, opt);
X    }
X}
X
Xvoid XtTblConfig(w, col, row, h_span, v_span, opt)
XWidget w;			/* Widget to position          */
XPosition col, row;		/* Position in array           */
XDimension h_span, v_span;	/* Horizonal and vertical span */
XXtTblMask opt;			/* Widget placement options    */
X/*
X * This routine positions a widget that has been created
X * under a widget of class tableWidgetClass.  The widget
X * will be placed at column `col' and row `row'.  The
X * widget will span the distances given by `h_span' and `v_span'.
X * The options argument is as described for TblPositionChild.
X */
X{
X    TblPositionChild(w, col, row, h_span, v_span, opt);
X}
X
+FUNKY+STUFF+
echo '-rw-r--r--  1 david       47358 Aug  6 09:41 Table.c    (as sent)'
chmod u=rw,g=r,o=r Table.c
ls -l Table.c
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.
--
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