<> <> <> 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.