DCOOPER%ESDSDF.DECnet@CRDGW1.GE.COM (05/17/89)
Some people have asked about tools for laying out widgets. I expect that very soon we will see amazing graphically oriented tools to do this, but at the moment there is nothing available. To fill this void I have constructed a widget layout interpreter. This package reads a layout from a text file and displays the corresponding user interface. There are many limitations some of which are described in the README file. Hope this comes in use for building sample user interfaces. The shell archive follows. Dwight Cooper GE Electronic Systems Dept. dcooper@esdsdf.decnet@crd.ge.com #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # README # ixtdemo.c # sample.Xt # xtdefs.h # xtdemo.c # xtlex.l # xtparse.y # This archive created: Mon May 15 13:42:29 1989 export PATH; PATH=/bin:$PATH echo shar: extracting "'Makefile'" '(484 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # Make xtdemo # # Define DEBUG to debug any problems INCFLAGS = -I/X11/include CFLAGS = -g $(INCFLAGS) YFLAGS = -d LFLAGS = -n OBJECTS = ixtdemo.o xtparse.o xtlex.o xtdemo.o LIBS = -lXaw -lXmu -lXt -lX11 -ll all: xtdemo xtdemo: $(OBJECTS) $(CC) -o xtdemo $(OBJECTS) $(LIBS) xtparse.c: xtparse.y xtlex.c: xtlex.l xtokens.h: xtparse.c mv y.tab.h xtokens.h touch xtokens.h ixtdemo.o: xtdefs.h xtlex.o: xtdefs.h xtokens.h xtparse.o: xtdefs.h xtokens.h SHAR_EOF fi # end of overwriting check echo shar: extracting "'README'" '(1916 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' This is a simple interpreter for constructing sample user interfaces from the Athena Widgets. Using it provides an easy way to construct demos, and try out widgets together. A very simple example is: Box "Form 1" Label "Label 1" [ string = "This is a test.", width = 100 ] Command "Press Here" To run xtdemo using this as input, put it into a file called test.Xt. Then run xtdemo using it as input. You can specify any Toolkit command line arguments to xtdemo. xtdemo -fn variable < test.Xt Will generate the box with a Label and Form as expected. You can specify a widget's Parent if it different than the last Composite widget (Box, Dialog, Form, VPane, or Viewport) specified. Any resource name can be specified in the [] block after a widget's name. Some resource values like background and justify can be specified as integers even though it is not clean, portable, and it is really hacking. Look at the more extensive example in the file sample.Xt Currently there is no provision for adding callbacks to a Command Button, so the demos built using this tool are for display purposes only, and there is no way to implement a thread of control. This demo also does not generate source code from which a demo can be converted into a real application, but this is quite easy to add by modifying the routine execute_IXTDEMO(). I except to see graphically oriented widget layout tools very soon, but at the moment this is a simple way of using widgets as building blocks without writing code. xtdemo has been tested on a sun3 running SunOS 4.0.1. xtdemo is free software, it may or may not be useful. Feel free to contact me if you have questions or comments, but I will not guarantee any support. If nothing else this software is a very simple example of using lex and yacc to write a small interpreter. Dwight Cooper GE Electronic Systems dcooper%esdsdf.decnet@crd.ge.com SHAR_EOF fi # end of overwriting check echo shar: extracting "'ixtdemo.c'" '(6812 characters)' if test -f 'ixtdemo.c' then echo shar: will not over-write existing file "'ixtdemo.c'" else cat << \SHAR_EOF > 'ixtdemo.c' /* * This is the interpreter for xtdemo */ #include <stdio.h> #include <varargs.h> #include <X11/Intrinsic.h> #include <X11/Composite.h> #include "xtdefs.h" /* * Structure, variable, and forward references for the list * of widget/string pairs stored after creation. */ typedef struct wlist { Widget w; char *string; struct wlist *next; } WLIST; static WLIST *wlisttop = NULL; static Widget GetWidget(); static char *GetString(); static void SetWidget(); static WLIST *AddOne(); extern char *malloc(); /* * global constants */ #define CODE_SIZE 1000 /* Max instructions */ #define STACK_SIZE 100 #define MAX_ARGS 1 typedef struct { /* an instruction */ OPCODE opcode; /* - what to do */ ARG arg[MAX_ARGS]; /* - argument for */ } INSTRUCTION; /* * module global variables */ static INSTRUCTION code[CODE_SIZE]; /* generated code */ static int pc; /* program counter */ static VALUE stack[STACK_SIZE]; static int sp = 0; /* * stack macros */ #define push(value) stack[sp++].i = value #define pop() stack[--sp].i #define fpush(value) stack[sp++].f = value #define fpop(value) stack[--sp].f #define spush(value) stack[sp++].str = value #define spop(value) stack[--sp].str #define reset_stack() sp = 0; /* * Initialize the interpreter, called before emiting instructions. */ void init_IXTDEMO() { pc = 0; /* reset PC */ } /* * emit instructions for the interpreter. */ void emit_IXTDEMO(va_alist) va_dcl { OPCODE op; /* instruction opcode */ va_list ap; /* vararg pointer */ va_start(ap); /* begin arg processing */ op = va_arg(ap, OPCODE); /* Get opcode */ code[pc].opcode = op; /* fill in opcode */ switch (op) { /************************************************/ /* No operands. */ /************************************************/ case OP_NOOP: case OP_START: case OP_END: case OP_INITARGS: break; /************************************************/ /* One integer operand. */ /************************************************/ case OP_PUSHI: case OP_SETI: code[pc].arg[0].value.i = va_arg(ap, int); break; /************************************************/ /* One float operand. */ /************************************************/ case OP_PUSHF: case OP_SETF: code[pc].arg[0].value.f = va_arg(ap, double); break; /************************************************/ /* One WidgetClass operand. */ /************************************************/ case OP_SET_CLASS: code[pc].arg[0].value.w = va_arg(ap, WidgetClass); break; /************************************************/ /* One string operand. */ /************************************************/ case OP_PUSHS: case OP_SETS: case OP_CREATE: case OP_SET_PARENT: code[pc].arg[0].value.str = va_arg(ap, char *); break; default: errorf("Error: %d is an invalid opcode.\n", op); exit(-1); } va_end(ap); /* end var arg processing */ pc++; } /* * Execute the instructions. */ int execute_IXTDEMO(argc, argv) int argc; char *argv[]; { register INSTRUCTION *i; /* current instruction */ Arg args[20]; int a; char *rname; WidgetClass wc; static Widget parent = NULL; Widget toplevel; static int zero = 0; pc = 0; /* init instruction pointer */ reset_stack(); /* reset expression stack */ #ifdef DEBUG printf("\nSuccessful parse, executing...\n\n"); #endif while (code[pc].opcode != OP_END) { i = &code[pc++]; switch (i->opcode) { case OP_NOOP: errorf("Warning: Hit an unpatched OP_NOOP intruction.\n"); break; case OP_START: toplevel = XtInitialize("XTdemo", "XTdemo", NULL, 0, &argc, argv); parent = toplevel; #ifdef DEBUG printf("parent is toplevel\n"); #endif break; case OP_INITARGS: a = 0; break; case OP_PUSHI: push(i->arg[0].value.i); break; case OP_PUSHF: fpush(i->arg[0].value.f); break; case OP_PUSHS: spush(i->arg[0].value.str); break; case OP_SETI: rname = spop(); #ifdef DEBUG printf("\tset [%d] %s = %d\n", a, rname, i->arg[0].value.i); #endif XtSetArg(args[a], rname, i->arg[0].value.i); a++; break; case OP_SETF: rname = spop(); #ifdef DEBUG printf("\tset [%d] %s = %f\n", a, rname, i->arg[0].value.f); #endif XtSetArg(args[a], rname, i->arg[0].value.f); a++; break; case OP_SETS: { char *sval; rname = spop(); sval = i->arg[0].value.str; #ifdef DEBUG printf("\tset [%d] %s = %s\n", a, rname, sval); #endif if ((strcmp(rname, "fromVert") == 0) || (strcmp(rname, "fromHoriz") == 0)) { XtSetArg(args[a], rname, GetWidget(sval)); a++; } else { XtSetArg(args[a], rname, i->arg[0].value.str); a++; } break; } case OP_SET_CLASS: wc = i->arg[0].value.w; break; case OP_SET_PARENT: { char *pstr; pstr = i->arg[0].value.str; parent = GetWidget(pstr); #ifdef DEBUG printf("parent is %s\n", pstr); #endif break; } case OP_CREATE: { Widget w; char *wstr; wstr = i->arg[0].value.str; #ifdef DEBUG printf("\tcreating %s (%s) [%d]\n", wstr, GetString(parent), a); #endif w = XtCreateManagedWidget(wstr, wc, parent, args, a); SetWidget(wstr, w); if (XtIsSubclass(w, compositeWidgetClass)) { parent = w; #ifdef DEBUG printf("parent is %s\n", wstr); #endif } break; } } } #ifdef DEBUG printf("realizing\n"); #endif XtRealizeWidget(toplevel); XtMainLoop(); } /* * Find the widget associated with a name. */ static Widget GetWidget(string) char *string; { WLIST *wptr; wptr = wlisttop; while (wptr) { if (strcmp(string, wptr->string) == 0) { return wptr->w; } wptr = wptr->next; } errorf("Warning: Widget %s not found\n", string); return NULL; } /* * Find the name associated with a widget. */ static char *GetString(widget) Widget widget; { WLIST *wptr; wptr = wlisttop; while (wptr) { if (widget == wptr->w) { return wptr->string; } wptr = wptr->next; } return NULL; } /* * Add a widget/string pair to the widget list. */ static void SetWidget(string, widget) char *string; Widget widget; { WLIST *wptr; WLIST *pptr; if (wlisttop == NULL) { wlisttop = AddOne(string, widget); } else { pptr = wptr = wlisttop; while (wptr) { if (strcmp(string, wptr->string) == 0) { errorf("Warning: More than one widget has the name %s.\n", string); } pptr = wptr; wptr = wptr->next; } wptr = AddOne(string, widget); pptr->next = wptr; } } /* * Allocation routine used by SetWidget. */ static WLIST *AddOne(string, widget) char *string; Widget widget; { WLIST *wptr; wptr = (WLIST *) malloc(sizeof(WLIST)); wptr->string = (char *) malloc(strlen(string) + 1); strcpy(wptr->string, string); wptr->w = widget; wptr->next = NULL; return wptr; } SHAR_EOF fi # end of overwriting check echo shar: extracting "'sample.Xt'" '(2990 characters)' if test -f 'sample.Xt' then echo shar: will not over-write existing file "'sample.Xt'" else cat << \SHAR_EOF > 'sample.Xt' # # This is a sample Tactical Control Panel # Pane "Pane 1" [ height = 320 ] Label "Tactical Control Panel" [ foreground = 0, background = 1, min = 30 ] Form "Form 1" Form "Form 2" Parent "Form 1" [ borderWidth = 0 ] Command "Apply" [ width = 60 ] Command "Halt" [ fromVert = "Apply", width = 60 ] Command "Edit" [ fromVert = "Halt", width = 60 ] Command "Quit" [ fromVert = "Edit", width = 60 ] Form "Form 3" Parent "Form 1" [ fromHoriz = "Form 2", borderWidth = 0 ] Command "Button 1" [ label = " ", background = 1 ] Label "Label 1" [ label = "Force Function", width = 120, fromHoriz = "Button 1", justify = 0, borderWidth = 0 ] Text "Text 1" [ string = "20", fromHoriz = "Label 1", width = 200, insertPosition = 2, ] Command "Button 2" [ label = " ", fromVert = "Button 1" ] Label "Label 2" [ label = "Stim", width = 120, fromHoriz = "Button 2", fromVert = "Label 1", justify = 0, borderWidth = 0 ] Text "Text 2" [ string = "stim_1", fromHoriz = "Label 2", fromVert = "Text 1", width = 200, ] Command "Button 3" [ label = " ", fromVert = "Button 2" ] Label "Label 3" [ label = "Stim Stack", width = 120, fromHoriz = "Button 3", fromVert = "Label 2", justify = 0, borderWidth = 0 ] Text "Text 3" [ fromHoriz = "Label 3", fromVert = "Text 2", width = 200, ] Command "Button 4" [ label = " ", fromVert = "Button 3" ] Label "Label 4" [ label = "Tactical Returns", width = 120, fromHoriz = "Button 4", fromVert = "Label 3", justify = 0, borderWidth = 0 ] Text "Text 4" [ string = "Tactical-Returns", fromHoriz = "Label 4", fromVert = "Text 3", width = 200, ] Form "Form 4" Parent "Pane 1" Label "Mode Label 1" [ label = "Abort on Error", justify = 0, borderWidth = 0, width = 150, ] Command "Mode Command 1" [ label = "No", fromHoriz = "Mode Label 1" ] Label "Mode Label 2" [ label = "Mode", justify = 0, borderWidth = 0, fromVert = "Mode Label 1", width = 150, ] Command "Mode Command 2" [ label = "Non-Continuous", fromHoriz = "Mode Label 2", fromVert = "Mode Command 1", ] Label "Mode Label 3" [ label = "Repeat Count", justify = 0, borderWidth = 0, fromVert = "Mode Label 2", width = 150, ] Command "Mode Command 3" [ label = "2", fromHoriz = "Mode Label 3", fromVert = "Mode Command 2", ] Label "Mode Label 4" [ label = "I/O Timeout Limit (msec)", justify = 0, borderWidth = 0, fromVert = "Mode Label 3", width = 150, ] Command "Mode Command 4" [ label = "1", fromHoriz = "Mode Label 4", fromVert = "Mode Command 3", ] Form "Form 5" Parent "Pane 1" [ fromVert = "Form 4", defaultDistance = 0 ] Text "Status Text" [ string = "Interface Ready", textOptions = 2, insertPosition = 15, ] SHAR_EOF fi # end of overwriting check echo shar: extracting "'xtdefs.h'" '(862 characters)' if test -f 'xtdefs.h' then echo shar: will not over-write existing file "'xtdefs.h'" else cat << \SHAR_EOF > 'xtdefs.h' /* *** %W% %G% *** */ /**************/ /* data types */ /**************/ typedef unsigned char BYTE; /* 8-bits */ typedef BYTE BOOLEAN; typedef enum { ITYPE, /* integer */ FTYPE, /* float */ STYPE, /* string */ WTYPE, /* WidgetClass */ } TYPE; typedef union { /* arguments for instructions */ int i; /* - an int */ float f; /* - any float */ char *str; /* - any text */ WidgetClass w; /* - WidgetClass */ } VALUE; typedef struct { TYPE type; VALUE value; } ARG; /****************************************/ /* Opcodes for the interpreter */ /****************************************/ typedef enum { OP_NOOP, OP_PUSHI, OP_PUSHF, OP_PUSHS, OP_INITARGS, OP_SETI, OP_SETF, OP_SETS, OP_CREATE, OP_SET_CLASS, OP_SET_PARENT, OP_END, OP_START, } OPCODE; SHAR_EOF fi # end of overwriting check echo shar: extracting "'xtdemo.c'" '(438 characters)' if test -f 'xtdemo.c' then echo shar: will not over-write existing file "'xtdemo.c'" else cat << \SHAR_EOF > 'xtdemo.c' #include <stdio.h> #include <varargs.h> int main(argc, argv) int argc; char *argv[]; { init_IXTDEMO(); yyparse(); execute_IXTDEMO(argc, argv); } void yyerror(s) char *s; { extern int yylineno; errorf("\nError: Line %d: %s\n", yylineno, s); exit(-1); } errorf(va_alist) va_dcl { va_list list; char *format; va_start(list); format = va_arg(list, char *); vfprintf(stderr, format, list); va_end(list); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'xtlex.l'" '(1456 characters)' if test -f 'xtlex.l' then echo shar: will not over-write existing file "'xtlex.l'" else cat << \SHAR_EOF > 'xtlex.l' %{ #include <stdio.h> typedef struct _WidgetClassRec *WidgetClass; #include "xtdefs.h" #include "xtokens.h" extern char *malloc(); %} digit [0-9] alpha [a-zA-Z] white [ \t]+ any [^\n] dot \. float {digit}*{dot}{digit}* nl [\n] dq-string \"[^\"]*\" sq-string \'[^\']*\' string ({dq-string}|{sq-string}) box [Bb][Oo][Xx] pane [Pp][Aa][Nn][Ee] command [Cc][Oo][Mm][Mm][Aa][Nn][Dd] dialog [Dd][Ii][Aa][Ll][Oo][Gg] form [Ff][Oo][Rr][Mm] label L[Aa][Bb][Ee][Ll] text [Tt][Ee][Xx][Tt] scroll [Ss][Cc][Rr][Oo][Ll][Ll] viewport [Vv][Ii][Ee][Ww][Pp][Oo][Rr][Tt] parent [Pp][Aa][Rr][Ee][Nn][Tt] %% {nl} ; {white} ; "," return(','); "[" return('['); "]" return(']'); "=" return('='); ^"#"{any}* { /* Comment */ } {box} return BOX; {pane} return PANE; {command} return COMMAND; {dialog} return DIALOG; {form} return FORM; {label} return LABEL; {text} return TEXT; {scroll} return SCROLL; {viewport} return VIEWPORT; {parent} return PARENT; {string} { yylval.sval = malloc(strlen(yytext) + 1); strcpy(yylval.sval, yytext+1); yylval.sval[strlen(yylval.sval) - 1] = '\0'; return STRING; } {digit}+ { yylval.ival = atoi(yytext); return VALUE; } {float} { yylval.fval = atof(yytext); return FLOAT; } {alpha}+ { yylval.sval = malloc(strlen(yytext) + 1); strcpy(yylval.sval, yytext); return RNAME; } {any} { errorf("Warning: Invalid character '%c' at line %d\n", *yytext, yylineno); } %% SHAR_EOF fi # end of overwriting check echo shar: extracting "'xtparse.y'" '(2327 characters)' if test -f 'xtparse.y' then echo shar: will not over-write existing file "'xtparse.y'" else cat << \SHAR_EOF > 'xtparse.y' %{ /* * This is the parser for xtdemo. As we parse the input file we * emit instructions. When we emit an OP_END the instructions are * all executed. */ #include <stdio.h> #include <X11/Intrinsic.h> #include <X11/Box.h> #include <X11/Command.h> #include <X11/Dialog.h> #include <X11/Form.h> #include <X11/Label.h> #include <X11/VPaned.h> #include <X11/Scroll.h> #include <X11/AsciiText.h> #include <X11/Viewport.h> #include "xtdefs.h" %} %union { int ival; float fval; char *sval; WidgetClass wval; } %token ',' %token '[' %token ']' %token '=' %token BOX COMMAND DIALOG FORM LABEL PANE %token PARENT SCROLL TEXT VIEWPORT %token <ival> VALUE %token <fval> FLOAT %token <sval> RNAME STRING %type <ival> value %type <fval> float %type <sval> name rname string %type <wval> widget %start program %% program : { emit_IXTDEMO(OP_START); } block { emit_IXTDEMO(OP_END); } ; block : line ; | block line ; line : widget name opt_parent opt_resources { emit_IXTDEMO(OP_CREATE, $2); } ; widget : BOX { emit_IXTDEMO(OP_SET_CLASS, boxWidgetClass); } | COMMAND { emit_IXTDEMO(OP_SET_CLASS, commandWidgetClass); } | DIALOG { emit_IXTDEMO(OP_SET_CLASS, dialogWidgetClass); } | FORM { emit_IXTDEMO(OP_SET_CLASS, formWidgetClass); } | LABEL { emit_IXTDEMO(OP_SET_CLASS, labelWidgetClass); } | PANE { emit_IXTDEMO(OP_SET_CLASS, vPanedWidgetClass); } | SCROLL { emit_IXTDEMO(OP_SET_CLASS, scrollbarWidgetClass); } | TEXT { emit_IXTDEMO(OP_SET_CLASS, asciiStringWidgetClass); } | VIEWPORT { emit_IXTDEMO(OP_SET_CLASS, viewportWidgetClass); } ; opt_parent : PARENT name { emit_IXTDEMO(OP_SET_PARENT, $2); } | ; opt_resources : '[' { emit_IXTDEMO(OP_INITARGS); } resource_list close_list | { emit_IXTDEMO(OP_INITARGS); } ; close_list : ',' ']' | ']' ; resource_list : resource | resource_list ',' resource ; resource : rname '=' rval ; rname : RNAME { emit_IXTDEMO(OP_PUSHS, $1); } ; rval : value { emit_IXTDEMO(OP_SETI, $1); } | float { emit_IXTDEMO(OP_SETF, $1); } | string { emit_IXTDEMO(OP_SETS, $1); } ; name : string ; string : STRING { #ifdef DEBUG printf("string = '%s'\n", $1); #endif } ; value : VALUE { #ifdef DEBUG printf("value = %d\n", $1); #endif } ; float : FLOAT ; %% SHAR_EOF fi # end of overwriting check # End of shell archive exit 0