mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-04-13 15:37:36 +00:00
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
4250 lines
99 KiB
OpenEdge ABL
4250 lines
99 KiB
OpenEdge ABL
{
|
|
File: BitEdit.i
|
|
|
|
Written by: Steve Horowitz, Peter Alley, and Craig Carper
|
|
|
|
Copyright: © 1990 by Apple Computer, Inc., all rights reserved.
|
|
|
|
Change History (most recent first):
|
|
|
|
<3> 2/5/90 dba get rid of BitMapPtr, since it is now in QuickDraw.p
|
|
<1> 1/22/90 JRM declare BitmapPtr as a type
|
|
|
|
To Do:
|
|
}
|
|
|
|
{ BitEdit IMPLEMENTATION section }
|
|
|
|
{ 8-18-87 }
|
|
{ version 2.0A1 10-29-89 by Craig Carper }
|
|
{ written by Steve Horowitz; further development by Craig Carper }
|
|
|
|
{ CHANGES
|
|
¥ (01-03-90 crc) BEBounds: Added LockHands, UnlockHands.
|
|
DrawLasso: Renamed local variable selRect to selBBox to avoid conflict with field name in
|
|
BESelectRect.
|
|
This file was changed to provide the implementation section only; it is included by the
|
|
interface file BitEdit.p.
|
|
Renamed fields of BitEditRecord to those used in interface file.
|
|
¥ (12-12-89 crc) BEInvalRect: Limit argument rectangle to it's intersection with rEdit. BEInvalRect is
|
|
called internally with this argument set to the selection, part of which may lie outside
|
|
rEdit--causing an invalid update of the views.
|
|
DragSelection: If dragging a copy, set the wasErased flag to true without erasing the original.
|
|
¥ (12-05-89 crc) BEObject: Eliminated "idle" and "select" parameter. "select" was only used to prevent
|
|
making an undo copy when dragging out a selection--this is inconsistent with other functions, and
|
|
does not appear to introduce any anomilies. "idle" was folded into the "flags" parameter.
|
|
BEPaste: Changed so that if pasting into a moved selection, the selection is replaced without
|
|
first putting it down.
|
|
BESelect: Fixed to always save undo state before creating a new selection
|
|
¥ (12-04-89 crc) Many changes so Undo restores selections:
|
|
BESetupUndo: Renamed SetupUndo, which is not exported.
|
|
BEUndoBegin,BEUndoEnd: Replacements for BESetupUndo to allow freezing the
|
|
undo state across multiple calls to the BitEdit package. These calls are counting, so
|
|
if nested, undo is not re-enabled untill first BEUndoBegin is matched by a BEUndoEnd.
|
|
¥ (12-01-89 crc) Collected all selection variables into a record structure.
|
|
¥ (11-30-89 crc) Implemented fShapeUnbounded in OvalDraw, RectDraw, and RndRectDraw.
|
|
¥ (11-29-89 crc)
|
|
IMPORTANT: These changes result in a 2.0 package that is INCOMPATABLE with the 1.0 version;
|
|
some existing routines were eliminated, others had changes to their parameter list. In any
|
|
event, all clients must relink since this version of the package is INCOMPATABLE with
|
|
previous versions of BEPackLib.a.
|
|
BEPaintBucket: Fills with current pattern; non-color support (untested).
|
|
BERotate: Fix for non-color support (untested).
|
|
BESetupOffScreen: Renamed to BESetupUndo.
|
|
BEScroll: Deleted (never implemented).
|
|
BELasso: Deleted (subsumed by BESelect).
|
|
BEDiagonalLine, BEFillOval, BEFillRect, BEFillRndRect, BECircle, BEFillCircle, BESquare,
|
|
BEFillSquare, BERndSquare, BEFillRndSquare: Deleted (subsumed by other routines).
|
|
BELine, BEOval, BERec, BEObject: Added flags parameter.
|
|
BERndRect: Renamed BERoundRect, added flags parameter, moved BitEditHandle parameter to end of parameter list.
|
|
BEFlipSelection, BERotateSelection, BENudgeSelection, BEDupSelection:
|
|
Renamed to BEFlip, BERotate, BENudge, and BEDuplicate, respectively.
|
|
BESelect: Added flags parameter.
|
|
BERect: Added refCon field.
|
|
BEPutSelBits: Renamed to BEPutSelection;
|
|
¥ (11-26-89 crc) BEColor, BEPaintBucket: New routines.
|
|
¥ (11-01-89 crc) BENudgeSelection: always draws image without ants, so caller can always copy
|
|
the image without picking up the ants.
|
|
BEObject: Invalidate pattern before and after drawing into the image, in case client uses
|
|
the same pattern to draw in a different GDevice.
|
|
¥ (10-31-89 crc) CenterScrap: changed to align rects larger than the edit image with the top
|
|
left; this allows pasting of larger PICTs.
|
|
BEPaste: Expand clip rgn & vis rgn to bounds of selection before drawing PICT;
|
|
eliminated redundant code to erase selection bits after creating a selection.
|
|
¥ (10-30-89 crc) BEPutSelBits: eliminated useless call to SetupRects.
|
|
??? Is invalid for BEInvalRect to be called between LockHands and UnlockHands ???
|
|
BEDupSelection: new routine.
|
|
ConstrainNudge: new routine.
|
|
¥ (10-29-89 crc) MarqueeDance: Called by BEIdle in place of MarqueeDraw; allows selRect to remain
|
|
partially outside the edit area (for rotate). Uses selRect instead of selection rectangle,
|
|
and allows ants to march out of the edit area.
|
|
BESetSelect: Constrain argument rectangle to editRect, then further constrain the bottom right
|
|
of selRect to be one pixel inside the bottom right of editRect. Also, moved call to
|
|
BEKillSelection ahead of DoQuickPortToDup, so ants are not copied.
|
|
DragSelection: Allow marquee selection to be dragged beyond edge of edit rectangle as long as
|
|
one edge of selection remains over the edit rectangle.
|
|
SetupRects, SetUpSelBits: Undid change described below, as this caused partially offscreen
|
|
selections to be scaled when copied to image.
|
|
¥ (10-28-89 crc) EraseUnderSelection: new routine, called by DragSelection, BENudgeSelection, and
|
|
BERotateSelection.
|
|
BERotateSelection, GetPix, SetPix, SetupExtract: new routines.
|
|
¥ (10-27-89 crc) SetupRects, SetUpSelBits: After calling StretchRect, intersect with bounds rect
|
|
of bitmap so any selection established by BESetSelect remains withing the bitmap.
|
|
BEFlipSelection: New routine.
|
|
¥ (10-02-89 crc) BEDraw: Call BWOffScreen if offHandle is Nil.
|
|
When drawing directly to the screen, don't need to lock & unlock offHandle.
|
|
BEView: Moved initialization of offPix to BENew; eliminated call to ResetOffScreen
|
|
since BEDraw will call it if necessary.
|
|
¥ ( 9-29-89 crc) BEActivate: On deactivate, discard offscreen bits & pixMap. This significantly
|
|
reduces the amount of memory used by the BitEdit record.
|
|
¥ ( 9-23-89 crc) BESquare, BEFillSquare, BERndSquare, BEFillRndSquare, BECircle,
|
|
BEFillCircle, BEDiagonalLine: New exported routines.
|
|
SquareRect, ClipAnchorRect, SquareDraw, FillSquareDraw, RndSquareDraw,
|
|
FillRndSquareDraw, CircleDraw, FillCircleDraw, DiagonalLineDraw, WidthHeightRect: New
|
|
routines.
|
|
RectDraw, FillRectDraw, RndRectDraw, FillRndRectDraw, OvalDraw, FillOvalDraw: Constrained
|
|
to keep within edit area.
|
|
¥ ( 7-24-89 crc) BEDraw: Constructs offscreen pixMap based on deepest device, not on the
|
|
window's port (which always reflects the main screen).
|
|
BEView: Do not initialize offPix (requires knowing deepest device).
|
|
BWOffscreen: Eliminated GrafPort^ parameter (not used).
|
|
ResetOffscreen: Takes GDHandle instead of a GrafPort.
|
|
¥ ( 7-17-89 crc) Note: The BitEdit package assumes that only PixMaps are edited in color
|
|
grafports. The package will fail if a BitMap is passed to BENew when the current port is
|
|
a color graf port. The package looks into the port's BitMap to find the bounds, for example,
|
|
without checking to see if the port contains a PixMap instead. This is probably due to the
|
|
fact that BitEdit was first a BitMap only editor, and color was added later.
|
|
¥ ( 5-31-89 crc) Changed MyDisposPixMap to take a PixMapHandle instead of a VAR PixMapHandle,
|
|
which bad news if the argument lies within an unlocked relocatable object.
|
|
Changed GetBWTable parameter to not be VAR since it was not necessary.
|
|
¥ ( 5-24-89 crc) BEDraw calls ResetOffscreen if the port's color table has changed, which means
|
|
that the inverse table no longer corresponds to the color table in offPix.
|
|
¥ (crc) Added ImageCt2DeviceCt to create a device color table from an image color table.
|
|
BENew was incorrectly installing an image color table as a device color table.
|
|
¥ (crc) Added the internal routine CopyPixels for transferring pixels to off-screen bitmaps.
|
|
This is to get around a bug (fixed in 32-bit QD) that causes CopyBits to colorize pixels.
|
|
(Peter Alley)
|
|
¥ Added CopySetToPort to BEPaste
|
|
¥ Added BESetupOffScreen to the end of BENew so that undo before cut, copy or clear
|
|
will not put garbage into the bitmap.
|
|
¥ Added BESelection routine 8/5/88.
|
|
}
|
|
|
|
{USES Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf}
|
|
|
|
CONST
|
|
antSpeed = 6;
|
|
|
|
{ Bit flags for shape drawing }
|
|
fShapeUnframed = $1; { INTERNAL USE ONLY }
|
|
|
|
{ Bit flags for MarqueeDraw }
|
|
fUseSelection = $00; { Keep the current selection rectangle }
|
|
fSetSelection = $01; { Set the selection rectangle }
|
|
|
|
{ Bit flags interpreted by BEObject }
|
|
fIdle = $8000;
|
|
|
|
PROCEDURE FixRect(VAR r: Rect); EXTERNAL;
|
|
PROCEDURE GetSelPat(patIndex: INTEGER; VAR pat: Pattern); EXTERNAL;
|
|
PROCEDURE PaintBits(blacken, erase: BOOLEAN; stPt, endPt: Point; hbe: BEHandle); FORWARD;
|
|
PROCEDURE SetUpSelBits(r: Rect; hbe: BEHandle); FORWARD;
|
|
PROCEDURE SetupUndo(hbe: BEHandle); FORWARD;
|
|
PROCEDURE MarqueeDraw(r: Rect; flags: BEDrawFlags; hbe: BEHandle); FORWARD;
|
|
PROCEDURE DrawLasso(startPt: Point; hbe: BEHandle); FORWARD;
|
|
PROCEDURE DragSelection(startPt: Point; flags: BESelectFlags; hbe: BEHandle); FORWARD;
|
|
PROCEDURE AlignBits(hbe: BEHandle); FORWARD;
|
|
PROCEDURE CenterScrap(VAR r:Rect; hbe: BEHandle); FORWARD;
|
|
PROCEDURE HiliteLasso(hbe: BEHandle); FORWARD;
|
|
PROCEDURE TrimBBox(dstBuf: QDPtr; VAR dstRect: Rect; rowB: INTEGER); EXTERNAL;
|
|
PROCEDURE CalcEdges(srcBuf,dstBuf: QDPtr;
|
|
topVert,height,rowBytes: INTEGER;
|
|
lassoBlack: BOOLEAN); EXTERNAL;
|
|
PROCEDURE ClearHandle(block: Handle); EXTERNAL;
|
|
PROCEDURE LockHands(hbe: BEHandle); FORWARD;
|
|
PROCEDURE UnlockHands(hbe: BEHandle); FORWARD;
|
|
PROCEDURE SetupRects(VAR r1, r2: Rect; hbe: BEHandle); FORWARD;
|
|
FUNCTION GetRgnMax: INTEGER; EXTERNAL;
|
|
FUNCTION NewPtrClr(logicalSize: Size): Ptr; EXTERNAL;
|
|
PROCEDURE ClipAnchorRect (VAR r: Rect; VAR rClip: Rect); FORWARD;
|
|
PROCEDURE SquareRect (VAR r: Rect); FORWARD;
|
|
PROCEDURE WidthHeightRect (VAR r: Rect; VAR pt: Point); FORWARD;
|
|
FUNCTION UIntMul(i,j: INTEGER): LONGINT; INLINE
|
|
{ move (sp)+,d0 } $301F,
|
|
{ mulu (sp)+,d0 } $C0DF,
|
|
{ move.l d0,(sp) } $2E80;
|
|
PROCEDURE CallDrawProc(r:Rect; flags: BEDrawFlags; hbe: BEHandle; proc: ProcPtr); INLINE
|
|
{ move.l (sp)+,a0 } $205F,
|
|
{ jsr (a0) } $4E90;
|
|
|
|
{ ---- Begin BitEdit Routines ---- }
|
|
|
|
PROCEDURE StretchRect(VAR r: Rect);
|
|
|
|
BEGIN
|
|
r.right := r.right + 1;
|
|
r.bottom := r.bottom + 1;
|
|
END;
|
|
|
|
|
|
PROCEDURE LockHands(hbe: BEHandle);
|
|
{ Lock down the handles to the bits and set the baseAddr field }
|
|
{ of the bitMap or pixMap (lock it if it's a pixMap) }
|
|
|
|
BEGIN
|
|
HLock(Handle(hbe));
|
|
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
IF dupHandle <> Nil THEN
|
|
BEGIN
|
|
HLock(dupHandle);
|
|
IF isColor THEN
|
|
{ lock the pixMap handle }
|
|
BEGIN
|
|
HLock(Handle(dupPix));
|
|
dupPix^^.baseAddr := dupHandle^;
|
|
END
|
|
ELSE
|
|
dupBits.baseAddr := dupHandle^;
|
|
END;
|
|
END; { WITH hbe^^ }
|
|
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
IF selHandle <> Nil THEN
|
|
BEGIN
|
|
HLock(selHandle);
|
|
IF hbe^^.isColor THEN
|
|
{ lock the pixMap handle }
|
|
BEGIN
|
|
HLock(Handle(selPix));
|
|
selPix^^.baseAddr := selHandle^;
|
|
END
|
|
ELSE
|
|
selBits.baseAddr := selHandle^;
|
|
END;
|
|
|
|
IF maskHandle <> Nil THEN
|
|
BEGIN
|
|
HLock(maskHandle);
|
|
IF hbe^^.isColor THEN
|
|
{ lock the pixMap handle }
|
|
BEGIN
|
|
HLock(Handle(maskPix));
|
|
maskPix^^.baseAddr := maskHandle^;
|
|
END
|
|
ELSE
|
|
maskBits.baseAddr := maskHandle^;
|
|
END;
|
|
END; { WITH hbe^^.selection }
|
|
END; { LockHands }
|
|
|
|
|
|
PROCEDURE UnlockHands(hbe: BEHandle);
|
|
{ unlock the handles to the Bits and unlock the pixMap handle if we're in color }
|
|
|
|
BEGIN
|
|
HUnlock(Handle(hbe));
|
|
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
IF dupHandle <> Nil THEN
|
|
BEGIN
|
|
HUnlock(dupHandle);
|
|
IF isColor THEN
|
|
HUnlock(Handle(dupPix));
|
|
END;
|
|
END; { WITH hbe^^ }
|
|
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
IF selHandle <> Nil THEN
|
|
BEGIN
|
|
HUnlock(selHandle);
|
|
IF hbe^^.isColor THEN
|
|
HUnlock(Handle(selPix));
|
|
END;
|
|
|
|
IF maskHandle <> Nil THEN
|
|
BEGIN
|
|
HUnlock(maskHandle);
|
|
IF hbe^^.isColor THEN
|
|
HUnlock(Handle(maskPix));
|
|
END;
|
|
END; { WITH hbe^^.selection }
|
|
END; { UnlockHands }
|
|
|
|
|
|
PROCEDURE SetupRects(VAR r1, r2: Rect; hbe: BEHandle);
|
|
|
|
VAR
|
|
b: BOOLEAN;
|
|
|
|
BEGIN
|
|
WITH hbe^^, hbe^^.selection DO
|
|
BEGIN
|
|
r1 := selRect;
|
|
StretchRect(r1);
|
|
|
|
IF maskHandle <> Nil THEN
|
|
BEGIN
|
|
IF isColor THEN
|
|
r2 := maskPix^^.bounds
|
|
ELSE
|
|
r2 := maskBits.bounds;
|
|
InsetRect(r2, 1, 1);
|
|
END;
|
|
END;
|
|
END; { SetupRects }
|
|
|
|
|
|
PROCEDURE GetMIndex(VAR mIndex: INTEGER);
|
|
|
|
VAR
|
|
now: INTEGER;
|
|
|
|
BEGIN
|
|
now := LoWrd(TickCount);
|
|
now := now DIV antSpeed;
|
|
mIndex := BAnd(now, 7);
|
|
END;
|
|
|
|
{ cc }
|
|
PROCEDURE CopyPixels (hpmSource, hpmDest: PixMapHandle);
|
|
|
|
BEGIN
|
|
BlockMove (hpmSource^^.baseAddr, hpmDest^^.baseAddr,
|
|
INTEGER(BAND(hpmDest^^.rowBytes, $7FFF))*(hpmDest^^.bounds.bottom-hpmDest^^.bounds.top));
|
|
END;
|
|
|
|
PROCEDURE CSelToPort(hbe: BEHandle; r1: Rect; isDrag: BOOLEAN);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
IF isDrag THEN
|
|
r := r1;
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(selection.selPix^)^, beGrafPtr^.portBits, selection.selPix^^.bounds, r, srcCopy, Nil)
|
|
ELSE
|
|
CopyBits(selection.selBits, beGrafPtr^.portBits, selection.selBits.bounds, r, srcCopy, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE OSelToPort(hbe: BEHandle; r1: Rect; isDrag: BOOLEAN);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
IF isDrag THEN
|
|
r := r1;
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(selection.selPix^)^, beGrafPtr^.portBits, srcRect, r, srcOr, Nil)
|
|
ELSE
|
|
CopyBits(selection.selBits, beGrafPtr^.portBits, srcRect, r, srcOr, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE MaskToPort(hbe: BEHandle; r1: Rect; isDrag: BOOLEAN);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
IF isDrag THEN
|
|
r := r1;
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(selection.maskPix^)^, beGrafPtr^.portBits, srcRect, r, srcBic, Nil)
|
|
ELSE
|
|
CopyBits(selection.maskBits, beGrafPtr^.portBits, srcRect, r, srcBic, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE CSelToDup(hbe: BEHandle);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(selection.selPix^)^, BitMapPtr(dupPix^)^, selection.selPix^^.bounds, r,
|
|
srcCopy, Nil)
|
|
ELSE
|
|
CopyBits(selection.selBits, dupBits, selection.selBits.bounds, r, srcCopy, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE OSelToDup(hbe: BEHandle);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(selection.selPix^)^, BitMapPtr(dupPix^)^, srcRect, r, srcOr, Nil)
|
|
ELSE
|
|
CopyBits(selection.selBits, dupBits, srcRect, r, srcOr, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE MaskToDup(hbe: BEHandle);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(selection.maskPix^)^, BitMapPtr(dupPix^)^, srcRect, r, srcBic, Nil)
|
|
ELSE
|
|
CopyBits(selection.maskBits, dupBits, srcRect, r, srcBic, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE DupToPort(hbe: BEHandle);
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
{ cc }
|
|
CopyPixels (dupPix, CGrafPtr(beGrafPtr)^.portPixMap)
|
|
{ CopyBits(BitMapPtr(dupPix^)^, beGrafPtr^.portBits, dupPix^^.bounds,
|
|
cGrafPtr(beGrafPtr)^.portPixMap^^.bounds, srcCopy, Nil) }
|
|
ELSE
|
|
CopyBits(dupBits, beGrafPtr^.portBits, dupBits.bounds,
|
|
beGrafPtr^.portBits.bounds, srcCopy, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE DupToSel(hbe: BEHandle);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(dupPix^)^, BitMapPtr(selection.selPix^)^, r, selection.selPix^^.bounds, srcCopy, Nil)
|
|
ELSE
|
|
CopyBits(dupBits, selection.selBits, r, selection.selBits.bounds, srcCopy, Nil);
|
|
END;
|
|
|
|
{ As modified by cc }
|
|
PROCEDURE OldPortToDup(hbe: BEHandle);
|
|
|
|
VAR
|
|
{ cc } rgbFore, rgbBack, rgbZeros, rgbOnes: RGBColor;
|
|
{ cc } thePort: GrafPtr;
|
|
{ cc } theDevice: GDHandle;
|
|
{ cc } pixelOnes, pixelZeros: LONGINT;
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
BEGIN
|
|
{ Set foreground color to black to prevent unpredictable colorizing during
|
|
copy bits }
|
|
GetForeColor (rgbFore);
|
|
GetBackColor (rgbBack);
|
|
Index2Color (0, rgbZeros);
|
|
Index2Color (BSL(1,bePixelSize)-1, rgbOnes);
|
|
RGBForeColor (rgbOnes);
|
|
RGBBackColor (rgbZeros);
|
|
pixelOnes := Color2Index (rgbOnes);
|
|
pixelZeros := Color2Index (rgbZeros);
|
|
theDevice := GetGDevice;
|
|
GetPort (thePort);
|
|
CopyBits(beGrafPtr^.portBits, BitMapPtr(dupPix^)^, cGrafPtr(beGrafPtr)^.portPixMap^^.bounds,
|
|
dupPix^^.bounds, srcCopy, Nil);
|
|
RGBForeColor (rgbFore);
|
|
RGBBackColor (rgbBack);
|
|
END
|
|
ELSE
|
|
CopyBits(beGrafPtr^.portBits, dupBits, beGrafPtr^.portBits.bounds, dupBits.bounds,
|
|
srcCopy, Nil);
|
|
END;
|
|
|
|
PROCEDURE PortToDup(hbe: BEHandle);
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
{ cc }
|
|
BEGIN
|
|
{
|
|
CopyPixels (CGrafPtr(beGrafPtr)^.portPixMap, dupPix)
|
|
}
|
|
OldPortToDup (hbe)
|
|
{
|
|
CopyBits(beGrafPtr^.portBits, BitMapPtr(dupPix^)^, cGrafPtr(beGrafPtr)^.portPixMap^^.bounds,
|
|
dupPix^^.bounds, srcCopy, Nil)
|
|
}
|
|
END
|
|
ELSE
|
|
CopyBits(beGrafPtr^.portBits, dupBits, beGrafPtr^.portBits.bounds, dupBits.bounds,
|
|
srcCopy, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE EdgeToPort(hbe: BEHandle; mode: INTEGER);
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(selection.edgePix^)^, beGrafPtr^.portBits, srcRect, r, mode, Nil)
|
|
ELSE
|
|
CopyBits(selection.edgeBits, beGrafPtr^.portBits, srcRect, r, mode, Nil);
|
|
END;
|
|
|
|
|
|
PROCEDURE CopySelToPort(hbe: BEHandle);
|
|
|
|
VAR
|
|
r: Rect;
|
|
|
|
BEGIN
|
|
IF hbe^^.marquee THEN
|
|
CSelToPort(hbe, r, False)
|
|
ELSE
|
|
BEGIN
|
|
MaskToPort(hbe, r, False);
|
|
OSelToPort(hbe, r, False);
|
|
END;
|
|
END;
|
|
|
|
|
|
PROCEDURE DoQuickDupToPort(hbe: BEHandle);
|
|
|
|
BEGIN
|
|
BEDrawBegin(hbe);
|
|
LockHands(hbe);
|
|
DupToPort(hbe);
|
|
UnlockHands(hbe);
|
|
BEDrawEnd(hbe);
|
|
END;
|
|
|
|
|
|
PROCEDURE DoQuickPortToDup(hbe: BEHandle);
|
|
|
|
BEGIN
|
|
BEDrawBegin(hbe);
|
|
PortToDup(hbe);
|
|
BEDrawEnd(hbe);
|
|
END;
|
|
|
|
|
|
PROCEDURE MyDisposPixMap(p: PixMapHandle);
|
|
|
|
VAR
|
|
n: Handle;
|
|
|
|
BEGIN
|
|
IF p <> Nil THEN
|
|
BEGIN
|
|
n := NewHandle(0);
|
|
p^^.pmTable := CTabHandle(n);
|
|
DisposPixMap(p);
|
|
END;
|
|
END;
|
|
|
|
|
|
PROCEDURE BEActivate(activate: BOOLEAN; hbe: BEHandle);
|
|
{ handle activate/deactivate events }
|
|
|
|
VAR
|
|
hUse: BEHandle;
|
|
|
|
BEGIN
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) AND NOT activate THEN
|
|
BEGIN
|
|
LockHands(hbe);
|
|
BEDrawBegin(hbe);
|
|
CopySelToPort(hbe);
|
|
BEDrawEnd(hbe);
|
|
UnlockHands(hbe);
|
|
|
|
BEInvalRect(hbe^^.beEditRect, hbe);
|
|
END;
|
|
|
|
hUse:= hbe;
|
|
REPEAT
|
|
IF activate THEN
|
|
hUse^^.active := TRUE
|
|
ELSE
|
|
BEGIN
|
|
hUse^^.active := FALSE;
|
|
IF hbe^^.offHandle <> Nil THEN
|
|
BEGIN
|
|
DisposHandle(hbe^^.offHandle);
|
|
hbe^^.offHandle := Nil;
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
DisposPixMap(hbe^^.offPix);
|
|
hbe^^.offPix := Nil
|
|
END;
|
|
END;
|
|
END;
|
|
hUse := hUse^^.sibling;
|
|
UNTIL hUse = hbe;
|
|
END; { BEActivate }
|
|
|
|
|
|
PROCEDURE BEDoDraw(draw: BOOLEAN; hbe: BEHandle);
|
|
{ turn drawing on and off }
|
|
|
|
VAR
|
|
hUse: BEHandle;
|
|
|
|
BEGIN
|
|
hUse := hbe;
|
|
REPEAT
|
|
IF draw THEN
|
|
hUse^^.drawEnabled := True
|
|
ELSE
|
|
hUse^^.drawEnabled := False;
|
|
hUse := hUse^^.sibling;
|
|
UNTIL hUse = hbe;
|
|
END; { BEDoDraw }
|
|
|
|
|
|
PROCEDURE AlignBits(hbe: BEHandle);
|
|
{ aligns the big offscreen bitmap with the screen for maximum copybits speed }
|
|
|
|
VAR
|
|
bitNum, width: INTEGER;
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
bitNum := (beViewRect.left - beGrafPtr^.portBits.bounds.left) MOD 32;
|
|
IF bitNum < 0 THEN bitNum := bitNum + 32;
|
|
WITH offBits.bounds DO
|
|
BEGIN
|
|
width := right - left;
|
|
left := beViewRect.left - bitNum;
|
|
right := left + width;
|
|
END;
|
|
END;
|
|
END; { AlignBits }
|
|
|
|
|
|
PROCEDURE BEBitmap(VAR bm: Bitmap; hbe: BEHandle);
|
|
{ set up a bitmap according to a BitEdit record }
|
|
|
|
BEGIN
|
|
WITH hbe^^, bm DO
|
|
BEGIN
|
|
baseAddr := POINTER(ORD(editHandle^) + editOffset);
|
|
rowBytes := beRowBytes;
|
|
bounds := beBounds;
|
|
END;
|
|
END; { BEBitmap }
|
|
|
|
|
|
PROCEDURE BEPixmap(VAR bm: PixMapHandle; hbe: BEHandle);
|
|
{ set up a pixmap according to a BitEdit record }
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
editPix^^.baseAddr := POINTER(ORD(editHandle^) + editOffset);
|
|
bm := editPix;
|
|
END;
|
|
END; { BEBitmap }
|
|
|
|
|
|
FUNCTION BEBit(pt: Point; hbe: BEHandle): BOOLEAN;
|
|
{ Get the value of the pixel at pt }
|
|
|
|
VAR
|
|
myRGB: RGBColor;
|
|
|
|
BEGIN
|
|
BEBit := FALSE;
|
|
BEPtXForm(pt, hbe);
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
IF PtInRect(pt, beEditRect) THEN
|
|
BEGIN
|
|
BEDrawBegin(hbe);
|
|
IF isColor THEN
|
|
BEGIN
|
|
GetCPixel(pt.h, pt.v, myRGB);
|
|
IF (myRGB.red = bePixColor.red) &
|
|
(myRGB.green = bePixColor.green) &
|
|
(myRGB.blue = bePixColor.blue) THEN
|
|
BEBit := True;
|
|
END
|
|
ELSE
|
|
BEBit := GetPixel(pt.h, pt.v);
|
|
BEDrawEnd(hbe);
|
|
END;
|
|
END;
|
|
END; { BEBit }
|
|
|
|
|
|
PROCEDURE BEColor (pt: Point; VAR rgb: RGBColor; hbe: BEHandle);
|
|
{ Returns in rgb the color of the pixel at pt; returns white if pt is outside beEditRect or
|
|
if the BitEdit object is not in color }
|
|
|
|
BEGIN
|
|
WITH rgb DO
|
|
BEGIN red := 0; green := 0; blue := 0; END;
|
|
BEPtXForm (pt, hbe);
|
|
IF PtInRect(pt,hbe^^.beEditRect) AND hbe^^.isColor THEN
|
|
BEGIN
|
|
BEDrawBegin (hbe);
|
|
GetCPixel (pt.h, pt.v, rgb);
|
|
BEDrawEnd (hbe);
|
|
END;
|
|
END; { BEColor }
|
|
|
|
|
|
PROCEDURE BEPaintBucket (startPt: Point; hbe: BEHandle);
|
|
{ Paint the bit/pixel at point startPt (in window coordinates) and all adjacent bits/pixels of the same value
|
|
with 1/the current color }
|
|
|
|
VAR
|
|
bmMask: BitMap;
|
|
r: Rect;
|
|
port: GrafPtr;
|
|
rgbBlack:RGBColor;
|
|
hpmPat: PixMapHandle;
|
|
bmPat: BitMap;
|
|
p: Ptr;
|
|
|
|
BEGIN
|
|
IF BESelection(hbe) THEN
|
|
BEPutSelection (hbe)
|
|
ELSE
|
|
SetupUndo (hbe);
|
|
|
|
{ Get the rectangle enclosing the image }
|
|
r := hbe^^.beBounds;
|
|
|
|
{ Setup the mask }
|
|
bmMask.rowBytes := ((r.right - r.left) + 7) DIV 8; { minimum number of bytes }
|
|
bmMask.rowBytes := BAND (bmMask.rowBytes+1, $FFFE); { make it an even number of bytes for SeedCFill }
|
|
bmMask.bounds := r;
|
|
bmMask.baseAddr := NewPtr (UIntMul(bmMask.rowBytes, (r.bottom - r.top)));
|
|
hbe^^.error := MemError;
|
|
If hbe^^.error <> NoErr THEN
|
|
Exit(BEPaintBucket);
|
|
|
|
{ Expand the pattern }
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
hpmPat := hbe^^.editPix;
|
|
hbe^^.error := HandToHand (Handle (hpmPat));
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
DisposPtr (bmMask.baseAddr);
|
|
Exit(BEPaintBucket);
|
|
END;
|
|
p := NewPtr (UIntMul(BAND (hpmPat^^.rowBytes, $7FFF), (r.bottom - r.top)));
|
|
hpmPat^^.baseAddr := p;
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
DisposPtr (bmMask.baseAddr);
|
|
HUnlock (Handle (hpmPat));
|
|
DisposHandle (Handle (hpmPat));
|
|
Exit(BEPaintBucket);
|
|
END;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
bmPat.bounds := r;
|
|
bmPat.rowBytes := hbe^^.beRowBytes;
|
|
bmPat.baseAddr := NewPtr (UIntMul(bmPat.rowBytes, (r.bottom - r.top)));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
DisposPtr (bmMask.baseAddr);
|
|
Exit(BEPaintBucket);
|
|
END;
|
|
END;
|
|
|
|
{ Create the pattern }
|
|
LockHands(hbe);
|
|
BEDrawBegin (hbe);
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
WITH rgbBlack DO
|
|
BEGIN red := 0; green := 0; blue := 0; END;
|
|
HLock (Handle (hpmPat));
|
|
SetPortPix (hpmPat);
|
|
RGBForeColor(hbe^^.bePixColor);
|
|
hbe^^.bePixPat^^.patXValid := -1;
|
|
FillCRect(r, hbe^^.bePixPat);
|
|
RGBForeColor (rgbBlack);
|
|
HUnlock (Handle (hpmPat));
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
SetPortBits (bmPat);
|
|
FillRect (r, hbe^^.beFillPat);
|
|
END;
|
|
BEDrawEnd (hbe);
|
|
UnlockHands(hbe);
|
|
|
|
{ Translate window point into bitmap local coordinates }
|
|
BEPtXForm (startPt, hbe);
|
|
|
|
LockHands(hbe);
|
|
BEDrawBegin (hbe);
|
|
GetPort (port);
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
{ Calculate the mask }
|
|
SeedCFill (port^.portBits, bmMask, r, r, startPt.h, startPt.v, nil, 0);
|
|
|
|
{ Spread the pattern }
|
|
HLock (Handle (hpmPat));
|
|
CopyMask (BitMapPtr(hpmPat^)^, bmMask, port^.portBits, r, r, r);
|
|
HUnlock (Handle (hpmPat));
|
|
|
|
{ Discard expanded pattern }
|
|
DisposPtr (hpmPat^^.baseAddr);
|
|
DisposHandle (Handle (hpmPat));
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
SeedFill (port^.portBits.baseAddr, bmMask.baseAddr, hbe^^.beRowBytes, bmMask.rowBytes, (r.bottom-r.top),
|
|
bmMask.rowBytes DIV 2, startPt.h, startPt.v);
|
|
CopyMask (bmPat, bmMask, port^.portBits, r, r, r);
|
|
|
|
{ Discard expanded pattern data }
|
|
DisposPtr (bmPat.baseAddr);
|
|
END;
|
|
|
|
BEDrawEnd (hbe);
|
|
UnlockHands(hbe);
|
|
|
|
{ Force redraw }
|
|
BEInvalRect (r, hbe);
|
|
|
|
{ Discard mask }
|
|
DisposPtr (bmMask.baseAddr);
|
|
END; { BEPaintBucket }
|
|
|
|
|
|
PROCEDURE DoSaveBits(hbe: BEHandle);
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
IF isColor THEN
|
|
savePixMap := cGrafPtr(beGrafPtr)^.portPixMap
|
|
ELSE
|
|
saveBitMap := beGrafPtr^.portBits;
|
|
END;
|
|
END;
|
|
|
|
|
|
PROCEDURE DoRestoreBits(hbe: BEHandle);
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
IF isColor THEN
|
|
SetPortPix(savePixMap)
|
|
ELSE
|
|
SetPortBits(saveBitMap);
|
|
END;
|
|
END;
|
|
|
|
|
|
FUNCTION BEInSelection(pt: Point; hbe: BEHandle): BOOLEAN;
|
|
{ tell whether or not the given point is over a selection. }
|
|
{ returns False if there is no selection. }
|
|
|
|
VAR
|
|
r: Rect;
|
|
saveBits: PixMapHandle;
|
|
tPt: Point;
|
|
myC: RGBColor;
|
|
|
|
BEGIN
|
|
WITH hbe^^, hbe^^.selection DO
|
|
BEGIN
|
|
BEInSelection := False;
|
|
IF NOT EmptyRect(selRect) OR (maskHandle <> Nil) THEN
|
|
BEGIN
|
|
r := selRect;
|
|
StretchRect(r);
|
|
BEPtXForm(pt, hbe);
|
|
IF marquee THEN
|
|
BEGIN
|
|
IF PtInRect(pt, r) THEN
|
|
BEInSelection := True;
|
|
END
|
|
ELSE
|
|
IF PtInRect(pt, r) THEN
|
|
BEGIN
|
|
DoSaveBits(hbe);
|
|
tPt := r.topLeft;
|
|
|
|
IF isColor THEN
|
|
BEGIN
|
|
maskPix^^.baseAddr := maskHandle^;
|
|
SetPortPix(maskPix);
|
|
SubPt(maskPix^^.bounds.topLeft, tPt);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
maskBits.baseAddr := maskHandle^;
|
|
SetPortBits(maskBits);
|
|
SubPt(maskBits.bounds.topLeft, tPt);
|
|
END;
|
|
|
|
SubPt(tPt, pt);
|
|
pt.h := pt.h + 1;
|
|
pt.v := pt.v + 1;
|
|
|
|
IF isColor THEN
|
|
BEGIN
|
|
GetCPixel(pt.h, pt.v, myC);
|
|
WITH myC DO
|
|
IF (red <> $FFFF) | (blue <> $FFFF) | (green <> $FFFF) THEN
|
|
BEInSelection := True;
|
|
END
|
|
ELSE
|
|
IF GetPixel(pt.h, pt.v) THEN
|
|
BEInSelection := True;
|
|
DoRestoreBits(hbe);
|
|
END;
|
|
END;
|
|
END;
|
|
END; { BEInSelection }
|
|
|
|
|
|
FUNCTION BESelection(hbe: BEHandle): BOOLEAN;
|
|
{ tell whether or not there is a selection. }
|
|
{ returns False if there is no selection. }
|
|
|
|
BEGIN
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
IF EmptyRect(selRect) AND (maskHandle = Nil) THEN
|
|
BESelection := FALSE
|
|
ELSE
|
|
BESelection := TRUE;
|
|
END;
|
|
END; { BESelection }
|
|
|
|
|
|
PROCEDURE GetBWTable(tempTable: CTabHandle);
|
|
|
|
VAR
|
|
i: INTEGER;
|
|
|
|
BEGIN
|
|
WITH tempTable^^ DO
|
|
FOR i := 0 to ctSize DO
|
|
BEGIN
|
|
IF (ctTable[i].rgb.red <> $FFFF) OR
|
|
(ctTable[i].rgb.green <> $FFFF) OR
|
|
(ctTable[i].rgb.blue <> $FFFF) THEN
|
|
BEGIN
|
|
ctTable[i].rgb.red := 0;
|
|
ctTable[i].rgb.green := 0;
|
|
ctTable[i].rgb.blue := 0;
|
|
END;
|
|
END;
|
|
END;
|
|
|
|
|
|
FUNCTION myGetPixel(x, y: INTEGER; hbe: BEHandle): BOOLEAN;
|
|
|
|
VAR
|
|
myC: RGBColor;
|
|
|
|
BEGIN
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
myGetPixel := False;
|
|
GetCPixel(x, y, myC);
|
|
WITH myC DO
|
|
IF (red <> $FFFF) OR (blue <> $FFFF) OR (green <> $FFFF) THEN
|
|
myGetPixel := True;
|
|
END
|
|
ELSE
|
|
myGetPixel := GetPixel(x,y);
|
|
END;
|
|
|
|
|
|
PROCEDURE BEBounds(VAR minimalRect: Rect; hbe: BEHandle);
|
|
{ returns the minimal bounds rect of the bitmap }
|
|
|
|
VAR
|
|
x, y: INTEGER;
|
|
tempRect: Rect;
|
|
|
|
BEGIN
|
|
LockHands(hbe);
|
|
WITH hbe^^.beEditRect DO
|
|
SetRect(minimalRect, right, bottom, left, top);
|
|
tempRect := minimalRect;
|
|
WITH hbe^^, beEditRect DO
|
|
BEGIN
|
|
BEDrawBegin(hbe);
|
|
HideCursor;
|
|
|
|
{ check for left boundary }
|
|
y := top;
|
|
x := left;
|
|
WHILE y < bottom DO
|
|
BEGIN
|
|
WHILE x < right DO
|
|
BEGIN
|
|
IF myGetPixel(x, y, hbe) THEN
|
|
IF minimalRect.left > x THEN minimalRect.left := x;
|
|
x := x + 1;
|
|
END;
|
|
y := y + 1;
|
|
x := left;
|
|
END;
|
|
|
|
{ check for right boundary }
|
|
y := top;
|
|
x := right - 1;
|
|
WHILE y < bottom DO
|
|
BEGIN
|
|
WHILE x >= left DO
|
|
BEGIN
|
|
IF myGetPixel(x, y, hbe) THEN
|
|
IF minimalRect.right < x THEN minimalRect.right := x;
|
|
x := x - 1;
|
|
END;
|
|
y := y + 1;
|
|
x := right - 1;
|
|
END;
|
|
|
|
{ check for top boundary }
|
|
y := top;
|
|
x := left;
|
|
WHILE x < right DO
|
|
BEGIN
|
|
WHILE y < bottom DO
|
|
BEGIN
|
|
IF myGetPixel(x, y, hbe) THEN
|
|
IF minimalRect.top > y THEN minimalRect.top := y;
|
|
y := y + 1;
|
|
END;
|
|
x := x + 1;
|
|
y := top;
|
|
END;
|
|
|
|
{ check for bottom boundary }
|
|
y := bottom - 1;
|
|
x := left;
|
|
WHILE x < right DO
|
|
BEGIN
|
|
WHILE y >= top DO
|
|
BEGIN
|
|
IF myGetPixel(x, y, hbe) THEN
|
|
IF minimalRect.bottom < y THEN minimalRect.bottom := y;
|
|
y := y - 1;
|
|
END;
|
|
x := x + 1;
|
|
y := bottom - 1;
|
|
END;
|
|
|
|
IF EqualRect(tempRect, minimalRect) THEN
|
|
SetRect(minimalRect, 0, 0, 0, 0)
|
|
ELSE
|
|
BEGIN
|
|
StretchRect(minimalRect);
|
|
END;
|
|
|
|
BEDrawEnd(hbe);
|
|
ShowCursor;
|
|
END;
|
|
|
|
UnlockHands(hbe);
|
|
END; { BEBounds }
|
|
|
|
|
|
PROCEDURE MySetDupBits(hbe: BEHandle);
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
IF isColor THEN
|
|
SetPortPix(dupPix)
|
|
ELSE
|
|
SetPortBits(dupBits);
|
|
END;
|
|
END;
|
|
|
|
|
|
PROCEDURE BEClear(hbe: BEHandle);
|
|
{ Clears the selection }
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) THEN
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
LockHands(hbe);
|
|
|
|
IF NOT hbe^^.selection.wasErased THEN
|
|
BEGIN
|
|
BEDrawBegin(hbe);
|
|
CopySelToPort(hbe);
|
|
IF hbe^^.marquee THEN
|
|
BEGIN
|
|
MySetDupBits(hbe);
|
|
EraseRect(r);
|
|
END
|
|
ELSE
|
|
MaskToDup(hbe);
|
|
BEDrawEnd(hbe);
|
|
END;
|
|
|
|
UnlockHands(hbe);
|
|
BEKillSelection(hbe);
|
|
|
|
END;
|
|
|
|
END; { BEClear }
|
|
|
|
|
|
FUNCTION BEGetView(pt: Point; VAR hbe: BEHandle): BOOLEAN;
|
|
|
|
VAR
|
|
found: Boolean;
|
|
hUse: BEHandle;
|
|
|
|
BEGIN
|
|
hUse := hbe;
|
|
REPEAT
|
|
found := PtInRect(pt, hUse^^.beViewRect);
|
|
IF found THEN
|
|
hbe := hUse
|
|
ELSE
|
|
hUse:= hUse^^.sibling;
|
|
UNTIL hUse = hbe;
|
|
BEGetView := found;
|
|
END; { BEGetView }
|
|
|
|
|
|
PROCEDURE BEUpdateRect(r: Rect; hbe: BEHandle);
|
|
{ Redraws the given rectangle (in screen space) }
|
|
|
|
VAR
|
|
theRect: rect;
|
|
hUse: BEHandle;
|
|
t: Boolean;
|
|
|
|
BEGIN
|
|
hUse:= hbe;
|
|
REPEAT
|
|
IF SectRect(r, hUse^^.beViewRect, theRect) THEN
|
|
BEGIN
|
|
BEPtXForm(theRect.topLeft, hUse);
|
|
BEPtXForm(theRect.botRight, hUse);
|
|
InsetRect(theRect, -1, -1);
|
|
t := SectRect(theRect, hUse^^.beEditRect, theRect);
|
|
BEDraw(theRect, hUse);
|
|
END;
|
|
hUse:= hUse^^.sibling;
|
|
UNTIL hUse = hbe;
|
|
END; { BEUpdateRect }
|
|
|
|
|
|
PROCEDURE BEInvalRect(r: Rect; hbe: BEHandle);
|
|
|
|
VAR
|
|
hFirst: BEHandle;
|
|
b: BOOLEAN;
|
|
|
|
BEGIN
|
|
b := SectRect (r, hbe^^.beEditRect, r);
|
|
hFirst := hbe;
|
|
REPEAT
|
|
BEDraw(r, hbe);
|
|
hbe := hbe^^.sibling;
|
|
UNTIL hFirst = hbe;
|
|
END; { BEInvalRect }
|
|
|
|
|
|
PROCEDURE PaintBits(blacken, erase: BOOLEAN; stPt, endPt: Point; hbe: BEHandle);
|
|
|
|
VAR
|
|
testPt: Point;
|
|
t: BOOLEAN;
|
|
r: Rect;
|
|
saveRgn: Handle;
|
|
blackRGB: RGBColor;
|
|
|
|
BEGIN
|
|
testPt := stPt;
|
|
BEPtXForm(stPt, hbe);
|
|
BEPtXForm(endPt, hbe);
|
|
GetPenState(hbe^^.savePen);
|
|
|
|
WITH blackRGB DO
|
|
BEGIN
|
|
red := 0; blue := 0; green := 0;
|
|
END;
|
|
|
|
IF (LongInt(stPt) <> LongInt(endPt)) |
|
|
(blacken <> BEBit(testPt, hbe)) | erase THEN
|
|
BEGIN
|
|
BEDrawBegin(hbe);
|
|
PenNormal;
|
|
|
|
IF NOT blacken THEN PenMode(patBic);
|
|
IF erase THEN penSize(hbe^^.beEraserSize.h, hbe^^.beEraserSize.v);
|
|
|
|
IF hbe^^.isColor THEN
|
|
RGBForeColor(hbe^^.bePixColor);
|
|
|
|
{ draw the line in small bitmap }
|
|
MoveTo(stPt.h, stPt.v);
|
|
LineTo(endPt.h, endPt.v);
|
|
|
|
IF hbe^^.isColor THEN
|
|
RGBForeColor(blackRGB);
|
|
|
|
BEDrawEnd(hbe);
|
|
|
|
{ figure out what the smallest rectangle to copy is }
|
|
Pt2Rect(stPt, endPt, r);
|
|
|
|
{ expand rect to enclose all pixels }
|
|
StretchRect(r);
|
|
|
|
IF erase THEN
|
|
BEGIN
|
|
r.bottom := r.bottom + (hbe^^.beEraserSize.v - 1);
|
|
r.right := r.right + (hbe^^.beEraserSize.h - 1);
|
|
END;
|
|
|
|
{ do our own clipping }
|
|
t := SectRect(hbe^^.beEditRect, r, r);
|
|
|
|
{ Draw all the views - turn off region collection }
|
|
saveRgn := hbe^^.beGrafPtr^.rgnSave;
|
|
hbe^^.beGrafPtr^.rgnSave := Nil;
|
|
|
|
BEInvalRect(r, hbe);
|
|
|
|
{ turn region collection back on }
|
|
hbe^^.beGrafPtr^.rgnSave := saveRgn;
|
|
|
|
END;
|
|
SetPenState(hbe^^.savePen);
|
|
END; { PaintBits }
|
|
|
|
|
|
PROCEDURE BWOffScreen (hbe: BEHandle);
|
|
|
|
VAR
|
|
n: Handle;
|
|
bitNum: INTEGER;
|
|
|
|
BEGIN
|
|
WITH hbe^^,offBits DO
|
|
BEGIN
|
|
{ figure out rowbytes from rectangle }
|
|
rowBytes := ((beViewRect.right - beViewRect.left) + 7) DIV 8;
|
|
|
|
{ allocate out to long word boundary + 1 long word }
|
|
rowBytes := rowBytes + rowBytes MOD 4 + 4;
|
|
|
|
{ figure out which bit in a long word the left edge occupies }
|
|
bitNum := (beViewRect.left - beGrafPtr^.portBits.bounds.left) MOD 32;
|
|
|
|
{ make sure answer is positive }
|
|
IF bitNum < 0 THEN bitNum := bitNum + 32;
|
|
|
|
with bounds do
|
|
begin
|
|
top := beViewRect.top;
|
|
left := beViewRect.left - bitNum;
|
|
bottom := beViewRect.bottom;
|
|
right := left + 8 * rowBytes;
|
|
end;
|
|
END;
|
|
|
|
n := NewHandle(hbe^^.offBits.rowBytes * (hbe^^.beViewRect.bottom - hbe^^.beViewRect.top));
|
|
hbe^^.error := MemError;
|
|
If hbe^^.error <> NoErr THEN { if not enough memory set error field true and leave }
|
|
Exit(BWOffScreen);
|
|
|
|
hbe^^.offHandle := n;
|
|
END;
|
|
|
|
|
|
PROCEDURE ResetOffScreen(hgd: GDHandle; hbe: BEHandle);
|
|
{ routine to reset the pixmap to the new pixel depth of the screen }
|
|
|
|
VAR
|
|
viewCTHndl, theHndl: Handle;
|
|
mySize: LongInt;
|
|
myErr: OSErr;
|
|
np: PixMapHandle;
|
|
|
|
BEGIN
|
|
{ if we already have an offBits, trash it }
|
|
IF hbe^^.offHandle <> Nil THEN
|
|
BEGIN
|
|
DisposHandle(hbe^^.offHandle);
|
|
IF hbe^^.isColor THEN
|
|
DisposPixMap(hbe^^.offPix);
|
|
END;
|
|
|
|
IF NOT hbe^^.isColor THEN
|
|
BEGIN
|
|
BWOffScreen (hbe);
|
|
Exit(ResetOffScreen);
|
|
END;
|
|
|
|
np := NewPixMap;
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
Exit(ResetOffScreen);
|
|
hbe^^.offPix := np;
|
|
DisposHandle (Handle(hbe^^.offPix^^.pmTable));
|
|
|
|
viewCTHndl := Handle (hgd^^.gdPMap^^.pmTable);
|
|
myErr := HandToHand (viewCTHndl);
|
|
|
|
WITH hbe^^.offPix^^ DO
|
|
BEGIN
|
|
{ figure out rowbytes from rectangle }
|
|
rowBytes := ((((hgd^^.gdPMap^^.pixelSize * (hbe^^.beViewRect.right - hbe^^.beViewRect.left)) + 15))
|
|
DIV 16) * 2;
|
|
pixelSize := hgd^^.gdPMap^^.pixelSize;
|
|
cmpSize := hgd^^.gdPMap^^.pixelSize;
|
|
pmTable := CTabHandle(viewCTHndl);
|
|
bounds := hbe^^.beViewRect;
|
|
END;
|
|
|
|
WITH hbe^^ DO
|
|
mySize := UIntMul((beViewRect.bottom - beViewRect.top), offPix^^.rowBytes);
|
|
|
|
theHndl := NewHandle(mySize);
|
|
hbe^^.error := MemError;
|
|
|
|
hbe^^.offHandle := theHndl;
|
|
hbe^^.offPix^^.rowBytes := hbe^^.offPix^^.rowBytes + $8000;
|
|
END;
|
|
|
|
|
|
PROCEDURE DoMyMapRect(hbe: BEHandle; VAR r: Rect; srcRect: Rect);
|
|
|
|
VAR
|
|
rvr: Rect;
|
|
|
|
BEGIN
|
|
WITH srcRect DO
|
|
BEGIN
|
|
bottom := top + 1;
|
|
right := left + 1;
|
|
END;
|
|
|
|
rvr.topLeft := hbe^^.beViewRect.topLeft;
|
|
WITH rvr, hbe^^ DO
|
|
BEGIN
|
|
bottom := top + fatbitsSize.v + fatbitsDelta.v;
|
|
right := left + fatbitsSize.h + fatbitsDelta.h;
|
|
END;
|
|
|
|
MapRect(r, srcRect, rvr);
|
|
END;
|
|
|
|
|
|
PROCEDURE BEDraw(r: Rect; hbe: BEHandle);
|
|
|
|
TYPE
|
|
TAPat = RECORD
|
|
CASE INTEGER OF
|
|
0: (pat: Pattern);
|
|
1: (lPat0, lPat1: LONGINT);
|
|
END;
|
|
|
|
VAR
|
|
myWhite: TAPat;
|
|
bigR, bmr, rvr: Rect;
|
|
bm: BitMap;
|
|
pm: PixMapHandle;
|
|
i: INTEGER;
|
|
t: Boolean;
|
|
saveDevice, maxDevice: GDHandle;
|
|
globalR: Rect;
|
|
|
|
BEGIN
|
|
IF hbe^^.drawEnabled THEN
|
|
BEGIN
|
|
GetPenState (hbe^^.savePen);
|
|
GetClip (hbe^^.saveClip);
|
|
|
|
HLock (Handle(hbe));
|
|
HLock (hbe^^.editHandle);
|
|
|
|
bigR := r;
|
|
bmr.topLeft := hbe^^.beBounds.topLeft;
|
|
|
|
DoMyMapRect(hbe, bigR, bmr);
|
|
|
|
t := SectRect(hbe^^.beViewRect, hbe^^.realRect, bmr);
|
|
ClipRect(bmr);
|
|
|
|
myWhite.lPat0 := 0;
|
|
myWhite.lPat1 := 0;
|
|
|
|
IF LongInt(hbe^^.fatbitsDelta) <> 0 THEN
|
|
{ Image to offscreen pixMap to avoid flicker }
|
|
BEGIN
|
|
|
|
{ Find deepest screen intersecting fatbits rectangle }
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
saveDevice := GetGDevice;
|
|
globalR := hbe^^.beViewRect;
|
|
LocalToGlobal (globalR.topLeft);
|
|
LocalToGlobal (globalR.botRight);
|
|
maxDevice := GetMaxDevice (globalR);
|
|
SetGDevice (maxDevice);
|
|
END;
|
|
|
|
{ check to see if pixel depth of screen has changed }
|
|
{ or if the port's color table has changed -- 5/24/89 crc }
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
IF (hbe^^.offPix = Nil)
|
|
|
|
|
(maxDevice^^.gdPMap^^.pixelSize <> hbe^^.offPix^^.pixelSize)
|
|
|
|
|
(maxDevice^^.gdPMap^^.pmTable^^.ctSeed <> hbe^^.offPix^^.pmTable^^.ctSeed)
|
|
THEN
|
|
ResetOffscreen (maxDevice, hbe);
|
|
END
|
|
ELSE
|
|
IF (hbe^^.offHandle = Nil) THEN
|
|
BWOffScreen (hbe);
|
|
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
HUnlock (Handle(hbe));
|
|
HUnlock (hbe^^.editHandle);
|
|
SetPenState(hbe^^.savePen);
|
|
SetClip(hbe^^.saveClip);
|
|
Exit(BEDraw);
|
|
END;
|
|
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
HLock (offHandle);
|
|
IF isColor THEN
|
|
HLock(Handle(offPix));
|
|
|
|
IF isColor THEN
|
|
offPix^^.baseAddr := offHandle^
|
|
ELSE
|
|
offBits.baseAddr := offHandle^;
|
|
|
|
{ make a pixmap out of bitEdit record }
|
|
IF isColor THEN
|
|
BEGIN
|
|
BEPixMap(pm, hbe);
|
|
HLock(Handle(cGrafPtr(beGrafPtr)^.portPixMap)) { crc: Why this? }
|
|
END
|
|
ELSE
|
|
BEBitmap(bm, hbe);
|
|
|
|
{ align the offscreen bitmaps }
|
|
IF NOT isColor THEN
|
|
AlignBits(hbe);
|
|
END;
|
|
|
|
DoSaveBits(hbe);
|
|
|
|
{ enlarge bits into offscreen }
|
|
IF hbe^^.isColor THEN
|
|
CopyBits (BitMapPtr(pm^)^, BitMapPtr(hbe^^.offPix^)^, r, bigR, srcCopy, Nil)
|
|
ELSE
|
|
CopyBits (bm, hbe^^.offBits, r, bigR, srcCopy, Nil);
|
|
|
|
{ draw the grid lines }
|
|
PenNormal;
|
|
PenMode(patBic);
|
|
|
|
IF hbe^^.isColor THEN
|
|
SetPortPix(hbe^^.offPix)
|
|
ELSE
|
|
SetPortBits(hbe^^.offBits);
|
|
|
|
{ draw horizontals }
|
|
i:= bigR.top;
|
|
WHILE i <= bigR.bottom DO
|
|
BEGIN
|
|
MoveTo(bigR.left, i);
|
|
LineTo(bigR.right, i);
|
|
i := i + hbe^^.fatbitsSize.v + hbe^^.fatbitsDelta.v;
|
|
END;
|
|
|
|
{ draw verticals }
|
|
i:= bigR.left;
|
|
WHILE i <= bigR.right DO
|
|
BEGIN
|
|
MoveTo(i, bigR.top);
|
|
LineTo(i, bigR.bottom);
|
|
i := i + hbe^^.fatbitsSize.h + hbe^^.fatbitsDelta.h;
|
|
END;
|
|
|
|
{ Dim out the pixels }
|
|
IF ((TAPat(hbe^^.fatbitsPat).lPat0 <> myWhite.lPat0) |
|
|
(TAPat(hbe^^.fatbitsPat).lPat1 <> myWhite.lPat1)) THEN
|
|
{ if pattern is white then don't paintrect }
|
|
BEGIN
|
|
PenPat(hbe^^.fatbitsPat);
|
|
PenMode(patBic);
|
|
PaintRect(bigR);
|
|
END;
|
|
|
|
DoRestoreBits(hbe);
|
|
|
|
{ copy FatBits to screen }
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
SetGDevice (saveDevice);
|
|
CopyBits(BitMapPtr(hbe^^.offPix^)^, hbe^^.beGrafPtr^.portBits,
|
|
bigR, bigR, srcCopy, Nil);
|
|
END
|
|
ELSE
|
|
CopyBits(hbe^^.offBits, hbe^^.beGrafPtr^.portBits, bigR, bigR, srcCopy, Nil);
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
HUnlock(Handle(hbe^^.offPix));
|
|
HUnlock(Handle(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap))
|
|
END;
|
|
HUnlock(hbe^^.offHandle);
|
|
END
|
|
ELSE
|
|
{ no grid lines, just blit to screen }
|
|
BEGIN
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
BEPixMap(pm, hbe);
|
|
CopyBits(BitMapPtr(pm^)^, hbe^^.beGrafPtr^.portBits, r, bigR, srcCopy, Nil);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
BEBitmap(bm, hbe);
|
|
CopyBits(bm, hbe^^.beGrafPtr^.portBits, r, bigR, srcCopy, Nil);
|
|
END;
|
|
|
|
{ Dim out the pixels }
|
|
IF ((TAPat(hbe^^.fatbitsPat).lPat0 <> myWhite.lPat0) |
|
|
(TAPat(hbe^^.fatbitsPat).lPat1 <> myWhite.lPat1)) THEN
|
|
{ if pattern is white then don't paintrect }
|
|
BEGIN
|
|
PenPat(hbe^^.fatbitsPat);
|
|
PenMode(patBic);
|
|
PaintRect(bigR);
|
|
END;
|
|
END;
|
|
|
|
SetPenState(hbe^^.savePen);
|
|
SetClip(hbe^^.saveClip);
|
|
HUnlock(hbe^^.editHandle);
|
|
HUnlock(Handle(hbe));
|
|
END;
|
|
END; { BEDraw }
|
|
|
|
FUNCTION AllocatePixMap (pmTable: CTabHandle; hbe: BEHandle): PixMapHandle;
|
|
{ Returns Nil if a PixMap cannot be allocated. If pmTable is not Nil,
|
|
it is used as the color table. }
|
|
|
|
VAR
|
|
hpm: PixMapHandle;
|
|
|
|
BEGIN
|
|
AllocatePixMap := Nil;
|
|
|
|
hpm := NewPixMap;
|
|
IF MemError = NoErr THEN
|
|
BEGIN
|
|
IF pmTable <> Nil THEN
|
|
BEGIN
|
|
DisposHandle (Handle(hpm^^.pmTable));
|
|
hpm^^.pmTable := pmTable
|
|
END;
|
|
AllocatePixMap := hpm;
|
|
END;
|
|
END; { AllocatePixMap }
|
|
|
|
|
|
PROCEDURE NewSelPixMaps (hbe: BEHandle);
|
|
{ This routine should be called once to allocate and partially initialize PixMaps
|
|
for repeated use in selections. This routine requires its argument handle to
|
|
be locked! }
|
|
|
|
VAR
|
|
hpm: PixMapHandle;
|
|
myWhite, myBlack: RGBColor;
|
|
pmTable: CTabHandle;
|
|
|
|
BEGIN
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
selPix := AllocatePixMap(hbe^^.beColorTable, hbe);
|
|
IF selPix = Nil THEN
|
|
EXIT (NewSelPixMaps);
|
|
|
|
selPix^^.pixelSize := hbe^^.bePixelSize;
|
|
selPix^^.cmpSize := hbe^^.bePixelSize;
|
|
|
|
maskPix := AllocatePixMap (Nil, hbe);
|
|
IF maskPix = Nil THEN
|
|
EXIT (NewSelPixMaps);
|
|
|
|
maskPix^^.pixelSize := 1;
|
|
maskPix^^.cmpSize := 1;
|
|
|
|
WITH myBlack DO
|
|
BEGIN
|
|
red := 0; blue := 0; green := 0;
|
|
END;
|
|
|
|
WITH myWhite DO
|
|
BEGIN
|
|
red := $FFFF; blue := $FFFF; green := $FFFF;
|
|
END;
|
|
|
|
{ Is this handle zero length? }
|
|
WITH maskPix^^.pmTable^^ DO
|
|
BEGIN
|
|
ctSeed := 1;
|
|
ctFlags := $8000;
|
|
ctSize := 1;
|
|
ctTable[0].value := 0;
|
|
ctTable[1].value := 0;
|
|
ctTable[0].rgb := myWhite;
|
|
ctTable[1].rgb := myBlack;
|
|
END;
|
|
|
|
pmTable := maskPix^^.pmTable;
|
|
|
|
edgePix := AllocatePixMap (pmTable, hbe);
|
|
IF edgePix = Nil THEN
|
|
EXIT (NewSelPixMaps);
|
|
|
|
edgePix^^.pixelSize := 1;
|
|
edgePix^^.cmpSize := 1;
|
|
END;
|
|
|
|
WITH hbe^^.undoSelection DO
|
|
BEGIN
|
|
selPix := AllocatePixMap(hbe^^.beColorTable, hbe);
|
|
IF selPix = Nil THEN
|
|
EXIT (NewSelPixMaps);
|
|
|
|
maskPix := AllocatePixMap (pmTable, hbe);
|
|
IF maskPix = Nil THEN
|
|
EXIT (NewSelPixMaps);
|
|
|
|
edgePix := AllocatePixMap (pmTable, hbe);
|
|
IF edgePix = Nil THEN
|
|
EXIT (NewSelPixMaps);
|
|
END;
|
|
END; { NewSelPixMaps }
|
|
|
|
|
|
PROCEDURE DisposeSelPixMaps (hbe: BEHandle);
|
|
BEGIN
|
|
MyDisposPixMap (hbe^^.undoSelection.edgePix);
|
|
MyDisposPixMap (hbe^^.undoSelection.maskPix);
|
|
MyDisposPixMap (hbe^^.undoSelection.selPix);
|
|
|
|
MyDisposPixMap (hbe^^.selection.edgePix);
|
|
IF hbe^^.selection.maskPix <> Nil THEN
|
|
DisposPixMap (hbe^^.selection.maskPix);
|
|
MyDisposPixMap (hbe^^.selection.selPix);
|
|
END;
|
|
|
|
|
|
PROCEDURE KillSelection (VAR selection: BESelectRec);
|
|
{ NOTE: if the argument is referenced by a BEHandle, make sure the handle is locked }
|
|
|
|
BEGIN
|
|
WITH selection DO
|
|
BEGIN
|
|
IF edgeHandle <> Nil THEN
|
|
BEGIN
|
|
DisposHandle(edgeHandle);
|
|
edgeHandle := Nil;
|
|
END;
|
|
|
|
IF maskHandle <> Nil THEN
|
|
BEGIN
|
|
DisposHandle(maskHandle);
|
|
maskHandle := Nil;
|
|
END;
|
|
|
|
IF selHandle <> Nil THEN
|
|
BEGIN
|
|
DisposHandle(selHandle);
|
|
selHandle := Nil;
|
|
END;
|
|
|
|
SetRect(selRect, 0, 0, 0, 0);
|
|
END;
|
|
END; { KillSelection }
|
|
|
|
|
|
PROCEDURE KillUndoSelection (hbe: BEHandle);
|
|
|
|
BEGIN
|
|
HLock (Handle (hbe));
|
|
KillSelection (hbe^^.undoSelection);
|
|
HUnlock (Handle (hbe));
|
|
END; { KillUndoSelection }
|
|
|
|
|
|
PROCEDURE SetupUndoSelection (hbe: BEHandle);
|
|
{ Save a copy of the current selection for undo. The current selection is not effected }
|
|
|
|
LABEL
|
|
1, 2, 3;
|
|
VAR
|
|
err: OSErr;
|
|
maskHandle, edgeHandle, selHandle: Handle;
|
|
|
|
BEGIN
|
|
IF hbe^^.undoFreeze = 0 THEN
|
|
BEGIN
|
|
err := noErr;
|
|
|
|
maskHandle := hbe^^.selection.maskHandle;
|
|
IF maskHandle <> Nil THEN
|
|
err := HandToHand (Handle(maskHandle));
|
|
IF err <> noErr THEN
|
|
GOTO 1;
|
|
|
|
edgeHandle := hbe^^.selection.edgeHandle;
|
|
IF edgeHandle <> Nil THEN
|
|
err := HandToHand (Handle(edgeHandle));
|
|
IF err <> noErr THEN
|
|
GOTO 2;
|
|
|
|
selHandle := hbe^^.selection.selHandle;
|
|
IF selHandle <> Nil THEN
|
|
err := HandToHand (Handle(selHandle));
|
|
IF err <> noErr THEN
|
|
GOTO 3;
|
|
|
|
KillUndoSelection (hbe);
|
|
|
|
hbe^^.undoSelection.maskHandle := maskHandle;
|
|
hbe^^.undoSelection.edgeHandle := edgeHandle;
|
|
hbe^^.undoSelection.selHandle := selHandle;
|
|
|
|
{ Update the bitMaps or pixMaps (note that all color tables are shared) }
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
hbe^^.undoSelection.maskPix^^ := hbe^^.selection.maskPix^^;
|
|
hbe^^.undoSelection.edgePix^^ := hbe^^.selection.edgePix^^;
|
|
hbe^^.undoSelection.selPix^^ := hbe^^.selection.selPix^^;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
hbe^^.undoSelection.maskBits := hbe^^.selection.maskBits;
|
|
hbe^^.undoSelection.edgeBits := hbe^^.selection.edgeBits;
|
|
hbe^^.undoSelection.selBits := hbe^^.selection.selBits;
|
|
END;
|
|
|
|
hbe^^.undoSelection.selRect := hbe^^.selection.selRect;
|
|
hbe^^.undoSelection.wasErased := hbe^^.selection.wasErased;
|
|
|
|
{ Normal exit }
|
|
GOTO 1;
|
|
|
|
{ Error exits }
|
|
3: DisposHandle(Handle(edgeHandle));
|
|
2: DisposHandle(Handle(maskHandle));
|
|
|
|
{ Normal and error exit }
|
|
1: hbe^^.error := err;
|
|
END;
|
|
|
|
END; { SetupUndoSelection }
|
|
|
|
|
|
PROCEDURE BEKillSelection(hbe: BEHandle);
|
|
{ kills the selection rect without putting down the bits }
|
|
|
|
VAR
|
|
r: Rect;
|
|
n: Handle;
|
|
|
|
BEGIN
|
|
IF BESelection(hbe) THEN
|
|
BEGIN
|
|
r := hbe^^.selection.selRect;
|
|
StretchRect(r);
|
|
|
|
{ Copy current selection for undo, then kill it }
|
|
SetupUndo (hbe);
|
|
HLock(Handle(hbe));
|
|
KillSelection(hbe^^.selection);
|
|
HUnlock(Handle(hbe));
|
|
|
|
{ copy from dupBits to BEBits }
|
|
DoQuickDupToPort(hbe);
|
|
|
|
{ hide selection in all views }
|
|
BEInvalRect(r, hbe);
|
|
END;
|
|
|
|
END; { BEKillSelection }
|
|
|
|
|
|
PROCEDURE BEPutSelection(hbe: BEHandle);
|
|
{ puts the marquee selection bits or lasso bits down and then kills the selection }
|
|
|
|
BEGIN
|
|
IF BESelection(hbe) THEN
|
|
BEGIN
|
|
BEUndoBegin (hbe);
|
|
LockHands(hbe);
|
|
|
|
{ plunk down bits }
|
|
IF hbe^^.marquee THEN
|
|
CSelToDup(hbe)
|
|
ELSE
|
|
BEGIN
|
|
MaskToDup(hbe);
|
|
OSelToDup(hbe);
|
|
END;
|
|
|
|
UnlockHands(hbe);
|
|
|
|
BEKillSelection(hbe);
|
|
BEUndoEnd (hbe);
|
|
END;
|
|
|
|
END; { BEPutSelection }
|
|
|
|
|
|
PROCEDURE BEClick(pt: Point; hbe: BEHandle);
|
|
{ Toggle the bit at the given screen point. If selection up hide it. }
|
|
|
|
VAR
|
|
blacken: BOOLEAN;
|
|
savePt: Point;
|
|
|
|
BEGIN
|
|
{ make sure there is no selection }
|
|
IF BESelection(hbe) THEN
|
|
BEPutSelection(hbe)
|
|
ELSE
|
|
SetupUndo(hbe);
|
|
|
|
blacken := NOT BEBit(pt, hbe);
|
|
|
|
LONGINT(savePt) := LONGINT(pt);
|
|
|
|
PaintBits(blacken, False, savePt, pt, hbe);
|
|
|
|
WHILE WaitMouseUp DO
|
|
BEGIN
|
|
GetMouse(pt);
|
|
IF LONGINT(savePt) <> LONGINT(pt) THEN
|
|
PaintBits(blacken, False, savePt, pt, hbe);
|
|
|
|
LONGINT(savePt) := LONGINT(pt);
|
|
END;
|
|
|
|
END; { BEClick }
|
|
|
|
|
|
PROCEDURE BEErase(pt: Point; hbe: BEHandle);
|
|
{ Erase the bit at the given screen point. If selection up hide it. }
|
|
|
|
VAR
|
|
savePort: GrafPtr;
|
|
savePt: Point;
|
|
hUse: BEHandle;
|
|
|
|
BEGIN
|
|
{ make sure there is no selection }
|
|
IF BESelection(hbe) THEN
|
|
BEPutSelection(hbe)
|
|
ELSE
|
|
SetupUndo(hbe);
|
|
|
|
LONGINT(savePt) := LONGINT(pt);
|
|
|
|
PaintBits(False, True, savePt, pt, hbe);
|
|
|
|
WHILE WaitMouseUp DO
|
|
BEGIN
|
|
GetMouse(pt);
|
|
IF LONGINT(savePt) <> LONGINT(pt) THEN
|
|
PaintBits(False, True, savePt, pt, hbe);
|
|
|
|
LONGINT(savePt) := LONGINT(pt);
|
|
END;
|
|
|
|
END; { BEErase }
|
|
|
|
|
|
PROCEDURE BECopy(hbe: BEHandle);
|
|
{ Copy selection to scrap as bitmap picture }
|
|
|
|
VAR
|
|
pict: PicHandle;
|
|
x: LONGINT;
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) THEN
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
|
|
BEDrawBegin(hbe);
|
|
LockHands(hbe);
|
|
|
|
pict := OpenPicture(r);
|
|
CopySelToPort(hbe);
|
|
ClosePicture;
|
|
|
|
UnlockHands(hbe);
|
|
BEDrawEnd(hbe);
|
|
|
|
x := ZeroScrap;
|
|
HLock(Handle(pict));
|
|
x := PutScrap(GetHandleSize(Handle(pict)), 'PICT', POINTER(pict^));
|
|
HUnlock(Handle(pict));
|
|
KillPicture(pict);
|
|
END;
|
|
|
|
END; { BECopy }
|
|
|
|
|
|
PROCEDURE BECut(hbe: BEHandle);
|
|
{ Cut the selection }
|
|
|
|
BEGIN
|
|
BECopy(hbe);
|
|
BEClear(hbe);
|
|
END; { BECut }
|
|
|
|
|
|
PROCEDURE BEDispose(hbe: BEHandle);
|
|
{ Dispose the bit edit record and the offscreen bitmaps }
|
|
|
|
BEGIN
|
|
BEPutSelection(hbe);
|
|
KillUndoSelection (hbe);
|
|
|
|
IF hbe^^.offHandle <> Nil THEN
|
|
BEGIN
|
|
DisposHandle(hbe^^.offHandle);
|
|
IF hbe^^.isColor THEN
|
|
DisposPixMap(hbe^^.offPix);
|
|
END;
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
DisposGDevice(hbe^^.beGDevice);
|
|
MyDisposPixMap(hbe^^.dupPix);
|
|
MyDisposPixMap(hbe^^.editPix);
|
|
MyDisposPixMap(hbe^^.undoPix);
|
|
DisposeSelPixMaps (hbe);
|
|
END;
|
|
|
|
DisposHandle(hbe^^.dupHandle);
|
|
DisposHandle(hbe^^.undoHandle);
|
|
DisposeRgn(hbe^^.saveClip);
|
|
DisposeRgn(hbe^^.saveVis);
|
|
DisposHandle(Handle(hbe));
|
|
END; { BEDispose }
|
|
|
|
|
|
PROCEDURE BEDrawBegin(hbe: BEHandle);
|
|
{ Prepares the grafPort for drawing into the bits offscreen }
|
|
|
|
VAR
|
|
savePort: GrafPtr;
|
|
theDevice: GDHandle;
|
|
myPixel:RGBColor;
|
|
|
|
BEGIN
|
|
GetPort(savePort);
|
|
|
|
WITH hbe^^, beGrafPtr^ DO BEGIN
|
|
SetPort(beGrafPtr);
|
|
DoSaveBits(hbe);
|
|
|
|
HLock(editHandle);
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
BEPixMap(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap, hbe);
|
|
HLock(Handle(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap));
|
|
END
|
|
ELSE
|
|
BEBitMap(portBits, hbe);
|
|
|
|
GetPenState(savePen);
|
|
|
|
GetClip(saveClip);
|
|
ClipRect(beEditRect);
|
|
|
|
CopyRgn(visRgn, saveVis);
|
|
IF hbe^^.isColor THEN
|
|
RectRgn(visRgn, cGrafPtr(hbe^^.beGrafPtr)^.portPixMap^^.bounds)
|
|
ELSE
|
|
RectRgn(visRgn, hbe^^.beGrafPtr^.portBits.bounds);
|
|
END;
|
|
|
|
SetPort(savePort);
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
theDevice := GetGDevice;
|
|
SetGDevice(hbe^^.beGDevice);
|
|
hbe^^.beGDevice := theDevice;
|
|
GetCPixel(0,0, myPixel);
|
|
SetCPixel(0,0, myPixel);
|
|
END;
|
|
|
|
END; { BEDrawBegin }
|
|
|
|
|
|
PROCEDURE BEDrawEnd(hbe: BEHandle);
|
|
{ Releases the grafport for drawing into the bits }
|
|
|
|
VAR
|
|
savePort: GrafPtr;
|
|
theDevice: GDHandle;
|
|
myPixel: RGBColor;
|
|
|
|
BEGIN
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
theDevice := GetGDevice;
|
|
SetGDevice(hbe^^.beGDevice);
|
|
hbe^^.beGDevice := theDevice;
|
|
END;
|
|
|
|
WITH hbe^^, beGrafPtr^ DO
|
|
BEGIN
|
|
GetPort(savePort);
|
|
SetPort(beGrafPtr);
|
|
|
|
IF hbe^^.isColor THEN
|
|
HUnlock(Handle(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap));
|
|
DoRestoreBits(hbe);
|
|
|
|
HUnlock(editHandle);
|
|
|
|
SetPenState(savePen);
|
|
SetClip(saveClip);
|
|
|
|
CopyRgn(saveVis, visRgn);
|
|
|
|
SetPort(savePort);
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
GetCPixel(0,0, myPixel);
|
|
SetCPixel(0,0, myPixel);
|
|
END;
|
|
END;
|
|
|
|
END; { BEDrawEnd }
|
|
|
|
|
|
PROCEDURE BEIdle(hbe: BEHandle);
|
|
{ Dance the selection rectangle or lasso if active and selection is there }
|
|
|
|
BEGIN
|
|
IF hbe^^.active THEN
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
IF (maskHandle <> Nil) THEN
|
|
HiliteLasso(hbe)
|
|
ELSE
|
|
IF (NOT EmptyRect(selRect)) THEN
|
|
BEObject(selRect.topLeft, @MarqueeDraw, BOR (fUseSelection, fIdle), hbe);
|
|
END;
|
|
END; { BEIdle }
|
|
|
|
|
|
PROCEDURE BEObject(startPt: Point; drawProc: ProcPtr; flags: BEDrawFlags; hbe: BEHandle);
|
|
|
|
VAR
|
|
endPt, testPt: Point;
|
|
r, saveRect, theRect: Rect;
|
|
t, firstFlag: Boolean;
|
|
idle: Boolean;
|
|
mIndex: INTEGER;
|
|
myBlack: RGBColor;
|
|
|
|
BEGIN
|
|
{ invalidate our pattern in case it has been expanded using another gDevice }
|
|
IF hbe^^.isColor THEN
|
|
hbe^^.bePixPat^^.patXValid := -1;
|
|
|
|
idle := BAND (flags, fIdle) <> 0;
|
|
|
|
{ make sure there is no selection }
|
|
IF NOT idle THEN
|
|
BEGIN
|
|
IF BESelection(hbe) THEN
|
|
BEPutSelection(hbe)
|
|
ELSE
|
|
SetupUndo(hbe);
|
|
END;
|
|
|
|
WITH myBlack DO
|
|
BEGIN
|
|
red := 0; blue := 0; green := 0;
|
|
END;
|
|
|
|
LockHands(hbe);
|
|
|
|
IF idle THEN
|
|
saveRect := hbe^^.selection.selRect
|
|
ELSE
|
|
SetRect(saveRect,0,0,0,0);
|
|
|
|
firstFlag := True;
|
|
BEPtXForm(startPt, hbe);
|
|
testPt := startPt;
|
|
|
|
{ make a copy of bits }
|
|
IF NOT idle THEN
|
|
DoQuickPortToDup(hbe);
|
|
|
|
PenNormal;
|
|
WHILE idle | WaitMouseUp DO
|
|
BEGIN
|
|
GetMouse(endPt);
|
|
BEPtXForm(endPt, hbe);
|
|
|
|
IF idle THEN
|
|
BEGIN
|
|
startPt := hbe^^.selection.selRect.topLeft;
|
|
endPt := hbe^^.selection.selRect.botRight;
|
|
END;
|
|
|
|
GetMIndex(mIndex);
|
|
|
|
IF (LongInt(endPt) <> LongInt(testPt)) | firstFlag | (NOT EmptyRect(hbe^^.selection.selRect)
|
|
& (mIndex <> hbe^^.oldIndex)) THEN
|
|
BEGIN
|
|
firstFlag := False;
|
|
testPt := endPt;
|
|
r.topLeft := startPt;
|
|
r.botRight := endPt;
|
|
|
|
{ refresh BEBits from dupBits or selBits }
|
|
|
|
BEDrawBegin(hbe);
|
|
IF idle THEN
|
|
CSelToPort(hbe, r, False)
|
|
ELSE
|
|
DupToPort(hbe);
|
|
|
|
{ draw shape }
|
|
IF hbe^^.isColor THEN
|
|
RGBForeColor(hbe^^.bePixColor);
|
|
|
|
PenSize(hbe^^.bePenSize.h, hbe^^.bePenSize.v);
|
|
CallDrawProc(r, flags, hbe, drawProc);
|
|
|
|
IF hbe^^.isColor THEN
|
|
RGBForeColor(myBlack);
|
|
|
|
BEDrawEnd(hbe);
|
|
|
|
{ figure out what the smallest rectangle to copy is }
|
|
Pt2Rect(startPt, endPt, r);
|
|
|
|
{ expand rect to enclose all pixels }
|
|
r.bottom := r.bottom + 1 + hbe^^.bePenSize.v;
|
|
r.right := r.right + 1 + hbe^^.bePenSize.h;
|
|
|
|
{ find out what the big rect is }
|
|
UnionRect(r, saveRect, theRect);
|
|
|
|
saveRect := r;
|
|
|
|
{ Draw all the views }
|
|
BEInvalRect(theRect, hbe);
|
|
|
|
END; { of draw }
|
|
|
|
IF idle THEN Leave;
|
|
|
|
END; { stilldown loop }
|
|
|
|
UnlockHands(hbe);
|
|
|
|
{ invalidate our pattern in case client uses it on another gDevice }
|
|
IF hbe^^.isColor THEN
|
|
hbe^^.bePixPat^^.patXValid := -1;
|
|
END; { BEObject }
|
|
|
|
|
|
PROCEDURE BELink(hbe1, hbe2: BEHandle);
|
|
{ Link in hbe1 with hbe2 in the circular list }
|
|
|
|
VAR
|
|
hbe: BEHandle;
|
|
|
|
BEGIN
|
|
hbe := hbe2^^.sibling;
|
|
hbe2^^.sibling := hbe1^^.sibling;
|
|
hbe1^^.sibling := hbe;
|
|
END; { BELink }
|
|
|
|
{ cc }
|
|
{ ImageCt2DeviceCt creates a device color table from an image color table.
|
|
The device color table always contains 2**pixelDepth entries, and entry i
|
|
contains the rgb color for pixel value i. In other words, for a device
|
|
color table, pixel value = table index. For image color tables, this equivalence
|
|
is not necessarily true.
|
|
}
|
|
FUNCTION ImageCt2DeviceCt (hctImage: CTabHandle; pixelDepth: INTEGER): CTabHandle;
|
|
|
|
VAR
|
|
hctDevice: CTabHandle;
|
|
i: INTEGER;
|
|
|
|
BEGIN
|
|
hctDevice := CTabHandle (NewHandle (8+BSL(1,pixelDepth)*8));
|
|
HLock (Handle (hctDevice));
|
|
WITH hctDevice^^ DO
|
|
BEGIN
|
|
ctSeed := 0;
|
|
ctFlags := $8000;
|
|
ctSize := BSL(1,pixelDepth)-1;
|
|
FOR i := ctSize DOWNTO 0 DO
|
|
WITH ctTable[i] DO
|
|
BEGIN
|
|
value := 0;
|
|
rgb.red := 0;
|
|
rgb.green := 0;
|
|
rgb.blue := 0;
|
|
END;
|
|
FOR i := hctImage^^.ctSize DOWNTO 0 DO
|
|
WITH ctTable[hctImage^^.ctTable[i].value].rgb DO
|
|
BEGIN
|
|
red := hctImage^^.ctTable[i].rgb.red;
|
|
green := hctImage^^.ctTable[i].rgb.green;
|
|
blue := hctImage^^.ctTable[i].rgb.blue;
|
|
END;
|
|
END;
|
|
HUnlock (Handle (hctDevice));
|
|
ImageCt2DeviceCt := hctDevice;
|
|
END; { ImageCt2DeviceCt }
|
|
|
|
|
|
FUNCTION BENew(editHandle: Handle; colorTable: CTabHandle; offset: LongInt; rowBytes: integer; pixelSize: integer; bounds: Rect): BEHandle;
|
|
{ Allocate a record and offscreen pixmaps/bitmaps }
|
|
{ If there was not enough memory to allocate pixmaps/bitmaps then return Nil in BEHandle }
|
|
|
|
VAR
|
|
hbe: BEHandle;
|
|
p, u : Handle;
|
|
err: OSErr;
|
|
theDevice: GDHandle;
|
|
ctabTemp: CTabHandle;
|
|
|
|
BEGIN
|
|
hbe := BEHandle(NewHandle(SIZEOF(BERec)));
|
|
err := MemError;
|
|
IF err <> NoErr THEN
|
|
BEGIN
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
|
|
HLock(Handle(hbe));
|
|
|
|
{ get storage for little offscreen bitmap }
|
|
p := NewHandle(GetHandleSize(editHandle) - offset);
|
|
err := MemError;
|
|
If err <> NoErr THEN { if not enough memory set handle to Nil and leave }
|
|
BEGIN
|
|
DisposHandle(Handle(hbe));
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
|
|
{ get storage for undo offscreen bitmap }
|
|
u := NewHandle(GetHandleSize(editHandle) - offset);
|
|
err := MemError;
|
|
If err <> NoErr THEN { if not enough memory set handle to Nil and leave }
|
|
BEGIN
|
|
DisposHandle(Handle(hbe));
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
|
|
{ can't do the NewPixMap calls within the WITH statement }
|
|
{ scramble bug, But its Locked so maybe we can?!?##!??}
|
|
hbe^^.editHandle := editHandle;
|
|
WITH hbe^^ DO BEGIN
|
|
editOffset := offset;
|
|
beRowBytes := rowBytes;
|
|
|
|
bePixelSize := pixelSize;
|
|
beColorTable := colorTable;
|
|
|
|
GetPort(beGrafPtr);
|
|
IF BAND(beGrafPtr^.portBits.rowBytes, $0000C000) = $0000C000 THEN
|
|
isColor := True
|
|
ELSE
|
|
isColor := False;
|
|
|
|
beBounds := bounds;
|
|
offHandle := Nil;
|
|
offPix := Nil;
|
|
|
|
beEraserSize.v := 1;
|
|
beEraserSize.h := 1;
|
|
|
|
bePenSize.v := 1;
|
|
bePenSize.h := 1;
|
|
|
|
{ setup offscreen pixMaps for objects/undo }
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
dupPix := NewPixMap;
|
|
error := MemError;
|
|
IF error <> NoErr THEN
|
|
BEGIN
|
|
DisposHandle(Handle(hbe));
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
DisposHandle(Handle(dupPix^^.pmTable));
|
|
dupPix^^.rowBytes := beRowBytes;
|
|
dupPix^^.bounds := beBounds;
|
|
dupPix^^.pixelSize := bePixelSize;
|
|
dupPix^^.cmpSize := bePixelSize;
|
|
dupPix^^.pmTable := beColorTable;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
dupBits.rowBytes := beRowBytes;
|
|
dupBits.bounds := beBounds;
|
|
END;
|
|
dupHandle := p;
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
undoPix := NewPixMap;
|
|
error := MemError;
|
|
IF error <> NoErr THEN
|
|
BEGIN
|
|
DisposHandle(Handle(hbe));
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
DisposHandle(Handle(undoPix^^.pmTable));
|
|
undoPix^^.rowBytes := beRowBytes;
|
|
undoPix^^.bounds := beBounds;
|
|
undoPix^^.pixelSize := bePixelSize;
|
|
undoPix^^.cmpSize := bePixelSize;
|
|
undoPix^^.pmTable := beColorTable;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
undoBits.rowBytes := beRowBytes;
|
|
undoBits.bounds := beBounds;
|
|
END;
|
|
undoHandle := u;
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
editPix := NewPixMap;
|
|
error := MemError;
|
|
IF error <> NoErr THEN
|
|
BEGIN
|
|
DisposHandle(Handle(hbe));
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
DisposHandle(Handle(editPix^^.pmTable));
|
|
editPix^^.rowBytes := beRowBytes;
|
|
editPix^^.bounds := beBounds;
|
|
editPix^^.pixelSize := bePixelSize;
|
|
editPix^^.cmpSize := bePixelSize;
|
|
editPix^^.pmTable := beColorTable;
|
|
END;
|
|
|
|
WITH selection DO
|
|
BEGIN
|
|
selHandle := Nil;
|
|
selPix := Nil;
|
|
maskHandle := Nil;
|
|
maskPix := Nil;
|
|
edgeHandle := Nil;
|
|
edgePix := Nil;
|
|
SetRect(selRect, 0, 0, 0, 0);
|
|
END;
|
|
undoSelection := selection;
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
NewSelPixMaps (hbe);
|
|
IF MemError <> noErr THEN
|
|
BEGIN
|
|
DisposeSelPixMaps (hbe);
|
|
DisposHandle(Handle(hbe));
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
END;
|
|
undoFreeze := 0;
|
|
oldIndex := -1;
|
|
|
|
error := noErr;
|
|
active := False;
|
|
drawEnabled := True;
|
|
|
|
saveClip := NewRgn;
|
|
saveVis := NewRgn;
|
|
sibling := hbe;
|
|
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
beGDevice := NewGDevice(0,-1);
|
|
error := MemError;
|
|
IF error <> NoErr THEN
|
|
BEGIN
|
|
DisposHandle(Handle(hbe));
|
|
BENew := Nil;
|
|
Exit(BeNew);
|
|
END;
|
|
DisposHandle(Handle(beGDevice^^.gdPMap^^.pmTable));
|
|
{ Since beGDevice is not locked, must not dereference it on lhs if rhs may move memory }
|
|
ctabTemp := ImageCt2DeviceCt (beColorTable, bePixelSize);
|
|
beGDevice^^.gdPMap^^.pmTable := ctabTemp;
|
|
SetDeviceAttribute(beGDevice, GDDevType, True);
|
|
WITH beGDevice^^ DO
|
|
BEGIN
|
|
gdID := 0;
|
|
gdType := 0;
|
|
gdSearchProc := Nil;
|
|
gdCompProc := Nil;
|
|
gdPMap^^.baseAddr := Nil;
|
|
gdPMap^^.rowBytes := beRowBytes;
|
|
gdPMap^^.bounds := beBounds;
|
|
gdPMap^^.pmVersion := 0;
|
|
gdPMap^^.packType := 0;
|
|
gdPMap^^.packSize := 0;
|
|
gdPMap^^.hRes := 72;
|
|
gdPMap^^.vRes := 72;
|
|
gdPMap^^.pixelType := 0;
|
|
gdPMap^^.pixelSize := bePixelSize;
|
|
gdPMap^^.cmpCount := 1;
|
|
gdPMap^^.cmpSize := bePixelSize;
|
|
gdPMap^^.planeBytes := 0;
|
|
gdPMap^^.pmReserved := 0;
|
|
gdNextGD := Nil;
|
|
gdRect := beBounds;
|
|
gdMode := 0;
|
|
gdReserved := 0;
|
|
END;
|
|
|
|
theDevice := GetGDevice;
|
|
SetGDevice(beGDevice);
|
|
MakeITable(Nil, Nil, 0);
|
|
SetGDevice(theDevice);
|
|
END;
|
|
END;
|
|
HUnlock(Handle(hbe));
|
|
|
|
{ Initialize the undo buffer with the current bits in case the user does an undo first. }
|
|
SetupUndo (hbe); { 7/7/88 PEA }
|
|
BENew := hbe;
|
|
END; { BENew }
|
|
|
|
|
|
PROCEDURE CenterScrap(VAR r:Rect; hbe: BEHandle);
|
|
{ Center scrap rectangle in current window if it will fit; if not, align it with the topLeft }
|
|
|
|
VAR
|
|
width,height: INTEGER;
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
width := r.right - r.left;
|
|
height := r.bottom - r.top;
|
|
|
|
WITH r DO
|
|
BEGIN
|
|
left := (beEditRect.left + beEditRect.right - width) DIV 2;
|
|
top := (beEditRect.top + beEditRect.bottom - height) DIV 2;
|
|
IF (left < beEditRect.left) THEN
|
|
left := beEditRect.left;
|
|
IF (top < beEditRect.top) THEN
|
|
top := beEditRect.top;
|
|
right := left + width;
|
|
bottom := top + height;
|
|
END;
|
|
END;
|
|
END; { CenterScrap }
|
|
|
|
|
|
PROCEDURE BEPaste(hbe: BEHandle);
|
|
{ paste the picture from the scrap into the selection. If no selection make one }
|
|
|
|
VAR
|
|
err, o: LongInt;
|
|
pHndl: PicHandle;
|
|
|
|
BEGIN
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) AND (NOT hbe^^.marquee) THEN
|
|
BEPutSelection(hbe)
|
|
ELSE
|
|
SetupUndo(hbe);
|
|
|
|
pHndl := PicHandle(NewHandle(0));
|
|
err := GetScrap(Handle(pHndl), 'PICT', o);
|
|
|
|
IF err >= 0 THEN
|
|
BEGIN
|
|
IF EmptyRect(hbe^^.selection.selRect) THEN
|
|
BEGIN
|
|
hbe^^.selection.selRect := pHndl^^.picFrame;
|
|
CenterScrap(hbe^^.selection.selRect, hbe);
|
|
hbe^^.selection.selRect.right := hbe^^.selection.selRect.right - 1;
|
|
hbe^^.selection.selRect.bottom := hbe^^.selection.selRect.bottom - 1;
|
|
hbe^^.marquee := True;
|
|
SetUpSelBits(hbe^^.selection.selRect, hbe);
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
SetRect(hbe^^.selection.selRect, 0, 0, 0, 0);
|
|
DisposHandle(Handle(pHndl));
|
|
Exit(BEPaste);
|
|
END;
|
|
END;
|
|
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) THEN
|
|
BEGIN
|
|
hbe^^.selection.wasErased := True;
|
|
|
|
LockHands(hbe);
|
|
DoQuickPortToDup(hbe);
|
|
|
|
BEDrawBegin(hbe);
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
SetPortPix(hbe^^.selection.selPix);
|
|
ClipRect(hbe^^.selection.selPix^^.bounds);
|
|
RectRgn(hbe^^.beGrafPtr^.visRgn, hbe^^.selection.selPix^^.bounds);
|
|
EraseRect(hbe^^.selection.selPix^^.bounds);
|
|
DrawPicture(pHndl, hbe^^.selection.selPix^^.bounds);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
SetPortBits(hbe^^.selection.selBits);
|
|
ClipRect(hbe^^.selection.selBits.bounds);
|
|
RectRgn(hbe^^.beGrafPtr^.visRgn, hbe^^.selection.selBits.bounds);
|
|
EraseRect(hbe^^.selection.selBits.bounds);
|
|
DrawPicture(pHndl, hbe^^.selection.selBits.bounds);
|
|
END;
|
|
BEDrawEnd(hbe);
|
|
|
|
{ Put the bits down so that other views derived from the bits can be updated.
|
|
PEA 4/1/88 }
|
|
BEDrawBegin (hbe);
|
|
CopySelToPort (hbe);
|
|
BEDrawEnd (hbe);
|
|
|
|
hbe^^.marquee := True;
|
|
|
|
{ And paint them - PEA 4/1/88 }
|
|
BEInvalRect (hbe^^.selection.selRect, hbe);
|
|
|
|
UnlockHands(hbe);
|
|
|
|
END
|
|
ELSE
|
|
SysBeep(20);
|
|
END;
|
|
DisposHandle(Handle(pHndl));
|
|
|
|
END; { BEPaste }
|
|
|
|
|
|
PROCEDURE BEPtUnXForm(VAR pt: Point; hbe: BEHandle);
|
|
{ Transforms the given fatbit point into screen point }
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO BEGIN
|
|
pt.h := beViewRect.left + (pt.h - beEditRect.left) * (fatbitsDelta.h + fatbitsSize.h);
|
|
pt.v := beViewRect.top + (pt.v - beEditRect.top) * (fatbitsDelta.v + fatbitsSize.v);
|
|
END;
|
|
END; { BEPtUnXForm }
|
|
|
|
|
|
PROCEDURE BEPtXForm(VAR pt: Point; hbe: BEHandle);
|
|
{ Transforms the given screen point into fatbits point }
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO BEGIN
|
|
pt.h := beEditRect.left + (pt.h - beViewRect.left) DIV (fatbitsDelta.h + fatbitsSize.h);
|
|
pt.v := beEditRect.top + (pt.v - beViewRect.top) DIV (fatbitsDelta.v + fatbitsSize.v);
|
|
END;
|
|
END; { BEPtXForm }
|
|
|
|
|
|
PROCEDURE LineDraw(r: Rect; flags: BEDrawFlags; hbe: BEHandle);
|
|
{ draw a line between the points specified in topleft and bottomright of rect,
|
|
constrained to horizontal, vertical, or diagonal lines according to flags }
|
|
|
|
VAR
|
|
hv: Point;
|
|
lineFlags: BEDrawFlags;
|
|
BEGIN
|
|
WITH r DO BEGIN
|
|
WidthHeightRect (r, hv);
|
|
lineFlags := BAND(flags, fShapeLineMask);
|
|
IF lineFlags = fLineOnAxis THEN
|
|
BEGIN
|
|
IF hv.v > hv.h THEN
|
|
right := left
|
|
ELSE
|
|
bottom := top;
|
|
END
|
|
ELSE IF lineFlags = fLineOnDiagonal THEN
|
|
BEGIN
|
|
IF hv.h > hv.v*2 THEN
|
|
bottom := top
|
|
ELSE IF hv.v > hv.h*2 THEN
|
|
right := left
|
|
ELSE
|
|
SquareRect (r);
|
|
END;
|
|
MoveTo(left, top);
|
|
LineTo(right, bottom);
|
|
END;
|
|
END; { LineDraw }
|
|
|
|
|
|
PROCEDURE BELine(startPt: Point; flags: BEDrawFlags; hbe: BEHandle);
|
|
{ Drag out a line starting at given point }
|
|
|
|
BEGIN
|
|
BEObject(startPt, @LineDraw, flags, hbe);
|
|
END; { BELine }
|
|
|
|
|
|
PROCEDURE OvalDraw( r: Rect; flags: BEDrawFlags; hbe: BEHandle );
|
|
{ Draw an oval in r; flags specify if framed, filled, or both, and if circle }
|
|
|
|
BEGIN
|
|
IF BAND (flags, fShapeUnbounded) = 0 THEN
|
|
ClipAnchorRect (r, hbe^^.beEditRect);
|
|
IF BAND (flags, fShapeSymmetric) <> 0 THEN
|
|
SquareRect (r);
|
|
FixRect(r);
|
|
StretchRect(r);
|
|
IF BAND (flags, fShapeFill) <> 0 THEN
|
|
IF hbe^^.isColor THEN
|
|
FillCOval(r, hbe^^.bePixPat)
|
|
ELSE
|
|
FillOval(r, hbe^^.beFillPat);
|
|
IF BAND (flags, fShapeUnframed) = 0 THEN
|
|
BEGIN
|
|
PenSize(hbe^^.bePenSize.h, hbe^^.bePenSize.v);
|
|
FrameOval(r);
|
|
END;
|
|
END; { OvalDraw }
|
|
|
|
|
|
PROCEDURE BEOval(startPt: Point; flags: BEDrawFlags; hbe: BEHandle);
|
|
{ Drag out an oval starting at given point }
|
|
|
|
BEGIN
|
|
BEObject(startPt, @OvalDraw, flags, hbe);
|
|
END; { BEOval }
|
|
|
|
|
|
PROCEDURE RndRectDraw( r: Rect; flags: BEDrawFlags; hbe: BEHandle );
|
|
{ Draw a round-cornered rect }
|
|
|
|
BEGIN
|
|
IF BAND (flags, fShapeUnbounded) = 0 THEN
|
|
ClipAnchorRect (r, hbe^^.beEditRect);
|
|
IF BAND (flags, fShapeSymmetric) <> 0 THEN
|
|
SquareRect (r);
|
|
FixRect(r);
|
|
StretchRect(r);
|
|
IF BAND (flags, fShapeFill) <> 0 THEN
|
|
IF hbe^^.isColor THEN
|
|
FillCRoundRect(r, Point(hbe^^.beDrawParm).v, Point(hbe^^.beDrawParm).h, hbe^^.bePixPat)
|
|
ELSE
|
|
FillRoundRect(r, Point(hbe^^.beDrawParm).v, Point(hbe^^.beDrawParm).h, hbe^^.beFillPat);
|
|
IF BAND (flags, fShapeUnframed) = 0 THEN
|
|
BEGIN
|
|
PenSize(hbe^^.bePenSize.h, hbe^^.bePenSize.v);
|
|
FrameRoundRect(r, Point(hbe^^.beDrawParm).v, Point(hbe^^.beDrawParm).h);
|
|
END;
|
|
END; { RndRectDraw }
|
|
|
|
|
|
PROCEDURE BERoundRect(startPt: Point; flags: BEDrawFlags; ovalWidth, ovalHeight: INTEGER; hbe: BEHandle);
|
|
{ Drag out a rect starting at given point }
|
|
|
|
BEGIN
|
|
Point(hbe^^.beDrawParm).v := ovalWidth;
|
|
Point(hbe^^.beDrawParm).h := ovalHeight;
|
|
BEObject(startPt, @RndRectDraw, flags, hbe);
|
|
END; { BERoundRect }
|
|
|
|
|
|
PROCEDURE RectDraw(r: Rect; flags: BEDrawFlags; hbe: BEHandle);
|
|
{ Draw a rect }
|
|
|
|
BEGIN
|
|
IF BAND (flags, fShapeUnbounded) = 0 THEN
|
|
ClipAnchorRect (r, hbe^^.beEditRect);
|
|
IF BAND (flags, fShapeSymmetric) <> 0 THEN
|
|
SquareRect (r);
|
|
FixRect(r);
|
|
StretchRect(r);
|
|
IF BAND (flags, fShapeFill) <> 0 THEN
|
|
IF hbe^^.isColor THEN
|
|
FillCRect(r, hbe^^.bePixPat)
|
|
ELSE
|
|
FillRect(r, hbe^^.beFillPat);
|
|
IF BAND (flags, fShapeUnframed) = 0 THEN
|
|
BEGIN
|
|
PenSize(hbe^^.bePenSize.h, hbe^^.bePenSize.v);
|
|
FrameRect(r);
|
|
END;
|
|
END; { RectDraw }
|
|
|
|
|
|
PROCEDURE BERect(startPt: Point; flags: BEDrawFlags; hbe: BEHandle);
|
|
{ Drag out a rect starting at given point }
|
|
|
|
BEGIN
|
|
BEObject(startPt, @RectDraw, flags, hbe);
|
|
END; { BERect }
|
|
|
|
|
|
PROCEDURE ClipAnchorRect (VAR r: Rect; VAR rClip: Rect);
|
|
{ Constrains the bottom right corner of r to lie within a rectangle
|
|
defined by rClip shrunk on the bottom and right by one pixel.
|
|
rClip is not changed.
|
|
}
|
|
|
|
BEGIN
|
|
IF r.right >= rClip.right THEN
|
|
r.right := rClip.right-1
|
|
ELSE IF r.right < rClip.left THEN
|
|
r.right := rClip.left;
|
|
IF r.bottom >= rClip.bottom THEN
|
|
r.bottom := rClip.bottom-1
|
|
ELSE IF r.bottom < rClip.top THEN
|
|
r.bottom := rClip.top;
|
|
END; { ClipAnchorRect }
|
|
|
|
|
|
PROCEDURE WidthHeightRect (VAR r: Rect; VAR pt: Point);
|
|
|
|
BEGIN
|
|
pt.h := ABS (r.right - r.left);
|
|
pt.v := ABS (r.bottom - r.top);
|
|
END; { WidthHeightRect }
|
|
|
|
|
|
PROCEDURE SquareRect (VAR r: Rect);
|
|
{ Convert a rectangle to the smallest contained square }
|
|
|
|
VAR
|
|
height,width,hs,ws: INTEGER;
|
|
BEGIN
|
|
IF r.right < r.left THEN
|
|
BEGIN
|
|
ws := -1;
|
|
width := r.left - r.right;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
ws := 1;
|
|
width := r.right - r.left;
|
|
END;
|
|
IF r.bottom < r.top THEN
|
|
BEGIN
|
|
hs := -1;
|
|
height := r.top - r.bottom;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
hs := 1;
|
|
height := r.bottom - r.top;
|
|
END;
|
|
|
|
IF width > height THEN
|
|
r.right := r.left + (height*ws)
|
|
ELSE
|
|
r.bottom := r.top + (width*hs);
|
|
END; { SquareRect }
|
|
|
|
|
|
PROCEDURE MarqueeDraw(r: Rect; flags: BEDrawFlags; hbe: BEHandle);
|
|
{ If the fSetSelection bit of flags is false, uses the current selection rectangle rather than setting it;
|
|
this allows the curent selection to remain partially outside the edit rectangle }
|
|
|
|
VAR
|
|
mIndex: INTEGER;
|
|
savePat: Pattern;
|
|
tempRect: Rect;
|
|
t: Boolean;
|
|
myBlack: RGBColor;
|
|
|
|
BEGIN
|
|
WITH myBlack DO
|
|
BEGIN
|
|
red := 0; blue := 0; green := 0;
|
|
END;
|
|
|
|
IF BAND (flags, fSquareMarquee) <> 0 THEN
|
|
SquareRect (r);
|
|
FixRect(r);
|
|
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
IF BAND (flags, fSetSelection) <> 0 THEN
|
|
BEGIN
|
|
t := SectRect(r, beEditRect, r);
|
|
IF r.right = beEditRect.right THEN r.right := r.right - 1;
|
|
IF r.bottom = beEditRect.bottom THEN r.bottom := r.bottom - 1;
|
|
selection.selRect := r;
|
|
END
|
|
ELSE
|
|
r := selection.selRect;
|
|
StretchRect(r);
|
|
|
|
GetMIndex(mIndex);
|
|
|
|
IF NOT EmptyRect(selection.selRect) AND active THEN
|
|
BEGIN
|
|
PenSize(1,1);
|
|
GetSelPat(mIndex, savePat);
|
|
PenPat(savePat);
|
|
IF isColor THEN
|
|
RGBForeColor(myBlack);
|
|
FrameRect(r);
|
|
oldIndex := mIndex;
|
|
END;
|
|
END;
|
|
END; { MarqueeDraw }
|
|
|
|
|
|
PROCEDURE SetUpSelBits(r: Rect; hbe: BEHandle);
|
|
|
|
VAR
|
|
p: Handle;
|
|
pix: PixMapHandle;
|
|
rb: INTEGER;
|
|
b: BOOLEAN;
|
|
|
|
BEGIN
|
|
HLock(Handle(hbe));
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
IF hbe^^.marquee THEN
|
|
BEGIN
|
|
StretchRect(r);
|
|
END;
|
|
|
|
IF hbe^^.isColor THEN
|
|
{ setup a temporary offscreen pixMap the size of the selection }
|
|
WITH selPix^^ DO
|
|
BEGIN
|
|
rowBytes := ((((hbe^^.bePixelSize * (r.right - r.left)) + 15)) DIV 16) * 2;
|
|
bounds := r;
|
|
rb := rowBytes;
|
|
rowBytes := rowBytes + $8000;
|
|
END
|
|
ELSE
|
|
WITH selBits DO
|
|
BEGIN
|
|
rowBytes := (((r.right - r.left) + 15) DIV 16) * 2;
|
|
bounds := r;
|
|
rb := rowBytes;
|
|
END;
|
|
|
|
p := NewHandle(UIntMul((r.bottom - r.top), rb));
|
|
hbe^^.error := MemError;
|
|
If hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
HUnlock(Handle(hbe));
|
|
Exit(SetUpSelBits);
|
|
END;
|
|
selHandle := p;
|
|
END;
|
|
|
|
HUnlock(Handle(hbe));
|
|
LockHands(hbe);
|
|
|
|
{ copy from the dupBits to the selBits bitmap }
|
|
IF hbe^^.marquee THEN
|
|
DupToSel(hbe);
|
|
|
|
UnlockHands(hbe);
|
|
|
|
END; { SetUpSelBits }
|
|
|
|
|
|
PROCEDURE EraseUnderSelection (hbe: BEHandle);
|
|
{ erase area under the selection prior to moving the selected bits }
|
|
|
|
VAR
|
|
r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
IF NOT hbe^^.selection.wasErased THEN
|
|
BEGIN
|
|
LockHands(hbe);
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
SetupRects(r, srcRect, hbe);
|
|
|
|
BEDrawBegin(hbe);
|
|
MySetDupBits(hbe);
|
|
IF marquee THEN
|
|
EraseRect(r)
|
|
ELSE
|
|
MaskToDup(hbe);
|
|
BEDrawEnd(hbe);
|
|
selection.wasErased := True;
|
|
END;
|
|
UnlockHands(hbe);
|
|
END;
|
|
END; { EraseUnderSelection }
|
|
|
|
|
|
PROCEDURE DragSelection(startPt: Point; flags: BESelectFlags; hbe: BEHandle);
|
|
|
|
VAR
|
|
testPt, deltaPt, endPt: Point;
|
|
oldSelRect, r, cRect, srcRect: Rect;
|
|
pt: Ptr;
|
|
rLimit: Rect;
|
|
vhSel: Point;
|
|
|
|
BEGIN
|
|
SetupUndo(hbe);
|
|
|
|
BEPtXForm(startPt, hbe);
|
|
testPt := startPt;
|
|
|
|
IF BAND(flags,fDragCopy) = 0 THEN
|
|
EraseUnderSelection (hbe)
|
|
ELSE IF hbe^^.selection.wasErased THEN
|
|
BEGIN
|
|
{ plunk down bits }
|
|
IF hbe^^.marquee THEN
|
|
CSelToDup(hbe)
|
|
ELSE
|
|
BEGIN
|
|
MaskToDup(hbe);
|
|
OSelToDup(hbe);
|
|
END;
|
|
END
|
|
ELSE
|
|
hbe^^.selection.wasErased := TRUE;
|
|
|
|
SetupRects(r, srcRect, hbe);
|
|
|
|
LockHands(hbe);
|
|
|
|
{ figure out bounding rect within which the drag point must remain }
|
|
WITH hbe^^, cRect DO
|
|
BEGIN
|
|
IF marquee THEN
|
|
BEGIN
|
|
{ Allow selection to move beyond edit rectangle, as long as one edge is visible }
|
|
vhSel.h := selection.selRect.right - selection.selRect.left;
|
|
vhSel.v := selection.selRect.bottom - selection.selRect.top;
|
|
rLimit.top := beEditRect.top - vhSel.v;
|
|
rLimit.left := beEditRect.left - vhSel.h;
|
|
rLimit.bottom := beEditRect.bottom + vhSel.v;
|
|
rLimit.right := beEditRect.right + vhSel.h;
|
|
END
|
|
ELSE
|
|
{ For lasso selections, keep entire selection within edit rectangle }
|
|
rLimit := beEditRect;
|
|
|
|
left := rLimit.left + (startPt.h - selection.selRect.left);
|
|
top := rLimit.top + (startPt.v - selection.selRect.top);
|
|
right := rLimit.right - (selection.selRect.right - startPt.h);
|
|
bottom := rLimit.bottom - (selection.selRect.bottom - startPt.v);
|
|
IF NOT marquee THEN
|
|
bottom := bottom + 1;
|
|
END;
|
|
|
|
{ draw image without ants on mousedown }
|
|
BEDrawBegin(hbe);
|
|
DupToPort(hbe);
|
|
CopySelToPort(hbe);
|
|
BEDrawEnd(hbe);
|
|
|
|
{ invalidate and redraw the rects }
|
|
BEInvalRect(r, hbe);
|
|
|
|
WHILE WaitMouseUp DO
|
|
BEGIN
|
|
GetMouse(endPt);
|
|
BEPtXForm(endPt, hbe);
|
|
|
|
endPt := Point(PinRect(cRect, endPt));
|
|
|
|
IF (LongInt(endPt) <> LongInt(testPt)) THEN
|
|
BEGIN { mouse moved }
|
|
deltaPt := endPt;
|
|
|
|
{ figure out distance moved }
|
|
SubPt(testPt, deltaPt);
|
|
|
|
oldSelRect := r;
|
|
OffSetRect(r, deltaPt.h, deltaPt.v);
|
|
|
|
{ get into BEBits and move the image }
|
|
BEDrawBegin(hbe);
|
|
|
|
UnionRect(oldSelRect, r, oldSelRect);
|
|
|
|
{ copy from dupBits to BEBits }
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
{ cc }
|
|
CopyPixels (dupPix, CGrafPtr(beGrafPtr)^.portPixMap)
|
|
{ CopyBits(BitMapPtr(dupPix^)^, beGrafPtr^.portBits, oldSelRect, oldSelRect, srcCopy, Nil) }
|
|
ELSE
|
|
CopyBits(dupBits, beGrafPtr^.portBits, oldSelRect, oldSelRect, srcCopy, Nil);
|
|
|
|
IF hbe^^.marquee THEN
|
|
CSelToPort(hbe, r, True)
|
|
ELSE
|
|
BEGIN
|
|
MaskToPort(hbe, r, True);
|
|
OSelToPort(hbe, r, True);
|
|
END;
|
|
|
|
BEDrawEnd(hbe);
|
|
|
|
{ invalidate and redraw the rects }
|
|
BEInvalRect(oldSelRect, hbe);
|
|
|
|
testPt := endPt;
|
|
|
|
END; { mouse moved }
|
|
|
|
END; { waitmouseup loop }
|
|
|
|
r.bottom := r.bottom - 1;
|
|
r.right := r.right - 1;
|
|
hbe^^.selection.selRect := r;
|
|
|
|
UnlockHands(hbe);
|
|
|
|
END; { DragSelection }
|
|
|
|
|
|
PROCEDURE BESelect(startPt: Point; flags: BESelectFlags; hbe: BEHandle);
|
|
{ Drag out a selection marquee or lasso starting at given point.
|
|
The selection is moved if startPt is inside the current selection,
|
|
even if that selection type is different than that specified in flags. }
|
|
|
|
VAR
|
|
kind: BESelectFlags;
|
|
BEGIN
|
|
IF BEInSelection(startPt, hbe) THEN
|
|
DragSelection(startPt, flags, hbe)
|
|
ELSE
|
|
BEGIN
|
|
kind := BAND (flags, fSelectKindMask);
|
|
IF kind = fSelectLasso THEN
|
|
DrawLasso(startPt, hbe)
|
|
ELSE
|
|
BEGIN
|
|
flags := BAND(flags, fSquareMarquee);
|
|
BEObject(startPt, @MarqueeDraw, BOR(flags, fSetSelection), hbe);
|
|
hbe^^.marquee := True;
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) THEN
|
|
BEGIN
|
|
SetUpSelBits(hbe^^.selection.selRect, hbe);
|
|
IF hbe^^.error <> NoErr THEN
|
|
SetRect(hbe^^.selection.selRect, 0, 0, 0, 0);
|
|
END;
|
|
hbe^^.selection.wasErased := False;
|
|
END
|
|
END;
|
|
END; { BESelect }
|
|
|
|
|
|
PROCEDURE ConstrainNudge (VAR deltaPt: Point; hbe: BEHandle);
|
|
|
|
VAR
|
|
cRect: Rect;
|
|
newPt: Point;
|
|
|
|
BEGIN
|
|
WITH hbe^^, cRect DO
|
|
BEGIN
|
|
IF marquee THEN
|
|
BEGIN
|
|
{ Allow selection to move beyond edit rectangle, as long as one edge is visible }
|
|
top := beEditRect.top - (selection.selRect.bottom - selection.selRect.top);
|
|
left := beEditRect.left - (selection.selRect.right - selection.selRect.left);
|
|
botRight := beEditRect.botRight;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
{ For lasso selections, keep entire selection within edit rectangle }
|
|
topLeft := beEditRect.topLeft;
|
|
right := beEditRect.right - (selection.selRect.right - selection.selRect.left);
|
|
bottom := beEditRect.bottom - (selection.selRect.bottom - selection.selRect.top) + 1;
|
|
END;
|
|
|
|
{ constrain deltaPt }
|
|
newPt := selection.selRect.topLeft;
|
|
AddPt (deltaPt, newPt);
|
|
newPt := Point(PinRect(cRect, newPt));
|
|
deltaPt := newPt;
|
|
SubPt (selection.selRect.topLeft, deltaPt);
|
|
END;
|
|
END; { ConstrainNudge }
|
|
|
|
|
|
PROCEDURE BEDuplicate (deltaPt: Point; hbe: BEHandle);
|
|
{ Duplicate the selection. DeltaPt is the preferred displacement and the minimal
|
|
margin on the bottom and right. It should be positive.
|
|
}
|
|
|
|
VAR
|
|
rInval: Rect;
|
|
origPt: Point;
|
|
|
|
BEGIN
|
|
IF BESelection(hbe) THEN
|
|
BEGIN
|
|
SetupUndo (hbe);
|
|
|
|
LockHands(hbe);
|
|
|
|
{ plunk down bits }
|
|
IF hbe^^.marquee THEN
|
|
CSelToDup(hbe)
|
|
ELSE
|
|
BEGIN
|
|
MaskToDup(hbe);
|
|
OSelToDup(hbe);
|
|
END;
|
|
|
|
{ draw image without ants }
|
|
BEDrawBegin(hbe);
|
|
DupToPort(hbe);
|
|
|
|
rInval := hbe^^.selection.selRect;
|
|
|
|
{ Move Selection }
|
|
{ If too close to bottom, move to the top; if too close to right edge, move to left.
|
|
The term "deltaPt.v <> origPt.v" is for lasso selections (which are constrained to the
|
|
edit area; the second term is for marquee selections (which may overhang).
|
|
}
|
|
origPt := deltaPt;
|
|
ConstrainNudge (deltaPt, hbe);
|
|
WITH hbe^^, hbe^^.selection DO
|
|
BEGIN
|
|
IF (deltaPt.v <> origPt.v) OR ((selRect.top + deltaPt.v) > (beEditRect.bottom - deltaPt.v)) THEN
|
|
deltaPt.v := (beEditRect.top + deltaPt.v) - selRect.top;
|
|
IF (deltaPt.h <> origPt.h) OR ((selRect.left + deltaPt.h) > (beEditRect.right - deltaPt.h)) THEN
|
|
deltaPt.h := (beEditRect.left + deltaPt.h) - selRect.left;
|
|
OffsetRect (selRect, deltaPt.h, deltaPt.v);
|
|
END;
|
|
|
|
CopySelToPort (hbe);
|
|
BEDrawEnd(hbe);
|
|
|
|
hbe^^.selection.wasErased := True;
|
|
|
|
UnlockHands(hbe);
|
|
|
|
UnionRect (rInval, hbe^^.selection.selRect, rInval);
|
|
StretchRect (rInval);
|
|
BEInvalRect(rInval, hbe);
|
|
END;
|
|
END; { BEDuplicate }
|
|
|
|
|
|
FUNCTION BENudge(deltaPt: Point; hbe: BEHandle): BOOLEAN;
|
|
|
|
VAR
|
|
oldSelRect, r, srcRect: Rect;
|
|
|
|
BEGIN
|
|
BENudge := FALSE;
|
|
IF BESelection(hbe) THEN
|
|
BEGIN
|
|
SetupUndo (hbe);
|
|
|
|
EraseUnderSelection (hbe);
|
|
|
|
{ draw image without ants }
|
|
LockHands(hbe);
|
|
BEDrawBegin(hbe);
|
|
DupToPort(hbe);
|
|
BEDrawEnd(hbe);
|
|
UnlockHands(hbe);
|
|
|
|
ConstrainNudge (deltaPt, hbe);
|
|
|
|
IF LongInt(DeltaPt) <> 0 THEN
|
|
BEGIN
|
|
LockHands(hbe);
|
|
|
|
SetupRects(r, srcRect, hbe);
|
|
|
|
{ invalidate and redraw the rects }
|
|
BEInvalRect(r, hbe);
|
|
|
|
oldSelRect := r;
|
|
OffSetRect(r, deltaPt.h, deltaPt.v);
|
|
|
|
{ get into BEBits and move the image }
|
|
BEDrawBegin(hbe);
|
|
|
|
UnionRect(oldSelRect, r, oldSelRect);
|
|
|
|
{ copy from dupBits to BEBits }
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
{ cc }
|
|
CopyPixels (dupPix, CGrafPtr(beGrafPtr)^.portPixMap)
|
|
{ CopyBits(BitMapPtr(dupPix^)^, beGrafPtr^.portBits, oldSelRect, oldSelRect, srcCopy, Nil) }
|
|
ELSE
|
|
CopyBits(dupBits, beGrafPtr^.portBits, oldSelRect, oldSelRect, srcCopy, Nil);
|
|
|
|
IF hbe^^.marquee THEN
|
|
CSelToPort(hbe, r, True)
|
|
ELSE
|
|
BEGIN
|
|
MaskToPort(hbe, r, True);
|
|
OSelToPort(hbe, r, True);
|
|
END;
|
|
|
|
BEDrawEnd(hbe);
|
|
|
|
{ invalidate and redraw the rects }
|
|
BEInvalRect(oldSelRect, hbe);
|
|
|
|
r.bottom := r.bottom - 1;
|
|
r.right := r.right - 1;
|
|
hbe^^.selection.selRect := r;
|
|
|
|
UnlockHands(hbe);
|
|
BENudge := TRUE;
|
|
END
|
|
END;
|
|
|
|
END; { BENudge }
|
|
|
|
|
|
PROCEDURE BEFlip(vertical: BOOLEAN; hbe: BEHandle);
|
|
{ flip the selection; if there is no selection or a lasso selection, flip the entire image }
|
|
{ Note that a lasso selection is canceled before fliping the entire image }
|
|
|
|
VAR
|
|
rInval, srcRect: Rect;
|
|
r: Rect;
|
|
rgbPt: RGBColor;
|
|
cpyHandle: Handle; { copy of selection bits }
|
|
cpyPix: PixMapHandle;
|
|
cpyBits: BitMap;
|
|
cpyRect, selRect: Rect;
|
|
i, limit: INTEGER;
|
|
|
|
BEGIN
|
|
IF BESelection(hbe) AND hbe^^.marquee THEN
|
|
BEGIN
|
|
SetupUndo(hbe);
|
|
|
|
SetupRects(rInval, srcRect, hbe);
|
|
|
|
LockHands(hbe);
|
|
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
{ Copy the selection }
|
|
cpyHandle := selection.selHandle;
|
|
error := HandToHand(cpyHandle);
|
|
IF error <> NoErr THEN Exit(BEFlip);
|
|
HLock (cpyHandle);
|
|
|
|
IF isColor THEN
|
|
BEGIN
|
|
cpyPix := selection.selPix;
|
|
error := HandToHand(Handle (cpyPix));
|
|
IF error <> NoErr THEN
|
|
BEGIN
|
|
HUnlock (cpyHandle);
|
|
DisposHandle (cpyHandle);
|
|
Exit(BEFlip);
|
|
END;
|
|
HLock (Handle (cpyPix));
|
|
cpyPix^^.baseAddr := cpyHandle^;
|
|
r := selection.selPix^^.bounds;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
cpyBits := selection.selBits;
|
|
cpyBits.baseAddr := cpyHandle^;
|
|
r := selection.selBits.bounds;
|
|
END;
|
|
|
|
BEDrawBegin(hbe);
|
|
|
|
IF vertical THEN
|
|
limit := r.bottom - r.top
|
|
ELSE
|
|
limit := r.right - r.left;
|
|
|
|
FOR i := 0 TO limit DO
|
|
BEGIN
|
|
IF vertical THEN
|
|
BEGIN
|
|
SetRect (cpyRect, r.left, r.top+i, r.right, r.top+i+1);
|
|
SetRect (selRect, r.left, r.bottom-i-1, r.right, r.bottom-i);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
SetRect (cpyRect, r.left+i, r.top, r.left+i+1, r.bottom);
|
|
SetRect (selRect, r.right-i-1, r.top, r.right-i, r.bottom);
|
|
END;
|
|
IF isColor THEN
|
|
CopyBits(BitMapPtr(cpyPix^)^, BitMapPtr(selection.selPix^)^, cpyRect, selRect, srcCopy, Nil)
|
|
ELSE
|
|
CopyBits(cpyBits, selection.selBits, cpyRect, selRect, srcCopy, Nil);
|
|
END;
|
|
|
|
HUnlock (cpyHandle);
|
|
DisposHandle (cpyHandle);
|
|
IF isColor THEN
|
|
BEGIN
|
|
HUnlock (Handle (cpyPix));
|
|
DisposHandle (Handle (cpyPix));
|
|
END;
|
|
|
|
DupToPort(hbe);
|
|
CopySelToPort(hbe);
|
|
|
|
BEDrawEnd(hbe);
|
|
UnlockHands(hbe);
|
|
END;
|
|
|
|
{ invalidate and redraw the rects }
|
|
BEInvalRect(rInval, hbe);
|
|
|
|
END;
|
|
END; { BEFlip }
|
|
|
|
|
|
PROCEDURE SetupExtract (bm: BitMapPtr; pt: Point; VAR offset, mask, shift: INTEGER);
|
|
{ Returns offset, mask and shift. Offset is the displacement from baseAddr to the byte containing
|
|
the argument point. Mask can be used to extract the pixel, and shift used to move the pixel
|
|
value into the least significant bits of the byte. This routine uses integer math to compute
|
|
bit offsets, so the width of the BitMap should be less than 4K for 8-bit pixels.
|
|
}
|
|
|
|
VAR
|
|
pixelSize: INTEGER;
|
|
rowBytes: INTEGER;
|
|
row: INTEGER;
|
|
rowOffset: INTEGER;
|
|
pixOffset: INTEGER;
|
|
bitOffset: INTEGER;
|
|
byteOffset: INTEGER;
|
|
pm: PixMapPtr;
|
|
|
|
BEGIN
|
|
IF BAND (bm^.rowBytes, $8000) <> 0 THEN
|
|
BEGIN
|
|
pm := PixMapPtr (bm);
|
|
pixelSize := pm^.pixelSize;
|
|
END
|
|
ELSE
|
|
pixelSize := 1;
|
|
rowBytes := BAND (bm^.rowBytes, $7FFF);
|
|
row := pt.v - bm^.bounds.top;
|
|
rowOffset := UIntMul (row, rowBytes);
|
|
pixOffset := pt.h - bm^.bounds.left;
|
|
bitOffset := UIntMul(pixOffset,pixelSize);
|
|
byteOffset := bitOffset DIV 8;
|
|
bitOffset := bitOffset MOD 8;
|
|
offset := rowOffset + byteOffset;
|
|
shift := (8 - pixelSize - bitOffset);
|
|
mask := BitShift(1, pixelSize) - 1;
|
|
mask := BitShift(mask, shift);
|
|
END;
|
|
|
|
FUNCTION GetPix (bm: BitMapPtr; pt: Point): INTEGER;
|
|
|
|
VAR
|
|
byte: INTEGER;
|
|
offset, mask, shift: INTEGER;
|
|
p: Ptr;
|
|
|
|
BEGIN
|
|
IF PtInRect (pt, bm^.bounds) THEN
|
|
BEGIN
|
|
SetupExtract (bm, pt, offset, mask, shift);
|
|
p := POINTER(ORD(bm^.baseAddr) + offset);
|
|
byte := p^;
|
|
GetPix := BitShift (BAND (byte, mask), -shift);
|
|
END
|
|
ELSE
|
|
GetPix := 0;
|
|
END; { GetPix }
|
|
|
|
|
|
PROCEDURE SetPix (bm: BitMapPtr; pt: Point; VAR pixel: INTEGER);
|
|
|
|
VAR
|
|
byte: INTEGER;
|
|
offset, mask, shift: INTEGER;
|
|
p: Ptr;
|
|
|
|
BEGIN
|
|
IF PtInRect (pt, bm^.bounds) THEN
|
|
BEGIN
|
|
SetupExtract (bm, pt, offset, mask, shift);
|
|
p := POINTER(ORD(bm^.baseAddr) + offset);
|
|
byte := BAND (p^, BXOR ($FFFF, mask));
|
|
pixel := BAND (BitShift (pixel,shift), mask);
|
|
byte := BOR (byte, pixel);
|
|
p^ := byte;
|
|
END
|
|
END; { SetPix }
|
|
|
|
|
|
PROCEDURE BERotate(hbe: BEHandle);
|
|
{ Requires a selection in order to perform a rotate, since rotate may move some bits off the
|
|
edit area--without a selection these bits are lost forever. For now, this selection must be
|
|
a rectangular marquee.
|
|
}
|
|
|
|
VAR
|
|
rInval, srcRect: Rect;
|
|
rectBounds: Rect;
|
|
rotHandle: Handle;
|
|
rotPix: PixMapHandle;
|
|
rotBits: BitMap;
|
|
hSel, vSel: INTEGER;
|
|
ptSel, ptRot: Point;
|
|
widthSel: INTEGER;
|
|
width, height: INTEGER;
|
|
pixel: INTEGER;
|
|
vhAdjust: Point;
|
|
|
|
BEGIN
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) AND (hbe^^.marquee) THEN
|
|
BEGIN
|
|
SetupUndo(hbe);
|
|
|
|
EraseUnderSelection (hbe);
|
|
|
|
SetupRects(rInval, srcRect, hbe);
|
|
LockHands(hbe);
|
|
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
{ Copy the selection }
|
|
IF isColor THEN
|
|
BEGIN
|
|
{ Make sure topLeft of selection is at (0,0) }
|
|
OffsetRect (selection.selPix^^.bounds, -selection.selPix^^.bounds.left, -selection.selPix^^.bounds.top);
|
|
|
|
rotPix := selection.selPix;
|
|
error := HandToHand(Handle (rotPix));
|
|
IF error <> NoErr THEN
|
|
Exit(BERotate);
|
|
HLock (Handle (rotPix));
|
|
|
|
{ Bounds of selPix are (0,0,hbe,v); bounds of rotated image are (0,0,v,hbe) }
|
|
WITH rotPix^^ DO
|
|
BEGIN
|
|
bounds.bottom := selection.selPix^^.bounds.right;
|
|
bounds.right := selection.selPix^^.bounds.bottom;
|
|
rowBytes := ((((pixelSize * (bounds.right - bounds.left)) + 15)) DIV 16) * 2;
|
|
rotHandle := NewHandle (UIntMul((bounds.bottom - bounds.top), rowBytes));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
HUnlock (Handle (rotPix));
|
|
DisposHandle (Handle (rotPix));
|
|
Exit(BERotate);
|
|
END;
|
|
rowBytes := rowBytes + $8000;
|
|
HLock (rotHandle);
|
|
baseAddr := rotHandle^;
|
|
END;
|
|
rectBounds := selection.selPix^^.bounds;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
{ Make sure topLeft of selection is at (0,0) }
|
|
OffsetRect (selection.selBits.bounds, -selection.selBits.bounds.left, -selection.selBits.bounds.top);
|
|
rotBits := selection.selBits;
|
|
rotBits.bounds.bottom := selection.selBits.bounds.right;
|
|
rotBits.bounds.right := selection.selBits.bounds.bottom;
|
|
rotBits.rowBytes := (((rotBits.bounds.right - rotBits.bounds.left) + 15) DIV 16) * 2;
|
|
rotHandle := NewHandle (UIntMul((rotBits.bounds.bottom - rotBits.bounds.top), rotBits.rowBytes));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
Exit(BERotate);
|
|
HLock (rotHandle);
|
|
rotBits.baseAddr := rotHandle^;
|
|
rectBounds := selection.selBits.bounds;
|
|
END;
|
|
|
|
{ Map pixels from selection to rotated image }
|
|
widthSel := rectBounds.right - rectBounds.left;
|
|
FOR vSel := rectBounds.top TO rectBounds.bottom-1 DO
|
|
FOR hSel := rectBounds.left TO rectBounds.right-1 DO
|
|
BEGIN
|
|
SetPt (ptSel, hSel, vSel);
|
|
SetPt (ptRot, vSel, -hSel-1+widthSel);
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
pixel := GetPix (BitMapPtr (selection.selPix^), ptSel);
|
|
SetPix (BitMapPtr (rotPix^), ptRot, pixel);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
pixel := GetPix (@selection.selBits, ptSel);
|
|
SetPix (@rotBits, ptRot, pixel);
|
|
END;
|
|
END;
|
|
|
|
{ Replace selection with rotated image }
|
|
DisposHandle(selection.selHandle);
|
|
selection.selHandle := rotHandle;
|
|
IF isColor THEN
|
|
BEGIN
|
|
MyDisposPixMap(selection.selPix);
|
|
selection.selPix := rotPix;
|
|
END
|
|
ELSE
|
|
selection.selBits := rotBits;
|
|
|
|
{ Adjust selRect to keep center of selection stationary }
|
|
WITH selection.selRect DO
|
|
BEGIN
|
|
{ Note that former selection width is now bounds.bottom of rotPix or rotBit }
|
|
width := right - left;
|
|
height := bottom - top;
|
|
top := top + (height - width) DIV 2;
|
|
left := left + (width - height) DIV 2;
|
|
bottom := top + width;
|
|
right := left + height;
|
|
|
|
{ But don't allow selection to move completely beyond the edit rectangle }
|
|
IF bottom <= beEditRect.top THEN
|
|
vhAdjust.v := (beEditRect.top+1) - bottom
|
|
ELSE IF top >= beEditRect.bottom THEN
|
|
vhAdjust.v := (beEditRect.bottom-1) - top
|
|
ELSE
|
|
vhAdjust.v := 0;
|
|
IF right <= beEditRect.left THEN
|
|
vhAdjust.h := (beEditRect.left+1) - right
|
|
ELSE IF left >= beEditRect.right THEN
|
|
vhAdjust.h := (beEditRect.right-1) - left
|
|
ELSE
|
|
vhAdjust.h := 0;
|
|
OffsetRect (selection.selRect, vhAdjust.h, vhAdjust.v);
|
|
END;
|
|
|
|
{ Must invalidate area under selection before and after rotation }
|
|
UnionRect (rInval, selection.selRect, rInval);
|
|
|
|
{ Copy rotated selection to image }
|
|
BEDrawBegin(hbe);
|
|
DupToPort(hbe);
|
|
CopySelToPort(hbe);
|
|
BEDrawEnd(hbe);
|
|
|
|
UnlockHands(hbe);
|
|
|
|
END;
|
|
|
|
{ invalidate and redraw the rects }
|
|
BEInvalRect(rInval, hbe);
|
|
END;
|
|
END; { BERotate }
|
|
|
|
|
|
PROCEDURE BESetSelect(r: Rect; hbe: BEHandle);
|
|
{ sets the selection rectangle to the given rect, removing existing one if there }
|
|
|
|
VAR
|
|
b: BOOLEAN;
|
|
|
|
BEGIN
|
|
IF BESelection(hbe) THEN
|
|
BEKillSelection(hbe)
|
|
ELSE
|
|
SetupUndo(hbe);
|
|
|
|
LockHands(hbe);
|
|
DoQuickPortToDup(hbe);
|
|
UnlockHands(hbe);
|
|
|
|
WITH hbe^^ DO
|
|
BEGIN
|
|
BEPtXForm(r.topLeft, hbe);
|
|
BEPtXForm(r.botRight, hbe);
|
|
b := SectRect(r, beEditRect, r);
|
|
IF r.right = beEditRect.right THEN r.right := r.right - 1;
|
|
IF r.bottom = beEditRect.bottom THEN r.bottom := r.bottom - 1;
|
|
selection.selRect := r;
|
|
selection.wasErased := False;
|
|
marquee := True;
|
|
END;
|
|
|
|
IF NOT EmptyRect(hbe^^.selection.selRect) THEN
|
|
BEGIN
|
|
SetUpSelBits(hbe^^.selection.selRect, hbe);
|
|
IF hbe^^.error <> NoErr THEN
|
|
SetRect(hbe^^.selection.selRect, 0, 0, 0, 0);
|
|
END;
|
|
|
|
END; { BESetSelect }
|
|
|
|
|
|
PROCEDURE DrawLasso(startPt: Point; hbe: BEHandle);
|
|
{ routine to implement arbitrary selection }
|
|
|
|
VAR
|
|
words: INTEGER;
|
|
lassoRgn, tempRgn: RgnHandle;
|
|
savePt, pt: Point;
|
|
selBBox, r: Rect;
|
|
s: Handle;
|
|
tempBits, mTBits: BitMap;
|
|
memLimit, theSize: LONGINT;
|
|
i: INTEGER;
|
|
tempTable, saveTable: CTabHandle;
|
|
saveColor, myBlack: RGBColor;
|
|
np: PixMapHandle;
|
|
|
|
BEGIN
|
|
{ make sure there is no selection }
|
|
IF BESelection(hbe) THEN
|
|
BEPutSelection(hbe)
|
|
ELSE
|
|
SetupUndo(hbe);
|
|
|
|
{ make a copy of the BEBits into dupBits buffer }
|
|
LockHands(hbe);
|
|
DoQuickPortToDup(hbe);
|
|
UnlockHands(hbe);
|
|
|
|
OpenRgn;
|
|
ShowPen;
|
|
|
|
savePt := startPt;
|
|
|
|
WITH myBlack DO
|
|
BEGIN
|
|
red := 0; blue := 0; green := 0;
|
|
END;
|
|
|
|
saveColor := hbe^^.bePixColor;
|
|
hbe^^.bePixColor := myBlack;
|
|
PaintBits(True, False, savePt, startPt, hbe);
|
|
|
|
memLimit := BitShift(CompactMem(maxSize), -1);
|
|
IF memLimit > 15000 THEN memLimit := 15000;
|
|
|
|
WHILE WaitMouseUp AND (GetRgnMax < memLimit) DO
|
|
BEGIN
|
|
GetMouse(pt);
|
|
BEPtXForm(pt, hbe);
|
|
pt := Point(PinRect(hbe^^.beEditRect, pt));
|
|
IF pt.v = hbe^^.beEditRect.bottom THEN pt.v := pt.v - 1;
|
|
IF pt.h = hbe^^.beEditRect.right THEN pt.h := pt.h - 1;
|
|
BEPtUnXform(pt, hbe);
|
|
|
|
IF LONGINT(savePt) <> LONGINT(pt) THEN
|
|
PaintBits(True, False, savePt, pt, hbe);
|
|
|
|
LONGINT(savePt) := LONGINT(pt);
|
|
END;
|
|
|
|
PaintBits(True, False, savePt, startPt, hbe);
|
|
hbe^^.bePixColor := saveColor;
|
|
|
|
{ got the region! }
|
|
lassoRgn := NewRgn;
|
|
CloseRgn(lassoRgn);
|
|
|
|
{ if it's empty, just blit bits back to screen }
|
|
IF NOT EmptyRgn(lassoRgn) THEN
|
|
BEGIN
|
|
{ enclose all the pixels which we lassoed }
|
|
tempRgn := NewRgn;
|
|
CopyRgn(lassoRgn, tempRgn);
|
|
OffSetRgn(tempRgn, 1, 0);
|
|
UnionRgn(tempRgn, lassoRgn, lassoRgn);
|
|
OffSetRgn(tempRgn, 0, 1);
|
|
UnionRgn(tempRgn, lassoRgn, lassoRgn);
|
|
OffSetRgn(tempRgn, -1, 0);
|
|
UnionRgn(tempRgn, lassoRgn, lassoRgn);
|
|
|
|
{ get the rectangle }
|
|
selBBox := lassoRgn^^.rgnBBox;
|
|
|
|
tempBits.bounds := selBBox;
|
|
tempBits.rowBytes := ((((selBBox.right - selBBox.left) + 15)) DIV 16) * 2;
|
|
tempBits.baseAddr := NewPtrClr(UIntMul((selBBox.bottom - selBBox.top),tempBits.rowBytes));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
Exit(DrawLasso);
|
|
|
|
LockHands(hbe);
|
|
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
BEGIN
|
|
tempTable := dupPix^^.pmTable;
|
|
error := HandToHand(Handle(tempTable));
|
|
IF error <> NoErr THEN Exit(DrawLasso);
|
|
|
|
GetBWTable(tempTable);
|
|
|
|
saveTable := dupPix^^.pmTable;
|
|
dupPix^^.pmTable := tempTable;
|
|
|
|
{ get a copy of the selected bits into temporary bitmap (black/white only) }
|
|
CopyBits(BitMapPtr(dupPix^)^, tempBits, selBBox, selBBox, srcCopy, lassoRgn);
|
|
|
|
dupPix^^.pmTable := saveTable;
|
|
END
|
|
ELSE
|
|
CopyBits(dupBits, tempBits, selBBox, selBBox, srcCopy, lassoRgn);
|
|
|
|
UnlockHands(hbe);
|
|
|
|
{ trim the rectangle }
|
|
{ must give TrimBBox a 0,0 upper coord }
|
|
OffSetRect(selBBox, -tempBits.bounds.left, -tempBits.bounds.top);
|
|
TrimBBox(tempBits.baseAddr, selBBox, tempBits.rowBytes);
|
|
selBBox.bottom := selBBox.bottom + 1;
|
|
|
|
{ now offset rectangle back to where it was }
|
|
OffSetRect(selBBox, tempBits.bounds.left, tempBits.bounds.top);
|
|
|
|
{ don't need tempBits ptr anymore }
|
|
DisposPtr(tempBits.baseAddr);
|
|
|
|
IF NOT EmptyRect(selBBox) THEN
|
|
BEGIN
|
|
|
|
{ flag that this is a lasso selection }
|
|
hbe^^.marquee := False;
|
|
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
{ it was not erased yet }
|
|
wasErased := False;
|
|
|
|
{ setup selRect the way that all routines expect it }
|
|
selRect := selBBox;
|
|
selRect.right := selRect.right - 1;
|
|
selRect.bottom := selRect.bottom - 1;
|
|
END;
|
|
|
|
{ expand the bitmap into which we place the bits }
|
|
r := selBBox;
|
|
InsetRect(r, -1, -1);
|
|
|
|
{ setup the selection bitmap }
|
|
SetUpSelBits(r, hbe);
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
SetRect(hbe^^.selection.selRect, 0, 0, 0, 0);
|
|
Exit(DrawLasso);
|
|
END;
|
|
|
|
LockHands(hbe);
|
|
|
|
{ clear the bitmap because we use a maskRgn in copyBits }
|
|
ClearHandle(hbe^^.selection.selHandle);
|
|
|
|
{ put only selected bits into selBits bitmap }
|
|
IF hbe^^.isColor THEN
|
|
CopyBits(BitMapPtr(hbe^^.dupPix^)^, BitMapPtr(hbe^^.selection.selPix^)^, selBBox, selBBox,
|
|
srcCopy, lassoRgn)
|
|
ELSE
|
|
CopyBits(hbe^^.dupBits, hbe^^.selection.selBits, selBBox, selBBox, srcCopy, lassoRgn);
|
|
|
|
UnlockHands(hbe);
|
|
|
|
IF hbe^^.isColor THEN
|
|
WITH hbe^^, selection.maskPix^^ DO
|
|
BEGIN
|
|
rowBytes := ((((selection.selPix^^.bounds.right - selection.selPix^^.bounds.left) + 15))
|
|
DIV 16) * 2;
|
|
bounds := selection.selPix^^.bounds;
|
|
theSize := UIntMul((bounds.bottom - bounds.top), rowBytes);
|
|
rowBytes := rowBytes + $8000;
|
|
words := ((bounds.right - bounds.left) + 15) DIV 16;
|
|
tempBits.rowBytes := rowBytes - $8000;
|
|
tempBits.bounds := bounds;
|
|
mTBits.rowBytes := rowBytes - $8000;
|
|
mTBits.bounds := bounds;
|
|
END
|
|
ELSE
|
|
WITH hbe^^, selection.maskBits DO
|
|
BEGIN
|
|
bounds := selection.selBits.bounds;
|
|
rowBytes := selection.selBits.rowBytes;
|
|
theSize := GetHandleSize(selection.selHandle);
|
|
words := ((bounds.right - bounds.left) + 15) DIV 16;
|
|
tempBits.rowBytes := rowBytes;
|
|
tempBits.bounds := bounds;
|
|
mTBits.rowBytes := rowBytes;
|
|
mTBits.bounds := bounds;
|
|
END;
|
|
|
|
{ make a bitmap for the mask }
|
|
s := NewHandle(theSize);
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
Exit(DrawLasso);
|
|
|
|
hbe^^.selection.maskHandle := s;
|
|
|
|
LockHands(hbe);
|
|
|
|
tempBits.baseAddr := NewPtrClr(GetHandleSize(hbe^^.selection.maskHandle));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN SysBeep(20);
|
|
|
|
mTBits.baseAddr := NewPtrClr(GetHandleSize(hbe^^.selection.maskHandle));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN SysBeep(20);
|
|
|
|
WITH hbe^^ DO
|
|
IF isColor THEN
|
|
BEGIN
|
|
saveTable := selection.selPix^^.pmTable;
|
|
selection.selPix^^.pmTable := tempTable;
|
|
CopyBits(BitMapPtr(selection.selPix^)^, tempBits, selection.selPix^^.bounds, tempBits.bounds, srcCopy, Nil);
|
|
selection.selPix^^.pmTable := saveTable;
|
|
END
|
|
ELSE
|
|
CopyBits(selection.selBits, tempBits, selection.selBits.bounds, tempBits.bounds, srcCopy, Nil);
|
|
|
|
{ calculate the mask bits }
|
|
CalcMask(tempBits.baseAddr, mTBits.baseAddr, { srcPtr, dstPtr }
|
|
tempBits.rowBytes, mTBits.rowBytes, { srcRow, dstRow }
|
|
tempBits.bounds.bottom - tempBits.bounds.top, words); { height, words }
|
|
|
|
IF hbe^^.isColor THEN
|
|
CopyBits(mTBits, BitMapPtr(hbe^^.selection.maskPix^)^, mTBits.bounds, hbe^^.selection.maskPix^^.bounds,
|
|
srcCopy, Nil)
|
|
ELSE
|
|
CopyBits(mTBits, hbe^^.selection.maskBits, mTBits.bounds, hbe^^.selection.maskBits.bounds,
|
|
srcCopy, Nil);
|
|
|
|
DisposPtr(tempBits.baseAddr);
|
|
DisposPtr(mTBits.baseAddr);
|
|
|
|
{ make sure the mask is correct }
|
|
BEDrawBegin(hbe);
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
SetPortPix(hbe^^.selection.maskPix);
|
|
RectRgn(tempRgn, hbe^^.selection.maskPix^^.bounds);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
SetPortBits(hbe^^.selection.maskBits);
|
|
RectRgn(tempRgn, hbe^^.selection.maskBits.bounds);
|
|
END;
|
|
|
|
DiffRgn(tempRgn, lassoRgn, tempRgn);
|
|
EraseRgn(tempRgn);
|
|
BEDrawEnd(hbe);
|
|
|
|
DisposeRgn(tempRgn);
|
|
|
|
s := NewHandle(GetHandleSize(hbe^^.selection.maskHandle));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
Exit(DrawLasso);
|
|
|
|
hbe^^.selection.edgeHandle := s;
|
|
|
|
{ setup a pixMap for the edges }
|
|
IF hbe^^.isColor THEN
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
edgePix^^.bounds := maskPix^^.bounds;
|
|
edgePix^^.rowBytes := maskPix^^.rowBytes;
|
|
END
|
|
ELSE
|
|
WITH hbe^^.selection DO
|
|
BEGIN
|
|
edgeBits.bounds := maskBits.bounds;
|
|
edgeBits.rowBytes := maskBits.rowBytes;
|
|
END;
|
|
|
|
UnlockHands(hbe);
|
|
END; { selBBox not empty }
|
|
|
|
IF hbe^^.isColor THEN
|
|
DisposHandle(Handle(tempTable));
|
|
END; { lassoRgn not empty }
|
|
|
|
DisposeRgn(lassoRgn);
|
|
|
|
{ copy original bits back to screen to get rid of lasso }
|
|
DoQuickDupToPort(hbe);
|
|
|
|
BEInvalRect(hbe^^.beEditRect, hbe);
|
|
|
|
END; { DrawLasso }
|
|
|
|
|
|
PROCEDURE HiliteLasso(hbe: BEHandle);
|
|
|
|
VAR
|
|
now, mIndex: INTEGER;
|
|
r, srcRect: Rect;
|
|
thePat: Pattern;
|
|
|
|
BEGIN
|
|
GetMIndex(mIndex);
|
|
|
|
SetupRects(r, srcRect, hbe);
|
|
|
|
IF mIndex <> hbe^^.oldIndex THEN
|
|
BEGIN
|
|
hbe^^.oldIndex := mIndex;
|
|
|
|
HLock(hbe^^.selection.edgeHandle);
|
|
IF hbe^^.isColor THEN
|
|
hbe^^.selection.edgePix^^.baseAddr := hbe^^.selection.edgeHandle^
|
|
ELSE
|
|
hbe^^.selection.edgeBits.baseAddr := hbe^^.selection.edgeHandle^;
|
|
|
|
{ start with a clean bitmap }
|
|
ClearHandle(hbe^^.selection.edgeHandle);
|
|
|
|
LockHands(hbe);
|
|
WITH hbe^^.selection DO
|
|
IF hbe^^.isColor THEN
|
|
CalcEdges(maskPix^^.baseAddr, edgePix^^.baseAddr, 0,
|
|
maskPix^^.bounds.bottom - maskPix^^.bounds.top,
|
|
(maskPix^^.rowBytes - $8000), True)
|
|
ELSE
|
|
CalcEdges(maskBits.baseAddr, edgeBits.baseAddr, 0,
|
|
maskBits.bounds.bottom - maskBits.bounds.top,
|
|
maskBits.rowBytes, True);
|
|
UnlockHands(hbe);
|
|
|
|
BEDrawBegin(hbe);
|
|
GetSelPat(mIndex, thePat);
|
|
PenPat(thePat);
|
|
PenMode(patBic);
|
|
EdgeToPort(hbe, srcBic);
|
|
WITH hbe^^.selection DO
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
SetPortPix(edgePix);
|
|
PaintRect(edgePix^^.bounds);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
SetPortBits(edgeBits);
|
|
PaintRect(edgeBits.bounds);
|
|
END;
|
|
BEDrawEnd(hbe);
|
|
|
|
BEDrawBegin(hbe);
|
|
EdgeToPort(hbe, srcOr);
|
|
BEDrawEnd(hbe);
|
|
|
|
HUnlock(hbe^^.selection.edgeHandle);
|
|
|
|
BEInvalRect(r, hbe);
|
|
|
|
END;
|
|
|
|
END; { HiliteLasso }
|
|
|
|
|
|
PROCEDURE SetupUndo(hbe: BEHandle);
|
|
{ copy bit image to offscreen for undo }
|
|
|
|
VAR
|
|
pm: PixMapHandle;
|
|
bm: BitMap;
|
|
|
|
BEGIN
|
|
IF hbe^^.undoFreeze = 0 THEN
|
|
BEGIN
|
|
IF BESelection(hbe) THEN
|
|
BEGIN
|
|
SetupUndoSelection(hbe);
|
|
DoQuickDupToPort(hbe);
|
|
END
|
|
ELSE
|
|
KillUndoSelection(hbe);
|
|
|
|
HLock(hbe^^.undoHandle);
|
|
HLock(Handle(hbe^^.editHandle));
|
|
|
|
{ setup offscreen bitmap baseAddr }
|
|
IF hbe^^.isColor THEN
|
|
BEGIN
|
|
hbe^^.undoPix^^.baseAddr := hbe^^.undoHandle^;
|
|
BEPixmap(pm, hbe);
|
|
HLock(Handle(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap));
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
hbe^^.undoBits.baseAddr := hbe^^.undoHandle^;
|
|
BEBitmap(bm, hbe);
|
|
END;
|
|
|
|
{ copy from BitEdit record bits to offscreen buffer }
|
|
BEDrawBegin(hbe);
|
|
IF hbe^^.isColor THEN
|
|
CopyBits(BitMapPtr(pm^)^, BitMapPtr(hbe^^.undoPix^)^, pm^^.bounds, hbe^^.undoPix^^.bounds,
|
|
srcCopy, Nil)
|
|
ELSE
|
|
CopyBits(bm, hbe^^.undoBits, bm.bounds, hbe^^.undoBits.bounds, srcCopy, Nil);
|
|
BEDrawEnd(hbe);
|
|
|
|
IF hbe^^.isColor THEN
|
|
HUnlock(Handle(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap));
|
|
HUnlock(hbe^^.undoHandle);
|
|
HUnlock(Handle(hbe^^.editHandle));
|
|
END;
|
|
|
|
END; { SetupUndo }
|
|
|
|
|
|
PROCEDURE BEUndoBegin(hbe: BEHandle);
|
|
{ Save an undo snapshot and retain it until the next call to BEUndoEnd }
|
|
|
|
BEGIN
|
|
SetupUndo (hbe);
|
|
hbe^^.undoFreeze := hbe^^.undoFreeze + 1;
|
|
END; { BEUndoBegin }
|
|
|
|
|
|
PROCEDURE BEUndoEnd(hbe: BEHandle);
|
|
{ Allow the next BitEdit routine to save a new undo state }
|
|
|
|
BEGIN
|
|
IF hbe^^.undoFreeze > 0 THEN
|
|
hbe^^.undoFreeze := hbe^^.undoFreeze - 1;
|
|
END; { BEUndoEnd }
|
|
|
|
|
|
PROCEDURE NoColorUndo(hbe: BEHandle);
|
|
|
|
VAR
|
|
bm, tempBits: Bitmap;
|
|
|
|
BEGIN
|
|
{ setup undo bitmap baseAddr }
|
|
HLock(hbe^^.undoHandle);
|
|
hbe^^.undoBits.baseAddr := hbe^^.undoHandle^;
|
|
|
|
{ make a bitmap out of bitEdit record }
|
|
HLock(Handle(hbe^^.editHandle));
|
|
BEBitmap(bm, hbe);
|
|
|
|
{ set up a temporary bitmap }
|
|
tempBits.baseAddr := NewPtr(GetHandleSize(Handle(hbe^^.undoHandle)));
|
|
hbe^^.error := MemError;
|
|
|
|
tempBits.bounds := hbe^^.undoBits.bounds;
|
|
tempBits.rowBytes := hbe^^.undoBits.rowBytes;
|
|
|
|
IF hbe^^.error = NoErr THEN
|
|
{ swap the bits }
|
|
BEGIN
|
|
CopyBits(bm, tempBits, bm.bounds, tempBits.bounds, srcCopy, Nil);
|
|
CopyBits(hbe^^.undoBits, bm, hbe^^.undoBits.bounds, bm.bounds, srcCopy, Nil);
|
|
CopyBits(tempBits, hbe^^.undoBits, tempBits.bounds, hbe^^.undoBits.bounds, srcCopy, Nil);
|
|
END
|
|
ELSE
|
|
{ copy from offscreen buffer to BitEdit record bits }
|
|
CopyBits(hbe^^.undoBits, bm, hbe^^.undoBits.bounds, bm.bounds, srcCopy, Nil);
|
|
|
|
HUnlock(hbe^^.undoHandle);
|
|
HUnlock(Handle(hbe^^.editHandle));
|
|
|
|
IF tempBits.baseAddr <> Nil THEN
|
|
DisposPtr(tempBits.baseAddr);
|
|
|
|
END;
|
|
|
|
|
|
PROCEDURE BEUndo(hbe: BEHandle);
|
|
{ routine to undo the last change }
|
|
|
|
VAR
|
|
bm, tempBits: PixMapHandle;
|
|
p: Ptr;
|
|
n: Handle;
|
|
tempSel: BESelectRec;
|
|
|
|
BEGIN
|
|
IF BESelection (hbe) THEN
|
|
BEGIN
|
|
{ draw image without ants }
|
|
LockHands(hbe);
|
|
BEDrawBegin(hbe);
|
|
DupToPort(hbe);
|
|
BEDrawEnd(hbe);
|
|
UnlockHands(hbe);
|
|
END;
|
|
|
|
IF NOT hbe^^.isColor THEN
|
|
NoColorUndo(hbe)
|
|
ELSE
|
|
BEGIN
|
|
{ setup undo bitmap baseAddr }
|
|
HLock(hbe^^.undoHandle);
|
|
hbe^^.undoPix^^.baseAddr := hbe^^.undoHandle^;
|
|
|
|
{ make a bitmap out of BitEdit record }
|
|
HLock(Handle(hbe^^.editHandle));
|
|
BEPixmap(bm, hbe);
|
|
HLock(Handle(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap));
|
|
|
|
{ set up a temporary bitmap }
|
|
tempBits := NewPixMap;
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
Exit(BEUndo);
|
|
|
|
p := NewPtr(GetHandleSize(Handle(hbe^^.undoHandle)));
|
|
hbe^^.error := MemError;
|
|
IF hbe^^.error <> NoErr THEN
|
|
BEGIN
|
|
DisposPixMap (tempBits);
|
|
Exit(BEUndo);
|
|
END;
|
|
DisposHandle(Handle(tempBits^^.pmTable));
|
|
|
|
tempBits^^.baseAddr := p;
|
|
tempBits^^.bounds := hbe^^.undoPix^^.bounds;
|
|
tempBits^^.rowBytes := hbe^^.undoPix^^.rowBytes;
|
|
tempBits^^.pixelSize := hbe^^.undoPix^^.pixelSize;
|
|
tempBits^^.cmpSize := hbe^^.undoPix^^.cmpSize;
|
|
tempBits^^.pmTable := hbe^^.undoPix^^.pmTable;
|
|
|
|
IF hbe^^.error = NoErr THEN
|
|
{ swap the bits }
|
|
BEGIN
|
|
CopyBits(BitMapPtr(bm^)^, BitMapPtr(tempBits^)^, bm^^.bounds, tempBits^^.bounds, srcCopy, Nil);
|
|
CopyBits(BitMapPtr(hbe^^.undoPix^)^, BitMapPtr(bm^)^, hbe^^.undoPix^^.bounds, bm^^.bounds, srcCopy, Nil);
|
|
CopyBits(BitMapPtr(tempBits^)^, BitMapPtr(hbe^^.undoPix^)^, tempBits^^.bounds, hbe^^.undoPix^^.bounds, srcCopy, Nil);
|
|
END
|
|
ELSE
|
|
{ copy from offscreen buffer to BitEdit record bits }
|
|
CopyBits(BitMapPtr(hbe^^.undoPix^)^, BitMapPtr(bm^)^, hbe^^.undoPix^^.bounds, bm^^.bounds, srcCopy, Nil);
|
|
|
|
HUnlock(Handle(cGrafPtr(hbe^^.beGrafPtr)^.portPixMap));
|
|
HUnlock(hbe^^.undoHandle);
|
|
HUnlock(Handle(hbe^^.editHandle));
|
|
|
|
IF tempBits^^.baseAddr <> Nil THEN
|
|
BEGIN
|
|
DisposPtr(tempBits^^.baseAddr);
|
|
MyDisposPixMap(tempBits);
|
|
END;
|
|
END;
|
|
|
|
{ Restore selection }
|
|
tempSel := hbe^^.undoSelection;
|
|
hbe^^.undoSelection := hbe^^.selection;
|
|
hbe^^.selection := tempSel;
|
|
|
|
{ Selection must be a lasso if a mask exists }
|
|
hbe^^.marquee := (hbe^^.selection.maskHandle = Nil);
|
|
|
|
IF BESelection (hbe) THEN
|
|
BEGIN
|
|
LockHands(hbe);
|
|
BEDrawBegin(hbe);
|
|
PortToDup(hbe);
|
|
CopySelToPort(hbe);
|
|
BEDrawEnd(hbe);
|
|
UnlockHands(hbe);
|
|
END;
|
|
|
|
{ force all views to be redrawn }
|
|
BEInvalRect(hbe^^.beEditRect, hbe);
|
|
|
|
END; { BEUndo }
|
|
|
|
|
|
PROCEDURE BEView(editRect: Rect; viewRect: Rect; bitsSize: Point; bitsDelta: Point; hbe: BEHandle);
|
|
{ Sets up a view of the bits }
|
|
|
|
BEGIN
|
|
WITH hbe^^ DO BEGIN
|
|
beEditRect := editRect;
|
|
beViewRect := viewRect;
|
|
fatbitsSize := bitsSize;
|
|
fatbitsDelta := bitsDelta;
|
|
StuffHex(@beFillPat, 'FFFFFFFFFFFFFFFF');
|
|
StuffHex(@fatbitsPat, '0000000000000000');
|
|
|
|
realRect := beEditRect;
|
|
DoMyMapRect(hbe, realRect, realRect);
|
|
END;
|
|
END; { BEView }
|