DIRECTORY BasicTime, CedarProcess, Commander, Controls, Convert, Draw2d, FileNames, FS, G2dBasic, G2dPopUp, G2dSpline, G2dTool, G2dZoom, Icons, Imager, ImagerBackdoor, ImagerMaskCache, ImagerSample, ImagerTransformation, IO, MessageWindow, Process, Real, RealFns, Rope, Vector2, ViewerClasses, ViewerOps, ViewerPrivate, ViewerTools; G2dZoomCmdImpl: CEDAR PROGRAM IMPORTS BasicTime, CedarProcess, Controls, Convert, Draw2d, FileNames, FS, G2dPopUp, G2dSpline, G2dTool, G2dZoom, Icons, ImagerBackdoor, ImagerMaskCache, ImagerSample, ImagerTransformation, IO, MessageWindow, Process, Real, RealFns, Rope, ViewerOps, ViewerPrivate, ViewerTools ~ BEGIN PixelMap: TYPE ~ Imager.PixelMap; SampleMap: TYPE ~ ImagerSample.SampleMap; Transformation: TYPE ~ ImagerTransformation.Transformation; ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Vector2.VEC; Viewer: TYPE ~ ViewerClasses.Viewer; Key: TYPE ~ REF KeyRep; KeyRep: TYPE ~ RECORD [keyNum: NAT ¬ 0, time, dx, dy, scale, rotate: REAL ¬ 0]; KeySequence: TYPE ~ REF KeySequenceRep; KeySequenceRep: TYPE ~ RECORD [ length: CARDINAL ¬ 0, element: SEQUENCE maxLength: CARDINAL OF Key ]; Frame: TYPE ~ RECORD [bw, a, b: SampleMap]; FrameSequence: TYPE ~ REF FrameSequenceRep; FrameSequenceRep: TYPE ~ RECORD [ length: CARDINAL ¬ 0, element: SEQUENCE maxLength: CARDINAL OF Frame ]; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ operation: ROPE ¬ NIL, stop, busy: BOOL ¬ FALSE, keys: KeySequence ¬ NIL, nFrame: INT ¬ -1, keyNum, selectedKey: NAT ¬ 0, spline: G2dSpline.Spline1dSequence ¬ NIL, knots: G2dBasic.RealSequence ¬ NIL, ticks: SampleMap ¬ NIL, frames: FrameSequence ¬ NIL, xMove, yMove: Controls.Control ¬ NIL, scale, rotate: Controls.Control ¬ NIL, speed, frameNum: Controls.Control ¬ NIL, outerData: Controls.OuterData ¬ NIL, outer, viewer, graphics: Viewer ¬ NIL ]; ZoomCmd: Commander.CommandProc ~ { d: Data ¬ NEW[DataRep]; d.xMove ¬ Controls.NewControl[name: "XMove", proc: XForm, type: hSlider, clientData: d, min: -10., max: 10.0, init: 0, x: 70, y: 15, w: 150, detents: LIST[[, 0.0]]]; d.yMove ¬ Controls.NewControl[name: "YMove", proc: XForm, type: vSlider, clientData: d, min: -10., max: 10.0, init: 0, x: 30, y: 15, h: 150, detents: LIST[[, 0.0]]]; d.scale ¬ Controls.NewControl[name: "Scale", proc: XForm, type: vSlider, taper: exp, clientData: d, min: 1.0/32.0, max: 32., init: 1, x: 235, y: 15, h: 150, detents: LIST[[, 0.5], [, 1.0], [, 2.0]]]; d.rotate ¬ Controls.NewControl[name: "Rotate", proc: XForm, type: dial, clientData: d, max: 360.0, init: 0.0, x: 100, y: 65, w: 100, h: 100, detents: LIST[[, 0.0]]]; d.speed ¬ Controls.NewControl[name: "Speed", type: vSlider, clientData: d, min: 1, max: 40, init: 30, x: 300, y: 15, h: 150, precision: 0, detents: LIST[[, 30]]]; d.frameNum ¬ Controls.NewControl[name: "Frame", proc: NFrame, type: vSlider, clientData: d, min: 0, max: 0, init: 0, x: 345, y: 15, h: 150, precision: 0]; d.outerData ¬ Controls.OuterViewer[ name: "2dZoom", column: right, buttons: LIST[ Controls.ClickButton[name: "Play:", row: 0], Controls.ClickButton[name:"STOP", proc:Button, clientData:d, guarded:TRUE, row:0, x:45], Controls.ClickButton["Interp", Button, d, 0], Controls.ClickButton["Replay", Button, d, 0], Controls.ClickButton["Cycle", Button, d, 0], Controls.ClickButton["BackForth", Button, d, 0], Controls.ClickButton["Time", Button, d, 0], Controls.ClickButton[name: "Keys:", row: 1], Controls.ClickButton["Add", Button, d, 1, 45], Controls.ClickButton["Del", Button, d, 1], Controls.ClickButton["Del All", Button, d, 1], Controls.ClickButton["Write", Button, d, 1], Controls.ClickButton["Read", Button, d, 1], Controls.ClickButton[name: " ", row: 2], Controls.ClickButton[name:"Get Viewer", proc:Button, clientData:d, guarded:TRUE, row:2, x:45], Controls.ClickButton[name: "Reset", proc: Button, clientData: d, guarded: TRUE, row: 2], Controls.ClickButton["IP Out", Button, d, 2], Controls.ClickButton["AISs Out", Button, d, 2], Controls.ClickButton["Help!", Button, d, 2]], controls: LIST[d.rotate, d.scale, d.xMove, d.yMove, d.speed, d.frameNum], typescriptHeight: 18, graphicsHeight: 105, drawProc: DrawProc, mouseProc: MouseProc, destroyProc: DestroyProc, clientData: d ]; d.outer ¬ d.outerData.parent; d.graphics ¬ d.outerData.graphics; [] ¬ ImagerMaskCache.GetNamedCache[$Bitmap]; [] ¬ ViewerPrivate.SetCreator[NIL]; TRUSTED {Process.Detach[FORK CycleIcon[d.outer]]}; }; CycleIcon: PROC [v: Viewer] ~ { PaintIcon: PROC [i: NAT] ~ { v.icon ¬ icons[i]; ViewerOps.PaintViewer[v, all]; Process.Pause[Process.MsecToTicks[100]]; }; v.icon ¬ icons[0]; WHILE NOT v.destroyed DO IF forwardIcon THEN FOR i: NAT IN [0..nIcons) DO IF v.iconic THEN PaintIcon[i]; ENDLOOP ELSE FOR i: NAT DECREASING IN [0..nIcons) DO IF v.iconic THEN PaintIcon[i]; ENDLOOP; forwardIcon ¬ NOT forwardIcon; Process.Pause[Process.SecondsToTicks[7]]; ENDLOOP; }; forwardIcon: BOOL ¬ TRUE; DestroyProc: Controls.DestroyProc ~ { d: Data ¬ NARROW[clientData]; d.stop ¬ TRUE; G2dZoom.Release[d.viewer]; }; Message: PROC [rope: ROPE, clear, blink: BOOL ¬ TRUE] ~ { MessageWindow.Append[Rope.Concat["\t\t\t", rope], clear]; IF blink THEN MessageWindow.Blink[]; }; XFromTime: PROC [d: Data, time: REAL] RETURNS [INTEGER] ~ { t: REAL ¬ IF d.keys = NIL OR d.keys[0].time = d.keys[d.keys.length-1].time THEN 0.5 ELSE (time-d.keys[0].time)/REAL[d.keys[d.keys.length-1].time-d.keys[0].time]; RETURN[Real.Round[25+t*(d.graphics.cw-50)]]; }; TimeFromX: PROC [d: Data, x: INTEGER] RETURNS [REAL] ~ { k: KeySequence ¬ d.keys; RETURN[SELECT TRUE FROM k = NIL OR k.length = 0 => 0.0, k.length = 1 OR d.graphics.cw = 0 => k[0].time, ENDCASE => (REAL[x-25]/(d.graphics.cw-50))*(k[k.length-1].time-k[0].time)+k[0].time]; }; Repaint: PROC [d: Data, whatChanged: REF ¬ NIL] ~ { ViewerOps.PaintViewer[d.graphics, client, FALSE, whatChanged]; }; DrawProc: Controls.DrawProc ~ { BufferTicks: PROC [op: {save, restore}] ~ { Save: PROC [pixelMap: PixelMap] ~ {d.ticks ¬ ImagerSample.Copy[pixelMap[0]]}; Restore: PROC [pixelMap: PixelMap] ~ {ImagerSample.Transfer[pixelMap[0], d.ticks]}; r: Imager.Rectangle ¬ [0, 0, d.graphics.ww, d.graphics.wh]; ImagerBackdoor.AccessBufferRectangle[context, IF op = save THEN Save ELSE Restore, r]; }; DrawTicks: PROC ~ { IF d.keys # NIL AND d.keys.length > 0 AND d.graphics.cw # 0 THEN { KeyX: PROC [n: NAT] RETURNS [x: REAL] ~ {x ¬ XFromTime[d, d.keys[n].time]}; lastT: REAL ¬ d.keys[d.keys.length-1].time; totalT: REAL ¬ lastT-d.keys[0].time; dT: REAL ¬ totalT*(80.0/d.graphics.cw); Draw2d.Line[context, [KeyX[0], 55], [KeyX[d.keys.length-1], 55]]; FOR n: NAT IN [0..d.keys.length) DO x: REAL ¬ KeyX[n]; Draw2d.Line[context, [x, 55], [x, 70]]; Draw2d.Label[context, [x-10, 75], IO.PutFR1["K%g", IO.int[d.keys[n].keyNum]]]; ENDLOOP; IF dT # 0.0 THEN { exp: INTEGER ¬ Real.Floor[RealFns.Log[10.0, totalT]]; div: REAL ¬ IF exp IN [-2..2] THEN 1.0 ELSE RealFns.Power[10.0, exp]; FOR t: REAL ¬ d.keys[0].time, t+dT WHILE t <= lastT DO tt: REAL ¬ IF lastT-t < dT THEN lastT ELSE t; x: REAL ¬ XFromTime[d, tt]; Draw2d.Line[context, [x, 40], [x, 55]]; Draw2d.Label[context, [x-10, 30], IO.PutFR1["%3.2f", IO.real[tt/div]]]; ENDLOOP; Draw2d.Label[context, [d.graphics.cw/2-40, 10], Rope.Concat[ "Time", IF div = 1.0 THEN NIL ELSE IO.PutFR1[" (X %6.4f)", IO.real[div]]]]; }; }; }; d: Data ¬ NARROW[clientData]; SELECT whatChanged FROM $Ticks => BufferTicks[restore]; ENDCASE => { Draw2d.DoWithBuffer[context, DrawTicks]; BufferTicks[save]; }; IF d.frames # NIL AND d.frames.length > 1 AND d.nFrame # -1 THEN { totalT: REAL ¬ d.keys[d.keys.length-1].time-d.keys[0].time; IF totalT # 0.0 THEN { x: REAL ¬ XFromTime[d, d.keys[0].time+totalT*(REAL[d.nFrame]/(d.frames.length-1))]; Draw2d.Line[context, [x, 55], [x, 85]]; Draw2d.Label[context, [x-10, 90], IO.PutFR1["F%g", IO.int[d.nFrame ]]]; }; }; }; MouseProc: Controls.MouseProc ~ { d: Data ¬ NARROW[clientData]; time: REAL ¬ TimeFromX[d, mouse.pos.x]; IF d.keys = NIL OR d.keys.length = 0 THEN RETURN; SELECT mouse.state FROM down => { close: REAL ¬ Real.LargestNumber; FOR n: NAT IN [0..d.keys.length) DO IF ABS[d.keys[n].time-time] > close THEN LOOP; close ¬ ABS[d.keys[n].time-time]; d.selectedKey ¬ n; ENDLOOP; }; held => { d.keys[d.selectedKey].time ¬ time; OrderKeys[d.keys]; Repaint[d]; }; ENDCASE; }; Interp: PROC [d: Data] ~ { IF d.keys # NIL AND d.keys.length > 0 THEN { reply: ROPE ¬ Controls.TypescriptRead[d.outerData.typescript, "Number of frames: "]; IF reply # NIL THEN { nFrames: CARDINAL ¬ Convert.IntFromRope[reply ! Convert.Error => GOTO Bad]; IF nFrames > 2 THEN { time0: REAL ¬ d.keys[0].time; time1: REAL ¬ d.keys[d.keys.length-1].time; d.frameNum.max ¬ nFrames-1; IF d.frames = NIL OR d.frames.maxLength < nFrames THEN d.frames ¬ NEW[FrameSequenceRep[nFrames]]; d.frames.length ¬ nFrames; FOR n: INT IN [0..nFrames) WHILE NOT d.stop DO SetTime[d, time0+(n/REAL[nFrames-1])*(time1-time0)]; Buffer[d, save, n]; ENDLOOP; IF d.stop THEN d.frames.length ¬ 0; }; }; EXITS Bad => Message["Bad value"]; }; }; OrderKeys: PROC [keys: KeySequence] ~ { Success: PROC RETURNS [BOOL ¬ TRUE] ~ { FOR n: NAT IN [1..keys.length) DO IF keys[n-1].time > keys[n].time THEN { temp: Key ¬ keys[n]; keys[n] ¬ keys[n-1]; keys[n-1] ¬ temp; RETURN[FALSE]; }; ENDLOOP; }; DO IF Success[] THEN EXIT; ENDLOOP; }; GetInterpReady: PROC [d: Data] ~ { IF d.spline = NIL OR d.spline.maxLength < d.keys.length THEN d.spline ¬ NEW[G2dSpline.Spline1dSequenceRep[d.keys.length-1]]; IF d.knots = NIL OR d.knots.maxLength < d.keys.length THEN d.knots ¬ NEW[G2dBasic.RealSequenceRep[d.keys.length]]; d.knots.length ¬ d.keys.length; }; SetTime: PROC [d: Data, time: REAL] ~ { SetFromKey: PROC [k: Key] ~ {rotate ¬ k.rotate; scale ¬ k.scale; dx ¬ k.dx; dy ¬ k.dy}; rotate, scale, dx, dy: REAL; GetInterpReady[d]; FOR n: NAT IN [0..d.keys.length) DO IF d.keys[n].time < time THEN LOOP; IF n = 0 THEN SetFromKey[d.keys[0]] ELSE { Field: TYPE ~ {rotate, scale, dx, dy}; GetValue: PROC [k: Key, f: Field] RETURNS [r: REAL] ~ { r ¬ SELECT f FROM dx => k.dx, dy => k.dy, scale => k.scale, ENDCASE => k.rotate; }; GetReal: PROC [f: Field] RETURNS [r: REAL] ~ { FOR n: NAT IN [0..d.keys.length) DO d.knots[n] ¬ GetValue[d.keys[n], f]; ENDLOOP; d.spline ¬ G2dSpline.Interpolate1d[d.knots, d.spline, TRUE]; r ¬ G2dSpline.Position1d[d.spline[n-1], t]; }; t: REAL ¬ (time-d.keys[n-1].time)/(d.keys[n].time-d.keys[n-1].time); rotate ¬ GetReal[rotate]; scale ¬ GetReal[scale]; dx ¬ GetReal[dx]; dy ¬ GetReal[dy]; EXIT; }; REPEAT FINISHED => SetFromKey[d.keys[d.keys.length-1]]; ENDLOOP; DoTransform[d, dx, dy, scale, rotate, FALSE]; }; Buffer: PROC [d: Data, op: {save, restore}, nFrame: NAT] ~ { }; Button: Controls.ClickProc ~ { d: Data ¬ NARROW[clientData]; d.operation ¬ parent.name; SELECT TRUE FROM Rope.Equal["STOP", parent.name] => IF d.busy THEN d.stop ¬ TRUE; d.busy => Message["Tool is busy!"]; ENDCASE => { d.busy ¬ TRUE; [] ¬ CedarProcess.Fork[Operation, d]; }; }; Operation: CedarProcess.ForkableProc ~ { Eq: PROC [r: ROPE] RETURNS [b: BOOL] ~ {b ¬ Rope.Equal[r, d.operation, FALSE]}; d: Data ¬ NARROW[data]; oldName: ROPE ¬ d.outer.name; d.outer.name ¬ Rope.Concat[oldName, "\t[Busy]"]; ViewerOps.PaintViewer[d.outer, caption]; SELECT TRUE FROM Eq["Interp"] => Interp[d]; Eq["Replay"] => Play[d, replay]; Eq["Cycle"] => Play[d, cycle]; Eq["BackForth"] => Play[d, backforth]; Eq["Time"] => Time[d]; Eq["Add"] => AddKey[d]; Eq["Del"] => DelKey[d]; Eq["Del All"] => DelAllKeys[d]; Eq["Write"] => WriteKey[d]; Eq["Read"] => ReadKey[d]; Eq["Get Viewer"] => GetViewer[d]; Eq["Reset"] => ResetViewer[d]; Eq["IP Out"] => IPOut[d]; Eq["AISs Out"] => AISOut[d]; Eq["Help!"] => Help[]; ENDCASE; d.outer.name ¬ oldName; ViewerOps.PaintViewer[d.outer, caption]; d.stop ¬ d.busy ¬ FALSE; }; AddKey: PROC [d: Data] ~ { reply: ROPE ¬ Controls.TypescriptRead[d.outerData.typescript, "Time = "]; IF reply # NIL THEN { time: REAL ¬ Convert.RealFromRope[reply ! Convert.Error => GOTO Bad]; key: Key ¬ NEW[KeyRep]; key­ ¬ [d.keyNum, time, d.xMove.value, d.yMove.value, d.scale.value, d.rotate.value]; d.keyNum ¬ d.keyNum+1; IF d.keys = NIL THEN d.keys ¬ NEW[KeySequenceRep[1]]; IF d.keys.length = d.keys.maxLength THEN { -- enlarge the sequence: old: KeySequence ¬ d.keys; d.keys ¬ NEW[KeySequenceRep[MAX[Real.Ceiling[1.3*old.maxLength], 3]]]; FOR i: NAT IN [0..old.length) DO d.keys[i] ¬ old[i]; ENDLOOP; d.keys.length ¬ old.length; }; d.keys[d.keys.length] ¬ key; d.keys.length ¬ d.keys.length+1; OrderKeys[d.keys]; Repaint[d]; EXITS Bad => Message["Bad value"]; }; }; DelAllKeys: PROC [d: Data] ~ { d.keys.length ¬ 0; IF d.frames # NIL THEN d.frames.length ¬ 0; Repaint[d]; }; DelKey: PROC [d: Data] ~ { IF d.keys.length = 0 THEN Message["No keys to delete"] ELSE { reply: ROPE ¬ Controls.TypescriptRead[d.outerData.typescript, "Key # "]; IF reply # NIL THEN { keyNum: NAT ¬ Convert.IntFromRope[reply ! Convert.Error => GOTO Bad]; FOR n: NAT IN [0..d.keys.length) DO IF d.keys[n].keyNum # keyNum THEN LOOP; FOR nn: NAT IN [n..d.keys.length-1) DO d.keys[nn] ¬ d.keys[nn+1]; ENDLOOP; d.keys.length ¬ d.keys.length-1; EXIT; REPEAT FINISHED => Message["No such key"]; ENDLOOP; IF d.frames # NIL THEN d.frames.length ¬ 0; Repaint[d]; EXITS Bad => Message["Bad value"]; }; }; }; WriteKey: PROC [d: Data] ~ { fileName: ROPE ¬ Controls.TypescriptReadFileName[d.outerData.typescript]; IF fileName # NIL THEN { out: IO.STREAM ¬ FS.StreamOpen[FileNames.ResolveRelativePath[fileName], create]; G2dZoom.WriteTransform[d.viewer, out]; IO.Close[out]; }; }; ReadKey: PROC [d: Data] ~ { fileName: ROPE ¬ Controls.TypescriptReadFileName[d.outerData.typescript]; IF fileName # NIL THEN { in: IO.STREAM; in ¬ FS.StreamOpen[FileNames.ResolveRelativePath[fileName] ! FS.Error => CONTINUE]; IF in = NIL THEN Message["Can't read file", FALSE, FALSE] ELSE { m: Transformation ¬ G2dZoom.ReadTransform[in]; f: ImagerTransformation.FactoredTransformation ¬ ImagerTransformation.Factor[m]; IO.Close[in]; DoTransform[d, f.t.x, f.t.y, f.s.x, f.r1]; }; }; }; NFrame: Controls.ControlProc ~ { d: Data ¬ NARROW[control.clientData]; IF d.frameNum.max < 2 OR d.busy OR (control.whatChanged # $TypedIn AND control.mouse.state = up) OR Real.Round[control.valuePrev] = Real.Round[control.value] THEN RETURN; IF d.frames = NIL OR control.value NOT IN [0..d.frames.length) THEN Message["Bad value"] ELSE Buffer[d, restore, Real.Round[control.value]]; }; Play: PROC [d: Data, op: {replay, cycle, backforth}] ~ { One: PROC ~ { period: REAL ¬ 1000000.0/d.speed.value; -- in microseconds nextTime: REAL ¬ BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[]]+period; Inner: PROC [n: NAT] ~ { WHILE BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[]] < nextTime DO ENDLOOP; nextTime ¬ nextTime+period; Buffer[d, restore, n]; }; IF forward THEN FOR n: NAT IN [0..d.frames.length) WHILE NOT d.stop DO Inner[n]; ENDLOOP ELSE FOR n: NAT DECREASING IN [0..d.frames.length) WHILE NOT d.stop DO Inner[n]; ENDLOOP; IF op = backforth THEN forward ¬ NOT forward; }; forward: BOOL ¬ TRUE; IF d.frames = NIL OR d.viewer = NIL THEN RETURN; IF op = replay THEN One[] ELSE WHILE NOT d.stop DO One[]; ENDLOOP; }; Time: PROC [d: Data] ~ { IF d.keys # NIL AND d.keys.length > 0 THEN { r: ROPE ¬ Controls.TypescriptRead[d.outerData.typescript, "Time: "]; IF r # NIL THEN SetTime[d, Convert.RealFromRope[r ! Convert.Error => GOTO Bad]]; EXITS Bad => Message["Bad value"]; }; }; GetViewer: PROC [d: Data] ~ {G2dZoom.Hijack[d.viewer ¬ ViewerTools.GetSelectedViewer[]]}; ResetViewer: PROC [d: Data] ~ { G2dZoom.Reset[d.viewer]; Controls.Reset[d.xMove, d.yMove, d.scale, d.rotate]; }; Help: PROC ~ {G2dPopUp.Help["2dZoom", left]}; IPOut: PROC [d: Data] ~ { fileName: ROPE ¬ Controls.TypescriptReadFileName[d.outerData.typescript]; IF fileName # NIL THEN G2dZoom.IPOut[d.viewer, fileName]; }; AISOut: PROC [d: Data] ~ { base: ROPE ¬ Controls.TypescriptReadFileName[d.outerData.typescript]; IF base # NIL THEN FOR n: NAT IN [0..d.frames.length) WHILE NOT d.stop DO name: ROPE ¬ IO.PutFR["%g.%g.ais", IO.rope[base], IO.int[n]]; f: Frame ¬ d.frames[n]; IF f.b # NIL THEN {Message["Sorry, can't write 24 bpp images right now"]; RETURN}; ENDLOOP; }; XForm: Controls.ControlProc ~ { d: Data ¬ NARROW[control.clientData]; IF d.busy OR (control.whatChanged # $TypedIn AND control.mouse.state = up) THEN RETURN; d.nFrame ¬ -1; -- no longer within an interpolation or playback G2dZoom.Transform[d.viewer, [d.xMove.value, d.yMove.value], d.scale.value, d.rotate.value]; }; DoTransform: PROC [d: Data, dx, dy, scale, rotate: REAL, fork: BOOL ¬ TRUE] ~ TRUSTED { Controls.SetSliderDialValue[d.rotate, rotate]; Controls.SetSliderDialValue[d.scale, scale]; Controls.SetSliderDialValue[d.xMove, dx]; Controls.SetSliderDialValue[d.yMove, dy]; G2dZoom.Transform[d.viewer, [dx, dy], scale, rotate, FALSE]; IF fork THEN Process.Detach[FORK ViewerOps.PaintViewer[d.viewer, client]] ELSE ViewerOps.PaintViewer[d.viewer, client]; }; nIcons: NAT ~ 8; icons: ARRAY [0..nIcons) OF Icons.IconFlavor; FOR i: NAT IN [0..nIcons) DO icons[i] ¬ Icons.NewIconFromFile["G2dUser.icons", i ! FS.Error => EXIT]; ENDLOOP; G2dTool.Register["Zoom", ZoomCmd, "Zoom around a viewer"]; END. Ψ G2dZoomCmdImpl.mesa Copyright Σ 1988, 1992 by Xerox Corporation. All rights reserved. Bloomenthal, August 25, 1992 2:24 pm PDT Glassner, September 14, 1989 1:14:41 pm PDT Types Pan/Zoom Command Enlarge the font cache for better performance: [] _ ImagerMaskCache.GetNamedCache[$Bitmap, 8000]; -- this doesn't work Display Interpolation Remaining (not = available) real memory: 512*VMInternal.freePages (SHARES VmInternal) v: Viewer _ d.viewer; vt: Terminal.Virtual _ Terminal.Current[]; fb: Terminal.FrameBuffer _ IF v.column = color THEN Terminal.GetColorFrameBufferA[vt] ELSE Terminal.GetBWFrameBuffer[vt]; nBits: NAT _ SELECT fb.bitsPerPixel FROM 1 => 1, 8 => 8, ENDCASE => 24; fbB: Terminal.FrameBuffer _ IF nBits = 24 THEN Terminal.GetColorFrameBufferB[vt] ELSE NIL; box: ImagerSample.Box _ [[fb.height-v.wy-v.ch, v.wx+v.cx], [fb.height-v.wy, v.ww]]; map: SampleMap _ ImagerSample.MapFromFrameBuffer[fb]; mapB: SampleMap _ --IF fbB # NIL THEN ImagerSample.MapFromFrameBuffer[fbB] ELSE-- NIL; clipped: SampleMap _ ImagerSample.Clip[map, box]; clippedB: SampleMap _ IF mapB # NIL THEN ImagerSample.Clip[mapB, box] ELSE NIL; d.nFrame _ nFrame; Repaint[d, $Ticks]; IF op = save THEN d.frames[nFrame] _ SELECT nBits FROM 1 => [ImagerSample.Copy[clipped], NIL, NIL], 8 => [NIL, ImagerSample.Copy[clipped], NIL], ENDCASE => [NIL, ImagerSample.Copy[clipped], ImagerSample.Copy[clippedB]] ELSE { f: Frame _ d.frames[nFrame]; IF (SELECT nBits FROM 1 => f.bw = NIL, 8 => f.b # NIL, ENDCASE => f.b = NIL) THEN { d.viewer _ NIL; Message["Viewer disagrees: please reselect a viewer"]; RETURN; }; SELECT nBits FROM 1 => { Terminal.WaitForBWVerticalRetrace[vt]; ImagerSample.Transfer[clipped, f.bw]; }; 8 => ImagerSample.Transfer[clipped, f.a]; ENDCASE => { ImagerSample.Transfer[clipped, f.a]; ImagerSample.Transfer[clippedB, f.b]; }; }; Button Parsing Key Operations Play Operations Miscellaneous Operations AISExtras.AISFromSampleMap[name, IF f.bw = NIL THEN f.a ELSE f.bw]; Transformation Start Code ΚI–"cedarcode" style•NewlineDelimiter ™™Jšœ Οeœ6™BJ™(J™+—˜šΟk œΓ˜ΜJ˜——šΠlnœžœž˜šžœ˜”J˜——Jšœž˜headšΟl™Jšœ žœ˜%Jšœ žœ˜,Jšœžœ'˜=Jšžœžœžœ˜Jšžœžœ žœ˜šœ žœ˜(J˜—Jšœžœžœ˜Jšœ žœžΟsœ‘ž‘œ‘œ‘œ‘œ‘œ‘œ‘œ‘ž‘œ‘œ˜SJšœžœžœ˜)šœžœžœ˜ Jšœžœ˜Jšœžœ žœžœ˜2˜J˜——Jšœ žœžœ˜/Jšœžœžœ˜-šœžœžœ˜"Jšœžœ˜Jšœžœ žœžœ˜4˜J˜——Jšœ žœžœ ˜šœ žœžœ˜Jšœžœžœ˜Jšœžœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœ+žœ˜/Jšœ&žœ˜*Jšœžœ˜Jšœžœ˜"Jšœ%žœ˜)Jšœ'žœ˜+Jšœ'žœ˜+Jšœ%žœ˜)Jšœ#ž˜&J˜——š ™šΠbnœ˜"Jšœ žœ ˜Jš œ ‘œ"‘œ5‘œ‘œ‘œžœ ˜₯Jš œ ‘œ"‘œ5‘œ‘œ‘œžœ ˜₯Jš œ ‘œ"‘œX‘œ‘œžœ˜ΗJšœ ‘œ‹žœ ˜₯Jšœ ‘œŠžœ ˜’Jšœ ‘œ˜š˜#Jšœ˜Jšœ˜šœ žœ˜Jšœ,˜,Jš œ!‘œ ‘œ ‘œžœ‘œ ˜XJšœ‘œ‘œ˜-Jšœ‘œ‘œ˜-Jšœ‘œ‘œ˜,Jšœ!‘œ‘œ˜0Jšœ‘œ‘œ˜+Jšœ,˜,Jšœ‘œ‘œ ˜.Jšœ‘œ‘œ˜*Jšœ‘œ‘œ˜.Jšœ‘œ‘œ˜,Jšœ‘œ‘œ˜+Jšœ,˜,Jšœ‘œ‘œ‘œ‘ œ‘œžœ‘œ‘œ˜^JšœJžœ ˜XJšœ‘œ‘œ˜-Jšœ ‘œ‘œ˜/Jšœ‘œ‘œ˜-—Jšœ žœ;˜IJ˜J˜J˜J˜Jšœ˜J˜ J˜—J˜J˜"J™.JšœH™HJ˜,Jšœžœ˜#Jšžœžœ˜2J˜J˜—šΟn œžœ˜š£ œžœžœ˜J˜Jšœ˜Jšœ(˜(J˜—J˜šžœžœ ž˜šžœ ˜Jšžœžœžœžœ žœžœ žœž˜HJšž‘ž‘œ‘žœž œžœ žœžœ žœžœ˜T—Jšœžœ ˜Jšœ)˜)Jšžœ˜—J˜Jšœ žœžœ˜J˜—š£ œ˜%Jšœ žœ ˜Jšœ žœ˜Jšœ˜Jšœ˜J˜—š £œžœžœžœžœ˜9J˜9Jšžœžœ˜$J˜——š ™š £ œžœžœžœžœ˜;š œžœžœ žœžœ.˜JJšžœžœžœ.˜V—Jšžœ&˜,J˜J˜—š £ œžœžœžœžœ˜8J˜šžœžœžœž˜Jšœžœžœ˜Jšœ žœ ˜/JšžœžœE˜U—J˜J˜—š£œžœžœžœ˜3Jšœ*žœ˜>Jšœ˜J˜—š£œ˜š£ œžœ˜+Jš£œžœC˜MJš £œ‘ž‘œ ‘œ ‘œ‘œ.˜SJ˜;Jšœ.žœ žœžœ ˜VJ˜—š£ œžœ˜š žœ žœžœžœžœ˜BJš£œžœžœžœžœ‘œ‘œ‘œ‘œ˜KJšœžœ ˜+Jšœžœ˜$Jšœžœ˜'J˜Ašžœžœžœž˜#Jšœžœ ˜J˜'Jšœ"žœžœ˜NJšžœ˜—šžœ žœ˜Jšœžœ)˜5Jš œžœžœžœ žœžœ˜Ešžœžœžœ ž˜6Jš œžœžœžœžœ˜-Jšœžœ˜J˜'Jšœ"žœžœ˜GJšžœ˜—˜˜Išžœ žœžœ˜Jšœžœ1žœ˜EJšœ žœ ˜J˜UJ˜Jšžœ žœžœ žœ˜5šžœ"žœ€˜CJ˜Jšœ žœžœ'˜FJš žœžœžœžœžœ˜=J˜J˜—J˜J˜ J˜J˜ Jšžœ˜"J˜—J˜J˜—š£ œžœ˜J˜Jšžœ žœžœ˜+J˜ J˜J˜—š£œžœ˜šžœ˜Jšžœ˜!šžœ˜Jšœžœ=˜Hšžœ žœžœ˜Jšœžœ0žœ˜Ešžœžœžœž˜#Jšžœžœžœ˜'šžœžœžœž˜&J˜Jšžœ˜—J˜ Jšžœ˜Jšž˜Jšžœ˜#Jšžœ˜—Jšžœ žœžœ˜+J˜ Jšžœ˜"J˜—J˜——J˜J˜—š£œžœ˜Jšœ žœ;˜Išžœ žœžœ˜Jšœžœžœžœ=˜PJšœ&˜&Jšžœ ˜J˜—J˜J˜—š£œžœ˜Jšœ žœ;˜Išžœ žœžœ˜Jšœžœžœ˜Jšœžœ6žœ žœ˜Sšžœž˜ Jšžœžœžœ˜-šžœ˜J˜.J˜PJšžœ ˜ J˜*J˜——J˜—J˜——š ™š£œ˜ Jšœ žœ˜%šžœžœž˜"Jšœ žœž˜@Jšœ:žœžœ˜F—š žœ žœžœžœžœ˜>Jšžœ˜Jšžœ/˜3—J˜J˜—š£œžœ.˜8š£œžœ˜ Jšœžœ€˜;Jšœ žœE˜Sš£œžœžœ˜šžœGž˜NJšžœ˜—J˜Jšœ˜J˜—šžœ˜ Jšžœžœžœžœžœžœžœ ž˜Mšž‘œ‘ž‘ž ‘ž‘œ‘ž‘ž‘œ‘ž˜FJšœ ˜ Jšžœ˜——Jšžœžœ žœ ˜-Jšœ˜—Jšœ žœžœ˜Jš žœ žœžœ žœžœžœ˜0Jšžœ žœžœžœžœžœžœ˜BJ˜J˜—š£œžœ˜šžœ žœžœžœ˜,Jšœžœ=˜DJšžœžœžœ6žœ˜PJšžœ˜"J˜—J˜——š ™š£ œžœJ˜YJ˜—š£ œžœ˜Jšœ˜Jšœ4˜4J˜J˜—š£œžœ#˜-J˜—š£œžœ˜Jšœ žœ;˜IJšžœ žœžœ#˜9J˜J˜—š£œžœ˜Jšœžœ;˜Ešžœžœžœžœžœžœžœžœž˜IJš œžœžœžœ žœ ˜=J˜Jšžœžœžœ9žœ˜RJšœ ‘ž‘œ‘œ‘ž‘ž‘œ‘ž‘œ™CJšžœ˜—J˜——š ™š£œ˜Jšœ žœ˜%Jšž‘œ‘ž‘œ‘œ‘œ‘ž‘œ‘œ‘œ‘ž‘žœ˜WJšœ€0˜@Jš œ‘œ‘œ‘œ‘œ˜[J˜J˜—š £ œžœ"žœžœžœžœ˜WJšœ.˜.Jšœ,˜,Jšœ)˜)Jšœ)˜)Jš œ‘œ‘œ‘œ‘œžœ˜<šžœ˜Jšžœžœ)˜AJšžœ)˜-—J˜——š  ™ Jšœžœ˜šœžœ žœ˜-J˜—šžœžœžœ ž˜Jšœ6žœ žœ˜HJšžœ˜J˜—J˜:J™—Jšžœ˜J˜—…—C|b