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