#include #include #include #include #include #include #include #include XtAppContext app_con; Widget app_sh, draw, rule_text, StartButton, StopButton; Boolean Running = False; typedef struct { short mag, size, rule; } ApplicationData, *ApplicationDataPtr; ApplicationData AppData; String fallback_resources[] = { "*FontList: *-helvetica-bold-r-*-140-75-*", "*background: grey90", "*.ruleText.width: 80", NULL }; XrmOptionDescRec options[] = { {"-mag","*nMag",XrmoptionSepArg,NULL}, {"-size","*nSize",XrmoptionSepArg,NULL}, {"-rule","*nRule",XrmoptionSepArg,NULL}, }; #define N_OPTIONS 3 XtResource resources[] = { {"nMag","NMag",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,mag),XtRImmediate,(XtPointer)4}, {"nSize","NSIZE",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,size),XtRImmediate,(XtPointer)120}, {"nRule","NRule",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,rule),XtRImmediate,(XtPointer)30}, }; char *field, *work; Display *dpy = NULL; GC gc; Window win; Pixmap pmap; unsigned short size; Pixel black, white; int CurrentRow = 0; int Rule; /* rule 4 (010 goes to 1, else 0) ... simple rule 22 (001,100, and 010 goto 1, else 0) rule 30 (001, 100, 010, and 011 go to 1, else 0) rule 54 (001,100, 010, and 101 go to 1, else 0) rule 110 (001,010,011,101,110 go to 1 else 0) ... complex */ void setup_draw_info() { dpy = XtDisplay(app_sh); gc = DefaultGC(dpy,0); win = XtWindow(draw); pmap = XCreatePixmap(dpy,win,size,size,DefaultDepth(dpy,0)); black = BlackPixel(dpy,0); white = WhitePixel(dpy,0); } void display() { int i, j; if (CurrentRow >= AppData.size) { XCopyArea(dpy,pmap,pmap,gc, 0,AppData.mag,size,size-AppData.mag,0,0); CurrentRow = AppData.size - 1; } for (i = 0; i < AppData.size; i ++) { XSetForeground(dpy,gc,(field[i]?white:black)); if (AppData.mag == 1) XDrawPoint(dpy,pmap,gc,i,CurrentRow); else XFillRectangle(dpy,pmap,gc, i*AppData.mag,CurrentRow*AppData.mag, AppData.mag,AppData.mag); } XCopyArea(dpy,pmap,win,gc,0,0,size,size,0,0); CurrentRow ++; } void reset() { int i; for (i = 0; i < AppData.size; i ++) field[i] = lrand48() & 1; CurrentRow = 0; XSetForeground(dpy,gc,black); XFillRectangle(dpy,pmap,gc,0,0,size,size); display(); } Boolean work_one_step(cl) XtPointer cl; { int i, left, right, s; char *p; for (i = 0; i < AppData.size; i ++) { left = (i + AppData.size-1) % AppData.size; right = (i + 1) % AppData.size; s = (field[left] << 2) | (field[i] << 1) | field[right]; work[i] = (Rule & (1 << s))? 1 : 0; } p = work; work = field; field = p; display(); return !Running; } void RedrawCB(w,cl,cd) Widget w; XtPointer cl,cd; { XmDrawingAreaCallbackStruct *d = (XmDrawingAreaCallbackStruct *)cd; XExposeEvent *e = &(d->event->xexpose); XCopyArea(dpy,pmap,win,gc,e->x,e->y,e->width,e->height,e->x,e->y); } void ResetCB(w,cl,cd) Widget w; XtPointer cl,cd; { reset(); } void QuitCB(w,cl,cd) Widget w; XtPointer cl,cd; { exit(0);} void StartCB(w,cl,cd) Widget w; XtPointer cl,cd; { Running = True; XtAppAddWorkProc(app_con,work_one_step,NULL); XtVaSetValues(StartButton,XmNsensitive,False,NULL); XtVaSetValues(StopButton,XmNsensitive,True,NULL); } void StopCB(w,cl,cd) Widget w; XtPointer cl,cd; { Running = False; XtVaSetValues(StopButton,XmNsensitive,False,NULL); XtVaSetValues(StartButton,XmNsensitive,True,NULL); } void StepCB(w,cl,cd) Widget w; XtPointer cl,cd; { StopCB(w,cl,cd); XtAppAddWorkProc(app_con,work_one_step,NULL); } void NewRuleCB(w,cl,cd) Widget w; XtPointer cl,cd; { char *v; XtVaGetValues(rule_text,XmNvalue,&v,NULL); if (v) Rule = atoi(v); } main(argc,argv) int argc; char *argv[]; { Widget main_win, menu_bar, ctl, button; char text_value[16]; Arg args[2]; app_sh = XtAppInitialize(&app_con,"Life Game",options,N_OPTIONS, &argc,argv,fallback_resources,NULL,0); XtGetApplicationResources(app_sh,(XtPointer)&AppData,resources, XtNumber(resources),NULL,0); if (AppData.mag < 1) AppData.mag = 1; if (AppData.size < 20) AppData.size = 20; field = (char *)malloc(AppData.size * AppData.size * 2); if (!field) { perror("malloc"); exit(1); } work = field + AppData.size * AppData.size; size = AppData.mag * AppData.size; Rule = AppData.rule; XtSetArg(args[0],XmNshowSeparator,True); XtManageChild(main_win=XmCreateMainWindow(app_sh,"main",args,1)); XtManageChild(menu_bar=XmCreateMenuBar(main_win,"bar",NULL,0)); XtManageChild(button=XmCreateCascadeButton(menu_bar,"Quit",NULL,0)); XtAddCallback(button,XmNactivateCallback,QuitCB,NULL); XtManageChild(button=XmCreateCascadeButton(menu_bar,"Reset",NULL,0)); XtAddCallback(button,XmNactivateCallback,ResetCB,NULL); XtManageChild(button=XmCreateCascadeButton(menu_bar,"Step",NULL,0)); XtAddCallback(button,XmNactivateCallback,StepCB,NULL); StartButton = XmCreateCascadeButton(menu_bar,"Start",NULL,0); XtManageChild(StartButton); XtAddCallback(StartButton,XmNactivateCallback,StartCB,NULL); XtSetArg(args[0],XmNsensitive,False); StopButton = XmCreateCascadeButton(menu_bar,"Stop",args,1); XtManageChild(StopButton); XtAddCallback(StopButton,XmNactivateCallback,StopCB,NULL); XtSetArg(args[0],XmNorientation,XmHORIZONTAL); XtManageChild(ctl=XmCreateRowColumn(main_win,"control",args,1)); XtManageChild(XmCreateLabel(ctl,"Rule:",NULL,0)); sprintf(text_value,"%d",Rule); XtSetArg(args[0],XmNvalue,text_value); XtManageChild(rule_text=XmCreateText(ctl,"ruleText",args,1)); XtManageChild(button=XmCreatePushButton(ctl,"Apply",NULL,0)); XtAddCallback(button,XmNactivateCallback,NewRuleCB,NULL); XtSetArg(args[0],XmNwidth,size); XtSetArg(args[1],XmNheight,size); XtManageChild(draw=XmCreateDrawingArea(main_win,"field",args,2)); XtVaSetValues(main_win,XmNcommandWindow,ctl,XmNworkWindow,draw,NULL); XtRealizeWidget(app_sh); setup_draw_info(); reset(); XtAddCallback(draw,XmNexposeCallback,RedrawCB,NULL); XtAppMainLoop(app_con); }