macintosh@felix.UUCP (01/30/87)
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# BlobDemo/DemoHeb.c
# BlobDemo/DemoLib.c
# BlobDemo/DemoMagicSquare.c
# BlobDemo/DemoMain.c
# BlobDemo/DemoMenu.c
# BlobDemo/DemoPeg.c
mkdir BlobDemo
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoHeb.c
X/*
X Blob Manager Demonstration: Hebrew Alephbet module
X
X 26 July 1986 Paul DuBois
X*/
X
X
X# include "BlobDemo.h"
X# include <ControlMgr.h>
X# include <ResourceMgr.h>
X
X
X# define nLetters 22 /* 22 letters in Hebrew alephbet */
X# define iconSize 32 /* standard icon is 32x32 */
X# define sitmSize 16 /* sicn item is 16 x 16 */
X# define rWidth 76 /* receptor blob width and height */
X# define rHeight 22
X# define rHGap 2 /* horizontal and vertical gaps */
X# define rVGap 5 /* between receptor blobs */
X# define dWidth sitmSize /* ditto for donors */
X# define dHeight sitmSize
X# define dHGap 12
X# define dVGap 4
X
X# define pauseAns 1 /* what kind of pause? */
X# define pauseMatch 2
X
Xtypedef int Sitm[sitmSize];
Xtypedef Sitm Sicn[1];
Xtypedef Sicn **SicnHandle;
X
Xstatic GrafPtr hebPort;
Xstatic BlobSetHandle hebDonors;
Xstatic BlobSetHandle hebReceptors;
X
Xstatic ControlHandle matchCtl;
Xstatic ControlHandle resumeCtl;
Xstatic ControlHandle resetCtl;
Xstatic ControlHandle shuffleCtl;
Xstatic ControlHandle ansCtl;
X
Xstatic Boolean paused = false;
Xstatic int pauseType;
X
X
X/*
X Plot sicn item in given rectangle.
X This is exactly analogous to the ToolBox PlotIcon routine,
X except that the item number within the sicn must be specified.
X*/
X
X
XPlotSicn (r, s, i)
XRect *r;
XSicnHandle s;
Xint i;
X{
XGrafPtr thePort;
XBitMap bm;
XSitm tmpSitm;
X
X /* create a small bitmap */
X BlockMove (&((**s)[i]), &tmpSitm, (long) sizeof (Sitm));
X bm.baseAddr = (Ptr) &tmpSitm;
X bm.rowBytes = 2; /* items are 16 bits wide */
X SetRect (&bm.bounds, 0, 0, sitmSize, sitmSize);
X GetPort (&thePort);
X CopyBits (&bm, &thePort->portBits, &bm.bounds, r, srcCopy, nil);
X}
X
X
XHebActivate (active)
XBoolean active;
X{
X if (active)
X {
X SetDragRects (hebPort);
X SetBCPermissions (true, true, false, true, true);
X }
X}
X
X
XHebUpdate (resized)
XBoolean resized;
X{
Xint mode;
XPattern p;
X
X DrawControls (hebPort);
X DrawBlobSet (hebDonors);
X GetBDimInfo (&p, &mode);
X if (paused && pauseType == pauseMatch)
X SetBDimInfo (black, patXor);
X DrawBlobSet (hebReceptors);
X SetBDimInfo (p, mode);
X}
X
X
XLightControls ()
X{
Xint i;
X
X i = (paused ? 0 : 255);
X HiliteControl (matchCtl, 255 - i);
X HiliteControl (resetCtl, 255 - i);
X HiliteControl (ansCtl, 255 - i);
X HiliteControl (resumeCtl, i);
X}
X
X
XHebMoveBlobs (bSet, n1, n2, x, y, xd)
XBlobSetHandle bSet;
Xint n1, n2, x, y, xd;
X{
X for ( ; n1 <= n2; ++n1)
X {
X MoveBlob (GetBlobHandle (bSet, n1), inFullBlob, x, y);
X x += xd;
X }
X}
X
X
XHebMakeBlobs ()
X{
Xint i;
Xint h, v;
XRect tRect, lRect, sitmRect;
XSicnHandle letterSicn;
XStr255 rName;
XBlobHandle b1, b2;
Xint hMid;
Xint x, y, delta;
X
X hMid = hebPort->portRect.right / 2 - 4;
X
X letterSicn = (SicnHandle) GetResource ('SICN', letrSicnNo);
X hebDonors = NewBlobSet ();
X hebReceptors = NewBlobSet ();
X for (i = 0; i < nLetters; ++i)
X {
X b1 = NewBlob (hebDonors, false, 1, false, 0L);
X b2 = NewBlob (hebReceptors, false, 0, true, 0L);
X NewBlobMatch (b1, b2); /* assign donor -> receptor mapping */
X GetIndString (&rName, nameStrNo, i+1);
X OpenBlob (); /* draw source blob */
X SetRect (&sitmRect, 0, 0, sitmSize, sitmSize);
X PlotSicn (&sitmRect, letterSicn, i);
X CloseRectBlob (b1, &sitmRect, &sitmRect);
X
X OpenBlob ();
X SetRect (&tRect, 0, 5, rWidth-sitmSize-1, rHeight);
X OffsetRect (&sitmRect, rWidth-sitmSize, 5);
X TextBox (rName + 1, (long) rName[0], &tRect, 1);
X EraseRect (&sitmRect);
X FrameRect (&sitmRect);
X CloseRectBlob (b2, &sitmRect, &tRect);
X
X }
X ReleaseResource (letterSicn);
X
X/*
X now arrange the blobs on the board.
X*/
X x = hMid - 5*(dWidth+dHGap) - dWidth/2;
X delta = dWidth + dHGap;
X y = 5;
X HebMoveBlobs (hebDonors, 0, 10, x, y, delta);
X y += dHeight + dVGap;
X HebMoveBlobs (hebDonors, 11, 21, x, y, delta);
X
X x = hMid - 3*(rWidth+rHGap);
X y += dHeight + dVGap + 5;
X delta = rWidth + rHGap;
X HebMoveBlobs (hebReceptors, 0, 5, x, y, delta);
X y += rHeight + rVGap;
X HebMoveBlobs (hebReceptors, 6, 11, x, y, delta);
X y += rHeight + rVGap;
X HebMoveBlobs (hebReceptors, 12, 17, x, y, delta);
X x = hMid - 2*(rWidth+rHGap);
X y += rHeight + rVGap;
X HebMoveBlobs (hebReceptors, 18, 21, x, y, delta);
X /*ShuffleBlobSet (hebDonors);*/
X}
X
X
XHebMouse (thePt, t, mods)
XPoint thePt;
Xlong t;
Xint mods;
X{
XControlHandle ctl;
XBlobHandle b, g;
Xint mode;
XPattern p;
X
X if (!paused)
X {
X BlobClick (thePt, t, hebDonors, hebReceptors);
X if (BlobSetQuiet (hebReceptors)) /* if all correct */
X { /* override normal */
X paused = true; /* control display */
X pauseType = pauseAns;
X LightControls ();
X HiliteControl (resumeCtl, 255);
X HiliteControl (resetCtl, 0);
X FreezeBlobSet (hebReceptors);
X }
X }
X if (FindControl (thePt, hebPort, &ctl))
X {
X if (TrackControl (ctl, thePt, nil))
X {
X if (ctl == matchCtl)
X {
X paused = true;
X pauseType = pauseMatch;
X GetBDimInfo (&p, &mode); /* hilite by inverting */
X SetBDimInfo (black, patXor);
X BlobFeedback (hebReceptors, normalDraw, dimDraw);
X SetBDimInfo (p, mode);
X LightControls ();
X if (BlobSetQuiet (hebReceptors)) /* if all correct */
X { /* override normal */
X HiliteControl (resumeCtl, 255); /* control display */
X HiliteControl (resetCtl, 0);
X }
X }
X else if (ctl == ansCtl)
X {
X paused = true;
X pauseType = pauseAns;
X LightControls ();
X for (b = FirstBlob (hebReceptors); b != nil; b = NextBlob (b))
X {
X SetBRefCon (b, BGlob (b)); /* save current glob setting */
X g = FirstBMatch (b); /* attach real answer */
X if (g != BGlob (b))
X {
X ZGlueGlob (g, b);
X }
X }
X }
X else if (ctl == resumeCtl)
X {
X paused = false;
X LightControls ();
X if (pauseType == pauseMatch)
X ThawBlobSet (hebReceptors);
X else
X {
X /* restore previous attachments */
X for (b = FirstBlob (hebReceptors); b != nil; b = NextBlob (b))
X {
X g = (BlobHandle) GetBRefCon (b);
X if (g != BGlob (b))
X {
X ZUnglueGlob (b);
X GlueGlob (g, b);
X }
X }
X }
X }
X else if (ctl == resetCtl)
X {
X paused = false;
X LightControls ();
X ThawBlobSet (hebReceptors);
X ZUnglueGlobSet (hebReceptors); /* clear and redraw */
X }
X else if (ctl == shuffleCtl)
X {
X ShuffleBlobSet (hebDonors); /* shuffle letters */
X ValidRect (&hebPort->portRect);
X }
X }
X }
X}
X
X
XHebInit ()
X{
XRect r;
Xint i, j;
X
X SkelWindow (hebPort = GetDemoWind (hebWindRes),
X HebMouse, /* mouse clicks */
X nil, /* key clicks */
X HebUpdate, /* updates */
X HebActivate, /* activate/deactivate events */
X nil, /* close window */
X DoWClobber, /* dispose of window */
X nil, /* idle proc */
X false); /* irrelevant, since no idle proc */
X
X HebMakeBlobs ();
X i = hebPort->portRect.bottom - 25;
X j = hebPort->portRect.right/2 - 205;
X SetRect (&r, j, i, j+70, i+20);
X matchCtl =
X NewControl (hebPort, &r, "\pCheck", true, 0, 0, 0, pushButProc, nil);
X OffsetRect (&r, 85, 0);
X resumeCtl =
X NewControl (hebPort, &r, "\pResume", true, 0, 0, 0, pushButProc, nil);
X OffsetRect (&r, 85, 0);
X ansCtl =
X NewControl (hebPort, &r, "\pAnswer", true, 0, 0, 0, pushButProc, nil);
X OffsetRect (&r, 85, 0);
X resetCtl =
X NewControl (hebPort, &r, "\pReset", true, 0, 0, 0, pushButProc, nil);
X OffsetRect (&r, 85, 0);
X shuffleCtl =
X NewControl (hebPort, &r, "\pShuffle", true, 0, 0, 0, pushButProc, nil);
X
X LightControls ();
X
X EnableBlobSet (hebDonors);
X EnableBlobSet (hebReceptors);
X HebUpdate ();
X ValidRect (&hebPort->portRect);
X}
X
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoLib.c
X/*
X Blob Manager Demonstration: library routines
X*/
X
X# include <QuickDraw.h>
X# include "BlobDemo.h"
X
Xstatic int charBlobSize = 18;
X
X
X
X/*
X StrCpy copies the second argument into the first.
X StrCat appends the second argument to the first.
X MovesLeft creates a string that says "n Moves Left"
X
X Both assume Pascal-style strings.
X*/
X
X
XStrCpy (dst, src)
XStringPtr dst, src;
X{
Xint i;
X
X for (i = 0; i <= src[0]; ++i)
X dst[i] = src[i];
X}
X
X
XStrCat (dst, src)
XStringPtr dst, src;
X{
Xint i, dlen, slen;
X
X slen = src[0];
X dlen = dst[0];
X for (i = 1; slen > 0; ++i, --slen)
X dst[dlen + i] = src[i];
X dst[0] += src[0];
X}
X
X
XMovesLeft (n, s)
Xint n;
XStringPtr s;
X{
X NumToString (n, s);
X StrCat (s, (n == 1 ? "\p Move Left" : "\p Moves Left"));
X}
X
X
X/*
X Create and dispose of offscreen port
X*/
X
XGrafPtr NewOffPort (r)
XRect r;
X{
XGrafPtr thePort, tmpPort;
XBitMap *theMap;
Xlong bitCount;
Xint rowBytes;
XPtr bits;
X
X rowBytes = ((r.right-r.left + 15) / 8) & (~1);
X bitCount = rowBytes * (r.bottom - r.top);
X bits = NewPtr (bitCount);
X if (bits)
X {
X thePort = (GrafPtr) NewPtr ((long) sizeof (GrafPort));
X if (thePort)
X {
X theMap = (BitMap *) NewPtr ((long) sizeof (BitMap));
X if (theMap)
X {
X theMap->bounds = r;
X theMap->rowBytes = rowBytes;
X theMap->baseAddr = bits;
X GetPort (&tmpPort);
X OpenPort (thePort);
X SetPortBits (theMap);
X PortSize (r.right - r.left, r.bottom - r.top);
X RectRgn (thePort->visRgn, &thePort->portRect);
X ClipRect (&thePort->portRect);
X EraseRect (&thePort->portRect);
X SetPort (tmpPort);
X return (thePort);
X }
X DisposPtr (thePort);
X }
X DisposPtr (bits);
X }
X return (nil);
X}
X
X
XDisposeOffPort (thePort)
XGrafPtr thePort;
X{
X ClosePort (thePort);
X DisposPtr (thePort->portBits.baseAddr);
X DisposPtr (&thePort->portBits);
X DisposPtr (thePort);
X}
X
X
X/*
X Make a simulated push button. It looks like a regular button,
X except that it's oriented vertically rather than horizontally.
X bSet is the blob set to add the button blob to, r defines the
X bounds rect, and title is a string containing the text to be drawn
X in the blob.
X
X The glueMax and mustMatch fields are assumed to be zero and false.
X
X The ShowPen call is necessary since both OpenBlob and OpenRgn
X perform implicit HidePen's - without ShowPen, nothing will
X be drawn! Then must balance with HidePen after drawing.
X*/
X
XBlobHandle NewVButtonBlob (bSet, r, title, visible, refCon)
XBlobSetHandle bSet;
XRect *r;
XStringPtr title;
Xlong refCon;
X{
XBlobHandle b;
XRgnHandle rgn, rgn2;
XFontInfo fInfo;
Xint cHeight; /* character height */
Xint tHeight; /* title height */
Xint h, v;
Xint i;
X
X/*
X Make the regions defining the blob first. The drag region is inset
X by one so that the text in the middle can be dimmed without dimming
X the frame.
X*/
X
X rgn = NewRgn ();
X OpenRgn ();
X FrameRoundRect (r, 10, 10);
X CloseRgn (rgn);
X rgn2 = NewRgn ();
X CopyRgn (rgn, rgn2);
X InsetRgn (rgn2, 1, 1);
X
X /* Now make the blob and define its image */
X
X b = NewBlob (bSet, visible, 0, false, refCon);
X GetFontInfo (&fInfo);
X cHeight = fInfo.ascent + fInfo.descent;
X tHeight = title[0] * (cHeight + fInfo.leading) - fInfo.leading;
X OpenBlob ();
X v = (r->top + r->bottom - tHeight ) / 2 + fInfo.ascent;
X FillRgn (rgn2, white);
X for (i = 1; i <= title[0]; ++i)
X {
X h = (r->left + r->right - CharWidth (title[i])) / 2;
X MoveTo (h, v);
X DrawChar (title[i]);
X v += cHeight + fInfo.leading;
X }
X FrameRoundRect (r, 10, 10);
X CloseRgnBlob (b, rgn2, rgn);
X DisposeRgn (rgn);
X DisposeRgn (rgn2);
X return (b);
X}
X
X
X/*
X Determine the rectangle that defines each element of a grid,
X and pass the rectangle to a blob-drawing proc. The proc draws
X whatever goes into the element. Creates blobs a row at a time.
X*/
X
XMakeBlobGrid (rows, cols, hOff, vOff, hWidth, vHeight, hGap, vGap, p)
Xint rows, cols, hOff, vOff, hWidth, vHeight, hGap, vGap;
XProcPtr p;
X{
Xint i, j;
Xint h, v;
XRect r;
X
X for (j = 0; j < rows; ++j)
X {
X for (i = 0; i < cols; ++i)
X {
X h = hOff + i * (hGap + hWidth);
X v = vOff + j * (vGap + vHeight);
X SetRect (&r, h, v, h + hWidth, v + vHeight);
X (*p) (&r);
X }
X }
X}
X
X
X/*
X Draw a grid with the given number of rows and columns. The upper
X left-hand corner of the top element is at (hoff, voff). The
X height and width of each element is vHeight and hWidth. The horizontal
X and vertical gaps between elements are hGap and vGap. A border is
X also drawn around the whole grid.
X*/
X
XDrawGrid (rows, cols, hOff, vOff, hWidth, vHeight, hGap, vGap)
Xint rows, cols, hOff, vOff, hWidth, vHeight, hGap, vGap;
X{
Xint i;
Xint h, v;
Xint len;
XRect r;
X
X hOff -= hGap;
X vOff -= vGap;
X PenSize (hGap, vGap);
X /* draw vertical lines */
X len = rows * (vGap + vHeight);
X for (i = 0; i <= cols; ++i)
X {
X h = hOff + i * (hGap + hWidth);
X MoveTo (h, vOff);
X LineTo (h, vOff + len);
X }
X /* draw horizontal lines */
X len = cols * (hGap + hWidth);
X for (i = 0; i <= rows; ++i)
X {
X v = vOff + i * (vGap + vHeight);
X MoveTo (hOff, v);
X LineTo (hOff + len, v);
X }
X PenNormal ();
X}
X
X
X/*
X Drawing proc for character blobs
X*/
X
XDrawCharBlob (bDst, bSrc, partCode)
XBlobHandle bDst, bSrc;
Xint partCode;
X{
XRect r;
Xchar c;
X
X r = BDragBox (bDst);
X c = (char) LoWord (GetBRefCon (bSrc));
X if (c == ' ')
X {
X EraseRoundRect (&r, 10, 10);
X FrameRoundRect (&r, 10, 10);
X }
X else
X {
X TextBox (&c, 1L, &r, 1);
X }
X}
X
X
X/*
X Make a blob with a character in the middle (or a frame if the
X character is a space). Pass all the normal NewBlob parameters
X except the reference constant, plus the horizontal and vertical
X coordinates, and the character to be drawn in the blob.
X
X The char is stored as the low word of the reference value. The
X application can put whatever it wants in the high word.
X*/
X
X
XBlobHandle MakeCharBlob (bSet, enable, glueMVal, mustMatch, h, v, c)
XBlobSetHandle bSet;
XBoolean enable;
Xint glueMVal;
XBoolean mustMatch;
Xint h, v;
Xchar c;
X{
XBlobHandle b;
XRect r;
X
X b = NewBlob (bSet, enable, glueMVal, mustMatch, (long) c);
X SetRect (&r, h, v, h + charBlobSize, v + charBlobSize);
X SetProcRectBlob (b, DrawCharBlob, &r, &r);
X return (b);
X}
X
X
X/*
X Set the size in which character blobs are created
X*/
X
XSetCharBlobSize (size)
Xint size;
X{
X charBlobSize = size;
X}SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoMagicSquare.c
X/*
X Blob Manager Demonstration: Magic Square
X
X All rows, columns and diagonals of a square must add up to 15.
X
X This is a donorless scenario. The receptors are created, then glued
X to themselves initially so that they will each have a glob to drag
X around.
X
X 26 July 1986 Paul DuBois
X*/
X
X# include "BlobDemo.h"
X# include <ControlMgr.h>
X
X
X# define vButton 5
X# define vBoard 30 /* offset of top of board */
X# define hGap 2
X# define vGap 2
X# define bSqSize 30 /* board square size */
X
X
Xstatic GrafPtr magicPort;
Xstatic BlobSetHandle receptors;
X
Xstatic Boolean wait;
Xstatic ControlHandle button;
Xstatic int hMid;
Xstatic int hBoard;
X
X
Xstatic Restart ()
X{
X
X HiliteControl (button, 255);
X ShuffleGlobSet (receptors);
X wait = false;
X}
X
X
Xstatic Boolean TestConfig (pos1, pos2, pos3)
Xint pos1, pos2, pos3;
X{
Xint sum;
X
X sum = GetBRefCon (BGlob (GetBlobHandle (receptors, pos1)))
X + GetBRefCon (BGlob (GetBlobHandle (receptors, pos2)))
X + GetBRefCon (BGlob (GetBlobHandle (receptors, pos3)));
X return (sum == 15);
X}
X
X
Xstatic CheckStatus ()
X{
X if (TestConfig (0, 1, 2) /* top row */
X && TestConfig (3, 4, 5) /* middle row */
X && TestConfig (6, 7, 8) /* bottom row */
X && TestConfig (0, 3, 6) /* left column */
X && TestConfig (1, 4, 7) /* middle column */
X && TestConfig (2, 5, 8) /* right column */
X && TestConfig (0, 4, 8) /* diagonal */
X && TestConfig (2, 4, 6) ) /* diagonal */
X {
X HiliteControl (button, 0);
X wait = true;
X }
X}
X
X
Xstatic Mouse (pt, t, mods)
XPoint pt;
Xlong t;
Xint mods;
X{
XBlobHandle b, d;
XControlHandle ctl;
X
X if (FindControl (pt, magicPort, &ctl))
X {
X if (TrackControl (ctl, pt, nil))
X Restart ();
X }
X else if (!wait)
X BlobClick (pt, t, nil, receptors);
X/*
X Check status even if user just restarted, since the square may
X by chance fall into a correct configuration. In that case,
X the CheckStatus will again enable the restart button.
X*/
X CheckStatus ();
X}
X
X
Xstatic Update (resized)
XBoolean resized;
X{
X DrawControls (magicPort);
X DrawBlobSet (receptors);
X}
X
X
Xstatic Activate (active)
XBoolean active;
X{
X if (active)
X {
X SetDragRects (magicPort);
X SetBCPermissions (false, false, false, true, true);
X }
X}
X
X
X/*
X Make receptor blob
X*/
X
Xstatic MakeRBlob (r)
XRect *r;
X{
XBlobHandle b;
Xchar c;
Xstatic long rno = 0L;
X
X b = NewBlob (receptors, false, infiniteGlue, false, ++rno);
X OpenBlob ();
X EraseRect (r);
X FrameRect (r);
X InsetRect (r, 5, 7);
X c = rno + '0';
X TextBox (&c, 1L, r, 1);
X InsetRect (r, -3, -5);
X InvertRect (r);
X InsetRect (r, -2, -2);
X CloseRectBlob (b, r, r);
X GlueGlob (b, b);
X}
X
X
Xstatic MakeReceptors ()
X{
X receptors = NewBlobSet ();
X MakeBlobGrid (3, 3, hBoard, vBoard, bSqSize, bSqSize,
X hGap, vGap, MakeRBlob);
X}
X
X
XMagicInit ()
X{
XRect r;
X
X magicPort = GetDemoWind (magicWindRes);
X SkelWindow (magicPort,
X Mouse, /* mouse clicks */
X nil, /* key clicks */
X Update, /* updates */
X Activate, /* activate/deactivate events */
X nil, /* close window */
X DoWClobber, /* dispose of window */
X nil, /* idle proc */
X false); /* irrelevant, since no idle proc */
X
X hMid = magicPort->portRect.right / 2;
X hBoard = hMid - (3 * (bSqSize + hGap) - hGap) / 2;
X SetRect (&r, hMid - 40, vButton, hMid + 40, vButton + 20);
X button = NewControl (magicPort, &r, "\pReset", true, 0, 0, 0,
X pushButProc, nil);
X
X MakeReceptors ();
X ShowBlobSet (receptors);
X Restart ();
X ValidRect (&magicPort->portRect);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoMain.c
X/*
X Blob Manager Demonstration: Main module
X
X 25 June 1986 Paul DuBois
X*/
X
X# include <QuickDraw.h>
X
X
Xlong diskInfoKludge;
X
X
X
Xmain ()
X{
Xint i;
X
X SkelInit (); /* initialize TransSkel */
X
X randSeed = TickCount ();
X
X SetupMenus ();
X
X/*
X Initialize the various scenarios. Any of them may be entirely
X disabled simply by commenting out the initialization line.
X*/
X
X WolfInit ();
X TohInit ();
X TttInit ();
X StatesInit ();
X PyrInit ();
X PongInit ();
X PegInit ();
X MagicInit ();
X HebInit ();
X HangInit ();
X FggInit ();
X FshInit ();
X FarInit ();
X SwapInit ();
X RadixInit ();
X AnagramInit ();
X
X AddWindowTitles (); /* add window names to Windows menu */
X
X SkelMain (); /* loop 'til Quit selected */
X
X DisposeBlobSets (); /* shut down the Blob Manager */
X SkelClobber (); /* and TransSkel */
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoMenu.c
X/*
X Blob Manager Demonstration: Handlers for standard menus (those
X that stick around all the time). Menus that exist only when
X are particular window is in front are installed and removed by
X the handler for that window.
X
X 12 July 1986 Paul DuBois
X*/
X
X# include "BlobDemo.h"
X# include <WindowMgr.h>
X# include <MenuMgr.h>
X# include <FontMgr.h>
X
X
Xstatic MenuHandle fileMenu;
Xstatic MenuHandle editMenu;
Xstatic MenuHandle windMenu;
X
X
X/*
X wPtr is used to map Windows menu items onto the windows associated
X with each item.
X*/
X
Xstatic WindowPtr wPtr[lastWindRes-firstWindRes];
Xstatic int wCount = 0;
X
X
XDoAbout ()
X{
X (void) Alert (aboutAlrtRes, nil);
X}
X
X
XDoFileMenu (item)
Xint item;
X{
XHandle h;
X
X switch (item)
X {
X case getInfo:
X {
X h = GetResource ('TEXT', helpTextRes);
X HLock (h);
X TextDialog (textDlogRes, h, 0, 0, true);
X HUnlock (h);
X ReleaseResource (h);
X break;
X }
X case quit:
X {
X SkelWhoa (); /* tell SkelMain to quit */
X break;
X }
X }
X}
X
X
XDoEditMenu (item)
Xint item;
X{
X (void) SystemEdit (item - 1); /* route to DA if appropriate */
X}
X
X
X/*
X The Windows menu is used to select a given window and bring it
X to the front. It also makes it visible if it wasn't already.
X*/
X
XDoWindMenu (item)
Xint item;
X{
X SelectWindow (wPtr[item-1]);
X ShowWindow (wPtr[item-1]);
X}
X
X
X/*
X Add title of each window to the Windows menu. Save the WindowPtr for
X use later if the window is selected from the menu.
X*/
X
X
X
XAddWindowTitles ()
X{
XWindowPeek theWind;
XStr255 title;
X
X theWind = (WindowPeek) FrontWindow ();
X while (theWind != nil)
X {
X GetWTitle (theWind, &title);
X AppendMenu (windMenu, title);
X wPtr[wCount++] = (WindowPtr) theWind;
X theWind = theWind->nextWindow;
X }
X}
X
X
X/*
X Clobber proc for menu handlers
X*/
X
XDoMClobber (theMenu)
XHandle theMenu;
X{
X ReleaseResource (theMenu);
X}
X
X
X/*
X Background task: enable Edit menu when a DA window is in front.
X Disable it when a demo window is in front. Since this procedure
X is executed continually, only mess with the menu bar on a change
X of state.
X*/
X
XBackground ()
X{
Xstatic Boolean editEnable = false;
XWindowPeek wPeek;
X
X if ( (wPeek = (WindowPeek) FrontWindow ()) == nil
X || wPeek->windowKind >= 0) /* DA not in front */
X {
X if (editEnable)
X {
X DisableItem (editMenu, 0);
X DrawMenuBar ();
X editEnable = false;
X };
X }
X else if (!editEnable) /* DA window in front */
X {
X EnableItem (editMenu, 0);
X DrawMenuBar ();
X editEnable = true;
X }
X}
X
X
X/*
X Set up menus: Tell LightSkel to make a default Apple menu handler,
X create handlers for the File, Edit and Windows menus. Install
X background task that enables/disables Edit menu.
X*/
X
XSetupMenus ()
X{
X
X SkelApple ("\pAbout BlobMgr DemoI", DoAbout);
X fileMenu = GetMenu (fileMenuRes);
X SkelMenu (fileMenu, DoFileMenu, DoMClobber);
X editMenu = GetMenu (editMenuRes);
X SkelMenu (editMenu, DoEditMenu, DoMClobber);
X windMenu = GetMenu (windMenuRes);
X SkelMenu (windMenu, DoWindMenu, DoMClobber);
X SkelBackground (Background);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > BlobDemo/DemoPeg.c
X/*
X Blob Manager Demonstration: Peg Solitaire module
X
X 31 July 1986 Paul DuBois
X*/
X
X
X# include "BlobDemo.h"
X# include <MenuMgr.h>
X
X
X# define rows 7 /* number of rows on board */
X# define columns 7 /* number of columns on board */
X# define pieceSize 20 /* size of each piece */
X# define vMessage 141 /* vertical position of message */
X
X/*
X bits used in configuration information
X
X bit 0 0 board position unused
X 1 board position used
X bit 1 0 position does not have marble at start
X 1 position has marble at start
X bit 2 0 position does not have marble at end
X 1 position has marble at end
X
X bits 1 and 2 are irrelevant unless bit 0 is on
X*/
X
X# define posUsedMask 1
X# define inStartMask 2
X# define inFinalMask 4
X
X
Xstatic GrafPtr pegPort;
Xstatic MenuHandle cnfgMenu;
X
X
Xstatic BlobSetHandle boardBlobs = nil; /* receptors */
Xstatic BlobHandle board[columns][rows];
X
Xstatic int hMid;
Xstatic int cnfgNo; /* current configuration */
Xstatic int moves; /* number of moves left */
Xstatic Boolean pause;
Xstatic Str255 statusStr = "\p";
X
X
Xtypedef struct
X{
X char *lName; /* name of configuration */
X char lCnfg[columns][rows]; /* board positions */
X} Layout;
X
X
Xstatic Layout centerToCenter =
X{
X "\pCenter To Center",
X {
X { 0, 0, 3, 3, 3, 0, 0 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 3, 3, 3, 3, 3, 3, 3 },
X { 3, 3, 3, 5, 3, 3, 3 },
X { 3, 3, 3, 3, 3, 3, 3 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 0, 0, 3, 3, 3, 0, 0 }
X }
X};
X
X
Xstatic Layout cornerToCorner =
X{
X "\pCorner To Corner",
X {
X { 0, 0, 1, 3, 3, 0, 0 },
X { 0, 3, 3, 3, 3, 3, 0 },
X { 3, 3, 3, 3, 3, 3, 3 },
X { 3, 3, 3, 3, 3, 3, 3 },
X { 3, 3, 3, 3, 3, 3, 3 },
X { 0, 3, 3, 3, 3, 3, 0 },
X { 0, 0, 3, 3, 7, 0, 0 }
X }
X};
X
X
Xstatic Layout doubleCross =
X{
X "\pDouble Cross",
X {
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 3, 1, 3, 1, 3, 0 },
X { 1, 1, 3, 3, 3, 1, 1 },
X { 3, 3, 3, 7, 3, 3, 3 },
X { 1, 1, 3, 3, 3, 1, 1 },
X { 0, 3, 1, 3, 1, 3, 0 },
X { 0, 0, 1, 3, 1, 0, 0 }
X }
X};
X
X
Xstatic Layout finalScore =
X{
X "\pFinal Score",
X {
X { 0, 0, 7, 7, 7, 0, 0 },
X { 0, 7, 3, 3, 3, 7, 0 },
X { 7, 3, 7, 3, 7, 3, 7 },
X { 7, 3, 3, 5, 3, 3, 7 },
X { 7, 3, 3, 3, 3, 3, 7 },
X { 0, 7, 3, 7, 3, 7, 0 },
X { 0, 0, 7, 7, 7, 0, 0 }
X }
X};
X
X
Xstatic Layout fiveCrosses =
X{
X "\pFive Crosses",
X {
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 1, 3, 3, 3, 1, 0 },
X { 1, 3, 1, 3, 1, 3, 1 },
X { 3, 3, 3, 7, 3, 3, 3 },
X { 1, 3, 1, 3, 1, 3, 1 },
X { 0, 1, 3, 3, 3, 1, 0 },
X { 0, 0, 1, 3, 1, 0, 0 }
X }
X};
X
X
Xstatic Layout footballTeam =
X{
X "\pFootball Team",
X {
X { 0, 0, 3, 3, 3, 0, 0 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 1, 1, 3, 3, 3, 1, 1 },
X { 1, 1, 3, 5, 3, 1, 1 },
X { 1, 1, 1, 1, 1, 1, 1 },
X { 0, 0, 1, 1, 1, 0, 0 },
X { 0, 0, 1, 1, 1, 0, 0 }
X }
X};
X
X
Xstatic Layout greekCross =
X{
X "\pGreek Cross",
X {
X { 0, 0, 1, 1, 1, 0, 0 },
X { 0, 0, 1, 3, 1, 0, 0 },
X { 1, 1, 1, 3, 1, 1, 1 },
X { 1, 3, 3, 7, 3, 3, 1 },
X { 1, 1, 1, 3, 1, 1, 1 },
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 0, 1, 1, 1, 0, 0 }
X }
X};
X
X
Xstatic Layout latinCross =
X{
X "\pLatin Cross",
X {
X { 0, 0, 1, 1, 1, 0, 0 },
X { 0, 0, 1, 3, 1, 0, 0 },
X { 1, 1, 3, 3, 3, 1, 1 },
X { 1, 1, 1, 7, 1, 1, 1 },
X { 1, 1, 1, 3, 1, 1, 1 },
X { 0, 0, 1, 1, 1, 0, 0 },
X { 0, 0, 1, 1, 1, 0, 0 },
X }
X};
X
X
Xstatic Layout leTricolet =
X{
X "\pLe Tricolet",
X {
X { 0, 0, 7, 3, 7, 0, 0 },
X { 0, 3, 3, 7, 3, 3, 0 },
X { 7, 3, 3, 7, 3, 3, 7 },
X { 3, 7, 7, 1, 7, 7, 3 },
X { 7, 3, 3, 7, 3, 3, 7 },
X { 0, 3, 3, 7, 3, 3, 0 },
X { 0, 0, 7, 3, 7, 0, 0 }
X }
X};
X
X
Xstatic Layout lonelyCross =
X{
X "\pLonely Cross",
X {
X { 0, 0, 7, 7, 7, 0, 0 },
X { 0, 7, 3, 3, 3, 7, 0 },
X { 7, 3, 3, 7, 3, 3, 7 },
X { 7, 3, 7, 5, 7, 3, 7 },
X { 7, 3, 3, 7, 3, 3, 7 },
X { 0, 7, 3, 3, 3, 7, 0 },
X { 0, 0, 7, 7, 7, 0, 0 }
X }
X};
X
X
Xstatic Layout octagon =
X{
X "\pOctagon",
X {
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 3, 3, 3, 3, 3, 0 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 3, 3, 3, 7, 3, 3, 3 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 0, 3, 3, 3, 3, 3, 0 },
X { 0, 0, 1, 3, 1, 0, 0 }
X }
X};
X
X
Xstatic Layout pentagon =
X{
X "\pPentagon",
X {
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 3, 3, 3, 7, 3, 3, 3 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 0, 0, 1, 1, 1, 0, 0 }
X }
X};
X
X
Xstatic Layout pyramidChefren =
X{
X "\pPyramid of Chefren",
X {
X { 0, 0, 1, 1, 1, 0, 0 },
X { 0, 1, 1, 1, 1, 1, 0 },
X { 1, 1, 1, 3, 1, 1, 1 },
X { 1, 1, 3, 7, 3, 1, 1 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 0, 1, 1, 1, 1, 1, 0 },
X { 0, 0, 1, 1, 1, 0, 0 },
X }
X};
X
X
Xstatic Layout pyramidCheops =
X{
X "\pPyramid of Cheops",
X {
X { 0, 0, 1, 1, 1, 0, 0 },
X { 0, 1, 1, 3, 1, 1, 0 },
X { 1, 1, 3, 3, 3, 1, 1 },
X { 1, 3, 3, 7, 3, 3, 1 },
X { 3, 3, 3, 3, 3, 3, 3 },
X { 0, 1, 1, 1, 1, 1, 0 },
X { 0, 0, 1, 1, 1, 0, 0 },
X }
X};
X
X
Xstatic Layout shrine =
X{
X "\pShrine",
X {
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 1, 1, 3, 1, 1, 0 },
X { 1, 3, 3, 7, 3, 3, 1 },
X { 1, 1, 1, 3, 1, 1, 1 },
X { 1, 1, 1, 3, 1, 1, 1 },
X { 0, 1, 3, 3, 3, 1, 0 },
X { 0, 0, 3, 3, 3, 0, 0 },
X }
X};
X
X
Xstatic Layout tiffanyLamp =
X{
X "\pTiffany Lamp",
X {
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 1, 1, 1, 7, 1, 1, 1 },
X { 1, 1, 1, 3, 1, 1, 1 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 0, 0, 3, 3, 3, 0, 0 },
X }
X};
X
X
Xstatic Layout tiltedSquare =
X{
X "\pTilted Square",
X {
X { 0, 0, 1, 3, 1, 0, 0 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 3, 3, 3, 5, 3, 3, 3 },
X { 1, 3, 3, 3, 3, 3, 1 },
X { 0, 0, 3, 3, 3, 0, 0 },
X { 0, 0, 1, 3, 1, 0, 0 }
X }
X};
X
X
Xstatic Layout nullLayout =
X{
X nil
X};
X
X
Xstatic Layout *configurations [] =
X{
X ¢erToCenter,
X &cornerToCorner,
X &doubleCross,
X &finalScore,
X &fiveCrosses,
X &footballTeam,
X &greekCross,
X &latinCross,
X &leTricolet,
X &lonelyCross,
X &octagon,
X &pentagon,
X &pyramidChefren,
X &pyramidCheops,
X &shrine,
X &tiffanyLamp,
X &tiltedSquare,
X &nullLayout
X};
X
X
Xstatic StatusMesg (s)
XStr255 s;
X{
XRect r;
X
X SetRect (&r, 0, vMessage, pegPort->portRect.right, vMessage + 12);
X TextBox (s+1, (long) s[0], &r, 1);
X StrCpy (statusStr, s);
X}
X
X
X/*
X Board position drawing procedure. This draws a blank for those
X positions that are unused. For used positions, the blob is filled
X with light gray if a peg should be in the position at the end of
X play. In the drag region, a hole is drawn if there is no glob,
X otherwise a peg is drawn. It does not matter what glob is attached,
X only whether there is one.
X*/
X
Xstatic DrawBoardPos (bDst, bSrc, partCode)
XBlobHandle bDst, bSrc;
Xint partCode; /* ignored - always draw entire blob */
X{
Xint blobType;
XRect r;
X
X blobType = GetBRefCon (bDst); /* indicates unused, used and present
X in final, or used and not present
X in final */
X r = BStatBox (bDst); /* blob outline */
X EraseRect (&r);
X if (blobType & posUsedMask)
X {
X if (blobType & inFinalMask)
X FillRect (&r, gray);
X if (BGlob (bDst) == nil) /* no peg, just draw hole */
X {
X InsetRect (&r, 7, 7);
X PaintOval (&r);
X }
X else
X {
X InsetRect (&r, 2, 2); /* draw peg */
X EraseOval (&r);
X PenSize (2, 2);
X FrameOval (&r);
X PenNormal ();
X }
X }
X}
X
X
X/*
X Build the board. All positions are initially given a reference
X value of 0, meaning an unused position. This means that the board
X is blank until a configuration is set up. The blobs are built by
X contructing the static and drag regions, without drawing anything,
X since they are drawn by procedure.
X*/
X
Xstatic InitBoard ()
X{
Xint h, v;
XRect r, r2;
XBlobHandle b;
X
X boardBlobs = NewBlobSet ();
X for (v = 0; v < rows; v++)
X {
X for (h = 0; h < columns; h++)
X {
X b = NewBlob (boardBlobs, false, infiniteGlue, true, (long) 0);
X board[h][v] = b;
X SetRect (&r, 0, 0, pieceSize, pieceSize);
X OffsetRect (&r, h * pieceSize, v * pieceSize);
X r2 = r;
X InsetRect (&r2, 2, 2);
X SetProcRectBlob (b, DrawBoardPos, &r2, &r);
X }
X }
X
X EnableBlobSet (boardBlobs);
X}
X
X
X/*
X Set the board to a given configuration. The first board blob is
X used as the general glob and as the match for final positions.
X*/
X
Xstatic SetupBoard (layout)
XLayout *layout;
X{
Xint h, v, val;
Xint startCount = 0;
Xint finalCount = 0;
XBlobHandle b;
XStr255 s;
X
X DisableBlobSet (boardBlobs); /* turn off drawing temporarily */
X for (v = 0; v < rows; v++)
X {
X for (h = 0; h < columns; h++)
X {
X b = board[h][v];
X val = (int) layout->lCnfg[v][h];
X SetBRefCon (b, val);
X UnglueGlob (b); /* clear any glob and match set */
X DisposeBlobMatchSet (b); /* from previous configuration */
X if (val & posUsedMask) /* check that position is used */
X {
X if (val & inStartMask) /* position has marble at start */
X {
X startCount++;
X GlueGlob (FirstBlob (boardBlobs), b);
X }
X if (val & inFinalMask) /* position has marble at end */
X {
X finalCount++;
X NewBlobMatch (FirstBlob (boardBlobs), b);
X }
X }
X }
X }
X
X ShowBlobSet (boardBlobs);
X moves = startCount - finalCount;
X MovesLeft (moves, s);
X StatusMesg (s);
X pause = false;
X}
X
X
Xstatic PegPause (msg)
XStringPtr msg;
X{
X StatusMesg (msg);
X pause = true;
X}
X
X
X/*
X Check whether a board position is empty. The coordinates must be
X legal, the position must be used in the current configuration,
X and the position must have a marble in it.
X*/
X
Xstatic Boolean BoardPosEmpty (h, v)
Xint h, v;
X{
X return (h >= 0 && h < columns && v >= 0 && v < rows
X && (GetBRefCon (board[h][v]) & posUsedMask)
X && BGlob (board[h][v]) == nil);
X}
X
X
Xstatic Boolean BoardPosFilled (h, v)
Xint h, v;
X{
X return (h >= 0 && h < columns && v >= 0 && v < rows
X && (GetBRefCon (board[h][v]) & posUsedMask)
X && BGlob (board[h][v]) != nil);
X}
X
X
X/*
X Test whether a piece can move or not
X*/
X
Xstatic Boolean CanMove (h, v)
Xint h, v;
X{
X return ((BoardPosEmpty (h - 2, v) && BoardPosFilled (h - 1, v))
X || (BoardPosEmpty (h + 2, v) && BoardPosFilled (h + 1, v))
X || (BoardPosEmpty (h, v - 2) && BoardPosFilled (h, v - 1))
X || (BoardPosEmpty (h, v + 2) && BoardPosFilled (h, v + 1)));
X}
X
X
X/*
X See if any more moves can be made. True if stalemated.
X*/
X
Xstatic Boolean HaveStaleMate ()
X{
XBlobHandle b;
Xint h, v;
X
X for (v = 0; v < rows; v++)
X {
X for (h = 0; h < columns; h++)
X {
X b = board[h][v];
X if (GetBRefCon (b) & posUsedMask)
X {
X if (BGlob (b) != nil && CanMove (h, v))
X return (false); /* at least 1 move can be made */
X }
X }
X }
X return (true);
X}
X
X
Xstatic Mouse (pt, t, mods)
XPoint pt;
Xlong t;
Xint mods;
X{
XStr255 s;
Xint i;
X
X
X if (!pause)
X {
X BlobClick (pt, t, nil, boardBlobs);
X if (BClickResult () == bcXfer)
X {
X --moves;
X if (BlobSetQuiet (boardBlobs))
X PegPause ("\pYou Win");
X else if (moves == 0)
X PegPause ("\pYou Lose");
X else if (HaveStaleMate ())
X PegPause ("\pYou Can't Move");
X else
X {
X MovesLeft (moves, s);
X StatusMesg (s);
X }
X }
X }
X}
X
X
X/*
X Given a blob handle, find the board position that corresponds to it.
X This is used to map hits in the blob set (a list) to the position in
X the board (a 2-d array).
X*/
X
Xstatic FindBoardPos (b, h, v)
XBlobHandle b;
Xint *h, *v;
X{
Xint i, j;
X
X for (i = 0; i < columns; ++i)
X {
X for (j = 0; j < rows; ++j)
X {
X if (board[i][j] == b)
X {
X *h = i;
X *v = j;
X return;
X }
X }
X }
X /* shouldn't ever get here */
X}
X
X
X
X/*
X When a piece is clicked on, the advisory checks whether the piece has
X any legal moves available to it. If so, it returns true, so that
X BlobClick is allowed to drag the piece. After the piece has been
X dragged, the advisory checks whether the position it was dragged to
X is legal. If it is, the piece that was jumped is removed from the
X board, and true is returned, so that BlobClick will complete the
X tranfer of the dragged piece to its new position.
X
X Messages passed to the advisory follow the pattern
X
X { { advRClick advRClick* } advXfer* }*
X
X where * means 0 or more instances of the thing *'ed. In particular,
X the advXfer message is never seen without a preceding advRClick.
X*/
X
Xstatic Boolean Advisory (mesg, b)
Xint mesg;
XBlobHandle b;
X{
Xstatic int h, v; /* static to save board position of click on piece */
Xint h2, v2;
X
X switch (mesg)
X {
X
X case advRClick: /* first click on piece */
X
X FindBoardPos (b, &h, &v); /* find where it is */
X return (CanMove (h, v));
X
X case advXfer: /* Mouse released after dragging piece */
X
X FindBoardPos (b, &h2, &v2);
X if ( ( (h2 == h - 2 && v2 == v)
X || (h2 == h + 2 && v2 == v)
X || (h2 == h && v2 == v - 2)
X || (h2 == h && v2 == v + 2) )
X && BoardPosFilled ((h + h2) / 2, (v + v2) / 2))
X {
X UnglueGlob (board[(h + h2) / 2][(v + v2) / 2]);
X return (true);
X }
X return (false);
X
X }
X}
X
X
Xstatic DoConfiguration (item)
Xint item;
X{
X CheckItem (cnfgMenu, cnfgNo + 1, false);
X SetupBoard (configurations [cnfgNo = item-1]);
X CheckItem (cnfgMenu, cnfgNo + 1, true);
X}
X
X
Xstatic Activate (active)
XBoolean active;
X{
XLayout *l;
X
X if (active)
X {
X SetDragRects (pegPort);
X SetBCPermissions (false, true, false, false, false); /* xfer only */
X SetBCAdvisory (Advisory);
X cnfgMenu = GetMenu (pegCnfgMenuRes);
X for (l = configurations[0]; l->lName != nil; ++l)
X {
X AppendMenu (cnfgMenu, l->lName);
X }
X SkelMenu (cnfgMenu, DoConfiguration, DoMClobber);
X CheckItem (cnfgMenu, cnfgNo+1, true);
X }
X else
X {
X SkelRmveMenu (cnfgMenu);
X SetBCAdvisory (nil);
X }
X}
X
X
Xstatic Update (resized)
XBoolean resized;
X{
X DrawBlobSet (boardBlobs);
X StatusMesg (statusStr);
X}
X
X
XPegInit ()
X{
XRect r;
X
X SkelWindow (pegPort = GetDemoWind (pegWindRes),
X Mouse, /* mouse clicks */
X nil, /* key clicks */
X Update, /* updates */
X Activate, /* activate/deactivate events */
X nil, /* close window */
X DoWClobber, /* dispose of window */
X nil, /* idle proc */
X false); /* irrelevant, since no idle proc */
X
X hMid = pegPort->portRect.right / 2;
X
X/*
X Make blobs and set initial configuration to the Latin Cross, which
X is good for learning some of the problems of peg solitaire.
X*/
X InitBoard ();
X SetupBoard (configurations[cnfgNo = 7]);
X ValidRect (&pegPort->portRect);
X}
SHAR_EOF
exit