<> <> <> DIRECTORY BitBlt USING [AlignedBBTable, BITBLT, BBptr, BBTableSpace], Buttons, Cursors USING [SetCursor], CGScreen USING [Bits], Environment USING [BitAddress], InputFocus, Mopcodes, Process, TIPUser, UserTerminal, ViewerLocks USING [LockViewerTree, ReleaseViewerTree], ViewerClasses, ViewerSpecs USING [screenH, screenW]; Magnifier: PROGRAM IMPORTS BitBlt, Buttons, Cursors, CGScreen, InputFocus, Process, TIPUser, UserTerminal, ViewerLocks SHARES ViewerLocks = BEGIN OPEN Mopcodes; pMask: REF; -- pointer to mask bits (0 => opaque, 1 => transparent) pImage: REF; -- pointer to image bits (0 => white, 1 => black) pSaved: REF; -- pointer to screen bits (0 => white, 1 => black) pRaster: CARDINAL; -- words per line pWidth: CARDINAL; -- width in bits pHeight: CARDINAL; -- height in lines pX, pY: INTEGER; -- last position lock: BOOL; -- viewer paints locked out magnify: BOOL _ FALSE; magX, magY, magW, magH: CARDINAL; AllocateBitmap: PROC [nWords: CARDINAL] RETURNS [REF] = INLINE BEGIN Words: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF CARDINAL]; RETURN[NEW[Words[nWords]]]; END; MagnifyRegion: PROC [leftX, topY, widthInWords, height: CARDINAL] = BEGIN magnify _ TRUE; magX _ leftX; magY _ topY; magW _ widthInWords; magH _ height; END; NewPicture: PROC [mask: REF, image: REF, raster, width, height, screenX, screenY: CARDINAL, lockPainting: BOOL _ TRUE] = BEGIN pMask _ mask; pImage _ image; pSaved _ AllocateBitmap[raster*height]; pRaster _ raster; pWidth _ width; pHeight _ height; pX _ MIN[screenX, ViewerSpecs.screenW-width]; screenY _ ViewerSpecs.screenH-screenY; -- invert conversion pY _ MIN[screenY, ViewerSpecs.screenH-height]; lock _ lockPainting; ComputeScreenPoint[]; sfsp.dst _ [LOOPHOLE[pSaved],,0]; sfsp.dstBpl _ pRaster*16; sfsp.width _ pWidth; sfsp.height _ pHeight; itsp.srcDesc.srcBpl _ pRaster*16; itsp.width _ pWidth; itsp.height _ pHeight; Cursors.SetCursor[blank]; IF lock THEN ViewerLocks.LockViewerTree[]; BLTImageToScreen[]; END; MovePicture: PROC [screenX, screenY: CARDINAL] = BEGIN BLTSavedToScreen[]; pX _ MIN[screenX, ViewerSpecs.screenW-pWidth]; screenY _ ViewerSpecs.screenH-screenY; -- invert conversion pY _ MIN[screenY, ViewerSpecs.screenH-pHeight]; ComputeScreenPoint[]; BLTImageToScreen[]; END; TakeDownPicture: PROC = BEGIN BLTSavedToScreen[]; IF lock THEN ViewerLocks.ReleaseViewerTree[]; Cursors.SetCursor[textPointer]; pMask _ pImage _ pSaved _ NIL; magnify _ FALSE; END; ComputeScreenPoint: PROC = INLINE BEGIN screenPoint.word _ screen + (LONG[pY]*(ViewerSpecs.screenW/16)) + (LONG[pX]/16); screenPoint.bit _ pX MOD 16; END; screen: LONG POINTER _ CGScreen.Bits[].base; screenPoint: Environment.BitAddress; sfsTable, itsTable: BitBlt.BBTableSpace; sfsp: BitBlt.BBptr _ BitBlt.AlignedBBTable[@sfsTable]; itsp: BitBlt.BBptr _ BitBlt.AlignedBBTable[@itsTable]; Pair: TYPE = ARRAY [0..1] OF CARDINAL; PairPtr: TYPE = LONG POINTER TO Pair; Get8: PROC [ptr: LONG POINTER, start: CARDINAL] RETURNS [word: CARDINAL] = INLINE { dist: INTEGER = CardinalAnd[start,15]; pp: PairPtr = LOOPHOLE[ptr, PairPtr] + start / 16; RETURN [ CardinalOr[ CardinalShiftLeft[pp[0], dist], CardinalShiftLeft[pp[1], dist-16]] / 256]; }; Put16: PROC [ptr: LONG POINTER, start: CARDINAL, word: CARDINAL] = INLINE { dist: INTEGER = CardinalAnd[start,15]; pp: PairPtr = LOOPHOLE[ptr, PairPtr] + start / 16; pp[0] _ CardinalOr[ CardinalShiftRight[word, dist], CardinalAnd[pp[0], CardinalShiftLeft[177777B, 16-dist]]]; pp[1] _ CardinalOr[ CardinalShiftLeft[word, 16-dist], CardinalAnd[pp[1], CardinalShiftRight[177777B, dist]]]; }; CardinalShiftLeft: PROC [word: CARDINAL, dist: INTEGER] RETURNS [CARDINAL] = MACHINE CODE { Mopcodes.zSHIFT; }; CardinalShiftRight: PROC [word: CARDINAL, dist: INTEGER] RETURNS [CARDINAL] = MACHINE CODE { Mopcodes.zNEG; Mopcodes.zSHIFT; }; CardinalOr: PROC [word1,word2: CARDINAL] RETURNS [CARDINAL] = MACHINE CODE { Mopcodes.zOR; }; CardinalAnd: PROC [word1,word2: CARDINAL] RETURNS [CARDINAL] = MACHINE CODE { Mopcodes.zAND; }; BLTImageToScreen: PROC = BEGIN itsp.dst _ sfsp.src _ screenPoint; BitBlt.BITBLT[sfsp]; -- save screen IF magnify THEN BEGIN screenAdd: LONG CARDINAL _ (magY+magH/4)*pRaster + magX/16; imageAdd: LONG CARDINAL _ magY*pRaster + magX/16; fetchOffset: CARDINAL = magX+magW*16/4; screen: LONG POINTER = LOOPHOLE[pSaved]; image: LONG POINTER = LOOPHOLE[pImage]; THROUGH [0..magH/2) DO FOR i: CARDINAL IN [0..magW) DO word: CARDINAL = twoPower[Get8[screen+screenAdd, fetchOffset+(8*i)]]; xOff: CARDINAL = magX+(16*i); Put16[image+imageAdd, xOff, word]; Put16[image+imageAdd+pRaster, xOff, word]; ENDLOOP; screenAdd _ screenAdd + pRaster; imageAdd _ imageAdd + (2*pRaster); ENDLOOP; END; IF pMask#NIL THEN BEGIN itsp.src _ [LOOPHOLE[pMask],,0]; itsp.flags.dstFunc _ and; BitBlt.BITBLT[itsp]; itsp.flags.dstFunc _ or; END; itsp.src _ [LOOPHOLE[pImage],,0]; BitBlt.BITBLT[itsp]; itsp.flags.dstFunc _ null; END; BLTSavedToScreen: PROC = INLINE BEGIN itsp.dst _ screenPoint; itsp.src _ [LOOPHOLE[pSaved],,0]; BitBlt.BITBLT[itsp]; END; twoPower: ARRAY [0..256) OF CARDINAL; BuildTwoPower: PROC = BEGIN scan: INTEGER; p: POINTER TO PACKED ARRAY [0..8) OF BOOL _ LOOPHOLE[@scan]; p2: POINTER TO PACKED ARRAY [0..16) OF BOOL _ LOOPHOLE[@twoPower]; FOR i: INTEGER IN [0..256) DO scan _ i; FOR j: INTEGER IN [0..8) DO p2[j*2] _ p[j]; p2[j*2+1] _ p[j]; ENDLOOP; p2 _ p2+1; ENDLOOP; END; magnifier: REF ARRAY [0..256) OF UNSPECIFIED _ LOOPHOLE[AllocateBitmap[256]]; magnifier2: REF ARRAY [0..512) OF UNSPECIFIED _ LOOPHOLE[AllocateBitmap[512]]; Start: Buttons.ButtonProc = TRUSTED BEGIN InputFocus.SetInputFocus[]; InputFocus.CaptureButtons[Notify, myTIPTable]; IF mouseButton#red THEN BEGIN MagnifyRegion[1, 1, 7, 62]; NewPicture[NIL, magnifier2, 8, 114, 64, 300, 300]; END ELSE BEGIN MagnifyRegion[1, 1, 3, 62]; NewPicture[NIL, magnifier, 4, 50, 64, 300, 300]; END; Process.Detach[FORK DoIt[]]; END; Notify: ViewerClasses.NotifyProc = TRUSTED {}; -- NOP myTIPTable: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["Magnifier.tip"]; -- Known NOP fudge: CARDINAL _ 150; -- fudge for retrace synch DoIt: PROCEDURE = BEGIN mouseBitsRec: TYPE = MACHINE DEPENDENT RECORD [ -- mouse buttons are inverted fill: [0..8192), red: BOOL, blue: BOOL, yellow: BOOL]; mouseP: LONG POINTER TO mouseBitsRec = LOOPHOLE[UserTerminal.keyboard]; mouse: UserTerminal.Coordinate; Process.SetPriority[3]; UNTIL ~mouseP.red DO wait: CARDINAL; UserTerminal.WaitForScanLine[ SELECT wait _ pY+fudge FROM >808 => 0, ENDCASE => wait]; IF UserTerminal.cursor^ # mouse THEN BEGIN mouse _ UserTerminal.cursor^; MovePicture[mouse.x, 808-mouse.y]; END; ENDLOOP; TakeDownPicture[]; InputFocus.ReleaseButtons[]; END; sfsp.flags.disjoint _ TRUE; sfsp.flags.disjointItems _ TRUE; sfsp.srcDesc.srcBpl _ ViewerSpecs.screenW; itsp.flags.disjoint _ TRUE; itsp.flags.disjointItems _ TRUE; itsp.dstBpl _ ViewerSpecs.screenW; BuildTwoPower[]; magnifier[0] _ magnifier[1] _ magnifier[2] _ 177777B; magnifier[252] _ magnifier[253] _ magnifier[254] _ 177777B; magnifier[3] _ 140000B; magnifier[255] _ 140000B; FOR i: INTEGER IN [0..248/4) DO magnifier[i*4+4] _ 100000B; magnifier[i*4+7] _ 040000B; ENDLOOP; FOR i: INTEGER IN [0..6] DO magnifier2[i] _ 177777B; magnifier2[i+504] _ 177777B; ENDLOOP; magnifier2[7] _ magnifier2[511] _ 140000B; FOR i: INTEGER IN [0..62) DO magnifier2[i*8+8] _ 100000B; magnifier2[i*8+15] _ 040000B; ENDLOOP; [] _ Buttons.Create[[name: "Magnifier"], Start]; END.