NMos8BitColors.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Monier, September 24, 1984 9:55:48 pm PDT
Last Edited by: Jacobi, October 29, 1984 5:46:54 pm PST
Last Edited by: Jacobi, April 11, 1985 11:22:20 am PST
Do not put to much effort into this module; the cmos version
is considered the master version.
DIRECTORY
Buttons,
CD,
CDColors,
CDIO,
CDMenus,
CDSequencer,
NMos,
ColorMap,
ColorWorld,
Commander,
Containers,
Convert,
GraphicsBasic,
GraphicsColor,
Icons,
Labels,
MessageWindow,
Process,
Real,
Rope,
Sliders,
Terminal,
TerminalIO,
UserProfile,
ViewerOps,
ViewerClasses,
WindowManager;
NMos8BitColors: CEDAR PROGRAM
IMPORTS Buttons, CDColors, CDIO, CDMenus, CDSequencer, NMos, ColorMap, ColorWorld, Commander, Containers, Convert, Icons, Labels, MessageWindow, Process, Real, Rope, Sliders, Terminal, TerminalIO, UserProfile, ViewerOps, WindowManager =
BEGIN
--**Patterns**************************************
Init8Patterns: Buttons.ButtonProc =
--all parameter are discarded
BEGIN
green1: CARDINAL = 1;
yellow: CARDINAL = 2;
blue: CARDINAL = 4;
pinktr: CARDINAL = 8;
red: CARDINAL = 16;
black: CARDINAL = 255;
Checker8: PROC[col1, col2: CARDINAL] RETURNS[REF CDColors.Brick] =
BEGIN
RETURN[NEW[CDColors.Brick ← [col1*256+col2, col2*256+col1, col1*256+col2, col2*256+col1]]]
END;
DefineDimmer8: PROC[lev: CD.Layer, color: CARDINAL] =
BEGIN
CDColors.DefineColor[lev, Checker8[color, 0], bit8, back];
END;
Full8: PROC[color: CARDINAL] RETURNS [b: REF CDColors.Brick] =
BEGIN
RETURN[Checker8[color, color]]
END;
CDColors.DefineColor[NMos.dif, Full8[green1], bit8];
CDColors.DefineColor[NMos.met, Full8[blue], bit8];
CDColors.DefineColor[NMos.met2, Full8[pinktr], bit8];
CDColors.DefineColor[NMos.pol, Full8[red], bit8];
CDColors.DefineColor[NMos.cut, Full8[black], bit8];
CDColors.DefineColor[NMos.imp, Full8[yellow], bit8];
CDColors.DefineColor[NMos.imp0, Checker8[yellow, 0], bit8];
CDColors.DefineColor[NMos.impWeak, Checker8[yellow, 0], bit8];
CDColors.DefineColor[NMos.cut2, Checker8[black, blue], bit8];
CDColors.DefineColor[NMos.bur, Checker8[black, 0], bit8];
CDColors.DefineColor[NMos.nwelCont, Checker8[green1, blue], bit8];
CDColors.DefineColor[NMos.ovg, Checker8[blue, pinktr], bit8];
CDColors.DefineColor[NMos.nwel, NEW[CDColors.Brick←[14, 13, 0, 0]], bit8];
CDColors.DefineColor[NMos.nwelCont, NEW[CDColors.Brick←[14, 14, 5, 0]], bit8];
CDColors.DefineColor[CD.backGround, NEW[CDColors.Brick ← [8, 0, 256*8, 0]], bit8];
CDColors.DefineColor[CD.highLightError, NEW[CDColors.Brick ← [255, 0, 0, 0]], bit8];
CDColors.DefineColor[CD.highLightShade, NEW[CDColors.Brick←[0, 255,0 , 255]], bit8];
DefineDimmer8[NMos.dif, green1];
DefineDimmer8[NMos.met, blue];
DefineDimmer8[NMos.met2, pinktr];
DefineDimmer8[NMos.pol, red];
DefineDimmer8[NMos.imp, yellow];
DefineDimmer8[NMos.cut, black];
DefineDimmer8[NMos.cut2, black];
-- no change for bur, nwelCont, pwelCont, and ovgc for this background
END;
--**end patterns**************************************
Color: TYPE = RECORD[r, g, b, weight: REAL ← 0];
ColorDescRec: TYPE = ARRAY [0..7) OF Color;
ColorDesc: TYPE = REF ColorDescRec;
color: ColorDesc = NEW[ColorDescRec];
-- The weights associated with every primary layer color: think of them as the transparency of each layer. The color of an intersection (i.e. green1 over blue) is the weighted sum of the rgb of each color. These weights are also optionally loaded from profile and editable by the user.
indLayer: CARDINAL ← 1;
previndLayer: CARDINAL ← 1; -- to deselect the previous layer button
CoefSlider: TYPE = RECORD [
value: Labels.Label ← NIL,
select: Buttons.Button ← NIL,
bar: Sliders.Slider ← NIL
];
ColorSlider: TYPE = RECORD [
value: Labels.Label ← NIL,
bar: Sliders.Slider ← NIL
];
Handle: TYPE = REF AdjustColorRec;
AdjustColorRec: TYPE = RECORD [
outer: Containers.Container ← NIL,
coefLayer: ARRAY [0..7) OF CoefSlider,
potarColor: ARRAY [0..3) OF ColorSlider,
height: CARDINAL ← 0  -- height measured from the top of the container
];
DataForSpecialProc: TYPE = REF DataForSpecialProcRec;
DataForSpecialProcRec: TYPE = RECORD [
my: Handle,
layer: CARDINAL
];
ColorModeIs8: PROC [] RETURNS [BOOL] = INLINE
BEGIN
virtual: Terminal.Virtual = Terminal.Current[];
RETURN [virtual.hasColorDisplay AND ~virtual.GetColorMode[].full AND virtual.GetColorMode[].bitsPerPixelChannelA=8];
END;
caption: Rope.ROPE = "nmos 8 bit color editor";
Check8BitMode: PROC [] RETURNS [ok: BOOL] =
BEGIN
ok ← ColorModeIs8[];
IF ~ok THEN
TRUSTED{Process.Detach[FORK TerminalIO.WriteRope["Put the display in 8 bit per pixel mode first\n"]]};
END;
UpdateWeightSlider: Sliders.SliderProc =
BEGIN
datac: DataForSpecialProc ← NARROW[clientData];
my: Handle ← datac.my;
layer: CARDINAL ← datac.layer;
IF ~ColorModeIs8[] THEN RETURN;
color[layer].weight ← value;
ComputeColors[];
Labels.Set[my.coefLayer[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]];
END;
UpdateColorSlider: Sliders.SliderProc =
BEGIN
data: DataForSpecialProc ← NARROW[clientData];
my: Handle ← data.my;
layer: CARDINAL ← data.layer;
IF ~ColorModeIs8[] THEN RETURN;
IF indLayer = 7 THEN RETURN; -- channel hack
Labels.Set[my.potarColor[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]];
SELECT layer FROM
0 => color[indLayer-1].r ← value;
1 => color[indLayer-1].g ← value;
2 => color[indLayer-1].b ← value;
ENDCASE=> ERROR;
ComputeColors[];
END;
ResetButton: Buttons.ButtonProc =
BEGIN
Init8Patterns[parent: parent, clientData: clientData];
ResetMapButton[parent: parent, clientData: clientData];
END;
ResetAndCreateButton: Buttons.ButtonProc =
BEGIN
viewer: ViewerClasses.Viewer ← ViewerOps.FindViewer[caption];
IF viewer=NIL THEN {
IF ColorWorld.HasMode[8] AND ~ColorModeIs8[] THEN {
pos: WindowManager.ScreenPos ← left;
IF Rope.Equal["right", UserProfile.Token[key: "ColorDisplay.Side"], FALSE] THEN pos ← right;
WindowManager.StartColorViewers[screenPos: pos, bitsPerPixel: 8];
};
ResetButton[parent: parent];
IF mouseButton=blue THEN CreateAnInstance[];
}
ELSE {
--we do only open the viewer,
--because resetting can not reset already painted sliders...
IF viewer.iconic THEN ViewerOps.OpenIcon[viewer]
ELSE MessageWindow.Append["use the color editor tool", TRUE];
};
END;
ResetMapButton: Buttons.ButtonProc =
--Resets color map;
--does not touch patterns
BEGIN
UpdateAllSliders: PROC [my: Handle] =
BEGIN
w: Sliders.NormalizedSliderValue;
FOR layer: CARDINAL IN [0..7) DO
w ← color[layer].weight;
Sliders.SetContents[my.coefLayer[layer].bar, 0];
Sliders.SetContents[my.coefLayer[layer].bar, w];
Labels.Set[my.coefLayer[layer].value,
  Convert.RopeFromInt[Real.Fix[color[layer].weight*100]]];
ENDLOOP;
ButtonProcLayerInternal[0, my];
END;
--ResetMapButton
IF Check8BitMode[] THEN {
SetUserColor[];
ComputeColors[];
IF clientData#NIL THEN UpdateAllSliders[NARROW[clientData, Handle]];
};
END;
ButtonProcLayer: Buttons.ButtonProc =
BEGIN
data: DataForSpecialProc ← NARROW[clientData];
IF Check8BitMode[] THEN {
IF data.layer = 6 THEN RETURN; -- (transistor channel hack)
ButtonProcLayerInternal[data.layer, data.my];
}
END;
ButtonProcLayerInternal: PROC[layer: CARDINAL, my: Handle] =
BEGIN
SetPotar: PROC[layer: CARDINAL, my: Handle] =
BEGIN
IF layer = 6 THEN RETURN; -- channel hack
Sliders.SetContents[my.potarColor[0].bar, color[layer].r];
Sliders.SetContents[my.potarColor[1].bar, color[layer].g];
Sliders.SetContents[my.potarColor[2].bar, color[layer].b];
Labels.Set[my.potarColor[0].value, Convert.RopeFromInt[Real.Fix[color[layer].r*100]]];
Labels.Set[my.potarColor[1].value, Convert.RopeFromInt[Real.Fix[color[layer].g*100]]];
Labels.Set[my.potarColor[2].value, Convert.RopeFromInt[Real.Fix[color[layer].b*100]]];
END;
-- ButtonProcLayerInternal
indLayer ← layer+1;
SetPotar[layer, my];
Buttons.SetDisplayStyle[my.coefLayer[previndLayer-1].select, $BlackOnWhite];
Buttons.SetDisplayStyle[my.coefLayer[indLayer-1].select, $WhiteOnBlack];
previndLayer ← indLayer;
END;
CreateAnInstance: PROC[] =
--create an icon of the tool;
--does not change any color setup at initialization of the tool
BEGIN
nameLayerButton: ARRAY [0..7) OF Rope.ROPE ← ["dif", "imp", "m1", "m2", "pol", "sub", "tr"];
nameColorSlider: ARRAY [0..3) OF Rope.ROPE ← ["R", "G", "B"];
coefX: CARDINAL = 10;
coefDX: CARDINAL = 25;
coefDeltaX: CARDINAL = coefDX+4;
coefSelectY: CARDINAL = 5;
coefSelectDY: CARDINAL = 15;
coefValueY: CARDINAL = coefSelectY+coefSelectDY+3;
coefValueDY: CARDINAL = 15;
coefBarY: CARDINAL = coefValueY+coefValueDY;
firstButtonY: CARDINAL = 10;
buttonDY: CARDINAL = 15;
interButtonY: CARDINAL = 3;
buttonX: CARDINAL = coefX+7*coefDeltaX+15;
buttonDX: CARDINAL = 80;
firstSliderY: CARDINAL = 10;
sliderDY: CARDINAL = 20;
interSliderY: CARDINAL = 5;
labelX: CARDINAL = buttonX+buttonDX+10; -- R, G, B
labelDX: CARDINAL = 14;
label2X: CARDINAL = labelX+labelDX; -- number
label2DX: CARDINAL = 30;
sliderX: CARDINAL = label2X+label2DX;
my: Handle = NEW[AdjustColorRec];
IF ~ColorModeIs8[] THEN
TerminalIO.WriteRope["The nmos 8 bit color tool works only after you put the display in 8 bit mode\n"];
IF ViewerOps.FindViewer[caption]#NIL THEN {
TerminalIO.WriteRope[caption];
TerminalIO.WriteRope[" viewer already exits\n"];
RETURN
};
my.outer ← Containers.Create[[
name: caption,
iconic: TRUE,
icon: Icons.NewIconFromFile[CDIO.GetWorkingDirectory[NIL].Cat["Chipndale.icons"], 2],
column: left,
scrollable: FALSE
]];
my.height ← firstSliderY+3*(sliderDY+interSliderY);
-- create sliders for weights
FOR indLayer: CARDINAL IN [0..7) DO
wInit: REAL ← color[indLayer].weight;
my.coefLayer[indLayer].select ← Buttons.Create[
info: [
name: nameLayerButton[indLayer],
iconic: TRUE,
wx: coefX+indLayer*coefDeltaX,
wy: coefSelectY,
wh: coefSelectDY,
ww: coefDX,
parent: my.outer,
border: TRUE],
proc: ButtonProcLayer,
clientData: NEW[DataForSpecialProcRec ← [my: my, layer: indLayer]]
]; 
my.coefLayer[indLayer].value ← Labels.Create[ [
name: Convert.RopeFromInt[Real.Fix[wInit*100]], -- initial contents
iconic: TRUE,
wx: coefX+indLayer*coefDeltaX,
wy: coefValueY,
wh: coefValueDY,
ww: coefDX,
parent: my.outer,
border: TRUE
]];
my.coefLayer[indLayer].bar ← Sliders.Create[
info: [
name: nameLayerButton[indLayer],
iconic: TRUE,
parent: my.outer,
wx: coefX+indLayer*coefDeltaX,
wy: coefBarY,
wh: - 5, --guardY
ww: coefDX,
border: TRUE],
sliderProc: UpdateWeightSlider,
orientation: vertical,
value: wInit,
clientData: NEW[DataForSpecialProcRec ← [my: my, layer: indLayer]
]];
Containers.ChildYBound[my.outer, my.coefLayer[indLayer].bar];
ENDLOOP;
-- create command buttons
[] ← Buttons.Create[
info: [name: "reset all",
wx: buttonX,
wy: firstButtonY,
wh: buttonDY,
ww: buttonDX,
parent: my.outer,
border: TRUE],
proc: ResetButton,
clientData: my,
fork: TRUE
]; 
[] ← Buttons.Create[
info: [name: "reset map",
wx: buttonX,
wy: firstButtonY+buttonDY+interButtonY,
wh: buttonDY,
ww: buttonDX,
parent: my.outer,
border: TRUE],
proc: ResetMapButton,
clientData: my,
fork: TRUE
]; 
[] ← Buttons.Create[
info: [name: "reset pattern",
wx: buttonX,
wy: firstButtonY+2*(buttonDY+interButtonY),
wh: buttonDY,
ww: buttonDX,
parent: my.outer,
border: TRUE],
fork: TRUE,
proc: Init8Patterns
]; 
-- create sliders for rgb colors
FOR iColor: CARDINAL IN [0..3) DO
cInit: REALSELECT iColor FROM
0 => color[indLayer-1].r,
1 => color[indLayer-1].g,
2 => color[indLayer-1].b,
ENDCASE => ERROR;
[] ← Labels.Create[
info: [name: nameColorSlider[iColor],
parent: my.outer,
wx: labelX,
wy: firstSliderY+iColor*(sliderDY+interSliderY),
ww: labelDX,
wh: sliderDY,
border: TRUE
]];
my.potarColor[iColor].bar ← Sliders.Create[
info: [parent: my.outer,
wx: sliderX,
wy: firstSliderY+iColor*(sliderDY+interSliderY),
ww: 10,
wh: sliderDY],
sliderProc: UpdateColorSlider,
orientation: horizontal,
value: cInit,
clientData: NEW[DataForSpecialProcRec ← [my: my, layer: iColor]]
];
Containers.ChildXBound[my.outer, my.potarColor[iColor].bar];
my.potarColor[iColor].value ← Labels.Create[[
name: Convert.RopeFromInt[Real.Fix[cInit*100]], -- initial contents
wx: label2X,
wy: firstSliderY+iColor*(sliderDY+interSliderY),
ww: label2DX,
wh: sliderDY,
parent: my.outer,
border: TRUE
]];
ENDLOOP;
ViewerOps.SetOpenHeight[my.outer, my.height]; -- hint our desired height
ViewerOps.PaintViewer[my.outer, all];    -- reflect above change
Buttons.SetDisplayStyle[my.coefLayer[0].select, $WhiteOnBlack];
END;
SaturationComm: CDSequencer.CommandProc =
BEGIN
valueLayer: CARDINAL ← 1;
IF Check8BitMode[] THEN {
indLayer ← TerminalIO.RequestSelection[
label: "Layers",
choice: LIST["diff", "imp", "met1", "met2", "poly", "substrate", "channel", "from profile"]
];
IF indLayer = 0 THEN RETURN[];
IF indLayer < 8 THEN
BEGIN
valueLayer ← TerminalIO.RequestSelection[
label: "Values",
choice: LIST["Invisible", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Saturated"]
];
IF valueLayer = 0 THEN RETURN[];
color[indLayer-1].weight ← Real.Float[valueLayer-1]/10;
END
ELSE SetUserColor[];
ComputeColors[];
};
END;
ComputeColors: PROC[] =
--takes a color setting (weights and rgb values) and sets up the device
BEGIN
SetMap: PROC[index: CARDINAL, color: Color] = {
ColorMap.SetRGBColor[index, color.r, color.g, color.b]
};
Adjust: PROC [value, x: REAL] RETURNS [REAL] = {
RETURN[IF x>0 THEN value+((1-value)*x) ELSE value+(value)*x]
};
ComposeColor: PROC[c1: Color, ind: CARDINAL] RETURNS [c: Color] = {
c ← [
c1.r+color[ind].weight*color[ind].r,
c1.g+color[ind].weight*color[ind].g,
c1.b+color[ind].weight*color[ind].b,
c1.weight+color[ind].weight]
};
c: Color;
indBackgnd: CARDINAL;
IF ~ColorModeIs8[] THEN RETURN;
-- we need a better way, using Basics.* or similar to access the bits of the index
FOR i0: CARDINAL IN [0..2) DO
FOR i1: CARDINAL IN [0..2) DO
FOR i2: CARDINAL IN [0..2) DO
FOR i3: CARDINAL IN [0..2) DO
FOR i4: CARDINAL IN [0..2) DO
FOR i5: CARDINAL IN [0..2) DO
c ← [0, 0, 0, 0];
-- compute the weighted sum of colors
IF i0=1 THEN {c ← ComposeColor[c, 0]};
IF i1=1 THEN {c ← ComposeColor[c, 1]};
IF i2=1 THEN {c ← ComposeColor[c, 2]};
IF i3=1 THEN {c ← ComposeColor[c, 3]};
IF i4=1 THEN {c ← ComposeColor[c, 4]};
indBackgnd ← IF i5=1 THEN 5 ELSE 6;
indBackgnd ← 5;
IF c.weight=0 OR color[indBackgnd].weight>=20
THEN c ← ComposeColor[c, indBackgnd];
IF c.weight#0 THEN c ← [c.r/c.weight, c.g/c.weight, c.b/c.weight, c.weight];
-- force yellow on transistors
IF i0+--i1+--i4=2 THEN {
c.r ← Adjust[c.r, color[6].weight];
c.g ← Adjust[c.g, color[6].weight];
c.b ← Adjust[c.b, -color[6].weight]
};
-- detect forbidden overlaps and display them white
--IF THEN c ← [1, 1, 1, 0];
SetMap[--32*i5+--16*i4+8*i3+4*i2+2*i1+i0, c];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
SetMap[index: 64, color: color[6]];    -- [background]
SetMap[index: 128, color: [r:1, g:1, b:0]];   -- [channels]
SetMap[index: 255, color: [r:0, g:0, b:0]];   -- [black]
SetMap[index: 254, color: [r:1, g:0, b:0]];   -- [pure red]
SetMap[index: 253, color: [r:0, g:1, b:0]];   -- [pure green]
SetMap[index: 252, color: [r:0, g:0, b:1]];   -- [pure blue]
SetMap[index: 251, color: [r:1, g:1, b:0]];   -- [pure yellow]
SetMap[index: 250, color: [r:1, g:1, b:1]];   -- [pure white]
[] ← Terminal.SetColorCursorPresentation[Terminal.Current[], onesAreWhite];
END;
SetUserColor: PUBLIC PROC [] =
--makes a default color setup; reads user profile
--does not set up the device
BEGIN
color[0].weight ← Real.Float[UserProfile.Number[key: "Chipndale.green1Weight", default: 100]]/100;
color[0].r ← Real.Float[UserProfile.Number[key: "Chipndale.green1.r", default: 0]]/100;
color[0].g ← Real.Float[UserProfile.Number[key: "Chipndale.green1.g", default: 100]]/100;
color[0].b ← Real.Float[UserProfile.Number[key: "Chipndale.green1.b", default: 0]]/100;
color[1].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.impWeight", default: 40]]/100;
color[1].r ← Real.Float[UserProfile.Number[key: "Chipndale.imp.r", default: 100]]/100;
color[1].g ← Real.Float[UserProfile.Number[key: "Chipndale.imp.g", default: 100]]/100;
color[1].b ← Real.Float[UserProfile.Number[key: "Chipndale.imp.b", default: 0]]/100;
color[2].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.blueWeight", default: 50]]/100;
color[2].r ← Real.Float[UserProfile.Number[key: "Chipndale.blue.r", default: 0]]/100;
color[2].g ← Real.Float[UserProfile.Number[key: "Chipndale.blue.g", default: 0]]/100;
color[2].b ← Real.Float[UserProfile.Number[key: "Chipndale.blue.b", default: 100]]/100;
color[3].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.pinkWeight", default: 50]]/100;
color[3].r ← Real.Float[UserProfile.Number[key: "Chipndale.pink.r", default: 50]]/100;
color[3].g ← Real.Float[UserProfile.Number[key: "Chipndale.pink.g", default: 50]]/100;
color[3].b ← Real.Float[UserProfile.Number[key: "Chipndale.pink.b", default: 70]]/100;
color[4].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.redWeight", default: 100]]/100;
color[4].r ← Real.Float[UserProfile.Number[key: "Chipndale.red.r", default: 100]]/100;
color[4].g ← Real.Float[UserProfile.Number[key: "Chipndale.red.g", default: 20]]/100;
color[4].b ← Real.Float[UserProfile.Number[key: "Chipndale.red.b", default: 0]]/100;
color[5].weight ← Real.Float[UserProfile.Number[key: "Chipndale.backgndWeight", default: 10]]/100;
color[5].r ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.r", default: 40]]/100;
color[5].g ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.g", default: 50]]/100;
color[5].b ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.b", default: 50]]/100;

color[6].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.channelWeight", default: 30]]/100;
END;
CDNmosColorCommand: Commander.CommandProc =
BEGIN
CreateAnInstance[];
END;
NmosColorComm: PROC [comm: CDSequencer.Command] =
BEGIN
CreateAnInstance[];
END;
Init8Patterns[NIL];
SetUserColor[];
ComputeColors[];
CDSequencer.ImplementCommand[$SaturationComm, SaturationComm, NMos.nmos, doQueue];
CDSequencer.ImplementCommand[$ColorToolN, NmosColorComm, NMos.nmos, dontQueue];
CDMenus.CreateEntry[$DisplayMenu, "nmos 8 bit tool", $ColorToolN];
[] ← Buttons.Create[info: [name: "nmos col"], proc: ResetAndCreateButton];
Commander.Register[
 key: "CDNmosColor",
 proc: CDNmosColorCommand,
 doc: "nmos 8 bit color tool"
 ];
END.