CDUserColorsImpl.mesa
Last Edited by: Monier, September 24, 1984 9:55:48 pm PDT
Last Edited by: Jacobi, October 29, 1984 5:46:54 pm PST
DIRECTORY
Buttons,
CDSequencer,
ColorMap,
ColorWorld,
Containers,
Convert,
GraphicsBasic,
GraphicsColor,
Icons,
Labels,
Real,
Rope,
MySliders,
Terminal,
TerminalIO,
UserProfile,
ViewerClasses,
ViewerOps,
WindowManager;
CDUserColorsImpl: CEDAR PROGRAM
IMPORTS Buttons, CDSequencer, ColorMap, ColorWorld, Containers, Convert, Icons, Labels, Real, MySliders, Terminal, TerminalIO, UserProfile, ViewerOps, WindowManager =
BEGIN
-- The basic colors
Color: TYPE = RECORD[r, g, b: REAL];
green1: Color = [r:0,  g:1,  b:0];  --1
green2: Color = [r:0,  g:1,  b:0];  --2
blue: Color =  [r:0,  g:0,  b:1];  --3
pink: Color =  [r:0.5,  g:0.5,  b:0.7];  --4
red: Color =  [r:1,  g:0.3,  b:0];  --5
yellow: Color = [r:0.6,  g:0.7,  b:0.4];  --6
backgnd: Color = [r:0.4,  g:0.5,  b:0.5 ];
black: Color = [r:0,  g:0,  b:0];
white: Color = [r:1,  g:1,  b:1]; -- error
indLayer, valueLayer, indColor, valueColor: CARDINAL ← 1;
-- The primary layer colors, initialized with the basic colors, optionally loaded from a special file, and editable by the user
primaryColors: ARRAY [0..8) OF Color; -- ← [green1, green2, blue, pink, red, yellow, backgnd];
-- 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.
weightColors: ARRAY [0..8) OF REAL;
-- for adjust colors
nameLayerButton: ARRAY [0..8) OF Rope.ROPE ← ["n+", "p+", "m1", "m2", "pol", "nW", "sub", "tr"];
nameColorSlider: ARRAY [0..3) OF Rope.ROPE ← ["red", "green", "blue"];
-- for placing the buttons, sliders and labels
guardX: CARDINAL = 5;
guardY: CARDINAL = 5;
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;
firstbcmdY: CARDINAL = 10;
bcmdDY: CARDINAL = 15;
interBcmd: CARDINAL = 3;
bcmdX: CARDINAL = 270;
bcmdDX: CARDINAL = 40;
firstSliderY: CARDINAL = 10;
sliderDY: CARDINAL = 20;
interSlider: CARDINAL = 5;
labelX: CARDINAL = bcmdX + 70;
labelDX: CARDINAL = 25;
sliderX: CARDINAL = labelDX+labelX;
CoefViewer: TYPE = RECORD [
value: Labels.Label ← NIL,
select: Buttons.Button ← NIL,
bar: MySliders.Slider ← NIL
];
CoefLayer: TYPE = ARRAY [0..8) OF CoefViewer;
ColorViewer: TYPE = RECORD [
value: Labels.Label ← NIL,
bar: MySliders.Slider ← NIL
];
PotarColor: TYPE = ARRAY [0..3) OF ColorViewer;
Handle: TYPE = REF AdjustColorRec;
AdjustColorRec: TYPE = RECORD [
outer: Containers.Container ← NIL,
coefLayer: CoefLayer,
potarColor: PotarColor,
height: CARDINAL ← 0  -- height measured from the top of the container
];
DataForSpecialProc: TYPE = REF DataForSpecialProcRec;
DataForSpecialProcRec:TYPE = RECORD [
my: Handle,
layer: CARDINAL
];
ColorMode8: PROC [] RETURNS [BOOL] = INLINE {
virtual: Terminal.Virtual = Terminal.Current[];
RETURN [virtual.hasColorDisplay AND ~virtual.GetColorMode[].full AND virtual.GetColorMode[].bitsPerPixelChannelA=8];
};
previndLayer: CARDINAL ← 1; -- to deselect the previous layer button
TwoToTheN: PROC[n: CARDINAL] RETURNS[p: ColorMap.Byte] =
{p ← 1; FOR i: CARDINAL IN [0..n) DO p ← p+p; ENDLOOP;};
IndexToColorInTable: PROC[index: CARDINAL] RETURNS[GraphicsBasic.Color] =
BEGIN
cool: RECORD [r, g, b: ColorMap.Byte];
IF ColorMode8[] THEN [cool.r, cool.g, cool.b] ← ColorMap.GetColor[index];
RETURN[GraphicsBasic.Color[r: cool.r, g: cool.g, b: cool.b]];
END;
LayerToColorInTable: PROC[layer: CARDINAL] RETURNS[GraphicsBasic.Color] =
BEGIN
cool: RECORD [r, g, b: ColorMap.Byte];
IF ColorMode8[] THEN [cool.r, cool.g, cool.b] ← ColorMap.GetColor[TwoToTheN[layer]];
RETURN[GraphicsBasic.Color[r: cool.r, g: cool.g, b: cool.b]];
END;
UpdateWeightSlider: MySliders.SliderProc =
BEGIN
datac: DataForSpecialProc ← NARROW[clientData];
my: Handle ← datac.my;
layer: CARDINAL ← datac.layer;
sliderData: MySliders.SliderData ← NARROW[slider.data];
IF ~ColorMode8[] THEN RETURN;
weightColors[layer] ← value;
ComputeColors;
sliderData.foreground ← LayerToColorInTable[layer];
Labels.Set[my.coefLayer[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]];
END;
UpdateAllSliders: PROC [my: Handle] =
BEGIN
w: MySliders.NormalizedSliderValue;
sliderData: MySliders.SliderData;
IF ~ColorMode8[] THEN RETURN;
ComputeColors[];
FOR layer: CARDINAL IN [0..8) DO
w ← weightColors[layer];
sliderData ← NARROW[my.coefLayer[layer].bar.data];
sliderData.foreground ← LayerToColorInTable[layer];
MySliders.SetContents[my.coefLayer[layer].bar, 0];
MySliders.SetContents[my.coefLayer[layer].bar, w];
Labels.Set[my.coefLayer[layer].value,
  Convert.RopeFromInt[Real.Fix[weightColors[layer]*100]]];
ENDLOOP;
ButtonProcLayerInternal[0, my];
END;
UpdateColorSlider: MySliders.SliderProc =
BEGIN
data: DataForSpecialProc ← NARROW[clientData];
my: Handle ← data.my;
layer: CARDINAL ← data.layer;
sliderData: MySliders.SliderData ← NARROW[slider.data];
IF ~ColorMode8[] THEN RETURN;
IF indLayer = 8 THEN RETURN; -- channel hack
Labels.Set[my.potarColor[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]];
SELECT layer FROM
0 => primaryColors[indLayer-1].r ← value;
1 => primaryColors[indLayer-1].g ← value;
2 => primaryColors[indLayer-1].b ← value;
ENDCASE=> ERROR;
ComputeColors[];
END;
ResetButton: Buttons.ButtonProc =
BEGIN
my: Handle = NARROW[clientData];
IF ~ColorMode8[] THEN RETURN;
SetUserColor[];
UpdateAllSliders[my];
END;
Set8BitMode: Buttons.ButtonProc =
BEGIN
IF ColorMode8[] OR ~ColorWorld.HasMode[8] THEN RETURN;
IF WindowManager.colorDisplayOn THEN WindowManager.StopColorViewers[];
WindowManager.StartColorViewers[
screenPos: (IF mouseButton=red THEN left ELSE right),
bitsPerPixel: 8];
END;
ButtonProcLayer: Buttons.ButtonProc =
BEGIN
data: DataForSpecialProc ← NARROW[clientData];
layer: CARDINAL ← data.layer;
IF ~ColorMode8[] THEN RETURN;
IF layer = 7 THEN RETURN; -- (transistor channel hack)
ButtonProcLayerInternal[layer, data.my];
END;
ButtonProcLayerInternal: PROC[layer: CARDINAL, my: Handle] =
BEGIN
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;
SetPotar: PROC[layer: CARDINAL, my: Handle] =
BEGIN
IF layer = 7 THEN RETURN; -- channel hack
MySliders.SetContents[my.potarColor[0].bar, primaryColors[layer].r];
MySliders.SetContents[my.potarColor[1].bar, primaryColors[layer].g];
MySliders.SetContents[my.potarColor[2].bar, primaryColors[layer].b];
Labels.Set[my.potarColor[0].value, Convert.RopeFromInt[Real.Fix[primaryColors[layer].r*100]]];
Labels.Set[my.potarColor[1].value, Convert.RopeFromInt[Real.Fix[primaryColors[layer].g*100]]];
Labels.Set[my.potarColor[2].value, Convert.RopeFromInt[Real.Fix[primaryColors[layer].b*100]]];
END;
CreateAnInstance: PROC[] =
BEGIN
my: Handle = NEW[AdjustColorRec];
my.outer ← Containers.Create[ [
name: "cmos color editor",
iconic: TRUE,
icon: Icons.NewIconFromFile["Chipndale.icons", 2],
column: left,
scrollable: FALSE ] ];
my.height ← firstSliderY+3*(sliderDY+interSlider);
-- create sliders for weights
FOR indLayer: CARDINAL IN [0..8) DO
wInit: REAL ← weightColors[indLayer];
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]]]; -- this will be passed to our button proc
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 ← MySliders.Create[
info: [
name: nameLayerButton[indLayer],
iconic: TRUE,
parent: my.outer,
wx: coefX+indLayer*coefDeltaX,
wy: coefBarY,
wh: - guardY,
ww: coefDX,
border: TRUE],
sliderProc: UpdateWeightSlider,
orientation: vertical,
foreground: LayerToColorInTable[indLayer],
background: GraphicsColor.white,
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",
wx: bcmdX,
wy: firstbcmdY,
wh: bcmdDY,
ww: bcmdDX,
parent: my.outer,
border: TRUE],
guarded: TRUE,
proc: ResetButton,
clientData: my
]; 
[] ← Buttons.Create[
info: [
name: "8 bit/pixel",
wx: bcmdX,
wy: firstbcmdY+bcmdDY+interBcmd,
wh: bcmdDY,
ww: bcmdDX,
parent: my.outer,
border: TRUE],
guarded: TRUE,
proc: Set8BitMode
]; 
-- create sliders for colors
FOR iColor: CARDINAL IN [0..3) DO
cInit: REALSELECT iColor FROM
0 => primaryColors[indLayer-1].r,
1 => primaryColors[indLayer-1].g,
2 => primaryColors[indLayer-1].b,
ENDCASE => ERROR;
my.potarColor[iColor].bar ← MySliders.Create[
info: [name: nameColorSlider[iColor],
iconic: TRUE,
parent: my.outer,
wx: sliderX,
wy:firstSliderY+iColor*(sliderDY+interSlider),
ww:10,
wh: sliderDY],
sliderProc: UpdateColorSlider,
orientation: horizontal,
foreground: IndexToColorInTable[254-iColor],
background: GraphicsColor.white,
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: labelX,
wy: firstSliderY+iColor*(sliderDY+interSlider),
ww: labelDX,
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;
RunLayerMenu: CDSequencer.CommandProc =
BEGIN -- space-L
indLayer ← TerminalIO.RequestSelection[
label: "Layers",
choice: LIST["n-diff", "p-diff", "met1", "met2", "poly", "nWell", "substrate", "channel", "from profile"]
];
IF ~ColorMode8[] THEN RETURN;
IF indLayer = 0 THEN RETURN[];
IF indLayer < 9 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[];
weightColors[indLayer-1] ← Real.Float[valueLayer-1]/10;
END
ELSE SetUserColor[];
ComputeColors[];
END;
ComputeColors: PROC[] =
BEGIN
DefineColor: PROC[index: CARDINAL ← 0, color: Color] =
{ColorMap.SetRGBColor[index, color.r, color.g, color.b]};
AdjustColor: 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+weightColors[ind]*primaryColors[ind].r,
c1.g+weightColors[ind]*primaryColors[ind].g,
c1.b+weightColors[ind]*primaryColors[ind].b]};
c: Color ← black;
sumWeight: REAL;
indBackgnd: CARDINAL;
IF ~ColorMode8[] 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 ← black; -- we start with r=g=b=0
sumWeight ← 0;
-- compute the weighted sum of colors
IF i0=1 THEN {c ← ComposeColor[c, 0];
sumWeight ← sumWeight+weightColors[0]};
IF i1=1 THEN {c ← ComposeColor[c, 1];
sumWeight ← sumWeight+weightColors[1]};
IF i2=1 THEN {c ← ComposeColor[c, 2];
sumWeight ← sumWeight+weightColors[2]};
IF i3=1 THEN {c ← ComposeColor[c, 3];
sumWeight ← sumWeight+weightColors[3]};
IF i4=1 THEN {c ← ComposeColor[c, 4];
sumWeight ← sumWeight+weightColors[4]};
indBackgnd ← IF i5=1 THEN 5 ELSE 6;
c ← ComposeColor[c, indBackgnd];
sumWeight ← sumWeight+weightColors[indBackgnd];
IF sumWeight#0 THEN c ← [c.r/sumWeight, c.g/sumWeight, c.b/sumWeight];
-- force yellow on transistors
IF i0+i1+i4=2 THEN {c.r ← AdjustColor[c.r, weightColors[7]]; c.g ← AdjustColor[c.g, weightColors[7]]; c.b ← AdjustColor[c.b, -weightColors[7]]};
-- detect forbidden overlaps and display them white
IF i0+i1=2 OR i0+i5=2 THEN c ← white;
DefineColor[32*i5+16*i4+8*i3+4*i2+2*i1+i0, c];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
DefineColor[index: 64, color: primaryColors[6]];     -- [background]
DefineColor[index: 128, color: [r:1, g:1, b:0]];   -- [channels]
DefineColor[index: 255, color: black];     -- [black]
DefineColor[index: 254, color: [r:1, g:0, b:0]];   -- [pure red]
DefineColor[index: 253, color: [r:0, g:1, b:0]];   -- [pure green]
DefineColor[index: 252, color: [r:0, g:0, b:1]];   -- [pure blue]
DefineColor[index: 251, color: [r:1, g:1, b:0]];   -- [pure yellow]
END;
SetUserColor: PUBLIC PROC [] =
BEGIN
weightColors[0] ← Real.Float[UserProfile.Number[key: "Chipndale.green1Weight", default: 100]]/100;
primaryColors[0].r ← Real.Float[UserProfile.Number[key: "Chipndale.green1.r", default: 0]]/100;
primaryColors[0].g ← Real.Float[UserProfile.Number[key: "Chipndale.green1.g", default: 100]]/100;
primaryColors[0].b ← Real.Float[UserProfile.Number[key: "Chipndale.green1.b", default: 0]]/100;
weightColors[1] ←
Real.Float[UserProfile.Number[key: "Chipndale.green2Weight", default: 100]]/100;
primaryColors[1].r ← Real.Float[UserProfile.Number[key: "Chipndale.green2.r", default: 0]]/100;
primaryColors[1].g ← Real.Float[UserProfile.Number[key: "Chipndale.green2.g", default: 100]]/100;
primaryColors[1].b ← Real.Float[UserProfile.Number[key: "Chipndale.green2.b", default: 0]]/100;
weightColors[2] ←
Real.Float[UserProfile.Number[key: "Chipndale.blueWeight", default: 50]]/100;
primaryColors[2].r ← Real.Float[UserProfile.Number[key: "Chipndale.blue.r", default: 0]]/100;
primaryColors[2].g ← Real.Float[UserProfile.Number[key: "Chipndale.blue.g", default: 0]]/100;
primaryColors[2].b ← Real.Float[UserProfile.Number[key: "Chipndale.blue.b", default: 100]]/100;
weightColors[3] ←
Real.Float[UserProfile.Number[key: "Chipndale.pinkWeight", default: 50]]/100;
primaryColors[3].r ← Real.Float[UserProfile.Number[key: "Chipndale.pink.r", default: 50]]/100;
primaryColors[3].g ← Real.Float[UserProfile.Number[key: "Chipndale.pink.g", default: 50]]/100;
primaryColors[3].b ← Real.Float[UserProfile.Number[key: "Chipndale.pink.b", default: 70]]/100;
weightColors[4] ←
Real.Float[UserProfile.Number[key: "Chipndale.redWeight", default: 100]]/100;
primaryColors[4].r ← Real.Float[UserProfile.Number[key: "Chipndale.red.r", default: 100]]/100;
primaryColors[4].g ← Real.Float[UserProfile.Number[key: "Chipndale.red.g", default: 20]]/100;
primaryColors[4].b ← Real.Float[UserProfile.Number[key: "Chipndale.red.b", default: 0]]/100;
weightColors[5] ←
Real.Float[UserProfile.Number[key: "Chipndale.yellowWeight", default: 30]]/100;
primaryColors[5].r ← Real.Float[UserProfile.Number[key: "Chipndale.yellow.r", default: 60]]/100;
primaryColors[5].g ← Real.Float[UserProfile.Number[key: "Chipndale.yellow.g", default: 70]]/100;
primaryColors[5].b ← Real.Float[UserProfile.Number[key: "Chipndale.yellow.b", default: 40]]/100;
weightColors[6] ←
Real.Float[UserProfile.Number[key: "Chipndale.backgndWeight", default: 30]]/100;
primaryColors[6].r ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.r", default: 40]]/100;
primaryColors[6].g ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.g", default: 50]]/100;
primaryColors[6].b ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.b", default: 50]]/100;

weightColors[7] ←
Real.Float[UserProfile.Number[key: "Chipndale.channelWeight", default: 30]]/100;
END;

adjustColorClass: ViewerClasses.ViewerClass = NEW[ViewerClasses.ViewerClassRec ← []];
ViewerOps.RegisterViewerClass[$VAdjustColor, adjustColorClass];
SetUserColor[];
ComputeColors[];
CreateAnInstance[];
CDSequencer.ImplementCommand[$RunLayerMenu, RunLayerMenu,, doQueue];
END.