ColorMapsImpl.mesa
Copyright © 1985, 1987 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, December 23, 1985 12:52:29 pm PST
Last edited by: Christian Jacobi, March 10, 1987 2:41:35 pm PST
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.ROPENIL;
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.ROPENIL] = {
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.STREAMNIL] = {
CheckSetUpSpecials: PROC [name: Rope.ROPE] RETURNS [done: BOOLTRUE] = {
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: BOOLFALSE] = {
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: "Color map read from file", bitsPerPixel: bpp, mapEntries: fullMap, gamma: 1];
ColorDisplayManager.Start[type: myAtom, side: Side[]];
[] ← Terminal.SetColorCursorPresentation[terminal, useCursor];
IF subsetMap#NIL THEN
ImagerColorMap.LoadEntries[vt: terminal, mapEntries: subsetMap, gamma: 1, shared: FALSE];
ImagerColorMap.SetGamma[terminal, gamma];
};
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.STREAMNIL] RETURNS [done: BOOLFALSE] = {
--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.STREAMIO.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.STREAMNIL; 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: REFNIL, msgs: IO.STREAMNIL] = {
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 RETURN;
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.