DIRECTORY Basics USING [BITAND, BITOR, BITXOR, LongMult, LongNumber], Buttons USING [ButtonProc, Create], Cursors USING [SetCursor], InterminalBackdoor USING [terminal], ImagerManhattan USING [CreateFromBox, Destroy, Difference, Polygon], ImagerPixelMap USING [BoundedWindow, Clear, Clip, Create, DeviceRectangle, Fill, Intersect, PixelMap, PixelMapRep, Reshape, ShiftMap, Transfer, Window], InputFocus USING [CaptureButtons, ReleaseButtons, SetInputFocus], Terminal USING [ColorCursorBitmapState, FrameBuffer, GetBWCursorPosition, GetBWFrameBuffer, GetColorBitmapState, GetColorCursorPosition, GetColorFrameBufferA, GetColorFrameBufferB, GetColorMode, GetKeys, Position, SetColorCursorState, Virtual, WaitForBWVerticalRetrace], TIPUser USING [InstantiateNewTIPTable, TIPTable], ViewerClasses USING [NotifyProc], ViewerLocks USING [CallUnderViewerTreeLock]; Magnifier: CEDAR PROGRAM IMPORTS Basics, Buttons, Cursors, ImagerManhattan, ImagerPixelMap, InputFocus, Terminal, TIPUser, ViewerLocks, InterminalBackdoor ~ BEGIN PixelMap: TYPE ~ ImagerPixelMap.PixelMap; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; Notify: ViewerClasses.NotifyProc = TRUSTED {}; -- NOP myTIPTable: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["Magnifier.tip"]; -- Known NOP hShift: INTEGER _ 0; locking: BOOLEAN _ TRUE; LFDisplay: UNSAFE PROC RETURNS [ImagerPixelMap.PixelMap] ~ UNCHECKED { frameBuffer: Terminal.FrameBuffer ~ Terminal.GetBWFrameBuffer[InterminalBackdoor.terminal]; refRep: REF ImagerPixelMap.PixelMapRep ~ NEW[ImagerPixelMap.PixelMapRep _ [ ref: frameBuffer, pointer: frameBuffer.base, words: LONG[frameBuffer.wordsPerLine]*frameBuffer.height, lgBitsPerPixel: 0, rast: frameBuffer.wordsPerLine, lines: frameBuffer.height ]]; frame: ImagerPixelMap.PixelMap ~ [ sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: frameBuffer.height, fSize: frameBuffer.width, refRep: refRep ]; RETURN [frame]; }; DoIt: PROCEDURE [width: NAT _ 420, height: NAT _ 260] ~ BEGIN vt: Terminal.Virtual _ InterminalBackdoor.terminal; It: PROC ~ { WHILE Terminal.GetKeys[vt][Red] = down DO ENDLOOP; UNTIL Terminal.GetKeys[vt][Red] = down DO mouse: Terminal.Position _ Terminal.GetBWCursorPosition[vt]; IF mouse = [-100, -100] THEN DoColor[width, height] ELSE DoBW[width, height]; ENDLOOP; }; Cursors.SetCursor[textPointer]; IF locking THEN { InputFocus.SetInputFocus[]; InputFocus.CaptureButtons[Notify, myTIPTable]; ViewerLocks.CallUnderViewerTreeLock[It]; InputFocus.ReleaseButtons[]; } ELSE It[]; END; TrimEdge: PROC [r: ImagerManhattan.Polygon] RETURNS [ImagerManhattan.Polygon] ~ { IF r=NIL OR r.rest#NIL OR r.first.sSize <= 2 OR r.first.fSize <= 2 THEN RETURN [r]; RETURN [LIST[[r.first.sMin+1, r.first.fMin+1, r.first.sSize-2, r.first.fSize-2]]] }; MouseOutOfBounds: SIGNAL ~ CODE; DoColor: PROCEDURE [width: NAT, height: NAT] ~ { vt: Terminal.Virtual _ InterminalBackdoor.terminal; BitDouble8: PROC [dest, source: PixelMap] ~ TRUSTED { srcr: DeviceRectangle _ source.BoundedWindow; dstr: DeviceRectangle _ ImagerPixelMap.Intersect[dest.BoundedWindow, [srcr.sMin*2, srcr.fMin*2, srcr.sSize*2, srcr.fSize*2]]; FOR s: INTEGER IN [dstr.sMin..dstr.sMin+dstr.sSize) DO destRow: LONG POINTER TO PACKED ARRAY [0..0) OF [0..256) _ dest.refRep.pointer + Basics.LongMult[(s - dest.sOrigin), dest.refRep.rast]; sourceRow: LONG POINTER TO PACKED ARRAY [0..0) OF [0..256) _ source.refRep.pointer + Basics.LongMult[NAT[s - 2*source.sOrigin]/2, source.refRep.rast]; FOR f: INTEGER IN [dstr.fMin..dstr.fMin+dstr.fSize) DO destRow[f-dest.fOrigin] _ sourceRow[NAT[f-2*source.fOrigin]/2]; ENDLOOP; ENDLOOP; }; BitDouble16: PROC [dest, source: PixelMap] ~ TRUSTED { srcr: DeviceRectangle _ source.BoundedWindow; dstr: DeviceRectangle _ ImagerPixelMap.Intersect[dest.BoundedWindow, [srcr.sMin*2, srcr.fMin*2, srcr.sSize*2, srcr.fSize*2]]; FOR s: INTEGER IN [dstr.sMin..dstr.sMin+dstr.sSize) DO destRow: LONG POINTER TO PACKED ARRAY [0..0) OF CARDINAL _ dest.refRep.pointer + Basics.LongMult[(s - dest.sOrigin), dest.refRep.rast]; sourceRow: LONG POINTER TO PACKED ARRAY [0..0) OF CARDINAL _ source.refRep.pointer + Basics.LongMult[NAT[s - 2*source.sOrigin]/2, source.refRep.rast]; FOR f: INTEGER IN [dstr.fMin..dstr.fMin+dstr.fSize) DO destRow[f-dest.fOrigin] _ sourceRow[NAT[f-2*source.fOrigin]/2]; ENDLOOP; ENDLOOP; }; Shuffle: PROC [ big, small: REF PixelMap, displayBounds: DeviceRectangle, BitDouble: PROC [dest, source: PixelMap], s, f: INTEGER, width, height: NAT ] ~ { r: DeviceRectangle _ small^.Window; IF r # big^.Window THEN ERROR; IF s = r.sMin AND f = r.fMin THEN Terminal.WaitForBWVerticalRetrace[vt] ELSE { newbox: DeviceRectangle _ [s, f, r.sSize, r.fSize]; sDelta: INTEGER _ s - r.sMin; fDelta: INTEGER _ f - r.fMin; old: ImagerManhattan.Polygon _ ImagerManhattan.CreateFromBox[r]; oldBig: PixelMap _ big^; new: ImagerManhattan.Polygon _ ImagerManhattan.CreateFromBox[newbox]; goodBigBits: ImagerManhattan.Polygon _ GoodBigBits[]; GoodBigBits: PROC RETURNS [ImagerManhattan.Polygon] ~ { b: DeviceRectangle _ ImagerPixelMap.Intersect[ [r.sMin+1, r.fMin+1, r.sSize-2, r.fSize-2], displayBounds ]; newb: DeviceRectangle _ b; newb.sMin _ newb.sMin + sDelta + sDelta; newb.fMin _ newb.fMin + fDelta + fDelta; newb _ ImagerPixelMap.Intersect[newb, b]; newb.sMin _ newb.sMin - sDelta; newb.fMin _ newb.fMin - fDelta; RETURN [ImagerManhattan.CreateFromBox[newb]] }; toRestoreFromSmall: ImagerManhattan.Polygon _ old.Difference[new]; toSaveIntoSmall: ImagerManhattan.Polygon _ new.Difference[old]; toRecompute: ImagerManhattan.Polygon _ TrimEdge[new].Difference[goodBigBits]; FOR p: LIST OF DeviceRectangle _ toRestoreFromSmall, p.rest UNTIL p=NIL DO big^.Transfer[small^.Clip[p.first]]; ENDLOOP; small^.Transfer[small^.ShiftMap[-sDelta, -fDelta]]; small.sOrigin _ small.sOrigin + sDelta; small.fOrigin _ small.fOrigin + fDelta; big.sMin _ big.sMin + sDelta; big.fMin _ big.fMin + fDelta; FOR p: LIST OF DeviceRectangle _ toSaveIntoSmall, p.rest UNTIL p=NIL DO small^.Transfer[big^.Clip[p.first]]; ENDLOOP; big^.Fill[[newbox.sMin, newbox.fMin, 1, newbox.fSize], 0]; big^.Fill[[newbox.sMin + newbox.sSize - 1, newbox.fMin, 1, newbox.fSize], 0]; big^.Fill[[newbox.sMin, newbox.fMin, newbox.sSize, 1], 0]; big^.Fill[[newbox.sMin, newbox.fMin + newbox.fSize - 1, newbox.sSize, 1], 0]; IF goodBigBits # NIL THEN big^.Clip[goodBigBits.first].Transfer[oldBig.ShiftMap[-sDelta, -fDelta]]; FOR p: LIST OF DeviceRectangle _ toRecompute, p.rest UNTIL p=NIL DO box: DeviceRectangle _ p.first; centeredBig: PixelMap _ big^.ShiftMap[-newbox.sMin - height/2, -newbox.fMin-width/2]; centeredSmall: PixelMap _ small^.ShiftMap[-newbox.sMin - height/2, -newbox.fMin-width/2]; box.sMin _ box.sMin - newbox.sMin - height/2; box.fMin _ box.fMin - newbox.fMin - width/2; BitDouble[centeredBig.Clip[box], centeredSmall]; ENDLOOP; old.Destroy; new.Destroy; goodBigBits.Destroy; toRestoreFromSmall.Destroy; toRecompute.Destroy; }; }; Do8BitColor: PROCEDURE [] ~ BEGIN oldColorCursorState: Terminal.ColorCursorBitmapState; small: REF PixelMap _ NEW[PixelMap _ ImagerPixelMap.Create[3, [-height, width, height, width]]]; big: REF PixelMap _ NEW[PixelMap]; displayBounds: DeviceRectangle; frameBuffer: Terminal.FrameBuffer ~ Terminal.GetColorFrameBufferA[vt]; big^ _ [sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: vt.colorHeight, fSize: vt.colorWidth, refRep: NEW [ImagerPixelMap.PixelMapRep _ [ pointer: frameBuffer.base, ref: frameBuffer.vm, words: LONG[frameBuffer.wordsPerLine]*frameBuffer.height, lgBitsPerPixel: 3, rast: frameBuffer.wordsPerLine, lines: frameBuffer.height ]] ]; displayBounds _ big^.Window; big.sOrigin _ 0; big.sMin _ -height; big.sSize _ height; big.fOrigin _ 0; big.fMin _ width; big.fSize _ width; oldColorCursorState _ vt.SetColorCursorState[invisible]; UNTIL Terminal.GetKeys[vt][Red] = down DO mouse: Terminal.Position _ Terminal.GetColorCursorPosition[vt]; s: INTEGER ~ INTEGER[mouse.y]-height/2; f: INTEGER ~ INTEGER[mouse.x]-width/2 + hShift; Shuffle[big, small, displayBounds, BitDouble8, s, f, width, height]; IF mouse = [-100, -100] THEN EXIT; ENDLOOP; big^.Transfer[small^]; [] _ vt.SetColorCursorState[oldColorCursorState]; END; Do24BitColor: PROCEDURE [] ~ BEGIN height2: NAT _ height/2; width2: NAT _ width/2; oldColorCursorState: Terminal.ColorCursorBitmapState; smallA: REF PixelMap _ NEW[PixelMap _ ImagerPixelMap.Create[4, [-height2, width2, height2, width2]]]; smallB: REF PixelMap _ NEW[PixelMap _ ImagerPixelMap.Create[3, [-height2, width2, height2, width2]]]; bigA: REF PixelMap _ NEW[PixelMap]; bigB: REF PixelMap _ NEW[PixelMap]; displayBounds: DeviceRectangle; A: Terminal.FrameBuffer ~ Terminal.GetColorFrameBufferA[vt]; B: Terminal.FrameBuffer ~ Terminal.GetColorFrameBufferB[vt]; bigA^ _ [sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: vt.colorHeight, fSize: vt.colorWidth, refRep: NEW [ImagerPixelMap.PixelMapRep _ [ pointer: A.base, ref: A.vm, words: LONG[A.wordsPerLine]*A.height, lgBitsPerPixel: 4, rast: A.wordsPerLine, lines: A.height ]] ]; bigB^ _ [sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: vt.colorHeight, fSize: vt.colorWidth, refRep: NEW [ImagerPixelMap.PixelMapRep _ [ pointer: B.base, ref: B.vm, words: LONG[B.wordsPerLine]*B.height, lgBitsPerPixel: 4, rast: B.wordsPerLine, lines: B.height ]] ]; displayBounds _ bigA^.Window; bigA.sOrigin _ bigB.sOrigin _ 0; bigA.sMin _ bigB.sMin _ -height2; bigA.sSize _ bigB.sSize _ height2; bigA.fOrigin _ bigB.fOrigin _ 0; bigA.fMin _ bigB.fMin _ width2; bigA.fSize _ bigB.fSize _ width2; oldColorCursorState _ vt.SetColorCursorState[invisible]; UNTIL Terminal.GetKeys[vt][Red] = down DO mouse: Terminal.Position _ Terminal.GetColorCursorPosition[vt]; s: INTEGER ~ INTEGER[mouse.y]-height2/2; f: INTEGER ~ INTEGER[mouse.x]-width2/2 + hShift; Shuffle[bigA, smallA, displayBounds, BitDouble16, s, f, width2, height2]; Shuffle[bigB, smallB, displayBounds, BitDouble8, s, f, width2, height2]; IF mouse = [-100, -100] THEN EXIT; ENDLOOP; bigA^.Transfer[smallA^]; bigB^.Transfer[smallB^]; [] _ vt.SetColorCursorState[oldColorCursorState]; END; SELECT TRUE FROM ~vt.hasColorDisplay OR vt.GetColorBitmapState=none => NULL; vt.GetColorMode.full => Do24BitColor[]; ENDCASE => { SELECT vt.GetColorMode.bitsPerPixelChannelA FROM 8 => Do8BitColor[]; ENDCASE; }; }; DoBW: PROCEDURE [width: NAT, height: NAT] ~ BEGIN sTemp: PixelMap _ ImagerPixelMap.Create[0, [0, 0, 100, 16]]; dTemp: PixelMap _ ImagerPixelMap.Create[0, [0, 0, 200, 32]]; BitDouble: PROC [dest, source: PixelMap] ~ { dstr: DeviceRectangle _ dest.BoundedWindow; src: PixelMap _ source.Clip[[(dstr.sMin-1)/2, (dstr.fMin-1)/2, (dstr.sSize+3)/2, (dstr.fSize+3)/2]]; srcr: DeviceRectangle _ src.BoundedWindow; sTemp _ ImagerPixelMap.Reshape[sTemp.refRep, 0, [srcr.sMin, srcr.fMin, srcr.sSize, 16]]; dTemp _ ImagerPixelMap.Reshape[dTemp.refRep, 0, [srcr.sMin*2, srcr.fMin*2, srcr.sSize*2, 32]]; sTemp.fSize _ src.fSize; WHILE sTemp.fSize >= 16 DO sTemp.Transfer[src]; TRUSTED {BitDoubleColumn[dest: dTemp.refRep.pointer, source: sTemp.refRep.pointer, sourceWords: sTemp.sSize]}; dest.Transfer[dTemp]; sTemp.fSize _ sTemp.fSize - 16; sTemp.fOrigin _ sTemp.fOrigin + 16; dTemp.fOrigin _ dTemp.fOrigin + 32; ENDLOOP; IF sTemp.fSize > 0 THEN { sTemp.Clear; sTemp.Transfer[src]; TRUSTED {BitDoubleColumn[dest: dTemp.refRep.pointer, source: sTemp.refRep.pointer, sourceWords: sTemp.sSize]}; dest.Transfer[dTemp]; }; }; vt: Terminal.Virtual _ InterminalBackdoor.terminal; small: PixelMap _ ImagerPixelMap.Create[0, [-height, width, height, width]]; big: PixelMap; displayBounds: DeviceRectangle; TRUSTED {big _ LFDisplay[]}; displayBounds _ big.Window; big.sOrigin _ 0; big.sMin _ -height; big.sSize _ height; big.fOrigin _ 0; big.fMin _ width; big.fSize _ width; UNTIL Terminal.GetKeys[vt][Red] = down DO mouse: Terminal.Position _ Terminal.GetBWCursorPosition[vt]; s: INTEGER ~ INTEGER[mouse.y]-height/2; f: INTEGER ~ INTEGER[mouse.x]-width/2 + hShift; r: DeviceRectangle _ small.Window; IF r # big.Window THEN ERROR; IF s = r.sMin AND f = r.fMin THEN Terminal.WaitForBWVerticalRetrace[vt] ELSE { newbox: DeviceRectangle _ [s, f, r.sSize, r.fSize]; sDelta: INTEGER _ s - r.sMin; fDelta: INTEGER _ f - r.fMin; old: ImagerManhattan.Polygon _ ImagerManhattan.CreateFromBox[r]; oldBig: PixelMap _ big; new: ImagerManhattan.Polygon _ ImagerManhattan.CreateFromBox[newbox]; goodBigBits: ImagerManhattan.Polygon _ GoodBigBits[]; GoodBigBits: PROC RETURNS [ImagerManhattan.Polygon] ~ { b: DeviceRectangle _ ImagerPixelMap.Intersect[ [r.sMin+1, r.fMin+1, r.sSize-2, r.fSize-2], displayBounds ]; newb: DeviceRectangle _ b; newb.sMin _ newb.sMin + sDelta + sDelta; newb.fMin _ newb.fMin + fDelta + fDelta; newb _ ImagerPixelMap.Intersect[newb, b]; newb.sMin _ newb.sMin - sDelta; newb.fMin _ newb.fMin - fDelta; RETURN [ImagerManhattan.CreateFromBox[newb]] }; toRestoreFromSmall: ImagerManhattan.Polygon _ old.Difference[new]; toSaveIntoSmall: ImagerManhattan.Polygon _ new.Difference[old]; toRecompute: ImagerManhattan.Polygon _ TrimEdge[new].Difference[goodBigBits]; FOR p: LIST OF DeviceRectangle _ toRestoreFromSmall, p.rest UNTIL p=NIL DO big.Transfer[small.Clip[p.first]]; ENDLOOP; small.Transfer[small.ShiftMap[-sDelta, -fDelta]]; small.sOrigin _ small.sOrigin + sDelta; small.fOrigin _ small.fOrigin + fDelta; big.sMin _ big.sMin + sDelta; big.fMin _ big.fMin + fDelta; FOR p: LIST OF DeviceRectangle _ toSaveIntoSmall, p.rest UNTIL p=NIL DO small.Transfer[big.Clip[p.first]]; ENDLOOP; big.Fill[[newbox.sMin, newbox.fMin, 1, newbox.fSize], 1]; big.Fill[[newbox.sMin + newbox.sSize - 1, newbox.fMin, 1, newbox.fSize], 1]; big.Fill[[newbox.sMin, newbox.fMin, newbox.sSize, 1], 1]; big.Fill[[newbox.sMin, newbox.fMin + newbox.fSize - 1, newbox.sSize, 1], 1]; IF goodBigBits # NIL THEN big.Clip[goodBigBits.first].Transfer[oldBig.ShiftMap[-sDelta, -fDelta]]; FOR p: LIST OF DeviceRectangle _ toRecompute, p.rest UNTIL p=NIL DO box: DeviceRectangle _ p.first; centeredBig: PixelMap _ big.ShiftMap[-newbox.sMin - height/2, -newbox.fMin-width/2]; centeredSmall: PixelMap _ small.ShiftMap[-newbox.sMin - height/2, -newbox.fMin-width/2]; box.sMin _ box.sMin - newbox.sMin - height/2; box.fMin _ box.fMin - newbox.fMin - width/2; BitDouble[centeredBig.Clip[box], centeredSmall]; ENDLOOP; old.Destroy; new.Destroy; goodBigBits.Destroy; toRestoreFromSmall.Destroy; toRecompute.Destroy; }; IF mouse = [-100, -100] THEN EXIT; ENDLOOP; big.Transfer[small]; END; Sqr: PROC [a: CARDINAL] RETURNS [LONG CARDINAL] ~ INLINE { RETURN [Basics.LongMult[a, a]] }; FourWords: TYPE ~ PACKED ARRAY [0..4) OF CARDINAL; DotStyle: TYPE ~ {normal, light, b1, b2}; dotStyle: DotStyle _ normal; BitDoubleColumn: UNSAFE PROC [dest: LONG POINTER TO FourWords, source: LONG POINTER TO CARDINAL, sourceWords: NAT] ~ UNCHECKED { FOR i: NAT IN [0..sourceWords) DO w,ww: Basics.LongNumber _ [lc[0]]; c: CARDINAL _ source^; WHILE c # 0 DO b: CARDINAL _ c; c _ Basics.BITAND[c, c-1]; w.lc _ w.lc + Sqr[b - c]; ENDLOOP; SELECT dotStyle FROM normal => {w.lc _ ww.lc _ w.lc + w.lc + w.lc}; light => NULL; b1 => { ww.lc _ w.lc + w.lc; ww.highbits _ Basics.BITOR[ww.highbits, 05555H]; ww.lowbits _ Basics.BITOR[ww.lowbits, 05555H] }; b2 => { w.lc _ ww.lc _ w.lc + w.lc + w.lc; ww.highbits _ Basics.BITXOR[ww.highbits, 05555H]; ww.lowbits _ Basics.BITXOR[ww.lowbits, 05555H] }; ENDCASE => ERROR; dest^ _ [w.highbits, w.lowbits, ww.highbits, ww.lowbits]; dest _ dest + SIZE[FourWords]; source _ source + SIZE[CARDINAL]; ENDLOOP; }; Start: Buttons.ButtonProc ~ BEGIN SELECT mouseButton FROM red => DoIt[240, 130]; yellow => DoIt[420, 260]; blue => DoIt[640, 480]; ENDCASE => ERROR; END; [] _ Buttons.Create[[name: "Mag"], Start]; END. DMagnifier.mesa Michael Plass, April 25, 1985 2:47:06 pm PST Last Edited by: Nickell, March 31, 1985 10:56:00 pm PST First restore old screen bits from small version Shift the small version around Salt away the newly-obscured screen bits Put up the new boundary Put the good big bits in their new place Compute the new big bits Main selection routine for DoColor First restore old screen bits from small version Shift the small version around Salt away the newly-obscured screen bits Put up the new boundary Put the good big bits in their new place Compute the new big bits Κδ˜J™J™,J™7šΟk ˜ Jš œœœœœ˜;Jšœœ˜#Jšœœ ˜Jšœœ ˜$Jšœœ/˜DJšœœ„˜˜Jšœ œ1˜AJšœ œ€˜ŽJšœœ$˜1Jšœœ˜!Jšœ œ˜,J˜—šœ  ˜Jšœz˜Jšœ˜Jšœ œ˜)Jšœœ"˜7Jšœ#œΟc˜5JšœPž ˜\Jšœœ˜šœ œœ˜J˜—š Οn œœœœ œ˜FJšœ[˜[šœœœ˜KIcodešœ˜Kšœ"œ.˜TKšœL˜LKšœ˜—šœ"˜"Kšœ)˜)KšœC˜CKšœ˜—Jšœ ˜J˜J˜—š Ÿœ œ œœ ˜=Jšœ3˜3šŸœœ˜ Jšœ"œ˜2šœ!˜)Jšœ<˜