mirror of
https://github.com/elliotnunn/supermario.git
synced 2025-02-16 14:30:32 +00:00
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 }
|