home *** CD-ROM | disk | FTP | other *** search
- /*
- * blk - Automatic Requester formatter and generator.
- *
- * Reads a requester description and formats graphically then generates the
- * appropriate C-code to specify the requester. See the examples and the
- * documentaion for using the program.
- *
- * Process flow: Box structure read by recursive-descent. Boxes formatted
- * and layed-out, also recursively. Borders generated and optimized into a
- * minimum set of Border structs. Working preview displayed for fiddling
- * with. Output declarations written to file.
- *
- * Problems: In a nutshell -- error recovery. It doesn't do too well if
- * it runs out of memory, especially in the Border optimization code.
- * Also, the user error messages on parse errors could be much better --
- * like giving line number or a sample of the code at that point -- something
- * that would give a clue as to what went wrong. Other than that, it's
- * pretty good.
- *
- * Differences from version 1: Version 1 was distributed on a Fish disk
- * and was a real hack. This version supports a 'C'-like preprocessor
- * with #include's and #define's and macros with arguments. This makes
- * the Requester source files look much nicer since the underlying
- * grammar is so unreadable.
- *
- * Disclaimer: This is a tool I hacked up for my own use in creating requesters
- * for Modeler 3D. It works for me, but I make no claim as to the robustness
- * or other quality of the code. It's not mouse-driven, but it's such a
- * useful tool that it's worth learning anyway. Besides, you can put it in
- * your makefile's and have it work just like any other compiler.
- *
- * I'm making this available as a service to Amiga developers. You are
- * encouraged to enhance or modify as you need to make it more useful for
- * your own purposes. If you make any changes that make this a better
- * general-purpose tool, let me know about them.
- *
- * Stuart Ferguson 1/89
- * (shf@well.UUCP)
- */
-
- #include <stdio.h>
- #include <functions.h>
- #include <exec/types.h>
- #include <intuition/intuition.h>
-
- /* STD.H is my collection of useful macros.
- */
- #include "std.h"
-
- /* LEX.H is the lexical analysis defines.
- */
- #include "lex.h"
-
-
- #define abs(x) ((x)<0 ? -(x) : (x))
-
- /* Size of font for text boxes (fixed width assumed).
- */
- #define FONTWIDTH 8
- #define FONTHEIGHT 8
-
- /* Box types
- */
- #define HBOX 1
- #define VBOX 2
- #define FILL 3
- #define BLOK 4
- #define TEXT 5
- #define HRULE 6
- #define VRULE 7
-
- /*
- * Extended Gadget structure to hold an optional special gadget ID name
- * and the parent box for this gadget.
- */
- struct SuperGadget {
- struct Gadget g;
- struct Box *box;
- char *gnam;
- };
-
- /*
- * A requester is constructed from a tree of Boxes. Boxes are arranged in a
- * binary tree, one subtree is what is inside the Box (sub), the other is the
- * remaining Boxes at the same level (next).
- */
- typedef struct Box {
- struct SuperGadget *gad; /* gadget - if any */
- struct Box *next, *sub; /* binary tree links */
- short type, /* box type - possibilities above */
- col; /* color - for borders and text */
- short xs, ys, /* box size (x,y) */
- x, y, /* box position (x,y) */
- nfil; /* number of filers inside this box */
- char *val; /* string for TEXT boxes */
- };
-
-
- /* GLOBAL */
-
- int infoLevel = 1, /* degree of verbosity (0=quiet,
- * 1=normal, 2=verbose)
- */
- printBoxes = 0, /* printout flag (false normally) */
- showPreview; /* preview flag (depends on whether there's
- * an output file and on the '-d' flag.
- */
- char *globStr = "static "; /* structures normally static */
-
- FILE *file; /* output file */
- char *base; /* base name */
- short def_bcol = 1, /* default border and */
- def_tcol = 1; /* text colors */
-
- /* String pointer ID's returned from the lexer.
- */
- char *fill_pstr, *tbox_pstr, *hbox_pstr, *vbox_pstr,
- *blok_pstr, *s_pstr, *p_pstr, *pv_pstr, *ph_pstr;
-
- /* The Requester structures, the lists of parts and the guy itself.
- */
- struct Border *blst = NULL; /* list header for border structs */
- struct IntuiText *itlst = NULL; /* list header for text structs */
- struct Gadget *glst = NULL; /* list header for gadgets */
-
- #define LATER 0
-
- struct Requester mreq = {
- NULL,5,5,LATER,LATER,0,0,LATER,LATER,LATER,
- 0,0,NULL,{NULL},NULL,NULL,{NULL}
- };
-
- /*
- * Generic templates for creating Intuition structures.
- */
- struct Border
- generic_border = {0, 0, LATER, 0, JAM1, LATER, LATER, LATER};
- struct Gadget
- generic_gadget = {
- LATER, LATER, LATER, LATER, LATER,
- GADGHCOMP,RELVERIFY,BOOLGADGET|REQGADGET,
- LATER, NULL, LATER, 0, LATER, LATER, NULL
- };
- struct IntuiText
- generic_itext = {LATER, 0, JAM2, LATER, LATER, LATER, LATER, LATER};
- struct StringInfo
- generic_sinfo = {LATER, NULL, 0, LATER, 0};
- struct PropInfo
- generic_pinfo = {AUTOKNOB|PROPBORDERLESS,0x8000,0x8000,0x8000,0x8000};
-
- /* Two macros to extract GadgetType info from a Gadget structure.
- */
- #define GADGETTYPEBITS (~GADGETTYPE)
- #define GTYPE(g) (((g)->GadgetType)&GADGETTYPEBITS)
-
- /*
- * The preview window.
- */
- struct NewWindow nwin = {
- 0, 0, 300, 150, -1, -1,
- CLOSEWINDOW | REQCLEAR | MOUSEMOVE | GADGETDOWN | GADGETUP | VANILLAKEY,
- WINDOWDEPTH | WINDOWDRAG,
- NULL, NULL, (UBYTE *) "Preview", NULL,
- NULL, 0, 0, 0, 0, WBENCHSCREEN
- };
-
- struct IntuitionBase *IntuitionBase;
-
-
- struct Box * ReadBoxList ();
- short Layin ();
- char * IMClass ();
-
- /* Lexer interface functions.
- */
- char * FindString ();
- short NextToken ();
-
-
- /*
- * Returns a new, initialized Box struct.
- */
- struct Box * NewBox (type)
- short type;
- {
- struct Box *b;
-
- if (!(b = NEW (struct Box))) {
- MemError ();
- return NULL;
- }
- b->type = type;
- b->nfil = 0;
- b->gad = NULL;
- b->val = NULL;
- b->next = b->sub = NULL;
- return b;
- }
-
-
- /*
- * Recursively frees Box tree.
- */
- FreeBox (box)
- struct Box *box;
- {
- register struct Gadget *g;
- register struct StringInfo *si;
-
- if (!box) return;
-
- FreeBox (box->sub);
- FreeBox (box->next);
-
- if (g = (struct Gadget *) box->gad) {
- if (GTYPE(g) == STRGADGET) {
- si = (struct StringInfo *) g->SpecialInfo;
- FREE_X (si, struct StringInfo, si->MaxChars);
- } else if (GTYPE(g) == PROPGADGET) {
- FREE (g->SpecialInfo, struct PropInfo);
- FREE (g->GadgetRender, struct Image);
- }
- FREE (g, struct SuperGadget);
- }
- FREI (box);
- }
-
-
- /*
- * Recursively examine all nodes of Box tree and allocate Border structs for
- * all the HRULE and VRULE boxes. Adds new Borders to the main list.
- * Returns 0 for failure, 1 for sucess.
- */
- int CreateBorder (box)
- register struct Box *box;
- {
- register struct Border *bd;
-
- if (!box) return 1;
-
- if (box->type == HRULE || box->type == VRULE) {
- if (!(bd = NEW (struct Border))) {
- MemError ();
- FreeBorder ();
- return 0;
- }
- *bd = generic_border;
- bd->FrontPen = box->col;
- bd->Count = 2;
- if (!(bd->XY = NEW_N (SHORT, 4))) {
- MemError ();
- FREI (bd);
- FreeBorder ();
- return 0;
- }
- bd->XY[0] = bd->XY[2] = box->x;
- bd->XY[1] = bd->XY[3] = box->y;
- if (box->type == HRULE) bd->XY[2] += box->xs - 1;
- else bd->XY[3] += box->ys - 1;
-
- bd->NextBorder = blst;
- blst = bd;
- }
- if (!CreateBorder (box->sub)) return 0;
- return (CreateBorder (box->next));
- }
-
-
- /*
- * Frees all Border structs in main Border list.
- */
- FreeBorder ()
- {
- register struct Border *b, *nxt;
-
- for (b = blst; b; b = nxt) {
- nxt = b->NextBorder;
- FREE_N (b->XY, SHORT, b->Count * 2);
- FREI (b);
- }
- blst = NULL;
- }
-
-
- /*
- * Recursively examine all nodes of Box tree and allocate IntuiText structs
- * for TEXT boxes that are not string gadgets. Adds new Borders to the main
- * list. Returns 1 for sucess, 0 for failure.
- */
- int CreateIText (box)
- register struct Box *box;
- {
- struct IntuiText *it;
-
- if (!box) return 1;
-
- /*
- * "box->val" may have been zero-ed by a string gadget grabbing
- * that text. If so, this is not an IntuiText.
- */
- if (box->type == TEXT && box->val) {
- if (!(it = NEW(struct IntuiText))) {
- MemError ();
- FreeIText ();
- return 0;
- }
- *it = generic_itext;
- it->IText = (UBYTE *) box->val;
- it->LeftEdge = box->x;
- it->TopEdge = box->y;
- it->FrontPen = box->col;
- it->NextText = itlst;
- itlst = it;
- }
- if (!CreateIText (box->sub)) return 0;
- return (CreateIText (box->next));
- }
-
-
- /*
- * Frees all IntuiText structs in the main list. (No need to free the
- * text itself since that is managed by the lexer.)
- */
- FreeIText ()
- {
- register struct IntuiText *it, *nxt;
-
- for (it = itlst; it; it = nxt) {
- nxt = it->NextText;
- FREI (it);
- }
- itlst = NULL;
- }
-
-
- /*
- * First pass at merging redundant Borders: Examines all the Borders in
- * the list for adjacency. Any borders that could use the same set of
- * polyline commands are merged into a single struct.
- */
- MergeBorders ()
- {
- register struct Border *a, *b;
- short i0, i1, x, y, *xy, j;
- register short i, ac, bc, merge;
-
- do {
- merge = -1;
- /*
- * Examine all pairs of borders, "a" and "b", that
- * are drawn with the same color, seaching for a pair
- * that can be merged. When loop exits with merge=-1,
- * all pairs have been merged.
- */
- for (a = blst; a; a = a->NextBorder) {
- for (b = a->NextBorder; b; b = b->NextBorder) {
- if (a->FrontPen != b->FrontPen) continue;
-
- /*
- * Examine the 4 pairs of endpoints of each
- * polyline to see if any are adjacent to
- * each other. If any are found, the pairs
- * located are encoded into "merge" and
- * the search loop exits.
- */
- ac = a->Count;
- bc = b->Count;
- for (i0 = 0; i0 < 2; i0++)
- for (i1 = 0; i1 < 2; i1++) {
- x = a->XY[i0*2 * (ac - 1)]
- - b->XY[i1*2 * (bc - 1)];
- y = a->XY[i0*2 * (ac - 1) + 1]
- - b->XY[i1*2 * (bc - 1) + 1];
- if (abs (x) + abs (y) == 1)
- merge = (i0 << 1) + i1;
- }
- if (merge != -1)
- break;
- }
- if (merge != -1)
- break;
- }
- if (merge == -1) continue;
-
- /*
- * Merging: Create a new polyline data array and move
- * the two parent polylines into the new one, possibly
- * reversing one or both in the process.
- * -- HELP ME: Is there a nice way out if this
- * allocation fails...?
- */
- xy = NEW_N (SHORT, (bc + ac) * 2);
- x = ((merge & 2) == 0); /* x = reverse "a" */
- y = ((merge & 1) == 1); /* y = reverse "b" */
- j = 0;
- for (i = 0; i < ac; i++) {
- i0 = (x ? ac - 1 - i : i) * 2;
- xy[j++] = a->XY[i0];
- xy[j++] = a->XY[i0 + 1];
- }
- for (i = 0; i < bc; i++) {
- i0 = (y ? bc - 1 - i : i) * 2;
- xy[j++] = b->XY[i0];
- xy[j++] = b->XY[i0 + 1];
- }
-
- /*
- * Set "a" to have the new polyline data array.
- */
- a->Count = j / 2;
- FREE_N (a->XY, SHORT, ac * 2);
- a->XY = xy;
-
- /*
- * Find "b's" predecessor and remove "b" from list.
- */
- for (a = blst; a && a->NextBorder != b; a = a->NextBorder);
- a->NextBorder = b->NextBorder;
- FREE_N (b->XY, SHORT, bc * 2);
- FREE (b, struct Border);
-
- } while (merge != -1);
- }
-
-
- /*
- * Second pass of Border merging: Eliminates linear segments from all
- * Borders XY lists. The first pass will create lots of redundant points
- * along linear line segments. This pass will compress those out.
- */
- MergeLinear ()
- {
- register struct Border *b;
- register short i0, i1, i2, k, *xy;
-
- /*
- * Examine all borders with more than 1 line segment.
- */
- for (b = blst; b; b = b->NextBorder) {
- if (b->Count < 3) continue;
-
- /*
- * Scan along the polyline list and compress out linear
- * segments by skiping over them.
- */
- xy = b->XY;
- i0 = 0;
- i1 = 1;
- i2 = 2;
- k = 2;
- while (i2 < b->Count) {
- /*
- * Skip past linear segments. (I.e. find the bend.)
- */
- while (i2 < b->Count &&
- (xy[i0 * 2] == xy[i1 * 2]
- && xy[i1 * 2] == xy[i2 * 2] ||
- xy[i0 * 2 + 1] == xy[i1 * 2 + 1]
- && xy[i1 * 2 + 1] == xy[i2 * 2 + 1])) {
- i1++;
- i2++;
- }
- if (i2 >= b->Count) continue;
-
- /*
- * Move polyline data to itself after skipping.
- */
- xy[k++] = xy[i1 * 2];
- xy[k++] = xy[i1 * 2 + 1];
- i0 = i1;
- i1 = i2;
- i2 = i1 + 1;
- }
- xy[k++] = xy[i1 * 2];
- xy[k++] = xy[i1 * 2 + 1];
-
- k /= 2;
- if (k == b->Count) continue;
-
- /*
- * If this border has gotten shorter, allocate a new
- * array and transfer the new polyline data.
- */
- xy = NEW_N (SHORT, k * 2);
- for (i0 = 0; i0 < k * 2; i0++) xy[i0] = b->XY[i0];
- FREE_N (b->XY, SHORT, b->Count * 2);
- b->XY = xy;
- b->Count = k;
- }
- }
-
-
- /*
- * Set the XSize and YSize fields for this box and all below.
- */
- Format (box)
- struct Box *box;
- {
- struct Box *b;
- short mx, my, sx, sy, nf;
-
- ASSERT (box);
-
- /*
- * Deal with the basis (leaf) cases.
- */
- switch (box->type) {
-
- /* Blok and text nodes have fixed, already computed size.
- */
- case BLOK:
- case TEXT:
- return;
-
- /* Fill node has no intrinsic size.
- */
- case FILL:
- box->xs = box->ys = 0;
- box->nfil = 1;
- return;
-
- /* H and VRULES have no intrinsic X or Y size, respectively.
- */
- case HRULE:
- box->xs = 0;
- return;
- case VRULE:
- box->ys = 0;
- return;
- }
-
- /*
- * H and VBOXes are the recursive case. First format each
- * internal box.
- */
- for (b = box->sub; b; b = b->next) Format (b);
-
- /*
- * Compute total and max sizes in each direction. Total (sx,sy) is sum
- * of all sub-boxes, max (mx,my) is max of sub-boxes. Also inherit
- * filler count.
- */
- my = mx = sx = sy = nf = 0;
- for (b = box->sub; b; b = b->next) {
- sx += b->xs;
- sy += b->ys;
- if (b->type == box->type || b->type == FILL) nf += b->nfil;
- if (b->xs > mx) mx = b->xs;
- if (b->ys > my) my = b->ys;
- }
- box->nfil = nf;
-
- /*
- * For horizontal boxes, bounding box is sum in x and max in y; for
- * vertical, bouding box is max in x and sum in y. This is the
- * minimum size of the containing box for the given subboxes. It
- * may still expand due to fillers.
- */
- if (box->type == HBOX) {
- box->xs = sx;
- box->ys = my;
- } else if (box->type == VBOX) {
- box->xs = mx;
- box->ys = sy;
- }
- }
-
-
- /*
- * Compute the position of the boxes internal to this box given that this
- * box has correct location. The box size computed by Format() is a minimum
- * size, "mx" and "my" are the max that the box can be expanded by filler.
- */
- Layout (box, mx, my)
- struct Box *box;
- short mx, my;
- {
- struct Box *b;
- short ish, z, nfil;
- long gap, ifil;
-
- ASSERT (box);
-
- /*
- * Rules fill out to their max possible size.
- */
- if (box->type == HRULE) box->xs = mx;
- else if (box->type == VRULE) box->ys = my;
-
- /*
- * Process only HBOX and VBOX cases recursively. Any other case (a
- * basis case) has its position set correctly (see assumptions at
- * head of function).
- */
- if (box->type != HBOX && box->type != VBOX) return;
-
- /* Get important values. Set the "is-hbox" (ish) flag. Get the
- * current X size for HBOXes or the Y size for VBOXes as "z".
- * "gap" is the differece between the max size and minimum size
- * given by the Format(), and is how much fillers can expand.
- */
- ish = (box->type == HBOX);
- z = (ish ? box->x : box->y);
- gap = (ish ? mx - box->xs : my - box->ys);
-
- /*
- * Set positions by setting filler sizes.
- */
- ifil = 0;
- Layin (box, &ifil, ish, z, box->nfil, gap);
-
- /* Update box size. If it had fillers, it got as big as
- * it could.
- */
- if (box->nfil) {
- if (ish) box->xs = mx;
- else box->ys = my;
- }
- }
-
-
- /*
- * Layout internal boxes. Having this as a recursive function deals with
- * the case of VBOXes within VBOXes and HBOXes within HBOXes.
- *
- * NOTE: I'd comment this function, but I can't figure it out. It seems to
- * figure out the horizonal position of each box and update it as it goes
- * along. It also calls itself when there are nested same-class boxes.
- * Oh well. There's probably a better way to do it anyway.
- */
- short Layin (box, ifil, ish, z, nfil, gap)
- struct Box *box;
- short *ifil, ish, z, nfil;
- long gap;
- {
- struct Box *b;
- short t;
-
- for (b = box->sub; b; b = b->next) {
- if (ish) {
- b->x = z;
- b->y = box->y;
- } else {
- b->x = box->x;
- b->y = z;
- }
-
- if (b->type == FILL) {
- t = (gap * (*ifil + 1)) / nfil - (gap ** ifil) / nfil;
- (*ifil)++;
- if (ish) b->xs = t;
- else b->ys = t;
-
- } else if ((ish && b->type == HBOX)
- || (!ish && b->type == VBOX)) {
- if (ish) b->ys = box->ys;
- else b->xs = box->xs;
- t = Layin (b, ifil, ish, z, nfil, gap) - z;
- if (ish) b->xs = t;
- else b->ys = t;
-
- } else Layout (b, box->xs, box->ys);
-
- z += (ish ? b->xs : b->ys);
- }
- return z;
- }
-
-
- /*
- * Use the computed position of the boxes to set the position of
- * the associated gadgets.
- */
- PositionGadgets ()
- {
- struct Box *b;
- struct Gadget *g;
-
- for (g = glst; g; g = g->NextGadget) {
- b = ((struct SuperGadget *) g)->box;
- g->LeftEdge = b->x;
- g->TopEdge = b->y;
- g->Width = b->xs;
- g->Height = b->ys;
- }
- }
-
-
- /*
- * Returns pointer to string containing box type name for printout.
- */
- char * BoxType (typ)
- short typ;
- {
- switch (typ) {
- case HBOX: return ("HBOX");
- case VBOX: return ("VBOX");
- case BLOK: return ("BLOK");
- case TEXT: return ("TEXT");
- case FILL: return ("FILL");
- case HRULE: return ("HRULE");
- case VRULE: return ("VRULE");
- }
- }
-
-
- /*
- * Recursively prints this box and all its contents.
- */
- PrintBox (box, lev)
- struct Box *box;
- short lev;
- {
- int i;
-
- if (!box) return;
-
- for (i = 0; i < lev; i++) printf (" ");
-
- printf ("%s (%d,%d) %dx%d", BoxType (box->type),
- box->x, box->y, box->xs, box->ys);
- if (box->type == TEXT) printf (" <%s>", box->val);
- if (box->gad) printf (" [gadget]");
- printf ("\n");
-
- PrintBox (box->sub, lev + 1);
- PrintBox (box->next, lev);
- }
-
-
-
- /*
- * ==== INPUT SECTION ====
- *
- * File input uses the "lex" front-end for macro processing. Main entry
- * points for this package are the NextToken() and Backspace() functions.
- * NextToken() returns the code for the next lexical item in the input
- * stream and sets a buffer pointer to point to its value. Backspace()
- * resets the lex package to re-read the last token read, so that the
- * file is effectively backspaced one token. FindString() is also used
- * to get the unique identifer pointer for a string from the hash table.
- */
-
-
- /*
- * Read a number if there is one. Otherwise return false and don't
- * change n's value.
- */
- BOOL Qnum (n, radix)
- short *n, radix;
- {
- short i = 0, tok;
- char *buf;
-
- tok = NextToken (&buf);
- if (tok != RT_NUM) {
- Backspace ();
- return 0;
- }
- for (; *buf >= '0' && *buf <= '9'; buf++) {
- i = i * radix + (*buf - '0');
- }
- *n = i;
- return 1;
- }
-
-
- /*
- * Reads a double-quoted string like
- * "stuff"
- * from the file. Returns pointer to the string contents.
- */
- char * ReadString ()
- {
- short tok;
- char *buf;
-
- tok = NextToken (&buf);
- if (tok != RT_STR) {
- fprintf (stderr, "String not found.\n");
- Backspace ();
- return NULL;
- }
- return buf;
- }
-
-
- /*
- * Read gadget ID of the form
- * :number
- * if there is one. Read as hex. If there is one, create a new
- * SuperGadget structure and add to the main gadget list.
- */
- struct SuperGadget * ReadOptGadget (box)
- struct Box *box;
- {
- struct SuperGadget *sg;
- short tok, id;
- char *buf;
-
- tok = NextToken (&buf);
- if (tok != RT_CHR || *buf != ':') {
- Backspace ();
- return NULL;
- }
- if (!Qnum (&id, 16)) {
- fprintf (stderr, "Error reading gadget ID number\n");
- return NULL;
- }
-
- if (!(sg = NEW (struct SuperGadget))) {
- MemError ();
- return NULL;
- }
- sg->g = generic_gadget;
- sg->gnam = NULL;
- sg->box = box;
- sg->g.GadgetID = id;
- sg->g.NextGadget = glst;
- glst = (struct Gadget *) sg;
- return sg;
- }
-
-
- /*
- * Get a box from the open file. Boxes are either single tokens ("f"
- * for FILL box, "-" and "|" for ordinary rules) or is a
- * composite of the form "("type data")". Type can be "h" for HBOX,
- * "v" for VBOX, "b" for BLOK, "t" for TEXT, or "-" and "|" again for
- * special rules.
- *
- * If there isn't a box here, ReadBox() returns NULL with the lexical
- * stream positioned back to read whatever was really there.
- */
- struct Box * ReadBox ()
- {
- short tok, i;
- char *buf, c;
- struct Box *b;
-
- tok = NextToken (&buf);
-
- if (tok == RT_ID && buf == fill_pstr) return NewBox (FILL);
-
- if (tok != RT_CHR) {
- Backspace ();
- return NULL;
- }
-
- c = *buf;
- if (c == '-') {
- if (!(b = NewBox (HRULE))) return NULL;
- b->ys = 1;
- b->col = def_bcol;
- return b;
- }
- if (c == '|') {
- if (!(b = NewBox (VRULE))) return NULL;
- b->xs = 1;
- b->col = def_bcol;
- return b;
- }
- if (c != '(') {
- Backspace ();
- return NULL;
- }
-
- /*
- * Decode the value inside the '('.
- */
- tok = NextToken (&buf);
- c = *buf;
- if (tok == RT_ID)
- if (buf == hbox_pstr) {
- if (!(b = NewBox (HBOX))) return NULL;
- b->sub = ReadBoxList ();
- } else if (buf == vbox_pstr) {
- if (!(b = NewBox (VBOX))) return NULL;
- b->sub = ReadBoxList ();
- } else if (buf == tbox_pstr) {
- if (!(b = NewBox (TEXT))) return NULL;
- b->col = def_tcol;
- Qnum (&b->col, 10);
- if (!(b->val = ReadString ())) {
- FreeBox (b);
- return NULL;
- }
- b->xs = strlen (b->val) * FONTWIDTH;
- b->ys = FONTHEIGHT;
- } else if (buf == blok_pstr) {
- if (!(b = NewBox (BLOK))) return NULL;
- i = Qnum (&b->xs, 10);
- i &= Qnum (&b->ys, 10);
- if (!i) {
- fprintf (stderr, "Block needs X and Y sizes\n");
- return NULL;
- }
- } else {
- fprintf (stderr, "Unrecognized box type <%s>\n", buf);
- return NULL;
- }
- else if (tok == RT_CHR)
- switch (c) {
- case '-':
- if (!(b = NewBox (HRULE))) return NULL;
- if (!Qnum (&b->ys, 10)) {
- fprintf (stderr, "Bad hrule structure.\n");
- return NULL;
- }
- b->col = def_bcol;
- Qnum (&b->col, 10);
- break;
- case '|':
- if (!(b = NewBox (VRULE))) return NULL;
- if (!Qnum (&b->xs, 10)) {
- fprintf (stderr, "Bad vrule structure\n");
- return NULL;
- }
- b->col = def_bcol;
- Qnum (&b->col, 10);
- break;
- default:
- fprintf (stderr, "Unrecognized box type <%c>\n", c);
- return NULL;
- }
- else {
- fprintf (stderr, "Unrecognized box type <%s>\n", buf);
- return NULL;
- }
- /*
- * Pick up the closing ')'.
- */
- tok = NextToken (&buf);
- if (tok != RT_CHR || *buf != ')') {
- fprintf (stderr, "Parse error - expected ')' !\n");
- FreeBox (b);
- return NULL;
- }
-
- /*
- * Read the optional Gadget for this box (as ":id").
- */
- b->gad = ReadOptGadget (b);
- return b;
- }
-
-
- /*
- * Read a list of boxes from the file stream. Recursive: read a box,
- * then read a list.
- */
- struct Box * ReadBoxList ()
- {
- struct Box *b;
-
- b = ReadBox ();
- if (!b) return NULL;
-
- b->next = ReadBoxList ();
- return b;
- }
-
-
- /*
- * Create a new StringInfo struct and initialize to point to the
- * given string buffer. Allocates space for the buffer along with
- * the info struct itself (NEW_X). Removes trailing spaces.
- */
- APTR NewStrInfo (buf)
- char *buf;
- {
- struct StringInfo *si;
- short i;
- char *str;
-
- i = strlen (buf) + 1;
- if (!(si = NEW_X (struct StringInfo, i))) {
- MemError ();
- return NULL;
- }
- *si = generic_sinfo;
- si->Buffer = (UBYTE *) (str = (char *) (si+1));
- si->MaxChars = i;
- strcpy (str, buf);
- for (i -= 2; i>=0 && str[i] == ' '; i--) str[i] = 0;
- return (APTR) si;
- }
-
-
- /* Create new PropInfo struct. Set the free motion flag based on the
- * id for this gadget "pv" = vert prop, "ph" = horiz prop, "p" = h+v prop.
- */
- APTR NewPropInfo (id)
- char *id;
- {
- register struct PropInfo *pi;
-
- if (!(pi = NEW (struct PropInfo))) {
- MemError ();
- return NULL;
- }
- *pi = generic_pinfo;
- if (id == p_pstr || id == pv_pstr) pi->Flags |= FREEVERT;
- if (id == p_pstr || id == ph_pstr) pi->Flags |= FREEHORIZ;
- return (APTR) pi;
- }
-
-
- /*
- * Reads the list of gadget info from the end of the file. Reads as much
- * as there is. Format is:
- * number {s|p|pv|ph} {:string} string
- * stuff in {}'s is optional. Each entry gives extra info for the numbered
- * gadget. {s|p} is string or prop flag. {:string} is the optional named
- * value rather than just the nubmer. The last string is the gadget flags.
- * Each set of info gets added to the corresponding gadget structure in
- * the main list.
- */
- ReadGadInfo ()
- {
- struct Gadget *g;
- struct Box *box;
- short tok;
- char *buf, c, *actf;
- short i;
- USHORT flag;
-
- while (Qnum (&i, 16)) {
- /*
- * Locate the gadget in question and it's associated box.
- */
- for (g = glst; g; g = g->NextGadget)
- if (g->GadgetID == i) break;
- if (!g) {
- fprintf (stderr, "Unknown gadget ID: %x\n", i);
- continue;
- }
- box = ((struct SuperGadget *) g)->box;
-
- /* Get the optional string or prop flag.
- */
- tok = NextToken (&buf);
- if (tok == RT_ID) {
- if (buf == s_pstr) {
- g->GadgetType &= ~GADGETTYPEBITS;
- g->GadgetType |= STRGADGET;
- if (!(g->SpecialInfo = NewStrInfo (box->val)))
- return;
- box->val = NULL;
- } else if (buf == p_pstr
- || buf == ph_pstr
- || buf == pv_pstr) {
- g->GadgetType &= ~GADGETTYPEBITS;
- g->GadgetType |= PROPGADGET;
- if (!(g->SpecialInfo = NewPropInfo (buf)))
- return;
- if (!(g->GadgetRender =
- (APTR) NEW (struct Image))) {
- MemError ();
- FREE (g->SpecialInfo, struct PropInfo);
- return;
- }
- } else {
- fprintf (stderr,
- "Expected \"s\" or \"p\": <%s>\n", buf);
- break;
- }
- tok = NextToken (&buf);
- }
-
- /* Get optional gadget ID name string.
- */
- if (tok == RT_CHR && *buf == ':') {
- ((struct SuperGadget *) g)->gnam = ReadString ();
- tok = NextToken (&buf);
- }
- Backspace ();
-
- /* Get and process required activation flags string.
- */
- actf = ReadString ();
- g->Activation &= ~RELVERIFY;
- for (; *actf; actf++) {
- switch (*actf) {
- case 'B':
- g->Flags &= ~GADGHIGHBITS;
- g->Flags |= GADGHBOX;
- flag = 0;
- break;
- case 't':
- flag = TOGGLESELECT;
- break;
- case 'v':
- flag = RELVERIFY;
- break;
- case 'e':
- flag = ENDGADGET;
- break;
- case 'i':
- flag = GADGIMMEDIATE;
- break;
- case 'c':
- flag = STRINGCENTER;
- break;
- case 'f':
- flag = FOLLOWMOUSE;
- break;
- }
- g->Activation |= flag;
- }
- }
- }
-
-
- /*
- * Get values for the identifier strings from the lexical analyzer.
- * The lexer will return the same pointer for any identifier which
- * matches.
- */
- AssignStrings ()
- {
- fill_pstr = FindString ("f");
- hbox_pstr = FindString ("h");
- vbox_pstr = FindString ("v");
- tbox_pstr = FindString ("t");
- blok_pstr = FindString ("b");
- s_pstr = FindString ("s");
- p_pstr = FindString ("p");
- ph_pstr = FindString ("ph");
- pv_pstr = FindString ("pv");
- }
-
-
- /*
- * To read file: open, read base name, read optional default border and text
- * colors, read a box (a BIG box), read gadget info blocks, close.
- */
- struct Box * ReadFile ()
- {
- struct Box *box;
- short i, tok;
- char *buf;
-
- AssignStrings ();
- tok = NextToken (&base);
- if (tok != RT_ID) {
- fprintf (stderr, "Cannot find base name\n");
- return NULL;
- }
- Qnum (&def_bcol, 10);
- Qnum (&def_tcol, 10);
-
- if (infoLevel > 1) printf ("base name: \"%s\"\ndefault border color:"
- " %d\ndefault text color: %d\n", base, def_bcol, def_tcol);
-
- box = ReadBox ();
- ReadGadInfo ();
-
- /*
- * Make sure we're at the end of the file to make the
- * lexer happy. Print up to 10 error messages unless there
- * is no box from the previous call in which case there's something
- * wrong anyway. (Unless in verbose mode, then show 'em all.)
- */
- i = ((box || infoLevel > 1) ? 10 : 0);
- while (NextToken (&buf) != RT_EOF) {
- if (i) {
- fprintf (stderr,
- "Token found after end of data: <%s>\n", buf);
- if (!--i) fprintf (stderr, "... etc.\n");
- }
- }
-
- return box;
- }
-
-
- /*
- * ==== OUTPUT SECTION ====
- *
- * Dumps structures created during the input and resolution phases of
- * the processing. Just takes a pointer to a Requester in WriteRequester()
- * and dumps the related structures as well.
- */
-
- /*
- * Write string info and buffer declarations from string gadgets
- * (if any).
- */
- WriteStrGad (glist)
- struct Gadget *glist;
- {
- struct Gadget *g;
- struct StringInfo *si;
- int i, n;
-
- /* Count number of string gadgets.
- */
- for (n = 0, g = glist; g; g = g->NextGadget)
- if (GTYPE(g) == STRGADGET) n++;
-
- if (!n) return;
-
- /* Write the necessary buffers for the string infos.
- */
- fprintf (file, "\n%sUBYTE %s_nbuf[%d][NUMCHR] = {\n\t",
- globStr, base, n);
- i = n;
- for (g = glist; g; g = g->NextGadget) {
- if (GTYPE(g) != STRGADGET) continue;
-
- si = (struct StringInfo *) g->SpecialInfo;
- fprintf (file, " \"%s\"", si->Buffer);
- if (--i) fprintf (file, ",");
- }
-
- fprintf (file, "\n};\n\n%sstruct StringInfo %s_sinfo[] = {\n",
- globStr, base);
- i = 0;
- for (g = glist; g; g = g->NextGadget) {
- if (GTYPE(g) != STRGADGET) continue;
-
- si = (struct StringInfo *) g->SpecialInfo;
- fprintf (file, "\t{&%s_nbuf[%d][0],undo,0,NUMCHR,0}",
- base, i++);
- if (--n) fprintf (file, ",");
- fprintf (file, "\n");
- }
- fprintf (file, "};\n");
-
- if (infoLevel > 1) printf ("wrote %d StringInfo structs\n", i);
- }
-
-
- /*
- * Write prop info and image declarations for prop gadgets (if any).
- */
- WritePropGad (glist)
- struct Gadget *glist;
- {
- struct Gadget *g;
- struct PropInfo *pi;
- int i, n;
-
- /* Count number of prop gadgets.
- */
- for (n = 0, g = glist; g; g = g->NextGadget)
- if (GTYPE(g) == PROPGADGET) n++;
-
- if (!n) return;
-
- /* Write the necessary images for the autoknobs.
- */
- fprintf (file, "\n%sstruct Image %s_pimg[%d];\n", globStr, base, n);
-
- /* Write the PropInfo structures themselves.
- */
- fprintf (file, "\n%sstruct PropInfo %s_pinfo[] = {\n", globStr, base);
- i = n;
- for (g = glist; g; g = g->NextGadget) {
- if (GTYPE(g) != PROPGADGET) continue;
-
- pi = (struct PropInfo *) g->SpecialInfo;
- fprintf (file, "\t{%u,%u,%u,%u,%u}", pi->Flags,
- pi->HorizPot, pi->VertPot,
- pi->HorizBody, pi->VertBody);
- if (--i) fprintf (file, ",");
- fprintf (file, "\n");
- }
- fprintf (file, "};\n");
-
- if (infoLevel > 1) printf ("wrote %d PropInfo structs\n", n);
- }
-
-
- /*
- * Write the gadgets from the main gadget list. Returns number of
- * gadgets written.
- */
- int WriteGadgets (glist)
- struct Gadget *glist;
- {
- struct Gadget *g;
- int k = 1, nimg=0, nprp=0, nstr=0;
- char *nam;
-
- if (!glist) return 0;
-
- WriteStrGad (glist);
- WritePropGad (glist);
-
- fprintf (file, "\n%sstruct Gadget %s_gad[] = {\n", globStr, base);
-
- for (g = glist; g; g = g->NextGadget) {
- if (g->NextGadget)
- fprintf (file, "\t{&%s_gad[%d]", base, k++);
- else
- fprintf (file, "\t{NULL");
-
- fprintf (file, ",%d,%d,%d,%d,%u,%u,%u,", g->LeftEdge,
- g->TopEdge, g->Width, g->Height, g->Flags,
- g->Activation, g->GadgetType);
-
- if (GTYPE(g) == PROPGADGET)
- fprintf (file, "(APTR)&%s_pimg[%d]", base, nimg++);
- else
- fprintf (file, "NULL");
-
- fprintf (file, ",\n\t NULL,NULL,0,(APTR)");
-
- if (GTYPE(g) == PROPGADGET)
- fprintf (file, "&%s_pinfo[%d]", base, nprp++);
- else if (GTYPE(g) == STRGADGET)
- fprintf (file, "&%s_sinfo[%d]", base, nstr++);
- else
- fprintf (file, "NULL");
-
- if (nam = ((struct SuperGadget *) g)->gnam)
- fprintf (file, ",%s", nam);
- else
- fprintf (file, ",0x%x", g->GadgetID);
-
- if (g->NextGadget)
- fprintf (file, "},\n");
- else
- fprintf (file, "}\n");
- }
- fprintf (file, "};\n");
-
- if (infoLevel > 1) printf ("wrote %d Gadget structs\n", k);
- return k;
- }
-
-
- /*
- * Write out list of IntuiText structs for main list. Returns number
- * of structures written.
- */
- int WriteText (tlist)
- struct IntuiText *tlist;
- {
- struct IntuiText *it;
- int k = 1;
-
- if (!tlist) return 0;
-
- fprintf (file, "\n%sstruct IntuiText %s_txt[] = {\n", globStr, base);
-
- for (it = tlist; it; it = it->NextText) {
- fprintf (file, "\t{%d,%d,%d,%d,%d,&ta,(UBYTE*)\"%s\",",
- it->FrontPen, it->BackPen, it->DrawMode,
- it->LeftEdge, it->TopEdge, it->IText);
- if (it->NextText)
- fprintf (file, "&%s_txt[%d]},\n", base, k++);
- else
- fprintf (file, "NULL},\n");
- }
- fprintf (file, "};\n");
-
- if (infoLevel > 1) printf ("wrote %d IntuiText structs\n", k);
- return k;
- }
-
-
- /*
- * Write out list of XY arrays from Border struct main list
- */
- WriteBorderXY (lst)
- struct Border *lst;
- {
- register struct Border *b;
- register short i;
-
- fprintf (file, "\n%sshort %s_brd_XY[] = {\n", globStr, base);
- for (b = lst; b; b = b->NextBorder) {
- fprintf (file, "\t");
- for (i = 0; i < b->Count; i++) {
- fprintf (file, "%d,%d", b->XY[i * 2], b->XY[i * 2 + 1]);
- if (i != b->Count - 1 || b->NextBorder)
- fprintf (file, ", ");
- }
- fprintf (file, "\n");
- }
- fprintf (file, "};\n");
- }
-
-
- /*
- * Write out list of Border structs from main list. Returns nubmer of
- * structures written.
- */
- int WriteBorder (lst)
- struct Border *lst;
- {
- register struct Border *b;
- register short i = 0, k = 1;
-
- if (!lst) return 0;
-
- WriteBorderXY (lst);
-
- fprintf (file, "\n%sstruct Border %s_brd[] = {\n", globStr, base);
- for (b = lst; b; b = b->NextBorder) {
- fprintf (file, "\t{0,0,%d,0,JAM1,%d,&%s_brd_XY[%d],",
- b->FrontPen, b->Count, base, i);
- i += b->Count * 2;
- if (b->NextBorder)
- fprintf (file, "&%s_brd[%d]},\n", base, k++);
- else
- fprintf (file, "NULL}\n");
- }
- fprintf (file, "};\n");
-
- if (infoLevel > 1) printf ("wrote %d Border structs\n", k);
- return k;
- }
-
-
- /*
- * Reverse the gadget list so it will make more sense to the client.
- * This way they will appear in the arrays in the order that they
- * appear in the description file.
- */
- struct Gadget * ReverseGadList (head)
- struct Gadget *head;
- {
- struct Gadget *newhead = NULL, *nxt;
-
- for (; head; head = nxt) {
- nxt = head->NextGadget;
- head->NextGadget = newhead;
- newhead = head;
- }
- return newhead;
- }
-
-
- /*
- * The main output function.
- */
- WriteRequester (name, req)
- char *name;
- struct Requester *req;
- {
- short i, ng, nt, nb;
-
- if (!(file = fopen (name, "w"))) {
- fprintf (stderr, "Can't open output file\n");
- return;
- }
-
- req->ReqGadget = ReverseGadList (req->ReqGadget);
- ng = WriteGadgets (req->ReqGadget);
- nt = WriteText (req->ReqText);
- nb = WriteBorder (req->ReqBorder);
-
- /*
- * The requester itself.
- */
- fprintf (file, "\n%sstruct Requester %s_req = {\n\
- \tNULL,0,0,%d,%d,0,0,", globStr, base, req->Width, req->Height);
- if (ng) fprintf (file, "%s_gad,", base);
- else fprintf (file, "NULL,");
- if (nb) fprintf (file, "%s_brd,", base);
- else fprintf (file, "NULL,");
- if (nt) fprintf (file, "%s_txt,", base);
- else fprintf (file, "NULL,");
- fprintf (file, "0,0,\n\tNULL,{NULL},NULL,NULL,{NULL}\n};\n");
-
- fclose (file);
- }
-
-
- MemError ()
- {
- fprintf (stderr, "Out of memory.\n");
- }
-
-
- /* Main entry point. Decode args and call body function. Args are:
- *
- * -p : Print box description
- * -q : Run silent, run deep
- * -v : Verbose (not much different than normal, really)
- * -d : Display preview (is default unless output requested)
- * -s : Send Requester declarations to stdout
- */
- main (argc, argv)
- int argc;
- char *argv[];
- {
- int i, junk = 0, prev = 0, tostdout = 0;
- char *infile = NULL, *outfile = NULL;
-
- /*
- * Decode arguments.
- */
- for (i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
- case 'p':
- printBoxes = 1;
- break;
- case 'q':
- infoLevel = 0;
- break;
- case 'v':
- infoLevel = 2;
- break;
- case 'd':
- prev = 1;
- break;
- case 's':
- tostdout = 1;
- break;
- case 'g':
- globStr = "";
- break;
- default:
- junk = 1;
- }
- } else {
- if (!infile) infile = argv[i];
- else if (!outfile) outfile = argv[i];
- else junk = 1;
- }
- }
- if (junk || !infile) {
- printf ("Usage: %s [-p|q|v|d|s|g] <file> [<outfile>]\n",
- argv[0]);
- exit (1);
- }
- if (tostdout) {
- outfile = "*";
- infoLevel = 0;
- }
- showPreview = (!outfile || prev);
-
- if (IntuitionBase = (struct IntuitionBase *)
- OpenLibrary ("intuition.library", 0L)) {
- Body (infile, outfile);
- CloseLibrary (IntuitionBase);
- }
- }
-
-
- Body (infile, outfile)
- char *infile, *outfile;
- {
- struct Window *win;
- struct Box *b;
- short h, w;
-
- if (infoLevel > 0) printf (
- "Requester generator v2 Jan 1989 Stuart Ferguson\n");
- if (!OpenLexFile (infile)) {
- fprintf (stderr, "Cannot open %s\n", infile);
- return;
- }
- if (b = ReadFile ()) {
- Format (b);
- b->x = b->y = 0;
- Layout (b, b->xs, b->ys);
- if (printBoxes) PrintBox (b, 0);
-
- if (CreateIText (b)) {
- if (CreateBorder (b)) {
- MergeBorders ();
- MergeLinear ();
- PositionGadgets ();
-
- mreq.Width = b->xs;
- mreq.Height = b->ys;
- mreq.ReqGadget = glst;
- mreq.ReqText = itlst;
- mreq.ReqBorder = blst;
-
- if (showPreview) PreviewRequester (&mreq);
- if (outfile) WriteRequester (outfile, &mreq);
-
- FreeBorder ();
- }
- FreeIText ();
- }
- FreeBox (b);
- } else fprintf (stderr, "Error reading box description.\n");
- LexCleanup ();
- }
-
-
- /*
- * Open a window to preview the requester layout.
- */
- PreviewRequester (req)
- struct Requester *req;
- {
- struct Window *win;
- short h, w;
-
- w = req->Width + 12;
- h = req->Height + 16;
- if (w > 640 || h > 200) {
- fprintf (stderr, "Requester too large for preview.\n");
- return;
- }
- if (w < 150) w = 150;
- if (h < 60) h = 60;
-
- nwin.Width = w;
- nwin.Height = h;
- if (!(win = OpenWindow (&nwin))) {
- fprintf (stderr, "Unable to open preview window.\n");
- return;
- }
-
- req->LeftEdge =
- (w - win->BorderRight + win->BorderLeft - req->Width) / 2;
- req->TopEdge =
- (h - win->BorderBottom + win->BorderTop - req->Height) / 2;
-
- RequesterLoop (win, req);
- CloseWindow (win);
- }
-
-
- RequesterLoop (win, req)
- struct Window *win;
- struct Requester *req;
- {
- struct Gadget *g;
- struct IntuiMessage *im;
- ULONG class, oldflags;
- USHORT code;
- int gend = 0, looping;
-
- /*
- * Determine if this requester can be terminated with a gadget.
- * If not, provide an alternate exit facility.
- */
- for (g = req->ReqGadget; g; g = g->NextGadget)
- if (g->Activation & ENDGADGET) {
- gend = 1;
- break;
- }
- oldflags = req->Flags;
- if (!gend) {
- if (infoLevel > 0) printf (
- "No Endgadget -- Press ESC to exit Requester.\n");
- req->Flags |= NOISYREQ;
- }
-
- if (!Request (req, win)) {
- fprintf (stderr, "Unable to post Requester.\n");
- req->Flags = oldflags;
- return;
- }
-
- looping = 1;
- while (looping) {
- im = (struct IntuiMessage *) GetMsg(win->UserPort);
- if (!im) {
- WaitPort (win->UserPort);
- continue;
- }
- class = im->Class;
- code = im->Code;
- ReplyMsg (im);
- if (class == VANILLAKEY && code == 27) break;
- if (infoLevel > 0) printf ("Message : %s\n", IMClass (class));
- if (class == REQCLEAR) looping = 0;
- }
- if (looping) EndRequest (req, win);
- req->Flags = oldflags;
- }
-
-
- /*
- * Returns name of message class. Lots more classes here than are
- * possible, but what the hell.
- */
- char * IMClass (class)
- ULONG class;
- {
- switch (class) {
- case SIZEVERIFY: return ("SIZEVERIFY");
- case NEWSIZE: return ("NEWSIZE");
- case REFRESHWINDOW: return ("REFRESHWINDOW");
- case MOUSEBUTTONS: return ("MOUSEBUTTONS");
- case MOUSEMOVE: return ("MOUSEMOVE");
- case GADGETDOWN: return ("GADGETDOWN");
- case GADGETUP: return ("GADGETUP");
- case REQSET: return ("REQSET");
- case MENUPICK: return ("MENUPICK");
- case CLOSEWINDOW: return ("CLOSEWINDOW");
- case RAWKEY: return ("RAWKEY");
- case REQVERIFY: return ("REQVERIFY");
- case REQCLEAR: return ("REQCLEAR");
- case MENUVERIFY: return ("MENUVERIFY");
- case NEWPREFS: return ("NEWPREFS");
- case DISKINSERTED: return ("DISKINSERTED");
- case DISKREMOVED: return ("DISKREMOVED");
- case WBENCHMESSAGE: return ("WBENCHMESSAGE");
- case ACTIVEWINDOW: return ("ACTIVEWINDOW");
- case INACTIVEWINDOW: return ("INACTIVEWINDOW");
- case DELTAMOVE: return ("DELTAMOVE");
- case VANILLAKEY: return ("VANILLAKEY");
- case INTUITICKS: return ("INTUITICKS");
- }
- }
-
-
- #define DEBUG
-
- /*
- * Debug routines.
- */
- #ifdef DEBUG
-
- PrintBorder ()
- {
- struct Border *b;
- short i;
-
- printf ("Borders:\n");
- for (b=blst; b; b=b->NextBorder) {
- printf ("%d %d %d %d\n:: ", b->LeftEdge,
- b->TopEdge, b->FrontPen, b->Count);
- for (i=0; i<b->Count; i++)
- printf ("%d,%d ", b->XY[i*2],b->XY[i*2+1]);
- printf ("\n");
- }
- }
-
-
- PrintGadget ()
- {
- USHORT typ;
- struct Gadget *g;
-
- printf ("Gadgets:\n");
- for (g=glst; g; g=g->NextGadget) {
- printf ("%d,%d %d,%d ", g->LeftEdge, g->TopEdge,
- g->Width, g->Height);
- typ = GTYPE(g);
- if (typ == PROPGADGET) printf ("PROP");
- if (typ == STRGADGET) printf ("STRING");
- if (typ == BOOLGADGET) printf ("BOOL");
- printf ("\n");
- }
- }
- #endif
-