DIRECTORY Basics USING [BITAND, BITOR, BITXOR, LongMult, LongNumber], Buttons USING [ButtonProc, Create], Cursors USING [SetCursor], ImagerFrameBuffer USING [LFDisplay], ImagerManhattan USING [CreateFromBox, Destroy, Difference, Polygon], ImagerPixelMaps USING [BoundedWindow, Clear, Clip, Create, DeviceRectangle, Fill, Intersect, PixelMap, PixelMapRep, Reshape, ShiftMap, Transfer, Window], InputFocus USING [CaptureButtons, ReleaseButtons, SetInputFocus], Terminal USING [ColorCursorBitmapState, Current, GetBWCursorPosition, GetColorBitmapState, GetColorCursorPosition, GetColorMode, GetKeys, Position, SetColorCursorState, Virtual, WaitForBWVerticalRetrace], TIPUser USING [InstantiateNewTIPTable, TIPTable], ViewerClasses USING [NotifyProc], ViewerLocks USING [LockViewerTree, ReleaseViewerTree]; Magnifier: CEDAR PROGRAM IMPORTS Basics, Buttons, Cursors, ImagerFrameBuffer, ImagerManhattan, ImagerPixelMaps, InputFocus, Terminal, TIPUser, ViewerLocks SHARES ViewerLocks ~ BEGIN PixelMap: TYPE ~ ImagerPixelMaps.PixelMap; DeviceRectangle: TYPE ~ ImagerPixelMaps.DeviceRectangle; Notify: ViewerClasses.NotifyProc = TRUSTED {}; -- NOP myTIPTable: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["Magnifier.tip"]; -- Known NOP hShift: INTEGER _ 0; locking: BOOLEAN _ TRUE; DoIt: PROCEDURE [width: NAT _ 420, height: NAT _ 260] ~ BEGIN vt: Terminal.Virtual _ Terminal.Current[]; Cursors.SetCursor[textPointer]; IF locking THEN { InputFocus.SetInputFocus[]; InputFocus.CaptureButtons[Notify, myTIPTable]; ViewerLocks.LockViewerTree[]; }; 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; IF locking THEN { InputFocus.ReleaseButtons[]; ViewerLocks.ReleaseViewerTree[]; }; 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]]] }; DoColor: PROCEDURE [width: NAT, height: NAT] ~ BEGIN Bit8Double: PROC [dest, source: PixelMap] ~ TRUSTED { srcr: DeviceRectangle _ source.BoundedWindow; dstr: DeviceRectangle _ ImagerPixelMaps.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; }; Bit4Double: PROC [dest, source: PixelMap] ~ TRUSTED { srcr: DeviceRectangle _ source.BoundedWindow; dstr: DeviceRectangle _ ImagerPixelMaps.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..16) _ dest.refRep.pointer + Basics.LongMult[(s - dest.sOrigin), dest.refRep.rast]; sourceRow: LONG POINTER TO PACKED ARRAY [0..0) OF [0..16) _ 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; }; Bit2Double: PROC [dest, source: PixelMap] ~ TRUSTED { srcr: DeviceRectangle _ source.BoundedWindow; dstr: DeviceRectangle _ ImagerPixelMaps.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..4) _ dest.refRep.pointer + Basics.LongMult[(s - dest.sOrigin), dest.refRep.rast]; sourceRow: LONG POINTER TO PACKED ARRAY [0..0) OF [0..4) _ 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; }; Bit1Double: PROC [dest, source: PixelMap] ~ TRUSTED { srcr: DeviceRectangle _ source.BoundedWindow; dstr: DeviceRectangle _ ImagerPixelMaps.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..2) _ dest.refRep.pointer + Basics.LongMult[(s - dest.sOrigin), dest.refRep.rast]; sourceRow: LONG POINTER TO PACKED ARRAY [0..0) OF [0..2) _ 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; }; vt: Terminal.Virtual _ Terminal.Current[]; IF vt.hasColorDisplay AND vt.GetColorBitmapState # none AND (vt.GetColorMode.bitsPerPixelChannelA = 8 OR vt.GetColorMode.bitsPerPixelChannelA = 4 OR vt.GetColorMode.bitsPerPixelChannelA = 2 OR vt.GetColorMode.bitsPerPixelChannelA = 1) THEN { lgBits: [0..4] ~ SELECT vt.GetColorMode.bitsPerPixelChannelA FROM 8 => 3, 4 => 2, 2 => 1, 1 => 0, ENDCASE => ERROR; BitDouble: PROC [dest, source: PixelMap] ~ SELECT vt.GetColorMode.bitsPerPixelChannelA FROM 8 => Bit8Double, 4 => Bit4Double, 2 => Bit2Double, 1 => Bit1Double, ENDCASE => ERROR; oldColorCursorState: Terminal.ColorCursorBitmapState; small: PixelMap _ ImagerPixelMaps.Create[lgBits, [-height, width, height, width]]; big: PixelMap; displayBounds: DeviceRectangle; big _ [sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: vt.colorHeight, fSize: vt.colorWidth, refRep: NEW [ImagerPixelMaps.PixelMapRep _ [ pointer: vt.colorBitmapA, words: LONG[vt.colorWordsPerLineA]*vt.colorHeight, lgBitsPerPixel: lgBits, rast: vt.colorWordsPerLineA, lines: vt.colorHeight ]] ]; 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; 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 _ ImagerPixelMaps.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 _ ImagerPixelMaps.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; }; IF mouse = [-100, -100] THEN EXIT; ENDLOOP; big.Transfer[small]; [] _ vt.SetColorCursorState[oldColorCursorState]; }; END; DoBW: PROCEDURE [width: NAT, height: NAT] ~ BEGIN sTemp: PixelMap _ ImagerPixelMaps.Create[0, [0, 0, 100, 16]]; dTemp: PixelMap _ ImagerPixelMaps.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 _ ImagerPixelMaps.Reshape[sTemp.refRep, 0, [srcr.sMin, srcr.fMin, srcr.sSize, 16]]; dTemp _ ImagerPixelMaps.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 _ Terminal.Current[]; small: PixelMap _ ImagerPixelMaps.Create[0, [-height, width, height, width]]; big: PixelMap; displayBounds: DeviceRectangle; TRUSTED {big _ ImagerFrameBuffer.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 _ ImagerPixelMaps.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 _ ImagerPixelMaps.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. "Magnifier.mesa Michael Plass, February 17, 1984 4:06:27 pm PST Last Edited by: Shand, August 17, 1984 3:14:19 am PDT 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 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 ÊL˜Icode™K™/J™5šÏk ˜ Kš œœœœœ˜;Kšœœ˜#Kšœœ ˜Kšœœ ˜$Kšœœ/˜DKšœœ„˜™Kšœ œ1˜AKšœ œ¾˜ÌKšœœ$˜1Kšœœ˜!Kšœ œ%˜6K˜—šÑaox œ ˜Kšœz˜Kšœ˜Kšœ œ˜*Kšœœ#˜8Kšœ#œÏc˜5KšœPŸ ˜\Kšœœ˜šœ œœ˜K˜—š Ïnœ œ œœ ˜=Kšœ*˜*Kšœ˜šœ œ˜Kšœ˜Kšœ.˜.Kšœ˜K˜—Kšœ"œ˜2šœ!˜)Kšœ<˜