<> <> <> <> <> DIRECTORY Basics, Buttons, CD, CDColors, CDEnvironment, CDSequencer, CMosB, Commander, Containers, Convert, Imager, ImagerColor, ImagerColorMap, ImagerDitherContext, InterminalBackdoor, Icons, Labels, PopUpSelection, Process, Real, Rope, Sliders, Terminal, TerminalIO, UserProfile, ViewerOps, ViewerClasses; CDCMosB8BitColors: CEDAR PROGRAM IMPORTS Basics, Buttons, CDColors, CDEnvironment, CDSequencer, CMosB, Commander, Containers, Convert, Icons, ImagerColor, ImagerColorMap, --ImagerDitherContext,-- InterminalBackdoor, Labels, PopUpSelection, Process, Real, Rope, Sliders, Terminal, TerminalIO, UserProfile, ViewerOps = BEGIN <<>> terminal: Terminal.Virtual _ InterminalBackdoor.terminal; <<>> <<--**color device**************************************>> useMapEntries: ImagerDitherContext.MapEntries _ NIL; ForceColors: PROC [mapEntries: ImagerDitherContext.MapEntries] = { useMapEntries _ mapEntries; ImagerColorMap.LoadEntries[vt: terminal, mapEntries: mapEntries, gamma: 1, shared: FALSE]; [] _ Terminal.SetColorCursorPresentation[terminal, onesAreWhite]; }; <<--**end color device**************************************>> ColorRec: TYPE = RECORD[r, g, b, w: REAL _ 0, name: Rope.ROPE _ NIL]; <<--w is a wight; The color of an intersection (i.e. green1 over blue) is the >> <<--weighted sum of the rgb of each color.>> ColorDescRep: TYPE = ARRAY [0..numberOfColors) OF ColorRec; <<--index 0 is supposed to be background>> Exception: TYPE = RECORD [x: CARDINAL, c: ColorRec, replace: BOOL _ TRUE]; <<--XXXXXXXXXXXXXXXX TECHNOLOGY XXXXXXXXXXXXXXXX>> technology: CD.Technology _ CMosB.cmosB; technologyName: Rope.ROPE _ technology.name; numberOfColors: INT = 9; --background, normal colors and extra colors numberOfNormalColors: INT = 7; --without background and extra colors cDefaults: REF ColorDescRep _ NEW[ColorDescRep _ [ [0.49, 0.62, 0.62, 0.05, "Sub"], --background [0, 1, 0, 1, "pD"], [0, 1, 0, 1, "nD"], [0.5, 0.5, 1, 0.5, "m1"], [0.7, 0.4, 0.7, 0.4, "m2"], [1, 0.2, 0, 1, "pol"], [0.8, 0.8, 0.5, 0.15, "nW"], [0.60, 0.70, 0.75, 0.15, "pW"], [1, 0.95, 0.0, 0.9, "Xx"] --channel hack ]]; channelX: INT _ 8; SetupSpecials: PROC [] = BEGIN cc: ColorRec _ currentColor[8]; --channel hack x: INT _ channelX+1; specials1 _ LIST[ [x: 1+16, c: [cc.r, cc.g, -cc.b, x*cc.w-1], replace: FALSE], --yellow on transistor [x: 2+16, c: [cc.r, cc.g, -cc.b, x*cc.w-1], replace: FALSE], --yellow on transistor [x: 32+64, c: [1, 1, 1, 1], replace: TRUE], --hack white error message [x: 1+32, c: [1, 1, 1, 1], replace: TRUE], --hack white error message [x: 2+64, c: [1, 1, 1, 1], replace: TRUE], --hack white error message [x: 127, c: [0, 0, 0, 1], replace: TRUE] --black for cuts ]; specials2 _ LIST[ [x: 2, c: [1, 1, 1, 1], replace: TRUE], --pdiff without well [x: 1+2, c: [0.8, 0.8, 0.8, 1], replace: TRUE] --light grey for inverted white ]; specials3 _ LIST[ [x: 245, c: [0, 0, 1, 1]], --get all nice colors back for other users [x: 247, c: [0, 1, 0, 1]], [x: 249, c: [0, 1, 1, 1]], [x: 250, c: [1, 0, 1, 1]], [x: 251, c: [1, 1, 0, 1]], [x: 252, c: [1, 1, 1, 1]], --white as opposite to 1+2 [x: 254, c: [1, 0, 0, 1]], IF whiteOutLine THEN Exception[x: 255, c: [1, 1, 1, 1]] ELSE Exception[x: 255, c: [0, 0, 0, 1]] --all bits set ]; END; Init8Patterns: Buttons.ButtonProc = <<--all parameter are discarded >> BEGIN nDiffColor: CARDINAL = 1; pDiffColor: CARDINAL = 2; met1Color: CARDINAL = 4; met2Color: CARDINAL = 8; polyColor: CARDINAL = 16; nWellColor: CARDINAL = 32; pWellColor: CARDINAL = 64; black: CARDINAL = 127; 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, pushedOut]; END; Full8: PROC[color: CARDINAL] RETURNS [b: REF CDColors.Brick] = BEGIN RETURN[Checker8[color, color]] END; CDColors.DefineColor[CMosB.ndif, Full8[nDiffColor], bit8]; CDColors.DefineColor[CMosB.pdif, Full8[pDiffColor], bit8]; CDColors.DefineColor[CMosB.met, Full8[met1Color], bit8]; CDColors.DefineColor[CMosB.met2, Full8[met2Color], bit8]; CDColors.DefineColor[CMosB.pol, Full8[polyColor], bit8]; CDColors.DefineColor[CMosB.nwell, Full8[nWellColor], bit8]; CDColors.DefineColor[CMosB.pwell, Full8[pWellColor], bit8]; CDColors.DefineColor[CMosB.cut, Full8[black], bit8]; CDColors.DefineColor[CMosB.cut2, Checker8[black, met1Color], bit8]; CDColors.DefineColor[CMosB.bur, Checker8[black, 0], bit8]; CDColors.DefineColor[CMosB.nwellCont, Checker8[pDiffColor, met1Color], bit8]; CDColors.DefineColor[CMosB.pwellCont, Checker8[nDiffColor, met1Color], bit8]; CDColors.DefineColor[CMosB.ovg, Checker8[met1Color, met2Color], bit8]; CDColors.DefineColor[CMosB.imp, NEW[CDColors.Brick_[14, 14, 0, 0]], bit8]; CDColors.DefineColor[CD.backgroundLayer, NEW[CDColors.Brick _ [8, 0, 256*8, 0]], bit8]; CDColors.DefineColor[CD.errorLayer, NEW[CDColors.Brick _ [255, 0, 0, 0]], bit8]; CDColors.DefineColor[CD.shadeLayer, NEW[CDColors.Brick_[0, 255,0 , 255]], bit8]; DefineDimmer8[CMosB.ndif, nDiffColor]; DefineDimmer8[CMosB.pdif, pDiffColor]; DefineDimmer8[CMosB.met, met1Color]; DefineDimmer8[CMosB.met2, met2Color]; DefineDimmer8[CMosB.pol, polyColor]; DefineDimmer8[CMosB.nwell, nWellColor]; DefineDimmer8[CMosB.cut, black]; DefineDimmer8[CMosB.cut2, black]; <<-- no change for bur, nwelCont, pwelCont, and ovgc for this background>> END; HackContextColors: PROC [] = BEGIN SetFilter[CMosB.ndif, 1]; SetFilter[CMosB.pdif, 2]; SetFilter[CMosB.met, 3]; SetFilter[CMosB.met2, 4]; SetFilter[CMosB.pol, 5]; SetFilter[CMosB.nwell, 6]; SetFilter[CMosB.pwell, 7]; END; <<>> <<--XXXXX end technology XXXXXXXXXXXXXXXXXXXXX>> whiteOutLine: BOOL; currentColor: REF ColorDescRep = NEW[ColorDescRep]; curLayer: INT _ 1; prevLayer: INT _ 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..numberOfColors) 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 ]; caption: Rope.ROPE = Rope.Concat[technologyName, " 8 bit color editor"]; ColorModeIs8: PROC [] RETURNS [BOOL] = INLINE BEGIN RETURN [terminal.hasColorDisplay AND ~terminal.GetColorMode[].full AND terminal.GetColorMode[].bitsPerPixelChannelA=8]; END; Check8BitMode: PROC [] RETURNS [ok: BOOL] = BEGIN ok _ ColorModeIs8[]; IF ~ok THEN TRUSTED{Process.Detach[FORK TerminalIO.PutRope["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; currentColor[layer].w _ 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; Labels.Set[my.potarColor[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]]; SELECT layer FROM 0 => currentColor[curLayer-1].r _ value; 1 => currentColor[curLayer-1].g _ value; 2 => currentColor[curLayer-1].b _ value; ENDCASE => ERROR; ComputeColors[]; END; ResetButton: Buttons.ButtonProc = BEGIN Init8Patterns[parent: parent, clientData: clientData]; ResetMapButton[parent: parent, clientData: clientData]; END; XSelection: Buttons.ButtonProc = BEGIN whiteOutLine _ ~whiteOutLine; ComputeColors[]; END; ResetMapButton: Buttons.ButtonProc = <<--Resets color map;>> <<--does not touch patterns>> BEGIN UpdateAllSliders: PROC [my: Handle] = BEGIN w: Sliders.NormalizedSliderValue; IF my=NIL OR my.outer=NIL OR my.outer.destroyed THEN RETURN; FOR layer: INT IN [0..numberOfColors) DO w _ currentColor[layer].w; Sliders.SetContents[my.coefLayer[layer].bar, 0]; Sliders.SetContents[my.coefLayer[layer].bar, w]; Labels.Set[my.coefLayer[layer].value, Convert.RopeFromInt[Real.Fix[currentColor[layer].w*100]]]; ENDLOOP; ButtonProcLayerInternal[0, my]; END; <<>> <<--ResetMapButton>> IF Check8BitMode[] THEN { ReadProfileColors[]; ComputeColors[]; IF clientData#NIL THEN UpdateAllSliders[NARROW[clientData, Handle]]; }; END; ButtonProcLayer: Buttons.ButtonProc = BEGIN data: DataForSpecialProc _ NARROW[clientData]; IF Check8BitMode[] THEN { ButtonProcLayerInternal[data.layer, data.my]; } END; ButtonProcLayerInternal: PROC[layer: CARDINAL, my: Handle] = BEGIN SetPotar: PROC[layer: CARDINAL, my: Handle] = BEGIN Sliders.SetContents[my.potarColor[0].bar, currentColor[layer].r]; Sliders.SetContents[my.potarColor[1].bar, currentColor[layer].g]; Sliders.SetContents[my.potarColor[2].bar, currentColor[layer].b]; Labels.Set[my.potarColor[0].value, Convert.RopeFromInt[Real.Fix[currentColor[layer].r*100]]]; Labels.Set[my.potarColor[1].value, Convert.RopeFromInt[Real.Fix[currentColor[layer].g*100]]]; Labels.Set[my.potarColor[2].value, Convert.RopeFromInt[Real.Fix[currentColor[layer].b*100]]]; END; <<>> <<-- ButtonProcLayerInternal>> curLayer _ layer+1; SetPotar[layer, my]; Buttons.SetDisplayStyle[my.coefLayer[prevLayer-1].select, $BlackOnWhite]; Buttons.SetDisplayStyle[my.coefLayer[curLayer-1].select, $WhiteOnBlack]; prevLayer _ curLayer; END; CreateAnInstance: PROC[] = <<--create an icon of the tool;>> <<--does not change any color setup at initialization of the tool>> BEGIN nameColorSlider: ARRAY [0..3) OF Rope.ROPE _ ["R", "G", "B"]; coefX: CARDINAL = 10; coefDX: CARDINAL = 25; coefDeltaX: CARDINAL = coefDX+4; coefSelectY: CARDINAL = 3; coefSelectDY: CARDINAL = 15; coefValueY: CARDINAL = coefSelectY+coefSelectDY+3; coefValueDY: CARDINAL = 15; coefBarY: CARDINAL = coefValueY+coefValueDY; firstButtonY: CARDINAL = 3; buttonX: CARDINAL = coefX+numberOfColors*coefDeltaX+8; buttonDX: CARDINAL = 80; firstSliderY: CARDINAL = 6; sliderDY: CARDINAL = 22; interSliderY: CARDINAL = 6; 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]; buttonWy: CARDINAL _ firstButtonY; NextButton: PROC [name: Rope.ROPE, proc: Buttons.ButtonProc] = BEGIN buttonDY: CARDINAL = 15; interButtonY: CARDINAL = 2; [] _ Buttons.Create[ info: [name: name, wx: buttonX, wy: buttonWy, wh: buttonDY, ww: buttonDX, parent: my.outer, border: TRUE], proc: proc, clientData: my, fork: TRUE ]; buttonWy _ buttonWy+buttonDY+interButtonY; END; IF ~ColorModeIs8[] THEN TerminalIO.PutRope["set display in 8 bit mode first\n"]; IF ViewerOps.FindViewer[caption]#NIL THEN { TerminalIO.PutRopes[caption, " viewer already exits\n"]; RETURN }; my.outer _ Containers.Create[[ name: caption, iconic: TRUE, icon: Icons.NewIconFromFile[Rope.Cat[CDEnvironment.GetWorkingDirectory[NIL], "Chipndale.icons"], 2], column: left, scrollable: FALSE ]]; my.height _ firstSliderY+3*(sliderDY+interSliderY); <<-- create sliders for weights>> FOR curLayer: INT IN [0..numberOfColors) DO wInit: REAL _ currentColor[curLayer].w; my.coefLayer[curLayer].select _ Buttons.Create[ info: [ name: cDefaults[curLayer].name, iconic: TRUE, wx: coefX+curLayer*coefDeltaX, wy: coefSelectY, wh: coefSelectDY, ww: coefDX, parent: my.outer, border: TRUE], proc: ButtonProcLayer, clientData: NEW[DataForSpecialProcRec _ [my: my, layer: curLayer]] ]; my.coefLayer[curLayer].value _ Labels.Create[ [ name: Convert.RopeFromInt[Real.Fix[wInit*100]], -- initial contents iconic: TRUE, wx: coefX+curLayer*coefDeltaX, wy: coefValueY, wh: coefValueDY, ww: coefDX, parent: my.outer, border: TRUE ]]; my.coefLayer[curLayer].bar _ Sliders.Create[ info: [ name: cDefaults[curLayer].name, iconic: TRUE, parent: my.outer, wx: coefX+curLayer*coefDeltaX, wy: coefBarY, wh: -5, --guardY ww: coefDX, border: TRUE], sliderProc: UpdateWeightSlider, orientation: vertical, value: wInit, clientData: NEW[DataForSpecialProcRec _ [my: my, layer: curLayer] ]]; Containers.ChildYBound[my.outer, my.coefLayer[curLayer].bar]; ENDLOOP; <<>> <<-- create command buttons>> NextButton["reset all", ResetButton]; NextButton["reset map", ResetMapButton]; NextButton["reset pattern", Init8Patterns]; NextButton["X Selection", XSelection]; <<>> <<-- create sliders for rgb colors>> FOR iColor: CARDINAL IN [0..3) DO cInit: REAL _ SELECT iColor FROM 0 => currentColor[curLayer-1].r, 1 => currentColor[curLayer-1].g, 2 => currentColor[curLayer-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 sat: CARDINAL _ 1; IF Check8BitMode[] THEN { list: LIST OF Rope.ROPE _ LIST["from profile"]; FOR i: INT DECREASING IN [0..numberOfColors) DO list _ CONS[cDefaults[i].name, list] ENDLOOP; curLayer _ PopUpSelection.Request[header: "Layers", choice: list]; IF curLayer=0 THEN RETURN[]; IF curLayer<=numberOfColors THEN { sat _ PopUpSelection.Request[ header: "Values", choice: LIST["Invisible", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Saturated"] ]; IF sat = 0 THEN RETURN[]; currentColor[curLayer-1].w _ Real.Float[sat-1]/10; } ELSE ReadProfileColors[]; ComputeColors[]; }; END; specials1: LIST OF Exception _ NIL; --specials in the range of stipples [use for any comb] specials2: LIST OF Exception _ NIL; --specials in the range of stipples [use for exact comb] specials3: LIST OF Exception _ NIL; --specials to be considered later ComputeColors: PROC[] = <<--takes a color setting (weights and rgb values) and sets up the device>> BEGIN ComposeColor: PROC[c1, wc2: ColorRec] RETURNS [c: ColorRec] = <<--c1 not weighted; wc2 weighted>> INLINE BEGIN w: REAL _ wc2.w; c _ [c1.r+w*wc2.r, c1.g+w*wc2.g, c1.b+w*wc2.b, c1.w+w] END; SetMap: PROC[index: CARDINAL, color: ColorRec] = BEGIN RtoC: PROC [r: REAL] RETURNS [c: [0..256)] = INLINE { c _ MAX[MIN[Real.Round[r*255], 255], 0] }; mapEntrie: ImagerColorMap.MapEntry _ [index, RtoC[color.r], RtoC[color.g], RtoC[color.b]]; mapEntries _ CONS[mapEntrie, mapEntries]; END; mapEntries: LIST OF ImagerColorMap.MapEntry _ NIL; c: ColorRec; bits: CARDINAL _ numberOfNormalColors; power: CARDINAL _ Basics.BITSHIFT[1, bits]; IF ~ColorModeIs8[] THEN RETURN; SetupSpecials[]; <<--colors in the range of layers>> FOR i: CARDINAL IN [0..power) DO c _ [0, 0, 0, 0]; <<--bit loop>> FOR bit: CARDINAL IN [0..bits) DO IF Basics.BITAND[i, Basics.BITSHIFT[1, bit]]#0 THEN { c _ ComposeColor[c, currentColor[bit+1]]; }; ENDLOOP; <<--check exception loops>> FOR list: LIST OF Exception _ specials1, list.rest WHILE list#NIL DO IF Basics.BITAND[i, list.first.x]=list.first.x THEN { IF list.first.replace THEN c _ list.first.c ELSE c _ ComposeColor[c, list.first.c]; }; ENDLOOP; FOR list: LIST OF Exception _ specials2, list.rest WHILE list#NIL DO IF i=list.first.x THEN { IF list.first.replace THEN c _ list.first.c ELSE c _ ComposeColor[c, list.first.c]; }; ENDLOOP; <<--assign color>> IF c.w<0.2 THEN c _ ComposeColor[c, currentColor[0]]; IF c.w=0 THEN c _ currentColor[0] ELSE c _ [c.r/c.w, c.g/c.w, c.b/c.w, 0]; SetMap[i, c]; ENDLOOP; <<--include further colors from exception loop>> FOR list: LIST OF Exception _ specials3, list.rest WHILE list#NIL DO IF list.first.x>=power THEN SetMap[list.first.x, list.first.c]; ENDLOOP; ForceColors[mapEntries: mapEntries]; HackContextColors[]; END; SetFilter: PROC [layer: CD.Layer, i: INT] = { CDColors.DefineIColor[layer: layer, col: ImagerColor.ColorFromRGB[[R: currentColor[i].r, G: currentColor[i].g, B: currentColor[i].b]], display: bit8 ]; }; ReadProfileColors: PUBLIC PROC [] = BEGIN DefaultColor: PROC [def: ColorRec] RETURNS [c: ColorRec] = BEGIN r: Rope.ROPE _ Rope.Cat["ChipNDale.", technologyName, ".", def.name]; c.w _ Real.Float[UserProfile.Number[key: r.Concat[".w"], default: Real.Round[def.w*100]]]/100; c.r _ Real.Float[UserProfile.Number[key: r.Concat[".r"], default: Real.Round[def.r*100]]]/100; c.g _ Real.Float[UserProfile.Number[key: r.Concat[".g"], default: Real.Round[def.g*100]]]/100; c.b _ Real.Float[UserProfile.Number[key: r.Concat[".b"], default: Real.Round[def.b*100]]]/100; END; FOR i: INT IN [0..numberOfColors) DO currentColor[i] _ DefaultColor[cDefaults[i]]; ENDLOOP; whiteOutLine _ UserProfile.Boolean[ key: Rope.Cat["ChipNDale." , technologyName, ".WhiteOutline"], default: TRUE ]; END; ColorCommand: Commander.CommandProc = { CreateAnInstance[]; }; ColorComm: PROC [comm: CDSequencer.Command] = { CreateAnInstance[]; }; Init8Patterns[NIL]; ReadProfileColors[]; IF UserProfile.Boolean[Rope.Cat["ChipNDale.", technologyName, ".StartColorMap8"], ~Rope.Equal[technologyName, "chipnsil", FALSE]] THEN ComputeColors[]; CDSequencer.ImplementCommand[$SaturationComm, SaturationComm, technology, doQueue]; CDSequencer.ImplementCommand[$ColorTool, ColorComm, technology, dontQueue]; Commander.Register[ key: Rope.Cat["CD", technologyName, "8BitColors"], proc: ColorCommand, doc: Rope.Concat[technologyName, " 8 bit color tool"] ]; END.