DIRECTORY Basics, BasicTime, Buttons, ColorDisplayFace, FS, Histograms, IdleBackdoor, Imager, ImagerBox, ImagerColor, ImagerColorMap, ImagerDitherContext, ImagerFont, ImagerInterpress, ImagerPixelMap, ImagerTerminal, IO, Menus, PaintPM, PrincOps, Process, Random, Real, RealFns, Rope, Terminal, ThisMachine, TIPUser, UserProfile, Vector2, ViewerClasses, ViewerOps; ColorKal: CEDAR MONITOR IMPORTS Basics, BasicTime, Buttons, ColorDisplayFace, FS, IdleBackdoor, Imager, ImagerBox, ImagerColor, ImagerColorMap, ImagerDitherContext, ImagerFont, ImagerInterpress, ImagerPixelMap, ImagerTerminal, IO, PaintPM, Process, Random, Real, RealFns, Rope, Terminal, ThisMachine, UserProfile = { ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; PixelMap: TYPE = ImagerPixelMap.PixelMap; Font: TYPE = ImagerFont.Font; ConstantColor: TYPE = Imager.ConstantColor; ColorMap: TYPE = PaintPM.ColorMap; ColorSequence: TYPE = PaintPM.ColorSequence; ColorMapEntryList: TYPE = LIST OF ImagerColorMap.MapEntry; PixelBits: TYPE = [2 .. 8]; Direction: TYPE = {forward, backward}; Generator: TYPE = REF GeneratorRep; GeneratorRep: TYPE = RECORD [a, b, c, countLow, countHigh, lastC: CARDINAL]; TextData: TYPE = RECORD [ texts: TextList, numTexts: NAT, totalProbability: REAL]; TextList: TYPE = LIST OF Text; Text: TYPE = RECORD [ text: ROPE, bounds: Imager.Box, cumProb: REAL ]; Control: TYPE = REF ControlPrivate; ControlPrivate: TYPE = RECORD [ shouldGo: BOOL _ FALSE, direction: Direction _ forward, ipSize: REAL--meters-- _ Imager.metersPerInch*3.0, wantIP, wantFlip, hold: BOOL _ FALSE, BitsPerPixel: PixelBits _ 4, symmetry: CARDINAL _ 8, periodLow: CARDINAL _ 10000, periodHigh: CARDINAL _ 10000, persistence: CARDINAL _ 5000, halfBMin: INTEGER _ (LAST[CARDINAL]-2000)/2, halfBMax: INTEGER _ (LAST[CARDINAL]-1500)/2, halfCMin: INTEGER _ 0, halfCMax: INTEGER _ (LAST[CARDINAL]-1)/2, upTextMin: Milliseconds _ 10*OneSecond, upTextMax: Milliseconds _ 60*OneSecond, downTextMin: Milliseconds _ 1*OneSecond, downTextMax: Milliseconds _ 6*OneSecond, doText: BOOL _ TRUE, xStateB: Generator _ NEW [GeneratorRep _ [1, 65536-1849, 3, , , ]], xStateE: Generator _ NEW [GeneratorRep], yStateB: Generator _ NEW [GeneratorRep _ [1, 65536-1809, 3, , , ]], yStateE: Generator _ NEW [GeneratorRep], cStateB: Generator _ NEW [GeneratorRep _ [1, 65536-1889, 3, , , ]], cStateE: Generator _ NEW [GeneratorRep], pausePeriod: Process.Ticks _ 0, holdPeriod: Process.Ticks _ Process.MsecToTicks[500], erase: BOOL _ TRUE, runningPriority: Process.Priority _ Process.priorityBackground, AtATime: NAT _ 64, retraces: NAT _ 1 ]; td: TextData; font: Font _ NIL; rs: Random.RandomStream _ Random.Create[seed: -1]; Milliseconds: TYPE = INT; OneSecond: Milliseconds = 1000; Root3Quarters: REAL _ RealFns.SqRt[0.75]; black: Imager.Color _ Imager.black; white: Imager.Color _ Imager.white; going: BOOL _ FALSE; machineName: ROPE _ ThisMachine.Name[]; ctl: Control _ NEW [ControlPrivate _ []]; ButtonControl: PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift, control: BOOL _ FALSE] = BEGIN OPEN ctl; SELECT control FROM FALSE => { shouldGo _ NOT going; IF shouldGo AND OKToGo[] THEN { symmetry _ SELECT shift FROM FALSE => 8, TRUE => 12, ENDCASE => ERROR; BitsPerPixel _ SELECT mouseButton FROM red => 8, yellow => 4, blue => 4, ENDCASE => ERROR; TRUSTED {Process.Detach[FORK Viewit[]]}; }; }; TRUE => { SELECT mouseButton FROM red => wantIP _ TRUE; yellow => wantFlip _ TRUE; blue => hold _ NOT hold; ENDCASE => ERROR; }; ENDCASE => ERROR; END; StopGoing: ENTRY PROC = {going _ FALSE}; OKToGo: ENTRY PROC RETURNS [go: BOOL] = {IF go _ NOT going THEN going _ TRUE}; StopViewing: PROC RETURNS [BOOL] = {OPEN ctl; RETURN [NOT shouldGo]}; Kalidle: PROC [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift, control: BOOL _ FALSE] = { OPEN ctl; symmetry _ SELECT shift FROM FALSE => 8, TRUE => 12, ENDCASE => ERROR; BitsPerPixel _ SELECT mouseButton FROM red => 8, yellow => 4, blue => 4, ENDCASE => ERROR --8--; [] _ IdleBackdoor.UseAlternateVT[vtProc: DoForVT, logout: NOT control]; }; vtContext: Imager.Context; vtPM: PixelMap; curMap: ColorMap _ NIL; curList: ColorMapEntryList _ NIL; GiveVTContext: PROC [to: PROC [context: Imager.Context, pm: PixelMap]] = {to[vtContext, vtPM]}; Viewit: PROC = { OPEN ctl; TRUSTED { Process.SetPriority[runningPriority]; }; VTWork[Terminal.Current[], StopViewing !UNWIND => StopGoing[]]; StopGoing[]; }; DoForVT: PROC [vt: Terminal.Virtual] = { context: Imager.Context; vt.Select[]; [] _ vt.SetBWBitmapState[allocated]; [] _ vt.SetBWBitmapState[displayed]; context _ ImagerTerminal.BWContext[vt: vt, pixelUnits: TRUE]; Imager.SetColor[context, Imager.white]; Imager.MaskRectangle[context, [0, 0, vt.bwWidth, vt.bwHeight]]; VTWork[vt, KeyTyped]; }; KeyTyped: PROC RETURNS [stop: BOOL] = { stop _ IdleBackdoor.KeyTyped[IdleBackdoor.defaultKeyFilter]}; useImagerDitherContext: BOOL _ TRUE; useImagerColorMap: BOOL _ TRUE; VTWork: PROC [vt: Terminal.Virtual, Stop: PROC RETURNS [BOOL]] = { OPEN ctl; SimpleSet: PROC [a, b: Terminal.ChannelValue _ 0, red, green, blue: Terminal.ColorValue, shared: BOOL _ TRUE] = { Terminal.SetColor[vt: vt, aChannelValue: a, bChannelValue: b, red: red, green: green, blue: blue]; }; WithContext: PROC = { IF useImagerColorMap THEN ImagerColorMap.Change[vt, WithVT] ELSE WithVT[SimpleSet]; }; WithVT: PROC [set: ImagerColorMap.MapProc] = { vt _ vt; FOR cml: ColorMapEntryList _ curList, cml.rest WHILE cml # NIL DO set[a: cml.first.mapIndex, b: 0, red: cml.first.red, green: cml.first.green, blue: cml.first.blue]; ENDLOOP; vt _ vt; Dewit[giveContext: GiveVTContext, xp0: 0, yp0: 0, xp1: vtPM.fSize, yp1: vtPM.sSize, bpp: BitsPerPixel, Stop: Stop, vt: vt, entries: curMap]; vt _ vt; }; [vtContext, vtPM] _ StartDeviceAndPM[vt, BitsPerPixel]; [curList, curMap] _ DefineColorMap[BitsPerPixel]; IF useImagerDitherContext THEN ImagerDitherContext.DoWithDitherMap[context: vtContext, mapEntries: curList, action: WithContext] ELSE WithContext[]; }; SampleMap: PROC [bpp: NAT, offset: NAT _ 0] = { square: NAT _ TwoToThe[bpp]; side: NAT _ TwoToThe[bpp/2]; IF bpp # TwoToThe[vtPM.refRep.lgBitsPerPixel] THEN ERROR; FOR s: NAT IN [0 .. vtPM.sSize) DO FOR f: NAT IN [0 .. vtPM.fSize) DO index: NAT _ ((s*side/vtPM.sSize) + (f*side/vtPM.fSize)*side + offset) MOD square; ImagerPixelMap.PutPixel[vtPM, s+vtPM.sMin, f+vtPM.fMin, index]; ENDLOOP; Process.CheckForAbort[]; ENDLOOP; }; upText, downText, T: Milliseconds _ 0; curText: Text; cto: Vector2.VEC; cts: REAL; FloorLog2: PROC [n: CARDINAL] RETURNS [log: INTEGER] = { log _ SELECT n FROM < 1B => ERROR, < 2B => 0, < 4B => 1, < 10B => 2, < 20B => 3, < 40B => 4, < 100B => 5, < 200B => 6, < 400B => 7, < 1000B => 8, < 2000B => 9, < 4000B => 10, < 10000B => 11, < 20000B => 12, < 40000B => 13, < 100000B => 14, ENDCASE => 15}; TwoToThe: ARRAY [0 .. 15] OF CARDINAL = [ 00001H, 00002H, 00004H, 00008H, 00010H, 00020H, 00040H, 00080H, 00100H, 00200H, 00400H, 00800H, 01000H, 02000H, 04000H, 08000H]; Advance: PROC [gen: Generator] = TRUSTED { OPEN ctl; gen.a _ Basics.BITXOR[gen.a + gen.b, gen.b]; IF (gen.countLow _ gen.countLow - 1) = 0 THEN { gen.b _ Basics.BITXOR[gen.b + gen.c, gen.c]; gen.countLow _ periodLow; IF (gen.countHigh _ gen.countHigh - 1) = 0 THEN { rs _ Random.Create[seed: gen.c]; [] _ rs.NextInt[]; gen.lastC _ gen.c; gen.c _ rs.ChooseInt[0, halfCMax]*2+1; gen.countHigh _ periodHigh; }; }; }; Retard: PROC [gen: Generator] = TRUSTED { OPEN ctl; IF gen.countLow = periodLow THEN { IF gen.countHigh = periodHigh THEN { gen.countHigh _ 0; gen.c _ gen.lastC; rs _ Random.Create[seed: gen.c]; [] _ rs.NextInt[]; --actually, we'd like PrevInt, but can't have it... gen.lastC _ rs.ChooseInt[0, halfCMax]*2+1; }; gen.countHigh _ gen.countHigh + 1; gen.countLow _ 0; gen.b _ CARDINAL[Basics.BITXOR[gen.b, gen.c]] - gen.c; }; gen.countLow _ gen.countLow + 1; gen.a _ CARDINAL[Basics.BITXOR[gen.a, gen.b]] - gen.b; }; Dewit: PROC [giveContext: PROC [to: PROC [context: Imager.Context, pm: PixelMap]], xp0, yp0, xp1, yp1, bpp: INTEGER, Stop: PROC RETURNS [BOOL], vt: Terminal.Virtual, entries: ColorMap] = { OPEN ctl; sMin, fMin: INTEGER; --bounds of used area sMid, fMid: INTEGER; --center of used area radius: LONG CARDINAL; --of used area radiusTimesRootThreeQuarters: LONG CARDINAL; max: INTEGER; --maximum z - zmin valMax: LONG CARDINAL _ TwoToThe[bpp] - 1; PickText: PROC [T: Milliseconds] = { p: REAL _ Choose[0, td.totalProbability*0.999]; tl: TextList; FOR tl _ td.texts, tl.rest WHILE p > tl.first.cumProb DO NULL ENDLOOP; curText _ tl.first; upText _ T + rs.ChooseInt[upTextMin, upTextMax]; downText _ upText + rs.ChooseInt[downTextMin, downTextMax]; cts _ (xp1 - xp0)/(curText.bounds.xmax - curText.bounds.xmin)/2; cto _ [ x: Choose[ xp0 - cts*curText.bounds.xmin, xp1 - cts*curText.bounds.xmax], y: Choose[ yp0 - cts*curText.bounds.ymin, yp1 - cts*curText.bounds.ymax]]; }; DrawText: PROC [context: Imager.Context, pm: PixelMap] = { InnerDoit: PROC = { context.SetXY[cto]; context.TranslateT[cto]; context.ScaleT[cts]; context.SetFont[font]; context.ShowRope[curText.text]; }; Imager.DoSave[context, InnerDoit]; }; pmBounds: DeviceBounds; DeviceBounds: TYPE = RECORD [sMin, fMin, sMax, fMax: INTEGER]; Spots: PROC [pm: PixelMap, u, v, val: CARDINAL] _ SELECT symmetry FROM 8 => Spots8, 12 => Spots12, ENDCASE => ERROR; Spots8: PROC [pm: PixelMap, u, v, val: CARDINAL] = TRUSTED { ur: NAT _ Basics.HighHalf[radius*u]; vr: NAT _ Basics.HighHalf[radius*v]; IF ur < vr THEN { cur: NAT _ max - ur; cvr: NAT _ max - vr; ImagerPixelMap.PutPixel[pm, sMin+ vr, fMin+ ur, val]; ImagerPixelMap.PutPixel[pm, sMin+cvr, fMin+ ur, val]; ImagerPixelMap.PutPixel[pm, sMin+ vr, fMin+cur, val]; ImagerPixelMap.PutPixel[pm, sMin+cvr, fMin+cur, val]; ImagerPixelMap.PutPixel[pm, sMin+ ur, fMin+ vr, val]; ImagerPixelMap.PutPixel[pm, sMin+cur, fMin+ vr, val]; ImagerPixelMap.PutPixel[pm, sMin+ ur, fMin+cvr, val]; ImagerPixelMap.PutPixel[pm, sMin+cur, fMin+cvr, val]; }; }; Spots12: PROC [pm: PixelMap, u, v, val: CARDINAL] = TRUSTED { vh: CARDINAL _ Basics.BITSHIFT[v, -1]; ur: NAT _ Basics.HighHalf[radius*u]; vr: NAT _ Basics.HighHalf[radius*vh]; urH: NAT _ Basics.BITSHIFT[ur, -1]; vrH: NAT _ Basics.BITSHIFT[vr, -1]; urRTQ: NAT _ Basics.HighHalf[radiusTimesRootThreeQuarters*u]; vrRTQ: NAT _ Basics.HighHalf[radiusTimesRootThreeQuarters*vh]; IF v < u THEN {OPEN IPME: ImagerPixelMap; IPME.PutPixel[pm, sMid+vrRTQ, fMid+ur - vrH, val]; IPME.PutPixel[pm, sMid+vrRTQ, fMid-ur + vrH, val]; IPME.PutPixel[pm, sMid-vrRTQ, fMid+ur - vrH, val]; IPME.PutPixel[pm, sMid-vrRTQ, fMid-ur + vrH, val]; IPME.PutPixel[pm, sMid+urRTQ - vrRTQ, fMid+urH + vrH, val]; IPME.PutPixel[pm, sMid+urRTQ - vrRTQ, fMid-urH - vrH, val]; IPME.PutPixel[pm, sMid-urRTQ + vrRTQ, fMid+urH + vrH, val]; IPME.PutPixel[pm, sMid-urRTQ + vrRTQ, fMid-urH - vrH, val]; IPME.PutPixel[pm, sMid+urRTQ, fMid+urH - vr, val]; IPME.PutPixel[pm, sMid+urRTQ, fMid-urH + vr, val]; IPME.PutPixel[pm, sMid-urRTQ, fMid+urH - vr, val]; IPME.PutPixel[pm, sMid-urRTQ, fMid-urH + vr, val]; }; }; SetBounds: PROC [pm: PixelMap] = { dr: ImagerPixelMap.DeviceRectangle _ pm.BoundedWindow[]; pmBounds _ [sMin: dr.sMin, fMin: dr.fMin, sMax: dr.sMin + dr.sSize - 1, fMax: dr.fMin + dr.fSize - 1]; }; DrawInit: PROC [context: Imager.Context, pm: PixelMap] = { Imager.SetColor[context, PickColor[context, entries, 0]]; Imager.MaskRectangle[context, [xp0, yp0, xp1 - xp0, yp1 - yp0]]; SetBounds[pm]; FOR i: CARDINAL IN [1 .. persistence] DO Advance[xStateB]; Advance[yStateB]; Advance[cStateB]; Spots[pm, xStateB.a, yStateB.a, Basics.HighHalf[valMax*cStateB.a] + 1]; ENDLOOP; }; DrawFinal: PROC [context: Imager.Context, pm: PixelMap] = { SetBounds[pm]; IF erase THEN FOR i: CARDINAL IN [1 .. persistence] DO Advance[xStateE]; Advance[yStateE]; Advance[cStateE]; Spots[pm, xStateE.a, yStateE.a, 0]; ENDLOOP; }; prevUp: BOOL _ FALSE; DrawDelta: PROC [context: Imager.Context, pm: PixelMap] = { shouldUp: BOOL _ (T >= upText) AND (T < downText); SetBounds[pm]; IF wantIP THEN { ipm: ImagerInterpress.Ref = ImagerInterpress.Create["ColorKal.ip"]; scale: REAL = ipSize/MAX[pm.sSize, pm.fSize]; PaintIt: PROC [context: Imager.Context] = { PaintPM.PaintPixelMap[context, pm, curMap, 0]; }; wantIP _ FALSE; ipm.DoPage[PaintIt, scale]; ipm.Close[]; }; SELECT direction FROM forward => { THROUGH [0 .. AtATime) DO IF erase THEN { Advance[xStateE]; Advance[yStateE]; Advance[cStateE]; Spots[pm, xStateE.a, yStateE.a, 0]; }; Advance[xStateB]; Advance[yStateB]; Advance[cStateB]; Spots[pm, xStateB.a, yStateB.a, Basics.HighHalf[valMax*cStateB.a] + 1]; ENDLOOP; }; backward => { THROUGH [0 .. AtATime) DO Spots[pm, xStateB.a, yStateB.a, 0]; Retard[xStateB]; Retard[yStateB]; Retard[cStateB]; IF erase THEN { Spots[pm, xStateE.a, yStateE.a, Basics.HighHalf[valMax*cStateE.a] + 1]; Retard[xStateE]; Retard[yStateE]; Retard[cStateE]; }; ENDLOOP; }; ENDCASE => ERROR; IF doText AND shouldUp # prevUp THEN { index: NAT _ rs.ChooseInt[1, entries.length-1]; Imager.SetColor[context, PickColor[context, entries, IF shouldUp THEN index ELSE 0]]; DrawText[context, pm]; prevUp _ shouldUp; }; IF T >= downText THEN PickText[T]; }; oldP: BasicTime.Pulses; SELECT symmetry FROM 8 => radius _ MIN[xp1 - xp0, yp1 - yp0]/2; 12 => radius _ MIN[xp1 - xp0, Real.FixC[(yp1 - yp0)/Root3Quarters]]/2; ENDCASE => ERROR; max _ radius*2 - 1; sMin _ yp0 + (yp1 - yp0 - (max+1))/2; fMin _ xp0 + (xp1 - xp0 - (max+1))/2; sMid _ (yp0 + yp1)/2; fMid _ (xp0 + xp1)/2; radiusTimesRootThreeQuarters _ Real.RoundC[Root3Quarters*radius]; PickText[T _ 0]; RandomizeB[]; xStateB.countLow _ periodLow; yStateB.countLow _ periodLow; cStateB.countLow _ periodLow; xStateB.countHigh _ periodHigh; yStateB.countHigh _ periodHigh; cStateB.countHigh _ periodHigh; xStateE^ _ xStateB^; yStateE^ _ yStateB^; cStateE^ _ cStateB^; giveContext[DrawInit]; oldP _ BasicTime.GetClockPulses[]; FOR i: INT _ 0, i+1 WHILE NOT Stop[] DO newP: BasicTime.Pulses; IF wantFlip THEN { direction _ SELECT direction FROM forward => backward, backward => forward, ENDCASE => ERROR; wantFlip _ FALSE; }; IF hold THEN Process.Pause[holdPeriod] ELSE giveContext[DrawDelta]; IF pausePeriod # 0 THEN Process.Pause[pausePeriod]; FOR i: NAT IN [0 .. retraces) DO Terminal.WaitForBWVerticalRetrace[vt]; ENDLOOP; newP _ BasicTime.GetClockPulses[]; IF newP > oldP THEN { Dt: Milliseconds _ BasicTime.PulsesToMicroseconds[newP - oldP]/1000; T _ T + Dt}; oldP _ newP; ENDLOOP; giveContext[DrawFinal]; }; PickColor: PROC [context: Imager.Context, entries: ColorMap, index: NAT] RETURNS [color: ConstantColor] = { color _ entries[index]; }; StartDeviceAndPM: PROC [vt: Terminal.Virtual, bpp: INT] RETURNS [context: Imager.Context, pm: PixelMap] = { OPEN ctl; fb: Terminal.FrameBuffer; IF ColorDisplayFace.displayType = none THEN [] _ ColorDisplayFace.SetDisplayType[profiledDisplayType]; [] _ Terminal.SetColorBitmapState[vt: vt, newState: displayed, newMode: [full: FALSE, bitsPerPixelChannelA: bpp, bitsPerPixelChannelB: 0], newVisibility: aOnly]; context _ ImagerTerminal.ColorContext[vt: vt, pixelUnits: TRUE]; IF vt.GetColorMode[].bitsPerPixelChannelA # bpp THEN ERROR; fb _ vt.GetColorFrameBufferA[]; pm _ FbPm[fb]; }; profiledDisplayType: ColorDisplayFace.ColorDisplayType; FbPm: PROC [fb: Terminal.FrameBuffer] RETURNS [pm: PixelMap] = { pm _ [ sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: fb.height, fSize: fb.width, refRep: NEW [ImagerPixelMap.PixelMapRep _ [ ref: fb.vm, pointer: fb.base, words: fb.vm.words, lgBitsPerPixel: FloorLog2[fb.bitsPerPixel], rast: fb.wordsPerLine, lines: fb.height]] ]; IF fb.bitsPerPixel # TwoToThe[pm.refRep.lgBitsPerPixel] THEN ERROR; }; DefineColorMap: PROC [bpp: PixelBits] RETURNS [list: ColorMapEntryList, seq: ColorMap] = { OPEN ctl; length: NAT = TwoToThe[bpp]; IF (cmLists[bpp] = NIL) # (cmSeqs[bpp] = NIL) THEN ERROR; IF cmLists[bpp] # NIL THEN RETURN [cmLists[bpp], cmSeqs[bpp]]; seq _ MakeEntries[length]; list _ NIL; FOR i: INT IN [0 .. length) DO rgb: ImagerColor.RGB _ MapRound[i, bpp]; list _ CONS [ [ mapIndex: i, red: Floor[rgb.R*255.99], green: Floor[rgb.G*255.99], blue: Floor[rgb.B*255.99] ], list ]; seq[i] _ ImagerColor.ColorFromRGB[rgb, cal]; ENDLOOP; cmLists[bpp] _ list; cmSeqs[bpp] _ seq; }; cal: ImagerColor.RGBCalibration _ ImagerColor.GetDefaultCalibration[]; cmLists: ARRAY PixelBits OF ColorMapEntryList _ ALL[NIL]; cmSeqs: ARRAY PixelBits OF ColorMap _ ALL[NIL]; FixC: PROC [r: REAL] RETURNS [c: CARDINAL] = {c _ Real.FixC[r]}; MapRound: PROC [i, bpp: NAT] RETURNS [rgb: ImagerColor.RGB] = { last: NAT _ TwoToThe[bpp]-1; SELECT i FROM = 000 => rgb _ [0, 0, 0]; <= last => rgb _ ImagerColor.RGBFromHSV[[H: (i-1.0)/last, S: 1, V: 1]]; ENDCASE => ERROR}; MapCopy: PROC [i, bpp: NAT] RETURNS [c: ConstantColor] = { c _ fromMap[i]; }; fromMap: ColorMap _ NIL; MakeEntries: PROC [length: NAT] RETURNS [entries: ColorMap] = {entries _ NEW[ColorSequence[length]]}; Floor: PROC [r: REAL] RETURNS [i: INT] = { d: INT _ 1 - Real.Fix[r]; i _ Real.Fix[r+d]-d}; Ceiling: PROC [r: REAL] RETURNS [i: INT] = { d: INT _ 1 + Real.Fix[r]; i _ Real.Fix[r-d]+d}; ReadTextData: PROC [fileName: ROPE] RETURNS [td: TextData] = { OPEN ctl; from: IO.STREAM _ FS.StreamOpen[fileName]; last: TextList _ NIL; td _ [ texts: NIL, numTexts: 0, totalProbability: 0]; DO prob: REAL; text: ROPE; this: TextList; [] _ from.SkipWhitespace[]; IF from.EndOf[] THEN EXIT; prob _ from.GetReal[]; text _ from.GetRopeLiteral[]; text _ Replace[text, "", machineName]; td.numTexts _ td.numTexts + 1; this _ LIST[ [ text: text, bounds: ImagerBox.BoxFromExtents[font.RopeBoundingBox[text]], cumProb: td.totalProbability _ td.totalProbability + prob] ]; IF last = NIL THEN td.texts _ this ELSE last.rest _ this; last _ this; ENDLOOP; from.Close[]; }; Choose: PROC [min, max: REAL] RETURNS [r: REAL] = {r _ min + (rs.ChooseInt[0, 10000]/1.0E4) * (max-min)}; Replace: PROC [in, what, with: ROPE] RETURNS [new: ROPE] = { start, len: INT; ousLen: INT _ what.Length[]; new _ in; WHILE (start _ new.Index[s2: what]) < (len _ new.Length[]) DO new _ new.Substr[len: start].Cat[with, new.Substr[start: start+ousLen, len: len - (start+ousLen)]]; ENDLOOP; }; CreateButton: PROC = { ctlButton _ Buttons.Create[info: [name: "cKal", column: static], proc: ButtonControl, documentation: "click to run/stop color kaleidoscope; left=8bpp, mid=4, right=2"]; }; ctlButton: Buttons.Button _ NIL; RandomizeB: PROC = { OPEN ctl; DO xStateB.b _ rs.ChooseInt[halfBMin, halfBMax]*2 + 1; yStateB.b _ rs.ChooseInt[halfBMin, halfBMax]*2 + 1; cStateB.b _ rs.ChooseInt[halfBMin, halfBMax]*2 + 1; IF xStateB.b # yStateB.b AND cStateB.b # yStateB.b AND xStateB.b # cStateB.b THEN EXIT; ENDLOOP; }; RandomizeC: PROC = { OPEN ctl; xStateB.c _ rs.ChooseInt[halfCMin, halfCMax]*2 + 1; yStateB.c _ rs.ChooseInt[halfCMin, halfCMax]*2 + 1; cStateB.c _ rs.ChooseInt[halfCMin, halfCMax]*2 + 1; }; NoteProfile: PROC [reason: UserProfile.ProfileChangeReason] --UserProfile.ProfileChangedProc-- = { displayTypeRope: ROPE _ UserProfile.Token["ColorDisplay.Type", "640x480"]; profiledDisplayType _ SELECT TRUE FROM displayTypeRope.Equal["1024x768", FALSE] => highResolution, displayTypeRope.Equal["640x480", FALSE] => standard, ENDCASE => standard; }; Start: PROC = { UserProfile.CallWhenProfileChanges[NoteProfile]; font _ ImagerFont.Find["Xerox/PressFonts/TimesRoman-MRR"]; td _ ReadTextData["Kal.texts"]; CreateButton[]; }; Start[]; }. abcdefghijklmnopqrstuvwxyz1234567890-=\[]_;',./ ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%~&*()+|{}^:"<>? abcdefghijklmnopqrstuvwxyz1234567890-=\[]_;',./ ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%~&*()+|{}^:"<>? *ColorKal.Mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Last Edited by: Spreitzer, May 13, 1986 2:45:55 pm PDT INVARIANT going IFF there is a process running the kaleidoscope. Code from 5.2: dd: ImagerDisplay.DisplayData; context _ Imager.Create[ SELECT bpp FROM 2 => $Std2bpp, 4 => $Std4bpp, 8 => $Std8bpp, ENDCASE => ERROR]; Imager.ConcatT[context, Imager.Invert[context.state.T]]; dd _ NARROW[context.data]; pm _ dd.pix[0]; entries _ LoadMap[context, bpp, maps[bpp]]; Previously problematic in 6.0: Works in 6.0, but gets Viewers in the way: IF vt # Terminal.Current[] THEN ERROR; ColorDisplay.SetColorDisplayStatus[on: TRUE, bpp: bpp]; LoadMap: PROC [vt: Terminal.Virtual, bpp: NAT] RETURNS [entries: ColorMap] = { length: NAT _ TwoToThe[bpp]; entries _ MakeEntries[length]; FOR i: INT IN [0 .. length) DO rgb: ImagerColor.RGB _ MapRound[i, bpp]; Terminal.SetColor[ vt: vt, aChannelValue: i, red: Floor[rgb.R*255.99], green: Floor[rgb.G*255.99], blue: Floor[rgb.B*255.99] ]; entries[i] _ ImagerColor.ColorFromRGB[rgb, cal]; ENDLOOP; }; Κ½– "cedar" style˜code™ Jšœ Οmœ1™Kš‘œžœžœžœ žœžœžœ˜tš‘œžœžœžœ˜šžœžœžœžœ˜)Kšžœ0˜4Kšžœ0˜4Kšžœ0˜4Kšžœ0˜4Kšžœ7˜;Kšžœ7˜;Kšžœ7˜;Kšžœ7˜;Kšžœ.˜2Kšžœ.˜2Kšžœ.˜2Kšžœ.˜2K˜—K˜—š‘ œžœ˜"Kšœ8˜8K˜fK˜—š‘œžœ,˜:Kšœ9˜9Kš œ ’œ’œ’œ’œ’œ’œ˜@Kšœ˜šžœžœžœž˜(K˜K˜K˜KšœG˜GKšžœ˜—K˜—š‘ œžœ,˜;Kšœ˜š žœžœžœžœžœž˜6K˜K˜K˜Kšœ#˜#Kšžœ˜—K˜—Kšœžœžœ˜š‘ œžœ,˜;Kšœ žœžœ˜2Kšœ˜šžœžœ˜KšœC˜CKšœžœ žœ˜-š‘œžœ˜+Kšœ.˜.K˜—Kšœ žœ˜Kšœ˜K˜ K˜—šžœ ž˜˜ šžœž˜šžœžœ˜K˜5Kšœ#˜#K˜—K˜5KšœG˜GKšžœ˜—K˜—˜ šžœž˜Kšœ#˜#K˜2šžœžœ˜KšœG˜GK˜2K˜—Kšžœ˜—K˜—Kšžœžœ˜—šžœžœžœ˜&Kšœžœ%˜/Kšœ5žœ žœžœ˜UKšœ˜Kšœ˜Kšœ˜—Kšžœžœ ˜"K˜—K˜šžœ ž˜Kš œžœ’œ’œ’œ’œ˜*Kš œžœ’œ’œ’œ’œ˜FKšžœžœ˜—K˜Kšœ’œ’œ’œ˜%Kšœ’œ’œ’œ˜%Kšœ ’œ’œ˜Kšœ ’œ’œ˜K˜AKšœ˜K˜ K˜K˜K˜K˜K˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜"š žœžœ žœžœž˜'K˜šžœ žœ˜šœ žœ ž˜!K˜K˜Kšžœžœ˜—Kšœ žœ˜K˜—Kšžœžœžœ˜CKšžœžœ˜3šžœžœžœž˜ Kšœ&˜&Kšžœ˜—K˜"šžœ žœ˜KšΟgœC˜DKšœ£œ˜ —Kšœ ˜ Kšžœ˜—K˜K˜—K˜š‘ œžœ5žœžœ˜kK˜K˜—K˜š‘œžœžœžœ,˜kKšžœ˜ Kšœ˜™K™šœ™šžœž™Kšœ™Kšœ™Kšœ™Kšžœžœ™——Kšœ4žœ™8Kšœžœ™K™Kšœ+™+—™Kšžœ%žœ;˜fKšœOžœM˜‘—™*Kšžœžœžœ™&Kšœ'žœ ™7—Kšœ:žœ˜@Kšžœ.žœžœ˜;Kšœ˜K˜K˜—K˜Kšœ7˜7K˜š‘œžœžœ˜@šœ˜K˜K˜K˜"šœžœ ˜+Kšœ ˜ Kšœ˜Kšœ˜Kšœ+˜+K˜K˜—K˜—Kšžœ6žœžœ˜CK˜—K˜š‘œžœžœ-˜ZKšžœ˜ Kšœžœ˜Kš žœžœžœžœžœ˜9Kšžœžœžœžœ˜>Kšœ˜Kšœžœ˜ šžœžœžœž˜Kšœžœ˜(šœž˜ šœ˜K˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜K˜—Kšœ,˜,Kšžœ˜—Kšœ˜Kšœ˜K˜KšœF˜FKš œ žœ žœžœžœ˜9Kš œžœ žœ žœžœ˜/—K˜š‘œžœžœžœ™NKšœžœ™Kšœ™šžœžœžœž™Kšœžœ™(™K™Kšœ™Kšœ™Kšœ™Kšœ™K™—Kšœ0™0Kšžœ™—K™—K˜Kš ‘œžœžœžœžœ˜@K˜š ‘œžœ žœžœžœ˜?Kšœžœ˜šžœž˜ Kšœ˜KšœG˜GKšžœžœ˜——K˜š‘œžœ žœžœ˜:K˜K˜Kšœžœ˜—K˜š‘ œžœ žœžœ˜=Kšœ žœ˜'—K˜š ‘œžœžœžœžœ˜*Kšœžœ˜K˜—K˜š ‘œžœžœžœžœ˜,Kšœžœ˜K˜—K˜š‘ œžœ žœžœ˜>Kšžœ˜ Kšœžœžœžœ˜*Kšœžœ˜˜Kšœžœ˜ K˜ K˜—šž˜Kšœžœ˜ Kšœžœ˜ K˜K˜Kšžœžœžœ˜K˜K˜K˜4Kšœ˜šœžœ˜K˜ Kšœ=˜=Kšœ=˜=—Kšžœžœžœžœ˜9K˜ Kšžœ˜—K˜ K˜—K˜š ‘œžœ žœžœžœ˜1K˜7—K˜š ‘œžœžœžœžœ˜