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
exitmacintosh@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