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:
REAL ←
SELECT 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.