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