david@jpl-devvax.jpl.nasa.gov (David E. Smyth) (12/18/90)
Submitted-by: david@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@sun.com / argv@ora.com Opinions expressed reflect those of the author only. -- dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.