macintosh@felix.UUCP (01/27/87)
#!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # BMgr/BlobMgr.h # BMgr/BMgrCalcRegion.c # BMgr/BMgrClick.c # BMgr/BMgrDrag.c # BMgr/BMgrDraw.c # BMgr/BMgrFlags.c # BMgr/BMgrFreeze.c # BMgr/BMgrHideShow.c mkdir BMgr sed 's/^X//' << 'SHAR_EOF' > BMgr/BlobMgr.h X/* Blob Manager global types and constants */ X X# ifndef _BlobMgr_ X X# define _BlobMgr_ X X# ifndef _Quickdraw_ X#include <QuickDraw.h> /* brings in MacTypes.h as well */ X# endif X X# ifndef nil X# define nil 0L X# endif X X X/* blob flag masks */ X Xenum X{ X bEnableMask = 1, X bFreezeMask = 2, X bStatModeMask = 4, X bDragModeMask = 8, X bDrawModeMask = 12, /* two bits, derived: bStatModeMask + bDragModeMask */ X bNeedGlobMask = 16, X bScaleMask = 32, X bHJustMask = 192, /* two bits: 64 + 128 */ X bVJustMask = 768, /* two bits: 256 + 512 */ X bPicMask = 1024 X}; X X X/* blob drawing modes */ X Xenum X{ X normalDraw = 1, /* draw blob normally */ X dimDraw = 2 /* draw dimmed blob */ X}; X X/* blob part codes */ X Xenum X{ X inStatBlob = 1, /* static region */ X inDragBlob = 2, /* drag region */ X inFullBlob = 3 /* entire blob */ X}; X X/* X special max glue count - no limit X*/ X X# define infiniteGlue 0x8000 X X X/* X BlobClick return codes X*/ X Xenum X{ X /* 0 = nothing done */ X bcGlue = 1, /* donor blob glued to receptor */ X bcUnglue, /* glob unglued from receptor */ X bcXfer, /* glob transferred from one receptor to another */ X bcDup, /* glob duplicated from one receptor onto another */ X bcSwap /* globs of two receptors swapped */ X}; X X X/* X Messages passed by BlobClick to advisory functions X*/ X Xenum X{ X advDClick, /* click in donor */ X advRClick, /* click in receptor */ X advGlue, /* glue transaction proposed */ X advUnglue, /* unglue transaction proposed */ X advXfer, /* transfer transaction proposed */ X advDup, /* duplicate transaction proposed */ X advSwap /* swap transaction proposed */ X}; X X X/* DragGrayRgn result code for bad drag - Inside Mac is wrong! */ X X# define badDragResult 0x80008000L X X X/* X BlobRecord structure X X flags: X bit 0: 1 = enabled, 0 = disabled X bit 1: 1 = frozen, 0 = thawed (1/0) X bit 2: 1 = static region is dimmed, 0 = normal X bit 3: 1 = drag region is dimmed, 0 = normal X bit 4: 1 = need explicit match, 0 = don't X X fzflags: X bit 2: 1 = static region was dimmed before freeze, 0 = was normal X bit 3: 1 = drag region was dimmed before freeze, 0 = was normal X X*/ X Xtypedef struct BlobRecord X{ X int flags; /* flags word */ X int fzFlags; /* freeze flags word */ X union /* pic if bPicMask flag word bit set*/ X { /* proc if bit clear */ X PicHandle bPic; /* blob picture (and original frame) */ X ProcPtr bDrawProc; /* blob drawing procedure */ X } bPicProc; X RgnHandle statRgn; /* current static region */ X RgnHandle dragRgn; /* current drag region */ X Rect statRect; /* original static region frame */ X Rect dragRect; /* original drag region frame */ X int glueMax; /* maximum times can glue to others */ X int glueCount; /* number of times glued to others */ X struct MatchRecord **matches; /* set of valid matches */ X struct BlobRecord **glob; /* currently glued blob */ X long bRefCon; /* reference value */ X struct BlobRecord **nextBlob; /* next blob in set */ X} BlobRecord, *BlobPtr, **BlobHandle; X X Xtypedef struct MatchRecord X{ X BlobHandle mBlob; /* blob that matches */ X struct MatchRecord **nextMatch; /* next match record */ X} MatchRecord, *MatchPtr, **MatchHandle; X X Xtypedef struct BlobSetRecord X{ X BlobHandle firstBlob; /* first Blob of set */ X BlobHandle lastBlob; /* last Blob of set */ X struct BlobSetRecord **nextBlobSet; /* next blob set */ X} BlobSetRecord, *BlobSetPtr, **BlobSetHandle; X X X/* X Pseudo-functions X*/ X X# define FirstBlob(bSet) ((**(bSet)).firstBlob) X# define LastBlob(bSet) ((**(bSet)).lastBlob) X# define NextBlob(b) ((**(b)).nextBlob) X# define SetBRefCon(b,val) ((**(b)).bRefCon = (long) (val)) X# define GetBRefCon(b) ((long) (**(b)).bRefCon) X# define BStatBox(b) ((**((**(b)).statRgn)).rgnBBox) X# define BDragBox(b) ((**((**(b)).dragRgn)).rgnBBox) X# define BGlob(b) ((**(b)).glob) X# define FirstBMatch(b) ((**((**(b)).matches)).mBlob) X X X/* X Functions returning non-integral values X*/ X XBlobHandle GetBlobHandle (); XBlobHandle NewBlob (); XBlobSetHandle NewBlobSet (); XBoolean BlobQuiet (); XBoolean BlobSetQuiet (); XBoolean InBlobMatchSet (); Xlong DTrackBlob (); Xlong TrackBlob (); XBoolean BlobDimmed (); XBoolean BlobActive (); XBoolean BlobFrozen (); XBoolean BlobEnabled (); XBoolean CanGlue (); XBoolean PicBlob (); XRgnHandle BCalcRegion (); XBoolean BTrackMouse (); X X# endifSHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrCalcRegion.c X# include "BlobMgr.h" X X X/* X Return copy of the region corresponding to the part code. The X caller is responsible for disposing of the region that is returned. X*/ X XRgnHandle BCalcRegion (b, partCode) XBlobHandle b; Xint partCode; X{ XRgnHandle rgn; X X rgn = NewRgn (); X if (partCode == inDragBlob) X CopyRgn ((**b).dragRgn, rgn); X else X { X CopyRgn ((**b).statRgn, rgn); X if (partCode == inFullBlob) X UnionRgn ((**b).dragRgn, rgn, rgn); X } X return (rgn); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrClick.c X/* X BlobClick and support routines. BlobClick is the basic blob X transaction handler. Other routines and variables are used X to modify the way BlobClick functions. X X X unglueZoom determines whether BlobClick will zoom an outline of the X receptor drag region back to the donor when a donor is unglued X from a receptor by double-clicking. X X badDragZoom determines whether the outline of a dragged donor will X be zoomed back where it was dragged from if it's not dragged X somewhere it can be glued to. X X The permission booleans control the types of transactions that X BlobClick is allowed to perform: X X ungluePerm is true if double-clicking detaches globs from receptors. X xferPerm is true if globs can be transferred between receptors. X swapPerm is true if globs can be swapped between receptors. X dupPerm is true if globs can be duplicated onto other receptors. X replacePerm is true if transfers, swaps and duplications can cause X a receptor's glob to be replaced by another. Note that if X replacePerm is false, transfers and duplications can only be made X to empty receptors, and swaps fail altogether. X X Swaps take precedence over duplications, and both take precedence X over transfers, if two or more of these flags are on. All are X subject to the value of the replacement flag, as noted above. X X lastWhen and lastWhere are for double-click detection. X If lastWhen is set to 0, the next click will not be interpreted X as a double-click. Since that's how it's initialized, BlobClick X never mistakes the first click passed to it for a double-click. X X BlobClick only saves the click time and location when the user X clicks in a receptor blob drag region and releases the mouse without X moving it, since that's the only time a double-click is relevant. X X bcAdvise is the BlobClick filter function. If it's nil, BlobClick X does all the work itself. If bcFilter is set to the address of X some function, that function is consulted in certain circumstances X to see whether to continue processing or not. If the filter returns X false, BlobClick terminates early. X X bcResult holds the result of the last call to BlobClick. db1, X db2, rb1 and rb2 are set to indicate which blobs were involved in X any transaction that occurs (these are known as the cast (as in X cast of thousands) of the transaction). The result code and the X cast may be obtained by the host program with the BClickResult X routine, and have meanings as follows: X X Glue: db1 = donor glued, rb1 = receptor glued to, db2 = donor replaced by X db1 (nil if none), rb2 nil. X Unglue: db1 = donor unglued, rb1 = receptor unglued from, db2, rb2 nil. X Transfer: db1 = donor transferred, rb1 = source receptor, X rb2 = destination receptor, db2 = donor replaced by db1 (nil if none). X Duplication: same as transfer, except db1 = donor duplicated. X Swap: db1 = donor originally on rb1, db2 = donor originally on rb2, X rb1 = source receptor, rb2 = dest receptor. X X The result code and the cast are undefined if a filter function X causes BlobClick to terminate early. X X srcRect and dstRect are used by BlobClick and BadDrag to keep X track of how to do zoomback on bad drags. X*/ X X# include "BlobMgr.h" X X Xstatic Boolean unglueZoom = true; Xstatic Boolean badDragZoom = true; X Xstatic Boolean ungluePerm = true; Xstatic Boolean xferPerm = true; Xstatic Boolean replacePerm = true; Xstatic Boolean dupPerm = false; Xstatic Boolean swapPerm = true; X X Xstatic long lastWhen = 0L; Xstatic Point lastWhere; X Xstatic Boolean (*bcAdvise)() = nil; X Xstatic int bcResult; Xstatic BlobHandle db1; Xstatic BlobHandle db2; Xstatic BlobHandle rb1; Xstatic BlobHandle rb2; X Xstatic Rect srcRect, dstRect; X X X/* X Set or get the flags determining zoomback behavior on bad drags X and unglue transactions X*/ X XSetBCZoomFlags (uGlueZoom, bDragZoom) XBoolean uGlueZoom, bDragZoom; X{ X unglueZoom = uGlueZoom; X badDragZoom = bDragZoom; X} X X XGetBCZoomFlags (uGlueZoom, bDragZoom) XBoolean *uGlueZoom, *bDragZoom; X{ X *uGlueZoom = unglueZoom; X *bDragZoom = badDragZoom; X} X X X/* X Set or get the flags determining transaction permissions X*/ X XSetBCPermissions (canUnglue, canXfer, canDup, canSwap, canRep) XBoolean canUnglue, canXfer, canDup, canSwap, canRep; X{ X ungluePerm = canUnglue; X xferPerm = canXfer; X dupPerm = canDup; X swapPerm = canSwap; X replacePerm = canRep; X} X X XGetBCPermissions (canUnglue, canXfer, canDup, canSwap, canRep) XBoolean *canUnglue, *canXfer, *canDup, *canSwap, *canRep; X{ X *canUnglue = ungluePerm; X *canXfer = xferPerm; X *canDup = dupPerm; X *canSwap = swapPerm; X *canRep = replacePerm; X} X X X/* X Set or get the address of the BlobClick advisory filter routine. X Pass nil to SetBCFilter to turn the filter off. X*/ X XSetBCAdvisory (p) XBoolean (*p)(); X{ X bcAdvise = p; X} X X XGetBCAdvisory (p) XBoolean (**p)(); X{ X *p = bcAdvise; X} X X X/* X FindReceptor is called with the point at which the mouse was released X after a donor or a receptor's glob was dragged. It returns true if X the mouse was released in a receptor that has an undimmed drag region X and either (i) has no glob, or (ii) has a glob but replacement X permission is on. Otherwise it returns false. X*/ X Xstatic Boolean FindReceptor (thePoint, rSet, r) XPoint thePoint; /* point at which mouse released */ XBlobSetHandle rSet; /* receptor set */ XBlobHandle *r; /* return receptor hit in this */ X{ X return (FindBlob (thePoint, rSet, r) X && GetBDrawMode (*r, inDragBlob) == normalDraw X && (BGlob (*r) == nil || replacePerm)); X} X X X/* X BlobClick blob transaction handler X*/ X XBlobClick (thePt, t, dSet, rSet) XPoint thePt; Xlong t; XBlobSetHandle dSet, rSet; X{ XBlobHandle d, r1, r2; XPoint thePoint; Xregister long dragDelta; Xregister Boolean badDrag = true; /* assume the worst */ X X thePoint = thePt; /* do setup: make local copy of point */ X bcResult = 0; /* and initialize status variables */ X db1 = db2 = rb1 = rb2 = nil; X X/* X Check for double-click if unglue permission is on. If so and both X clicks were in drag region of a non-dim receptor that has a glob X glued to it, unglue the glob. (Note that the hit-tests only work X if the blob is not dimmed - which is as things should be.) X*/ X if (ungluePerm && t - lastWhen <= GetDblTime ()) X { X if (rSet != nil X && FindBlob (thePoint, rSet, &r1) == inDragBlob X && TestBlob (r1, lastWhere) == inDragBlob) X { X if (bcAdvise == nil || (*bcAdvise) (advUnglue, r1)) X { X db1 = BGlob (r1); X rb1 = r1; X bcResult = bcUnglue; X X if (unglueZoom) X ZUnglueGlob (r1); X else X UnglueGlob (r1); X } X } X lastWhen = 0L; X return; X } X X lastWhen = 0L; X X/* X See if the mouse was clicked in a donor blob. If so, drag an X outline around. If the dragged outline ends up somewhere it X can be glued to, do so, else zoom the outline back if appropriate. X*/ X X if (dSet != nil && FindBlob (thePoint, dSet, &d) == inDragBlob) X { X if (bcAdvise != nil && (*bcAdvise) (advDClick, d) == false) X return; /* advisory says "quit" */ X X dragDelta = DTrackBlob (d, inDragBlob, thePoint); X if (dragDelta != badDragResult && dragDelta != 0) X { X thePoint.h += LoWord (dragDelta); X thePoint.v += HiWord (dragDelta); X srcRect = dstRect = BDragBox (d); X OffsetRect (&dstRect, LoWord (dragDelta), HiWord (dragDelta)); X if (rSet != nil && FindReceptor (thePoint, rSet, &r1)) X { X if (bcAdvise == nil || (*bcAdvise) (advGlue, r1)) X { X db1 = d; X db2 = BGlob (r1); X rb1 = r1; X bcResult = bcGlue; X GlueGlob (d, r1); X badDrag = false; X } X } X if (badDrag && badDragZoom) X ZoomRect (&dstRect, &srcRect); X } X } X X/* X Mouse was not clicked in a donor. If it was clicked in a receptor, X a glob may have been dragged back to the donor, or to another X receptor, so get ready to process possible unglue or inter-receptor X transaction. Can quit early if no receptor set was given X (rSet = nil) or no inter-receptor or unglue transactions are allowed. X*/ X else if (rSet != nil && (ungluePerm || xferPerm || swapPerm || dupPerm)) X { X if (FindBlob (thePoint, rSet, &r1) == inDragBlob && BGlob (r1) != nil) X { X if (bcAdvise != nil && (*bcAdvise) (advRClick, r1) == false) X return; /* advisory says "quit" */ X X/* X If the mouse is released without being moved, then save the click X info, since it might be the first click of a double-click. There's X no need to check any further for a possible transaction since the X glob wasn't dragged anywhere. X*/ X if ((dragDelta = DTrackBlob (r1, inDragBlob, thePoint)) == 0L) X { X lastWhen = t; /* save click info for possible */ X lastWhere = thePt; /* double-click next time */ X } X else if (dragDelta != badDragResult) X { X thePoint.h += LoWord (dragDelta); X thePoint.v += HiWord (dragDelta); X X/* X Was the glob dragged back to it's owner? If so, unglue it if X unglue permission is on. Can't use TestBlob, 'cause that'll X be false if the donor is dimmed. X*/ X d = BGlob (r1); X if (ungluePerm && BlobActive (d) X && (PtInRgn (thePoint, (**d).dragRgn) X || PtInRgn (thePoint, (**d).statRgn))) X { X if (bcAdvise == nil || (*bcAdvise) (advUnglue, r1)) X { X db1 = d; X rb1 = r1; X bcResult = bcUnglue; X UnglueGlob (r1); /* no zooming */ X } X return; X } X X srcRect = dstRect = BDragBox (r1); X OffsetRect (&dstRect, LoWord (dragDelta), HiWord (dragDelta)); X X if (FindReceptor (thePoint, rSet, &r2) && r1 != r2) X { X X /* X Now know where the glob was dragged, so possibly have some kind X of inter-receptor transaction. If replaces aren't allowed, then X don't continue unless the receptor that was dragged to has no glob. X Otherwise do whichever of swapping, duplicating or transferring is X allowed. Precedence is in that order if more than one of them is X allowed. X */ X rb1 = r1; /* set cast now, but they */ X rb2 = r2; /* won't be meaningful if */ X db1 = BGlob (r1); /* no transaction is performed */ X db2 = BGlob (r2); X if (db2 != nil && swapPerm) X { X if (bcAdvise == nil || (*bcAdvise) (advSwap, r2)) X { X SwapGlob (r1, r2); X bcResult = bcSwap; X badDrag = false; X } X } X else if (dupPerm) X { X if (CanGlue (db1)) X { X if (bcAdvise == nil || (*bcAdvise) (advDup, r2)) X { X DupGlob (r1, r2); /* duplicate blob */ X bcResult = bcDup; X badDrag = false; X } X } X } X else if (xferPerm) X { X if (bcAdvise == nil || (*bcAdvise) (advXfer, r2)) X { X TransferGlob (r1, r2); /* transfer blob */ X bcResult = bcXfer; X badDrag = false; X } X } X } X if (badDrag && badDragZoom) X ZoomRect (&dstRect, &srcRect); X } X } X } X} X X X/* X Result result code of last call to BlobClick. X*/ X XBClickResult () X{ X return (bcResult); X} X X X/* X Result cast of characters involved in last call to BlobClick. X*/ X XBClickCast (d1, d2, r1, r2) XBlobHandle *d1, *d2, *r1, *r2; X{ X *d1 = db1; X *d2 = db2; X *r1 = rb1; X *r2 = rb2; X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrDrag.c X# include <WindowMgr.h> X# include "BlobMgr.h" X X X/* -------------------------------------------------------------------- */ X/* Blob Tracking and Dragging Routines */ X/* -------------------------------------------------------------------- */ X X X/* X Blob dragging variables. See discussion of DragGrayRgn in X the WIndow Manager section of Inside Mac. The defaults for the X limit and slop rects are inappropriate and really should be set X by the application. X*/ X XRect blobLimitRect = { -30000, -30000, 30000, 30000 }; XRect blobSlopRect = { -30000, -30000, 30000, 30000 }; Xint blobAxis = noConstraint; X X X/* Set blob dragging limit and slop rectangles */ X XSetBDragRects (limitRect, slopRect) XRect *limitRect, *slopRect; X{ X blobLimitRect = *limitRect; X blobSlopRect = *slopRect; X} X X X/* get current blob dragging limit and slop rectangles */ X XGetBDragRects (limitRect, slopRect) XRect *limitRect, *slopRect; X{ X *limitRect = blobLimitRect; X *slopRect = blobSlopRect; X} X X X/* Set blob dragging axis constraints */ X XSetBDragAxis (axis) Xint axis; X{ X blobAxis = axis; X} X X X/* Get current blob dragging axis constraints */ X XGetBDragAxis () X{ X return (blobAxis); X} X X X/* X Track blob by dragging an outline of the indicated part around X until the mouse button is released. Return the difference between X the starting and ending x and y coordinates in the low and high X order words of the result. X*/ X X Xlong TrackBlob (b, partCode, startPoint, limitRect, slopRect, axis) XBlobHandle b; Xint partCode; XPoint startPoint; XRect *limitRect, *slopRect; Xint axis; X{ XRgnHandle rgn; XRect limit, bounds; Xlong result; X X rgn = BCalcRegion (b, partCode); X/* X adjust the limit rectangle so the outline of the dragged regiopn X always fits completely within the bounds rectangle X*/ X limit = *limitRect; X bounds = (**rgn).rgnBBox; X limit.left += startPoint.h - bounds.left; X limit.top += startPoint.v - bounds.top; X limit.right -= bounds.right - startPoint.h - 1; X limit.bottom -= bounds.bottom - startPoint.v - 1; X X result = DragGrayRgn (rgn, startPoint, &limit, slopRect, axis, nil); X DisposeRgn (rgn); X return (result); X} X X X/* X Track a blob, using the default limit and slop rects X*/ X Xlong DTrackBlob (b, partCode, startPoint) XBlobHandle b; Xint partCode; XPoint startPoint; X{ X X return (TrackBlob (b, partCode, startPoint, X &blobLimitRect, &blobSlopRect, blobAxis)); X} X X X/* X Drag a blob by tracking it, and then moving it to the point X where the mouse button was released. X*/ X XDragBlob (b, startPoint, limitRect, slopRect, axis) XBlobHandle b; XPoint startPoint; XRect *limitRect, *slopRect; Xint axis; X{ Xlong result; X X result = TrackBlob (b, inFullBlob, startPoint, X limitRect, slopRect, axis); X X if ((result != badDragResult) && (result != 0)) X OffsetBlob (b, inFullBlob, LoWord (result), HiWord (result)); X} X X XDDragBlob (b, startPoint) XBlobHandle b; XPoint startPoint; X{ X DragBlob (b, startPoint, &blobLimitRect, &blobSlopRect, blobAxis); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrDraw.c X/* --------------------------------------------------------------------- */ X/* Blob Manager Low-level Drawing Routines */ X/* --------------------------------------------------------------------- */ X X# include "BlobMgr.h" X X X X/* X Blob dimming parameters. dimPat and dimMode are the pattern and X drawing mode used to dim out blobs. The initial pattern is gray. X*/ X Xstatic Pattern dimPat = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }; Xstatic int dimMode = patBic; X Xstatic RgnHandle oldClipRgn; X X X/* X Set or get the pattern to be used to dim blobs X*/ X XSetBDimInfo (p, mode) XPattern *p; Xint mode; X{ X BlockMove (p, &dimPat, sizeof (Pattern)); X dimMode = mode; X} X XGetBDimInfo (p, mode) XPattern *p; Xint *mode; X{ X BlockMove (&dimPat, p, sizeof (Pattern)); X *mode = dimMode; X} X X X/* X Set the clipping to the given region of the given blob. Return X a handle to the region, or nil if the region is empty and doesn't X need to be drawn. The handle should not be disposed of by the X caller - it's a copy of the handle, not a copy of the region. X If the handle returned is not nil, call RestoreDrawClip after doing X the drawing to restore the clipping properly. X*/ X Xstatic RgnHandle SetDrawClip (b, partCode) XBlobHandle b; Xint partCode; X{ Xregister RgnHandle drawRgn, newClipRgn; X X drawRgn = (partCode == inDragBlob ? (**b).dragRgn : (**b).statRgn); X if (EmptyRgn (drawRgn)) /* don't bother if fail here! */ X return (nil); X X oldClipRgn = NewRgn (); X newClipRgn = NewRgn (); X GetClip (oldClipRgn); X SectRgn (drawRgn, oldClipRgn, newClipRgn); X SetClip (newClipRgn); X DisposeRgn (newClipRgn); X return (drawRgn); X} X X Xstatic RestoreDrawClip () X{ X SetClip (oldClipRgn); /* restore original clipping */ X DisposeRgn (oldClipRgn); X} X X X/* X Dim the given region. X*/ X Xstatic DimRgn (rgn) XRgnHandle rgn; X{ XPenState ps; X X GetPenState (&ps); /* save current pen state */ X PenPat (dimPat); X PenMode (dimMode); X PaintRgn (rgn); X SetPenState (&ps); /* restore pen state */ X} X X X/* X Given a picture and a rectangle corresponding to a portion of the picture X frame DrawBlobPic draws the picture in the given part of the given blob, X accounting for size and location differences. Any portion of sRect X lying outside of the picture's frame will not be drawn. X The partCode must be inDragBlob or inFullBlob. X X The drawing is clipped to the region the be drawn X (respecting current clipping). X*/ X Xstatic DrawBlobPic (b, partCode, p, srcRect) XBlobHandle b; Xint partCode; XPicHandle p; XRect *srcRect; X X{ Xregister RgnHandle rgn; XRect dstRect, pFrame; X X rgn = SetDrawClip (b, partCode); X if (p != nil && rgn != nil) /* don't bother if fail here! */ X { X pFrame = (**p).picFrame; /* map frame to correct size */ X dstRect = (**rgn).rgnBBox; /* and location in relation */ X MapRect (&pFrame, srcRect, &dstRect); /* to region to be drawn */ X DrawPicture (p, &pFrame); X if (GetBDrawMode (b, partCode) == dimDraw) /* region is dimmed */ X DimRgn (rgn); X } X if (rgn != nil) X RestoreDrawClip (); /* restore original clipping */ X} X X X/* X Draw a blob using a drawing procedure. bDst is the blob to be drawn, X partCode specifies the region of bDst to draw (either inDragBlob or X inStatBlob). bSrc is the blob whose region is to be drawn in the X specified region of bDst, and proc is the drawing procedure to use. X bSrc is different than bDst if partCode is inDragBlob and bDst has X a glob. X*/ X Xstatic CallBDrawProc (bDst, bSrc, proc, partCode) XBlobHandle bDst, bSrc; XProcPtr proc; Xint partCode; X{ Xregister RgnHandle rgn; X X rgn = SetDrawClip (bDst, partCode); X if (proc != nil && rgn != nil) X { X (*proc) (bDst, bSrc, partCode); X if (GetBDrawMode (bDst, partCode) == dimDraw) /* region is dimmed */ X DimRgn (rgn); X } X if (rgn != nil) X RestoreDrawClip (); /* restore original clipping */ X} X X X/* X DrawBlob draws the indicated part of the blob (the entire blob X if partCode is inFullBlob). X X The blob must be enabled. If draw mode is dimDraw then draw X it dimmed. X*/ X X XDrawBlob (b, partCode) XBlobHandle b; Xint partCode; X X{ Xregister BlobHandle b2; Xregister PicHandle pic; XRect srcFrame; X X if (BlobEnabled (b)) X { X if ((partCode == inStatBlob) || (partCode == inFullBlob)) X { X if (PicBlob (b)) X { X srcFrame = (**b).statRect; X DrawBlobPic (b, inStatBlob, (**b).bPicProc.bPic, &srcFrame); X } X else X CallBDrawProc (b, b, (**b).bPicProc.bDrawProc, inStatBlob); X } X X if ((partCode == inDragBlob) || (partCode == inFullBlob)) X { X /* X Set b2 to the blob that should have it's drag region drawn X in b's drag region. If b has no glob, then it's b. X */ X if ((b2 = BGlob (b)) == nil) X b2 = b; X if (PicBlob (b2)) X { X pic = (**b2).bPicProc.bPic; /* picture to draw */ X srcFrame = (**b2).dragRect; /* part of picture to draw */ X DrawBlobPic (b, inDragBlob, pic, &srcFrame); X } X else X CallBDrawProc (b, b2, (**b2).bPicProc.bDrawProc, inDragBlob); X } X } X} X X XDrawBlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc2 (&DrawBlob, bSet, inFullBlob); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrFlags.c X# include "BlobMgr.h" X X X/* -------------------------------------------------------------------- */ X/* Blob Flag Manipulation Routines */ X/* */ X/* These routines operate only on the content of the blob state fields.*/ X/* They do NOT do any redrawing or change the display in any way. */ X/* */ X/* -------------------------------------------------------------------- */ X X XSetBlobFlags (b, bitMask) XBlobHandle b; Xint bitMask; X{ X (**b).flags |= bitMask; X} X X XClearBlobFlags (b, bitMask) XBlobHandle b; Xint bitMask; X{ X (**b).flags &= ~bitMask; /* what's the operator here? */ X} X X X/* X Test the function result to be sure it's equal to the bitMask X passed in, if exact match is required. X*/ X XTestBlobFlags (b, bitMask) XBlobHandle b; Xint bitMask; X{ X return ((**b).flags & bitMask); X} X X XEnableBlob (b) XBlobHandle b; X{ X SetBlobFlags (b, bEnableMask); X} X X XEnableBlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&EnableBlob, bSet); X} X X XDisableBlob (b) XBlobHandle b; X{ X ClearBlobFlags (b, bEnableMask); X} X X XDisableBlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&DisableBlob, bSet); X} X X X XGetBDrawMode (b, partCode) XBlobHandle b; Xint partCode; X{ Xint mask; X X mask = 0; X switch (partCode) X { X case inDragBlob: mask = bDragModeMask; break; X case inStatBlob: mask = bStatModeMask; break; X } X return (TestBlobFlags (b, mask) == mask ? dimDraw : normalDraw); X} X X XSetBDrawMode (b, partCode, mode) XBlobHandle b; Xint partCode; Xint mode; X{ Xint mask; X X switch (partCode) X { X case inFullBlob: mask = bDrawModeMask; break; X case inDragBlob: mask = bDragModeMask; break; X case inStatBlob: mask = bStatModeMask; break; X } X if (mode == dimDraw) X SetBlobFlags (b, mask); X else X ClearBlobFlags (b, mask); X} X X XGetFzBDrawMode (b, partCode) XBlobHandle b; Xint partCode; X{ Xint mask; X X mask = 0; X switch (partCode) X { X case inDragBlob: mask = bDragModeMask; break; X case inStatBlob: mask = bStatModeMask; break; X } X return (((**b).fzFlags & mask) == mask ? dimDraw : normalDraw); X} X X X XBoolean BlobDimmed (b, partCode) XBlobHandle b; Xint partCode; X{ Xint bitMask; X X switch (partCode) X { X case inFullBlob: bitMask = bDrawModeMask; break; X case inStatBlob: bitMask = bStatModeMask; break; X case inDragBlob: bitMask = bDragModeMask; break; X } X return (TestBlobFlags (b, bitMask) == bitMask); X} X X XBoolean BlobEnabled (b) XBlobHandle b; X{ X return (TestBlobFlags (b, bEnableMask) == bEnableMask); X} X X XBoolean BlobFrozen (b) XBlobHandle b; X{ X return (TestBlobFlags (b, bFreezeMask) == bFreezeMask); X} X X X/* X Active = enabled, but not frozen. X*/ X XBoolean BlobActive (b) XBlobHandle b; X{ X return (TestBlobFlags (b, bEnableMask | bFreezeMask) == bEnableMask); X} X X X/* X Return true if the blob can be glued to another blob. This is true X if the blob is infinitely gluable or the current glue count is less X than the blob's maximum glue count. X*/ X XBoolean CanGlue (b) XBlobHandle b; X{ Xint glueMax; X X glueMax = GetBGlueMax (b); X return (glueMax == infiniteGlue || glueMax > (**b).glueCount); X} X X X/* X Return true if the blob is a picture blob, false if it's a X procedure blob X*/ X XBoolean PicBlob (b) XBlobHandle b; X{ X return (TestBlobFlags (b, bPicMask) == bPicMask); X}SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrFreeze.c X# include "BlobMgr.h" X X XFreezeBlob (b) XBlobHandle b; X{ X if (!BlobFrozen (b)) X { X SetBlobFlags (b, bFreezeMask); X (**b).fzFlags = ((**b).flags & (bDrawModeMask)); X } X} X X XFreezeBlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&FreezeBlob, bSet); X} X X XThawBlob (b) XBlobHandle b; X{ X if (BlobFrozen (b)) X { X ClearBlobFlags (b, bFreezeMask); /* unfreeze blob */ X HiliteBlob (b, inStatBlob, GetFzBDrawMode (b, inStatBlob)); X HiliteBlob (b, inDragBlob, GetFzBDrawMode (b, inDragBlob)); X } X} X X XThawBlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&ThawBlob, bSet); X} X X X/* X Display enabled quiet blobs with drawing mode quietMode, display X enabled noisy blobs with drawing mode noisyMode. Freezes all enabled X blobs, so should be balanced with a call to ThawBlobs. X*/ X X XBlobFeedback (bSet, quietMode, noisyMode) XBlobSetHandle bSet; Xint quietMode, noisyMode; X{ XBlobHandle b; X X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X { X FreezeBlob (b); X HiliteBlob (b, inFullBlob, (BlobQuiet (b) ? quietMode : noisyMode)); X } X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrHideShow.c X# include "BlobMgr.h" X X X X/* X If blob not already hidden, hide it by filling both the bounds X box of each region with current grafport's background pattern, X and accumulate the boxes into the update region. X*/ X XHideBlob (b) XBlobHandle b; X{ XGrafPtr thePort; XRect r; X X if (BlobEnabled (b)) /* ignore if already disabled */ X { X DisableBlob (b); X GetPort (&thePort); X X r = BStatBox (b); X FillRect (&r, &thePort->bkPat); X InvalRect (&r); X X r = BDragBox (b); X FillRect (&r, &thePort->bkPat); X InvalRect (&r); X } X} X X XHideBlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&HideBlob, bSet); X} X X X/* X If blob is not already enabled, show it. X*/ X XShowBlob (b) XBlobHandle b; X{ X if (BlobEnabled (b) == false) /* ignore if already enabled */ X { X EnableBlob (b); X DrawBlob (b, inFullBlob); X } X} X X XShowBlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&ShowBlob, bSet); X} SHAR_EOF exit
macintosh@felix.UUCP (01/28/87)
References: #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # BMgr/BMgrHilite.c # BMgr/BMgrHitTest.c # BMgr/BMgrIndex.c # BMgr/BMgrLoop.c # BMgr/BMgrMatch.c # BMgr/BMgrMove.c # BMgr/BMgrNew.c # BMgr/BMgrPict.c # BMgr/BMgrRand.c # BMgr/BMgrSetProc.c # BMgr/BMgrSetRgns.c # BMgr/BMgrShuffle.c # BMgr/BMgrTrackMouse.c # BMgr/BMgrTrans.c # BMgr/BMgrZTrans.c # BMgr/BMgrZoom.c mkdir BMgr sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrHilite.c X# include "BlobMgr.h" X X X/* -------------------------------------------------------------------- */ X/* Blob State Change Display Routines */ X/* -------------------------------------------------------------------- */ X X X X/* X Set the drawing mode for the given part of the blob. X Redraw if it changes. X*/ X XHiliteBlob (b, partCode, mode) XBlobHandle b; Xint partCode; Xint mode; X{ X X if ((partCode == inDragBlob) || (partCode == inFullBlob)) X { X if (GetBDrawMode (b, inDragBlob) != mode) X { X SetBDrawMode (b, inDragBlob, mode); X DrawBlob (b, inDragBlob); X } X } X if ((partCode == inStatBlob) || (partCode == inFullBlob)) X { X if (GetBDrawMode (b, inStatBlob) != mode) X { X SetBDrawMode (b, inStatBlob, mode); X DrawBlob (b, inStatBlob); X } X } X} X X XHiliteBlobSet (bSet, partCode, mode) XBlobSetHandle bSet; Xint partCode; Xint mode; X X{ Xregister BlobHandle b; X X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X { X HiliteBlob (b, partCode, mode); X } X} X X X/* X Increment use count of blob and dim drag area if at or above maximum X glue count. X*/ X XIncBlobGlue (b) XBlobHandle b; X{ X if ((**b).glueMax != infiniteGlue) X { X ++((**b).glueCount); X if ((**b).glueCount >= (**b).glueMax) X HiliteBlob (b, inDragBlob, dimDraw); X } X} X X X/* X Decrement use count of blob and undim drag area if less than maximum X glue count. X*/ X XDecBlobGlue (b) XBlobHandle b; X{ X if ((**b).glueMax != infiniteGlue) X { X --((**b).glueCount); X if ((**b).glueCount < (**b).glueMax) X HiliteBlob (b, inDragBlob, normalDraw); X } X} X X XSetBGlueMax (b, max) XBlobHandle b; Xint max; X{ X (**b).glueMax = max; X X/* dim or undim appropriately */ X X if ((**b).glueCount < max || max == infiniteGlue) X HiliteBlob (b, inDragBlob, normalDraw); X else X HiliteBlob (b, inDragBlob, dimDraw); X} X X XGetBGlueMax (b) XBlobHandle b; X{ X return ((**b).glueMax); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrHitTest.c X# include "BlobMgr.h" X X X X X/* -------------------------------------------------------------------- */ X/* Blob Hit Testing Routines */ X/* -------------------------------------------------------------------- */ X X X/* X Test whether the blob contains the point, and if so, return a part X of the part of the blob that the point is in. Does not consider X dimmed parts of blobs. Blob must be active (enabled, not frozen). X Return zero if no hit. X*/ X XTestBlob (b, thePoint) XBlobHandle b; XPoint thePoint; X{ Xint result; X X result = 0; X if (BlobActive (b)) X { X if (!BlobDimmed (b, inDragBlob) && PtInRgn (thePoint, (**b).dragRgn)) X result = inDragBlob; X else if (!BlobDimmed (b, inStatBlob) X && PtInRgn (thePoint, (**b).statRgn)) X result = inStatBlob; X } X return (result); X} X X X/* X If the point is in an undimmed region of any active blob of the set, X return a handle to the blob in b and the part code as the function X result. X*/ X XFindBlob (thePoint, bSet, bPtr) XPoint thePoint; XBlobSetHandle bSet; XBlobHandle *bPtr; /* pointer to blobhandle */ X X{ XBlobHandle b; Xint partCode; Xint result; X X result = 0; X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X { X partCode = TestBlob (b, thePoint); X if (partCode != 0) X { X result = partCode; X *bPtr = b; X break; X } X } X return (result); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrIndex.c X# include "BlobMgr.h" X X X/* X Get the handle of the (i)th blob in the list. The first X blob is numbered 0. X*/ X XBlobHandle GetBlobHandle (bSet, i) XBlobSetHandle bSet; Xint i; X{ Xregister BlobHandle b; X X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X { X --i; X if (i < 0) break; /* found it */ X } X return (b); X} X X X/* X Get the index of the given blob in the list, given its handle. X The blob is assumed to be in the set. Returns a number from X 0 to BlobSetSize (bSet)-1. X*/ X XGetBlobIndex (b, bSet) XBlobHandle b; XBlobSetHandle bSet; X{ Xregister BlobHandle b2; Xregister int i; X X i = 0; X for (b2 = FirstBlob (bSet); b2 != nil; b2 = NextBlob (b2)) X { X if (b == b2) break; /* found it */ X ++i; X } X return (i); X} X X XBlobSetSize (bSet) XBlobSetHandle bSet; X{ Xregister BlobHandle b; Xregister int i; X X for (i = 0, b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X { X ++i; X } X return (i); X}SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrLoop.c X# include "BlobMgr.h" X X X/* -------------------------------------------------------------------- */ X/* Blob Loop Routines */ X/* */ X/* These routines loop through the given blob set, calling the given */ X/* procedure for every element of the set. */ X/* -------------------------------------------------------------------- */ X X XBlobLoopProc1 (p, bSet) XProcPtr p; XBlobSetHandle bSet; X{ Xregister BlobHandle b; X X if (bSet != nil) X { X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X (*p) (b); X } X} X X XBlobLoopProc2 (p, bSet, partCode) XProcPtr p; XBlobSetHandle bSet; Xint partCode; X{ Xregister BlobHandle b; X X if (bSet != nil) X { X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X (*p) (b, partCode); X } X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrMatch.c X# include "BlobMgr.h" X X X/* -------------------------------------------------------------------- */ X/* Blob Match Testing Operations */ X/* -------------------------------------------------------------------- */ X X X/* X Return true if b1 is in b2's match set. X*/ X XBoolean InBlobMatchSet (b1, b2) XBlobHandle b1, b2; X{ XMatchHandle m; XBoolean result; X X result = false; X for (m = (**b2).matches; m != nil; m = (**m).nextMatch) X { X if ((**m).mBlob == b1) X { X result = true; /* found it */ X break; X } X } X return (result); X} X X X/* X Default quiet test procedure. X X A blob requiring an explicit match is quiet if it has a glob and X the glob is a member of the match set, or, if the match set is X empty, it has no glob. A blob not requiring an X explicit match is quiet if it has an explicit match, or if it X has a glob but an empty match set, or if it has no glob. X X Otherwise the blob is noisy. X*/ X Xstatic Boolean DefaultQuietTest (b) XBlobHandle b; X{ XBlobHandle g; XBoolean needGlob; XBoolean result; X X g = (**b).glob; X needGlob = (TestBlobFlags (b, bNeedGlobMask) != 0); X/* X if the blob has no glob, it is matched if it's a non-explicit X blob. If it's an explicit blob, it's matched if the match set X is empty. X*/ X if (g == nil) X result = (needGlob ? (**b).matches == nil : true); X else /* has a glob - is it ok? */ X { X/* X if the blob doesn't need a glob but has one, then it's still X quiet if the match set is empty ("any glob will do"). X*/ X if (!needGlob && ((**b).matches == nil)) X result = true; X else X result = InBlobMatchSet (g, b); /* see if in match set */ X } X return (result); X} X X Xstatic Boolean (*bQuietTest) () = DefaultQuietTest; X X XBoolean BlobQuiet (b) XBlobHandle b; X{ X return ((*bQuietTest) (b)); X} X X X/* X Install quiet test function for BlobQuiet. Pass nil to restore X default. X*/ X XSetBQuietTest (f) XBoolean (*f)(); X{ X bQuietTest = (f == nil ? DefaultQuietTest : f); X} X X XBoolean BlobSetQuiet (bSet) XBlobSetHandle bSet; X{ XBlobHandle b; XBoolean result; X X result = true; X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X { X if (!BlobQuiet (b)) X { X result = false; X break; X } X } X return (result); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrMove.c X# include "BlobMgr.h" X X X/* -------------------------------------------------------------------- */ X/* Blob Movement Operations */ X/* -------------------------------------------------------------------- */ X X X/* X Offset a blob or part of a blob by (hoff, voff). If the blob is enabled, X hide it and redraw at the new location. X*/ X XOffsetBlob (b, partCode, hoff, voff) XBlobHandle b; Xint partCode, hoff, voff; X{ XBoolean vis; X X if ((hoff == 0) && (voff == 0)) return; /* avoid unnecessary redraw */ X X vis = false; X if (BlobEnabled (b)) X { X vis = true; X HideBlob (b); X } X X if ((partCode == inDragBlob) || (partCode == inFullBlob)) X OffsetRgn ((**b).dragRgn, hoff, voff); X if ((partCode == inStatBlob) || (partCode == inFullBlob)) X OffsetRgn ((**b).statRgn, hoff, voff); X X if (vis) X ShowBlob (b); X} X X X/* X Move a blob or part of a blob to (h, v). If the blob is enabled, X hide it and redraw at the new location. If partCode is inDragBlob X or inStatBlob, move the appropriate region to the location. If X inFullBlob, move both regions in synchrony so static region is at X given location, drag region is at same location relative to the X static region as it was before. X*/ X XMoveBlob (b, partCode, h, v) XBlobHandle b; Xint partCode, h, v; X{ X if (partCode == inDragBlob) X { X h -= (**((**b).dragRgn)).rgnBBox.left; /* convert to offsets */ X v -= (**((**b).dragRgn)).rgnBBox.top; X } X else /* it's inStatBlob or inFullBLob */ X { X h -= (**((**b).statRgn)).rgnBBox.left; X v -= (**((**b).statRgn)).rgnBBox.top; X } X OffsetBlob (b, partCode, h, v); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrNew.c X# include "BlobMgr.h" X X X X# define New(x) (x **) NewHandle ((Size) sizeof (x)) X X/* X Handle to list of all existing blob sets - empty initially X*/ X Xstatic BlobSetHandle blobSetMaster = nil; X X X/* ---------------------------------------------------------------------- */ X/* Object Creation Routines */ X/* ---------------------------------------------------------------------- */ X X X XNewBlobMatch (b1, b2) XBlobHandle b1, b2; X{ XMatchHandle m; X X m = New (MatchRecord); X if (m != nil) X { X (**m).mBlob = b1; X (**m).nextMatch = (**b2).matches; X (**b2).matches = m; X } X} X X X/* Add a blob to (the END of) a blob set */ X XAddBlob (b, bSet) XBlobHandle b; XBlobSetHandle bSet; X{ X X if (FirstBlob (bSet) == nil) X { X FirstBlob (bSet) = b; X LastBlob (bSet) = b; X } X else X { X NextBlob (LastBlob (bSet)) = b; X LastBlob (bSet) = b; X } X NextBlob (b) = nil; X} X X X/* X Create a new blob, adding it to the given set. The blob is enabled X or not according to the enable parameter. The blob is given empty X static and drag regions and rectangles, nil picture, match set, and X glob handles. The drawing modes are set according to statDraw X and dragDraw. The blob is set to be single-use or not by the X glueMax parameter. mustMatch determines whether the blob must X have a glue blob to be matched. The refCon is installed in the X record. X*/ X XBlobHandle NewBlob (bSet, /* set to add blob to */ X enable, /* whether blob is enabled or not */ X glueMVal, /* maximum glue count */ X mustMatch, /* whether must have glob to be matched */ X refCon) /* reference constant */ X XBlobSetHandle bSet; XBoolean enable; Xint glueMVal; XBoolean mustMatch; Xlong refCon; X{ XBlobHandle bHand; XBlobPtr b; XRect r; X X bHand = New (BlobRecord); X if (bHand != nil) X { X AddBlob (bHand, bSet); /* sets nextBlob field */ X b = *bHand; X b->flags = 0 | bPicMask; /* clear flags, then set appropriate fields */ X if (enable) X EnableBlob (bHand); X if (mustMatch) X SetBlobFlags (bHand, bNeedGlobMask); X b->bPicProc.bPic = nil; /* no picture or drawing proc */ X SetRect (&r, 0, 0, 0, 0); X b->statRect = r; /* empty rects */ X b->dragRect = r; X b->statRgn = NewRgn (); /* empty regions */ X b->dragRgn = NewRgn (); X b->glueMax = glueMVal; X b->glueCount = 0; X b->glob = nil; X b->matches = nil; X b->bRefCon = refCon; X X } X X return (bHand); X} X X X/* X Create a new, empty blob set. Add it to the master blob set list. X Return a handle to it. X*/ X XBlobSetHandle NewBlobSet () X{ XBlobSetHandle bSet; X X bSet = New (BlobSetRecord); X if (bSet != nil) X { X FirstBlob (bSet) = nil; /* initialize to empty set */ X LastBlob (bSet) = nil; X (**bSet).nextBlobSet = blobSetMaster; /* add to master list */ X blobSetMaster = bSet; X } X X return (bSet); X} X X X/* ---------------------------------------------------------------------- */ X/* Object Disposal Routines */ X/* ---------------------------------------------------------------------- */ X X XDisposeBlobPic (b) XBlobHandle b; X{ X if (PicBlob (b) && (**b).bPicProc.bPic != nil) X { X KillPicture ((**b).bPicProc.bPic); X (**b).bPicProc.bPic = nil; X } X} X X XDisposeBlobMatchSet (b) XBlobHandle b; X{ XMatchHandle m1, m2; X X m1 = (**b).matches; X (**b).matches = nil; X for (;;) X { X if (m1 == nil) return; X m2 = (**m1).nextMatch; X DisposHandle (m1); X m1 = m2; X } X} X X XDisposeBlob (b) XBlobHandle b; X{ X DisposeRgn ((**b).statRgn); X DisposeRgn ((**b).dragRgn); X DisposeBlobPic (b); X DisposeBlobMatchSet (b); X DisposHandle (b); X} X X X/* X Remove blob set from the master blob set list, then dispose of X everything in the list. All handles to the set or elements in X it become invalid. X*/ X XDisposeBlobSet (bSet) XBlobSetHandle bSet; X{ XBlobHandle b1, b2; XBlobSetHandle bSet2; X X/* X remove set from master list X*/ X if (bSet == blobSetMaster) /* first set in list */ X blobSetMaster = (**blobSetMaster).nextBlobSet; X else X { X bSet2 = blobSetMaster; X for (;;) X { X if (bSet2 == nil) return; /* set isn't in master list */ X if ((**bSet2).nextBlobSet == bSet) /* found it */ X { X (**bSet2).nextBlobSet = (**bSet).nextBlobSet; X break; X } X bSet2 = (**bSet2).nextBlobSet; /* try next one */ X } X } X/* X toss elements of set X*/ X b1 = (**bSet).firstBlob; X for (;;) X { X if (b1 == nil) break; X b2 = (**b1).nextBlob; X DisposeBlob (b1); X b1 = b2; X } X/* X toss set header X*/ X DisposHandle (bSet); X} X X X/* X Dispose of all existing sets. This is the routine to call at X the end of the host program to dispose of all Blob Manager X structures. X*/ X XDisposeBlobSets () X{ X for (;;) X { X if (blobSetMaster == nil) break; /* no more sets */ X DisposeBlobSet (blobSetMaster); /* changes the master list */ X } X} X X X/* X Delete a blob from a blob list. Should not be done lightly, e.g., X if the blob is some other blob's glob. Check to be sure that the X current glueCount is zero first. All handles to the blob become X invalid. X*/ X XClobberBlob (b, bSet) XBlobHandle b; XBlobSetHandle bSet; X{ XBlobHandle b2; X X if ((**bSet).firstBlob == b) /* special case - first in list */ X { X (**bSet).firstBlob = (**b).nextBlob; X if ((**bSet).lastBlob == b) /* if true, set is now empty */ X (**bSet).lastBlob = nil; X } X else X { X b2 = (**bSet).firstBlob; X for (;;) X { X if (b2 == nil) return; /* NOT break! */ X if ((**b2).nextBlob == b) X { X (**b2).nextBlob = (**b).nextBlob; X if ((**bSet).lastBlob == b) /* clobbering last one */ X (**bSet).lastBlob = b2; /* back pointer up */ X break; X } X b2 = (**b2).nextBlob; X } X } X DisposeBlob (b); X} X X X/* X Delete s from the match set of d X*/ X XClobberBlobMatch (b1, b2) XBlobHandle b1, b2; X{ XMatchHandle m1, m2; X X m1 = (**b2).matches; X if (m1 != nil) /* don't look if match set empty */ X { X if ((**m1).mBlob == b1) /* is it the first one in the list? */ X { X (**b2).matches = (**m1).nextMatch; X } X else /* it's not first one */ X { X for (;;) X { X m2 = (**m1).nextMatch; X if (m2 == nil) return; /* NOT break! */ X if ((**m2).mBlob == b1) /* found it */ X { X (**m1).nextMatch = (**m2).nextMatch; X break; X } X m1 = m2; X } X } X DisposHandle (m2); X } X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrPict.c X/* -------------------------------------------------------------------- */ X/* Blob Picture Creation Routines */ X/* -------------------------------------------------------------------- */ X X X# include "BlobMgr.h" X X X/* X Internal picture drawing scratch variables X*/ X Xstatic PicHandle picHand; Xstatic Rect picRect = { -30000, -30000, 30000, 30000 }; X X XOpenBlob () X{ X picHand = OpenPicture (&picRect); X} X X X/* X Close a picture blob. The picture that was begin with OpenBlob is X installed in the blob record and the blob type is set to picture X (as opposed to proc) blob. The picture is replayed with a frame X that is the union of the bounding boxes of the static and drag regions. X This will usually be sufficiently reasonable to avoid the problem X of overflow that sometimes results from scaling the clipping region X when a picture is drawn in a different size than the original. X The dragRect and statRect fields are set to those rects bounding X the parts of the picture corresponding to the two regions. These X are used to cope in the event that the blob is moved or resized. X (See DrawBlob and DrawBlobPic.) X X ClosePicBlob does NOT set the blob's regions. That must be done X by the caller after calling ClosePicBlob. X*/ X Xstatic ClosePicBlob (b, dragRect, statRect) XBlobHandle b; XRect *dragRect, *statRect; X{ XRect pRect; XPicHandle p; XRgnHandle oldClip; X X ClosePicture (); /* stop saving picture definition */ X DisposeBlobPic (b); /* toss any pic the blob might have had */ X UnionRect (dragRect, statRect, &pRect); X oldClip = NewRgn (); X GetClip (oldClip); X ClipRect (&pRect); /* avoid clipping problem on picture */ X p = OpenPicture (&pRect); /* replay later on - this prevents */ X DrawPicture (picHand, &picRect); /* overflow if pic is scaled up */ X ClosePicture (); X KillPicture (picHand); /* don't need original picture now */ X SetClip (oldClip); X DisposeRgn (oldClip); X (**b).bPicProc.bPic = p; X X (**b).dragRect = *dragRect; /* install original drag Rect */ X (**b).statRect = *statRect; /* install original static Rect */ X X SetBlobFlags (b, bPicMask); /* set type as picture blob */ X} X X X/* X Close a blob whose regions are defined by rectangles. X*/ X XCloseRectBlob (b, dragRect, statRect) XBlobHandle b; XRect *dragRect, *statRect; X{ X ClosePicBlob (b, dragRect, statRect); X SetBlobRects (b, dragRect, statRect); X if (BlobEnabled (b)) X DrawBlob (b, inFullBlob); X X} X X X/* X Close a blob. X*/ X XCloseRgnBlob (b, dragRgn, statRgn) XBlobHandle b; XRgnHandle dragRgn, statRgn; X{ XRect dragRect, statRect; X X dragRect = (**dragRgn).rgnBBox; X statRect = (**statRgn).rgnBBox; X ClosePicBlob (b, &dragRect, &statRect); X SetBlobRgns (b, dragRgn, statRgn); X if (BlobEnabled (b)) X DrawBlob (b, inFullBlob); X X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrRand.c X/* X Blob random number routines X*/ X X# include <MacTypes.h> X# define nil 0L X X Xstatic DefaultRand (max) Xint max; X{ Xregister int t; X X t = Random (); X if (t < 0) t = -t; X return (t % (max + 1)); X} X X Xstatic ProcPtr bRandProc = DefaultRand; X X X/* X return integer between zero and max (inclusive). assumes max is X non-negative. X*/ X X XBlobRand (max) Xint max; X{ X return ((*bRandProc) (max)); X} X X X/* X Install procedure as random number generator for BlobRand X*/ X XSetBlobRand (f) XProcPtr f; X{ X bRandProc = (f == nil ? DefaultRand : f); X}SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrSetProc.c X/* -------------------------------------------------------------------- */ X/* Blob Draw Proc Installation */ X/* -------------------------------------------------------------------- */ X X X# include "BlobMgr.h" X X X X/* X Set a blob's draw procedure and regions. This routine makes COPIES X of the regions passed in, so the caller should dispose of the regions X it passes in itself. X*/ X XSetProcRgnBlob (b, proc, dragRgn, statRgn) XBlobHandle b; XProcPtr proc; XRgnHandle dragRgn, statRgn; X{ X DisposeBlobPic (b); /* toss any pic the blob might have */ X (**b).bPicProc.bDrawProc = proc;/* install drawing procedure */ X ClearBlobFlags (b, bPicMask); /* set blob type to proc blob */ X SetBlobRgns (b, dragRgn, statRgn); X if (BlobEnabled (b)) X DrawBlob (b, inFullBlob); X} X X X/* X Set a blob's draw procedure and regions, where the regions are X defined by rectangles. X*/ X XSetProcRectBlob (b, proc, dragRect, statRect) XBlobHandle b; XProcPtr proc; XRect *dragRect, *statRect; X{ X DisposeBlobPic (b); /* toss any pic the blob might have */ X (**b).bPicProc.bDrawProc = proc;/* install drawing procedure */ X ClearBlobFlags (b, bPicMask); /* set blob type to proc blob */ X SetBlobRects (b, dragRect, statRect); X if (BlobEnabled (b)) X DrawBlob (b, inFullBlob); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrSetRgns.c X/* -------------------------------------------------------------------- */ X/* Blob Rect/Rgn Installation */ X/* -------------------------------------------------------------------- */ X X X# include "BlobMgr.h" X X X X X/* X Set a blob's regions. This routine makes COPIES of the regions X passed in, so the caller should dispose of the regions it passes X in itself. This routine relies on the fact that a blob should X never have nil handles for its regions (NewBlob installs empty X regions, so those regions are just changed here, not created). X X The drag region is set equal to the drag region passed in. The X static region is set to the difference of the static and drag X regions passed in. X*/ X XSetBlobRgns (b, dragRgn, statRgn) XBlobHandle b; XRgnHandle dragRgn, statRgn; X{ X X CopyRgn (dragRgn, (**b).dragRgn); X DiffRgn (statRgn, dragRgn, (**b).statRgn); X} X X X/* X Set a blob's regions, where the regions are defined by rectangles. X*/ X XSetBlobRects (b, dragRect, statRect) XBlobHandle b; XRect *dragRect, *statRect; X{ XRgnHandle dragRgn, statRgn; X X dragRgn = NewRgn (); X statRgn = NewRgn (); X RectRgn (dragRgn, dragRect); X RectRgn (statRgn, statRect); X SetBlobRgns (b, dragRgn, statRgn); X DisposeRgn (dragRgn); X DisposeRgn (statRgn); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrShuffle.c X# include "BlobMgr.h" X X X/* X Shuffle the locations of the blobs in the given set. If it is X undesirable to show all the redrawing that takes place during X this, HideBlobSet should be called before ShuffleBlobSet, and X ShowBlobSet after. X X ShuffleBlobSet deals with the following problem. Suppose two blobs X to be switched are both visible. The first is moved, i.e., hidden X and redrawn at the location of the second. Then the second is moved, X i.e., hidden and redrawn at the previous location of the first. X But moving the second blob erases the newly drawn first blob! To X avoid this, ShuffleBlobset hides the first blob before moving them, X and redraws it afterward. X X ShuffleBlobSet usually results in an update event being generated X since hiding a blob adds its region to the update region for the X window. ValidRect can be called (with the window's portRect) X to defeat it. X X The static region is often empty, which is why the drag regions are used X to determine the offsets. X*/ X X XShuffleBlobSet (bSet) XBlobSetHandle bSet; X{ Xregister BlobHandle b1, b2; Xregister int size, h, v; XBoolean vis1 = false; X X size = BlobSetSize (bSet); X for (b1 = FirstBlob (bSet); b1 != nil; b1 = NextBlob (b1)) X { X b2 = GetBlobHandle (bSet, BlobRand (size - 1)); X h = BDragBox (b1).left - BDragBox (b2).left; X v = BDragBox (b1).top - BDragBox (b2).top; X if (BlobEnabled (b1)) X { X HideBlob (b1); X vis1 = true; X } X OffsetBlob (b1, inFullBlob, -h, -v); X OffsetBlob (b2, inFullBlob, h, v); X if (vis1) X ShowBlob (b1); X } X} X X X/* X Shuffle the globs attached to the blobs in the given set. X*/ X X XShuffleGlobSet (bSet) XBlobSetHandle bSet; X{ Xregister BlobHandle b; Xregister int size; X X size = BlobSetSize (bSet); X for (b = FirstBlob (bSet); b != nil; b = NextBlob (b)) X { X SwapGlob (b, GetBlobHandle (bSet, BlobRand (size-1))); X } X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrTrackMouse.c X# include "BlobMgr.h" X X X/* X Track the mouse while the button is held down. Invert the given X blob region whenever the mouse is in the region. Return true if X the mouse is released inside of the region, false otherwise. X*/ X XBoolean BTrackMouse (b, startPt, partCode) XBlobHandle b; XPoint startPt; Xint partCode; X{ XBoolean inBlob; XRgnHandle rgn; XPoint pt; X X rgn = BCalcRegion (b, partCode); X pt = startPt; X inBlob = false; X for (;;) X { X if (PtInRgn (pt, rgn) != inBlob) /* invert on change of state */ X { X InvertRgn (rgn); X inBlob = !inBlob; X } X if (!StillDown ()) X break; X GetMouse (&pt); X } X if (inBlob) /* leave region uninverted */ X InvertRgn (rgn); X DisposeRgn (rgn); X return (inBlob); X} SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrTrans.c X# include "BlobMgr.h" X X X/* ---------------------------------------------------------------------- */ X/* Blob Transaction Routines */ X/* ---------------------------------------------------------------------- */ X X X/* X If the blob has a blob glued to its drag area, dissociate the glued blob. X Redraw the drag area. Decrement the use count of the glued blob, X undimming it if necessary. X*/ X XUnglueGlob (b) XBlobHandle b; X{ XBlobHandle g; X X g = (**b).glob; X if (g != nil) /* skip if don't really have glued blob */ X { X (**b).glob = nil; X DrawBlob (b, inDragBlob); X DecBlobGlue (g); /* dec use count and undim if necessary */ X } X} X X XUnglueGlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&UnglueGlob, bSet); X} X X X/* X Glue donor blob d to receptor r. Redraw the drag area of r. X Increment the use count of d, dimming it if necessary. If r X already has a glue blob, unglue it first (undimming if necessary). X*/ X X XGlueGlob (d, r) XBlobHandle d, r; X{ XBlobHandle g; X X g = (**r).glob; /* currently glued blob */ X if (g != d) /* ignore if has a glob and it's same */ X { X if (g != nil) /* if it has a glob already, then */ X DecBlobGlue (g); /* detach and undim if necessary */ X (**r).glob = d; X IncBlobGlue (d); /* increment use and dim if necessary */ X DrawBlob (r, inDragBlob); /* now have source in drag area - redraw */ X } X} X X X/* X Transfer a glued blob from one blob to another (r1 -> r2). Redraw X the drag areas of the blob losing the glued blob, and the one X receiving it, but the use count of the transferred blob does not X change, so it's not necessary to redraw it. X*/ X XTransferGlob (r1, r2) XBlobHandle r1, r2; X{ XBlobHandle g1, g2; X X if (r1 != r2) /* ignore unless different */ X { X g1 = BGlob (r1); X g2 = BGlob (r2); X if (g1 != nil) /* can't transfer if nothing there! */ X { X BGlob (r1) = nil; /* detach and redraw drag area */ X DrawBlob (r1, inDragBlob); X if (g2 != nil) /* toss this first if something there */ X DecBlobGlue (g2); /* undim if necessary */ X BGlob (r2) = g1; X DrawBlob (r2, inDragBlob); /* new donor in drag area - redraw */ X } X } X} X X X/* X Swap the globs glued to r1 and r2. If one of them doesn't actually X have a glob, this is equivalent to a transfer. X*/ X XSwapGlob (r1, r2) XBlobHandle r1, r2; X{ XBlobHandle g1, g2; X X if (r1 != r2) /* ignore unless different */ X { X g1 = BGlob (r1); X g2 = BGlob (r2); X if (g1 != g2) /* ignore if both have same glob */ X { X BGlob (r1) = g2; X BGlob (r2) = g1; X DrawBlob (r1, inDragBlob); X DrawBlob (r2, inDragBlob); X } X } X} X X X/* X Glue the glob that's glued to r1 onto r2 as well. No check X is made whether it's really gluable another time or not. X*/ X XDupGlob (r1, r2) XBlobHandle r1, r2; X{ XBlobHandle g; X X if ((g = BGlob (r1)) != nil) X GlueGlob (g, r2); /* duplicate blob */ X} X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrZTrans.c X# include "BlobMgr.h" X X X/* -------------------------------------------------------------------- */ X/* Blob Transaction Routines - with zooming */ X/* -------------------------------------------------------------------- */ X X X/* X Same as UnglueGlob, except that a rectangle is zoomed X from the destination blob back to the source blob. X*/ X XZUnglueGlob (b) XBlobHandle b; X{ XBlobHandle g; XRect r1, r2; X X g = (**b).glob; X if (g != nil) /* skip if don't really have glued blob */ X { X (**b).glob = nil; X DrawBlob (b, inDragBlob); X r1 = BDragBox (b); X r2 = BDragBox (g); X ZoomRect (&r1, &r2); X DecBlobGlue (g); /* dec use count and undim if necessary */ X } X} X X XZUnglueGlobSet (bSet) XBlobSetHandle bSet; X{ X BlobLoopProc1 (&ZUnglueGlob, bSet); X} X X X/* X Same as GlueGlob, but zooms the donor to the receptor first X*/ X XZGlueGlob (d, r) XBlobHandle d, r; X{ XRect r1, r2; X X r1 = BDragBox (d); X r2 = BDragBox (r); X ZoomRect (&r1, &r2); X GlueGlob (d, r); X} X X X/* X Same as DupGlob, but zooms from the first receptor to the second X before duplicating. X X This really should use the drag region of the first receptor's glob, X mapped to the shape and position of the receptor, rather than the X receptor's drag region - since it's the glob that's being transferred. X But that requires mapping (and scaling when it's put in). X*/ X XZDupGlob (r1, r2) XBlobHandle r1, r2; X{ XRect rect1, rect2; X X if (BGlob (r1) != nil) X { X rect1 = BDragBox (r1); X rect2 = BDragBox (r2); X ZoomRect (&rect1, &rect2); X DupGlob (r1, r2); X } X} X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > BMgr/BMgrZoom.c X# include <QuickDraw.h> X X/* X Zooming parameters. zoomSteps is the number of steps in the X interpolative series. It must not be zero. zoomShow is the number X of steps that show at any one time in the series. It must be less X than or equal to zoomSteps. X*/ X X# define zoomSteps 10 X# define zoomShow 3 X X X/* X ZoomRect zooms a dotted rectangle from r1 to r2. The effect is X transparent (screen no different afterwards). The shape of the zoomed X rectangles changes for smooth interpolation. X*/ X XZoomRect (r1, r2) XRect *r1, *r2; X{ Xregister int r1left, r1top; Xint hDiff, vDiff, widDiff, htDiff; Xint l, t, r, b; Xint rWid, rHt; Xint i, j; XRect zoomRect[zoomSteps]; XPenState ps; X X r1left = r1->left; /* these two statements make code shorter and */ X r1top = r1->top; /* impervious to mem mgr if rects passed by handle */ X hDiff = r2->left - r1left; /* positive if moving to right */ X vDiff = r2->top - r1top; /* positive if moving down */ X rWid = r1->right - r1left; X rHt = r1->bottom - r1top; X widDiff = (r2->right - r2->left) - rWid; X htDiff = (r2->bottom - r2->top) - rHt; X /* set pen gray, mode xor */ X GetPenState (&ps); /* save current pen state */ X PenPat (gray); X PenMode (patXor); X for (i = 0; i < zoomSteps; ++i) X { X j = i + 1; X l = r1left + (hDiff * j) / zoomSteps; X t = r1top + (vDiff * j) / zoomSteps; X r = l + rWid + (widDiff * j) / zoomSteps; X b = t + rHt + (htDiff * j) / zoomSteps; X SetRect (&zoomRect[i], l, t, r, b); X FrameRect (&zoomRect[i]); /* draw in xor */ X if (i >= zoomShow) X FrameRect (&zoomRect[i-zoomShow]); X } X for (i = zoomSteps - zoomShow; i < zoomSteps; ++i) X { X FrameRect (&zoomRect[i]); X } X /* set pen normal */ X SetPenState (&ps); /* restore pen state */ X X} SHAR_EOF exit