<> <> <> <> DIRECTORY Atom, Buttons, ColorDisplayManager, ColorMaps, Commander, CommandTool, Convert, FS, FileNames, Imager, ImagerColorMap, ImagerDitherContext, InterminalBackdoor, IO, MessageWindow, PopUpMenus, Rope, SymTab, Terminal, UserProfile, WindowManager; ColorMapsImpl: CEDAR MONITOR IMPORTS Atom, Buttons, ColorDisplayManager, Commander, CommandTool, Convert, FS, FileNames, ImagerColorMap, ImagerDitherContext, InterminalBackdoor, IO, MessageWindow, PopUpMenus, Rope, SymTab, Terminal, UserProfile, WindowManager EXPORTS ColorMaps = BEGIN OPEN ColorMaps; myAtom: ATOM = $ColorMapsFromFile; last: Rope.ROPE _ NIL; terminal: Terminal.Virtual _ InterminalBackdoor.terminal; regTab: SymTab.Ref _ SymTab.Create[]; callBackList: LIST OF PROC _ NIL; Equal: PROC [s1, s2: Rope.ROPE] RETURNS [BOOL] = { RETURN [Rope.Equal[s1, s2, FALSE]] }; RegisterSetUp: PUBLIC PROC [entryName: Rope.ROPE, fileName: Rope.ROPE_NIL] = { IF Rope.IsEmpty[fileName] THEN [] _ SymTab.Delete[regTab, entryName] ELSE [] _ SymTab.Store[regTab, entryName, fileName] }; RegisterCallBack: PUBLIC ENTRY PROC [p: PROC] = { IF p#NIL THEN callBackList _ CONS [p, callBackList]; }; CallList: PROC [] = { FOR l: LIST OF PROC _ callBackList, l.rest WHILE l#NIL DO l.first[] ENDLOOP }; LastFile: PUBLIC PROC [] RETURNS [fileName: Rope.ROPE] = { RETURN [last]; }; Side: PROC [] RETURNS [side: ColorDisplayManager.Side] = { old: ColorDisplayManager.State = ColorDisplayManager.NextState[]; side _ IF old.type#NIL THEN old.side ELSE IF Equal["left", UserProfile.Token[key: "ColorDisplay.Side"]] THEN left ELSE right }; SetUp: PUBLIC PROC [name: Rope.ROPE, msgs: IO.STREAM_NIL] = { CheckSetUpSpecials: PROC [name: Rope.ROPE] RETURNS [done: BOOL_TRUE] = { old: ColorDisplayManager.State = ColorDisplayManager.NextState[]; SELECT TRUE FROM Equal[name, "LowRes"] => ColorDisplayManager.Start[type: old.type, side: Side[], level: old.level, resolution: standard]; Equal[name, "HighRes"] => ColorDisplayManager.Start[type: old.type, side: Side[], level: old.level, resolution: highResolution]; Equal[name, "Left"] => ColorDisplayManager.Start[type: old.type, side: left, level: old.level]; Equal[name, "Right"] => ColorDisplayManager.Start[type: old.type, side: right, level: old.level]; Equal[name, "Off"] => {ColorDisplayManager.Stop[]; last _ NIL}; Equal[name, "onesAreWhite"] => [] _ Terminal.SetColorCursorPresentation[terminal, onesAreWhite]; Equal[name, "onesAreBlack"] => [] _ Terminal.SetColorCursorPresentation[terminal, onesAreBlack]; ENDCASE => done _ FALSE }; CheckSetupStandard: PROC [name: Rope.ROPE] RETURNS [done: BOOL_FALSE] = { old: ColorDisplayManager.State = ColorDisplayManager.NextState[]; FOR each: LIST OF ATOM _ old.registered, each.rest UNTIL each = NIL DO n: Rope.ROPE _ Atom.GetPName[each.first]; IF Equal[name, n] THEN { last _ n; ColorDisplayManager.Start[type: each.first, side: Side[]]; RETURN [TRUE]; }; ENDLOOP; }; IF ~terminal.hasColorDisplay OR Rope.IsEmpty[name] THEN RETURN ELSE IF Equal[name, "Standard"] THEN { [] _ CheckSetupStandard["Dither8"]; [] _ Terminal.SetColorCursorPresentation[terminal, onesAreBlack]; } ELSE IF Equal[name, "?"] THEN { IO.PutRope[msgs, "current color map from: "]; IO.PutRope[msgs, last]; IO.PutRope[msgs, "\n"]; RETURN } ELSE IF CheckSetupStandard[name] THEN NULL ELSE IF CheckSetUpSpecials[name] THEN NULL ELSE IF SetUpFile[name, msgs] THEN NULL ELSE RETURN; CallList[]; }; ButtonHit: Buttons.ButtonProc = { state: ColorDisplayManager.State = ColorDisplayManager.NextState[]; menu: PopUpMenus.Menu _ PopUpMenus.Create["Color Display"]; EachRegisteredFile: SymTab.EachPairAction = {quit _ FALSE; [] _ PopUpMenus.Entry[menu: menu, entry: key, doc: NARROW[val], entryData: val]; }; IF WindowManager.colorDisplayOn THEN { [] _ PopUpMenus.Entry[menu: menu, entry: "Off", doc: "Turn off the color display", entryData: $Off]; IF state.side=left THEN [] _ PopUpMenus.Entry[menu: menu, entry: "Right", doc: "Color Display on right on B&W display", entryData: $Right] ELSE [] _ PopUpMenus.Entry[menu: menu, entry: "Left", doc: "Color Display on left on B&W display", entryData: $Left]; IF state.resolution=highResolution THEN [] _ PopUpMenus.Entry[menu: menu, entry: "LowRes", doc: "Change to low resolution", entryData: $LowRes] ELSE [] _ PopUpMenus.Entry[menu: menu, entry: "HighRes", doc: "Change to high resolution", entryData: $HighRes]; IF Terminal.GetColorCursorPresentation[terminal]=onesAreWhite THEN [] _ PopUpMenus.Entry[menu: menu, entry: "Cursor black", doc: "Color cursor representation onesAreBlack", entryData: $onesAreBlack] ELSE [] _ PopUpMenus.Entry[menu: menu, entry: "Cursor white", doc: "Color cursor representation onesAreWhite", entryData: $onesAreWhite]; }; [] _ SymTab.Pairs[regTab, EachRegisteredFile]; FOR each: LIST OF ATOM _ state.registered, each.rest UNTIL each = NIL DO IF each.first=myAtom THEN LOOP; [] _ PopUpMenus.Entry[menu: menu, entry: Atom.GetPName[each.first], entryData: each.first, doc: ColorDisplayManager.FetchCreator[each.first].documentation ]; ENDLOOP; [] _ PopUpMenus.Timeout[menu, 120]; WITH PopUpMenus.Call[menu] SELECT FROM a: ATOM => SetUp[Atom.GetPName[a]]; r: Rope.ROPE => SetUp[r]; ENDCASE => NULL; Message[]; }; Message: PROC [] = { r: Rope.ROPE _ LastFile[]; IF r=NIL THEN r _ "not loaded from a file"; MessageWindow.Append[Rope.Concat["color map: ", r], TRUE]; }; ForceColors: PROC [fullMap, subsetMap: ImagerDitherContext.MapEntries, useCursor: Terminal.ColorCursorPresentation _ onesAreBlack, gamma: REAL _ 2.2, bpp: INT _ 8] = { IF bpp<1 OR bpp>8 THEN bpp _ 8; ImagerDitherContext.RegisterDisplayType[type: myAtom, documentation: "DATools 8 bit mode", bitsPerPixel: bpp, mapEntries: fullMap, gamma: gamma]; ColorDisplayManager.Start[type: myAtom, side: Side[]]; [] _ Terminal.SetColorCursorPresentation[terminal, useCursor]; <> <> }; ExtendName: PROC [name: Rope.ROPE] RETURNS [fn: Rope.ROPE] = { fn _ name; IF Rope.Find[fn, "."]<1 THEN fn _ Rope.Concat[fn, ".ColorMap"]; }; SetUpFile: PROC [fileName: Rope.ROPE, msgs: IO.STREAM_NIL] RETURNS [done: BOOL_FALSE] = { <<--don't optimize and check what most recently loaded; >> <<--an other package might have fooled around unnoticed>> fullMap: LIST OF ImagerColorMap.MapEntry _ NIL; subsetMap: LIST OF ImagerColorMap.MapEntry _ NIL; cursor: Terminal.ColorCursorPresentation _ onesAreBlack; gamma: REAL _ 1; bpp: INT _ 8; maxIndex: INT _ 255; OneLine: PROC [line: Rope.ROPE] = { Range: PROC [i: INT] RETURNS [c: [0..256)] = { i _ MAX[0, MIN[i, 255]]; c _ i }; stream: IO.STREAM _ IO.RIS[line]; i, index, r, g, b: INT; mapEntrie: ImagerColorMap.MapEntry; i _ IO.GetInt[stream]; r _ IO.GetInt[stream]; g _ IO.GetInt[stream]; b _ IO.GetInt[stream]; index _ MIN[maxIndex, ABS[i] MOD 256]; mapEntrie _ [Range[index], Range[r], Range[g], Range[b]]; fullMap _ CONS[mapEntrie, fullMap]; IF index=i THEN subsetMap _ CONS[mapEntrie, subsetMap]; }; IF terminal.hasColorDisplay THEN { file: IO.STREAM _ NIL; line: Rope.ROPE; IF msgs=NIL THEN msgs _ IO.noWhereStream; fileName _ ExtendName[fileName]; file _ FS.StreamOpen[fileName ! FS.Error => { IO.PutF[msgs, "not done: %g\n", IO.rope[error.explanation]]; GOTO oops }]; line _ IO.GetLineRope[file ! IO.EndOfStream => GOTO oops]; IF ~Rope.Match["*ColorMap*", line, FALSE] THEN { IO.PutRope[msgs, "not a ColorMap file\n"]; GOTO oops }; line _ IO.GetLineRope[file ! IO.EndOfStream => GOTO oops]; DO SELECT TRUE FROM Rope.Match["*onesAreBlack*", line, FALSE] => cursor _ onesAreBlack; Rope.Match["*onesAreWhite*", line, FALSE] => cursor _ onesAreWhite; Rope.Match["*Gamma*", line, FALSE] => { line _ Rope.Substr[line, Rope.Find[line, "Gamma", 0, FALSE]+5]; gamma _ Convert.RealFromRope[line ! Convert.Error => CONTINUE]; }; Rope.Match["*BitsPerPixel*", line, FALSE] => { line _ Rope.Substr[line, Rope.Find[line, "BitsPerPixel", 0, FALSE]+12]; bpp _ Convert.IntFromRope[line ! Convert.Error => CONTINUE]; SELECT bpp FROM 8 => maxIndex _ 255; 4 => maxIndex _ 15; 2 => maxIndex _ 3; 1 => maxIndex _ 1; ENDCASE => {GOTO oops}; }; ENDCASE => EXIT; line _ IO.GetLineRope[file ! IO.EndOfStream => GOTO oops]; ENDLOOP; IF ~Terminal.LegalColorMode[terminal, [FALSE, bpp, 0]] THEN { IO.PutRope[msgs, "not done: bits per pixel not supported"] } ELSE { BEGIN DO IF ~Rope.IsEmpty[line] THEN OneLine[line]; line _ IO.GetLineRope[file ! IO.EndOfStream => {GOTO eof}]; ENDLOOP; EXITS eof => NULL END; ForceColors[fullMap, subsetMap, cursor, gamma, bpp]; done _ TRUE; last _ fileName; }; IO.Close[file]; }; EXITS oops => NULL }; CreateFile: PUBLIC PROC [fileName: Rope.ROPE, special: REF_NIL, msgs: IO.STREAM_NIL] = { m: Terminal.ColorMode = Terminal.GetColorMode[terminal]; max: BYTE; file: IO.STREAM; IF msgs=NIL THEN msgs _ IO.noWhereStream; IF ~WindowManager.colorDisplayOn THEN { IO.PutRope[msgs, "not done; color display not on\n"]; GOTO oops }; IF m.full THEN { IO.PutRope[msgs, "not done; color display in full color mode\n"]; GOTO oops }; SELECT m.bitsPerPixelChannelA FROM 1 => max _ 1; 2 => max _ 3; 4 => max _ 15; 8 => max _ 255; ENDCASE => { IO.PutRope[msgs, "not done; bits per pixel mode not supported for files\n"]; GOTO oops }; fileName _ ExtendName[fileName]; file _ FS.StreamOpen[fileName, create ! FS.Error => { IO.PutRope[msgs, "not done:"]; IO.PutRope[msgs, error.explanation]; IO.PutRope[msgs, "\n"]; GOTO oops }]; IO.PutRope[file, "ColorMap\n"]; IF Terminal.GetColorCursorPresentation[terminal]=onesAreBlack THEN IO.PutRope[file, "onesAreBlack\n"] ELSE IO.PutRope[file, "onesAreWhite\n"]; IO.PutF1[file, "Gamma %g\n", [real[ImagerColorMap.GetGamma[terminal]]]]; IO.PutF1[file, "BitsPerPixel %g\n", [integer[m.bitsPerPixelChannelA]]]; FOR i: Terminal.ChannelValue IN [0..max] DO red, green, blue: Terminal.ColorValue; index: INT _ i; [red, green, blue] _ Terminal.GetColor[terminal, i]; IF special=$i THEN index _ -index; IO.PutF[file, " %g %g %g %g\n", IO.int[index], IO.card[red], IO.card[green], IO.card[blue]]; ENDLOOP; IO.Close[file]; IO.PutF[msgs, "color map file %g created\n", [rope[fileName]]]; EXITS oops => NULL }; ColorMapCommand: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO oops}]; IF argv.argc<=1 OR argv[1].IsEmpty[] THEN GO TO oops; IF argv[1].Fetch[0]#'- THEN SetUp[argv[1], cmd.out] ELSE { --switches.. SELECT TRUE FROM Equal[argv[1], "-register"] => { --register menu command fn: Rope.ROPE; IF argv.argc<=3 THEN {msg _ "needs key and filename"; GO TO oops}; fn _ FileNames.FileWithSearchRules[root: argv[3], defaultExtension: ".ColorMap", requireExtension: FALSE, requireExact: TRUE, searchRules: NIL].fullPath; IF Rope.IsEmpty[fn] THEN {msg _ "file not found"; GO TO oops}; RegisterSetUp[argv[2], FileNames.StripVersionNumber[fn]]; }; Equal[argv[1], "-create"] => {--create file IF argv.argc<=2 THEN {msg _ "needs filename"; GO TO oops}; CreateFile[argv[2], NIL, cmd.out]; }; ENDCASE => {msg _ "only known switches: -register, -create"; GO TO oops}; }; EXITS oops => result _ $Failure; }; documentation: Rope.ROPE = "Set up color display ColorMaps {name | -register menuEntry fileName | -create fileName}"; IF terminal.hasColorDisplay THEN [] _ Buttons.Create[info: [name: "Color Display"], proc: ButtonHit, fork: TRUE]; Commander.Register[key: "ColorMaps", proc: ColorMapCommand, doc: documentation]; Commander.Register[key: "///7.0/Commands/ColorMaps", proc: ColorMapCommand, doc: documentation]; <<--needs full path registration because of funny people in DA group>> END.