DIRECTORY Basics USING [BITAND, BITOR, BITXOR, LongMult, LongNumber], 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]; NewMagnifier: CEDAR PROGRAM IMPORTS Basics, 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[]; 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; DoColor: PROCEDURE [width: NAT, height: NAT] ~ BEGIN BitDouble: 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; }; vt: Terminal.Virtual _ Terminal.Current[]; IF vt.hasColorDisplay AND vt.GetColorBitmapState # none AND vt.GetColorMode.bitsPerPixelChannelA = 8 THEN { oldColorCursorState: Terminal.ColorCursorBitmapState; small: PixelMap _ ImagerPixelMaps.Create[3, [-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: 3, 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]; new: ImagerManhattan.Polygon _ ImagerManhattan.CreateFromBox[newbox]; goodBigBits: ImagerManhattan.Polygon _ GoodBigBits[]; GoodBigBits: PROC RETURNS [ImagerManhattan.Polygon] ~ { b: DeviceRectangle _ [r.sMin+1, r.fMin+1, r.sSize-2, r.fSize-2]; b _ ImagerPixelMaps.Intersect[b, displayBounds]; b.sMin _ b.sMin - sDelta; b.fMin _ b.fMin - fDelta; b _ ImagerPixelMaps.Intersect[b, displayBounds]; RETURN [ImagerManhattan.CreateFromBox[b]] }; toRestoreFromSmall: ImagerManhattan.Polygon _ old.Difference[new]; toSaveIntoSmall: ImagerManhattan.Polygon _ new.Difference[old]; toRecompute: ImagerManhattan.Polygon _ new.Difference[goodBigBits]; big.Clip[newbox].Transfer[big.ShiftMap[-sDelta, -fDelta]]; 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; 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; 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]; 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]; new: ImagerManhattan.Polygon _ ImagerManhattan.CreateFromBox[newbox]; goodBigBits: ImagerManhattan.Polygon _ GoodBigBits[]; GoodBigBits: PROC RETURNS [ImagerManhattan.Polygon] ~ { b: DeviceRectangle _ [r.sMin+1, r.fMin+1, r.sSize-2, r.fSize-2]; b _ ImagerPixelMaps.Intersect[b, displayBounds]; b.sMin _ b.sMin - sDelta; b.fMin _ b.fMin - fDelta; b _ ImagerPixelMaps.Intersect[b, displayBounds]; RETURN [ImagerManhattan.CreateFromBox[b]] }; toRestoreFromSmall: ImagerManhattan.Polygon _ old.Difference[new]; toSaveIntoSmall: ImagerManhattan.Polygon _ new.Difference[old]; toRecompute: ImagerManhattan.Polygon _ new.Difference[goodBigBits]; big.Clip[newbox].Transfer[big.ShiftMap[-sDelta, -fDelta]]; 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; 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; 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]; 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; }; END. JNewMagnifier.mesa Michael Plass, February 13, 1984 12:19:55 pm PST Ê m˜J™J™0šÏk ˜ Jš œœœœœ˜;Jšœœ ˜$Jšœœ/˜DJšœœ„˜™Jšœ œ1˜AJšœ œ¾˜ÌJšœœ$˜1Jšœœ˜!Jšœ œ%˜6J˜—šœ ˜Jšœh˜oJšœ˜Jšœ œ˜*Jšœœ#˜8Jšœ#œÏc˜5JšœPž ˜\Jšœœ˜šœ œœ˜J˜—š Ïnœ œ œœ ˜=Jšœ*˜*šœ œ˜Jšœ˜Jšœ.˜.Jšœ˜J˜—Jšœ"œ˜2šœ!˜)Jšœ<˜