NMos8BitColors.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Jacobi, October 29, 1984 5:46:54 pm PST
Last Edited by: Jacobi, March 19, 1986 12:58:18 pm PST
Last edited by: Christian Jacobi, August 25, 1986 12:36:20 pm PDT
DIRECTORY
Basics,
Buttons,
CD,
CDCommandOpsExtras2,
CDColors,
CDIO,
CDSequencer,
NMos,
Commander,
Containers,
Convert,
Imager,
ImagerColorMap,
ImagerDitherContext,
ImagerTerminal,
InterminalBackdoor,
Icons,
Labels,
MessageWindow,
Process,
Real,
Rope,
Sliders,
Terminal,
TerminalIO,
UserProfile,
ViewerOps,
ViewerClasses,
ViewerPrivate,
WindowManager;
NMos8BitColors: CEDAR PROGRAM
IMPORTS Basics, Buttons, CDColors, CDCommandOpsExtras2, CDIO, CDSequencer, NMos, Commander, Containers, Convert, Icons, ImagerColorMap, ImagerDitherContext, ImagerTerminal, InterminalBackdoor, Labels, MessageWindow, Process, Real, Rope, Sliders, Terminal, TerminalIO, UserProfile, ViewerOps, ViewerPrivate, WindowManager =
BEGIN
terminal: Terminal.Virtual ← InterminalBackdoor.terminal;
--**color device**************************************
useMapEntries: ImagerDitherContext.MapEntries ← NIL;
ContextCreator: ViewerPrivate.ContextCreatorProc =
BEGIN
context: Imager.Context;
SELECT screen FROM
bw => context ← ImagerTerminal.BWContext[vt: terminal, pixelUnits: TRUE];
color => {
context ← ImagerTerminal.ColorContext[vt: terminal, pixelUnits: TRUE];
IF useMapEntries#NIL THEN
ImagerDitherContext.SetDitherMap[context, useMapEntries];
--experimenting showed that the following line was necessary....
[] ← Terminal.SetColorCursorPresentation[terminal, onesAreWhite];
}
ENDCASE => ERROR;
RETURN [context]
END;
ForceColors: PROC [mapEntries: ImagerDitherContext.MapEntries] =
BEGIN
useMapEntries ← mapEntries;
ImagerColorMap.LoadEntries[vt: terminal, mapEntries: mapEntries, gamma: 1, shared: FALSE];
FOR list: ImagerDitherContext.MapEntries ← mapEntries, list.rest WHILE list#NIL DO
Terminal.SetColor[terminal, list.first.mapIndex, 0, list.first.red, list.first.green, list.first.blue];
ENDLOOP;
[] ← Terminal.SetColorCursorPresentation[terminal, onesAreWhite];
[] ← ViewerPrivate.SetCreator[ContextCreator];
END;
CallMenu: Buttons.ButtonProc =
BEGIN
p: CDSequencer.CommandProc ← CDSequencer.FetchCommand[$ColorDisplayMenuC, technology].proc;
IF p#NIL THEN p[NIL];
END;
--**end color device**************************************
ColorRec: TYPE = RECORD[r, g, b, w: REAL ← 0, name: Rope.ROPENIL];
--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: BOOLTRUE];
--XXXXXXXXXXXXXXXX TECHNOLOGY XXXXXXXXXXXXXXXX
technology: CD.Technology ← NMos.nmos;
technologyName: Rope.ROPE ← technology.name;
numberOfColors: INT = 7; --background, normal colors and extra colors
numberOfNormalColors: INT = 5; --without background and extra colors
cDefaults: REF ColorDescRep ← NEW[ColorDescRep ← [
[0.49, 0.62, 0.62, 0.05, "Sub"], --background
[0, 1, 0, 1, "dif"],
[1, 1, 0.2, 0.20, "imp"],
[0.5, 0.5, 1, 0.5, "m1"],
[0.7, 0.4, 0.7, 0.4, "m2"],
[1, 0.2, 0, 1, "pol"],
[1, 0.95, 0.0, 0.9, "Xx"] --channel hack
]];
channelX: INT ← 6;
SetupSpecials: PROC [] =
BEGIN
cc: ColorRec ← currentColor[channelX]; --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
];
specials2 ← NIL;
specials3 ← LIST[
[x: 127, c: [0, 0, 0, 1], replace: TRUE], --black for cuts
[x: 243, c: [1, 0, 0, 1]], --get all nice colors back for other users
[x: 245, c: [0, 0, 1, 1]],
[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]],
[x: 254, c: [0, 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
green1: CARDINAL = 1;
yellow: CARDINAL = 2;
blue: CARDINAL = 4;
pinktr: CARDINAL = 8;
red: CARDINAL = 16;
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[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.ovg, Checker8[blue, pinktr], 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[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 and ovgc for this background
-- no change for bur, nwelCont, pwelCont, and ovgc for this background
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.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;
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;
ResetAndCreateButton: Buttons.ButtonProc =
BEGIN
viewer: ViewerClasses.Viewer ← ViewerOps.FindViewer[caption];
IF viewer=NIL THEN {
IF mouseButton=yellow THEN CallMenu[NIL]
ELSE {
IF Terminal.LegalColorMode[terminal, [FALSE, 8, 0]] 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;
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.WriteRope["The 8 bit color tool works only after setting 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 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];
NextButton["Menu", CallMenu];
-- create sliders for rgb colors
FOR iColor: CARDINAL IN [0..3) DO
cInit: REALSELECT 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.ROPELIST["from profile"];
FOR i: INT DECREASING IN [0..numberOfColors) DO
list ← CONS[cDefaults[i].name, list]
ENDLOOP;
curLayer ← TerminalIO.RequestSelection[label: "Layers", choice: list];
IF curLayer=0 THEN RETURN[];
IF curLayer<=numberOfColors THEN {
sat ← TerminalIO.RequestSelection[
label: "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[0, MIN[255, Real.RoundI[r*255]]]
};
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];
END;
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.RoundI[def.w*100]]]/100;
c.r ← Real.Float[UserProfile.Number[key: r.Concat[".r"], default: Real.RoundI[def.r*100]]]/100;
c.g ← Real.Float[UserProfile.Number[key: r.Concat[".g"], default: Real.RoundI[def.g*100]]]/100;
c.b ← Real.Float[UserProfile.Number[key: r.Concat[".b"], default: Real.RoundI[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 =
BEGIN
CreateAnInstance[];
END;
ColorComm: PROC [comm: CDSequencer.Command] =
BEGIN
CreateAnInstance[];
END;
Init8Patterns[NIL];
ReadProfileColors[];
ComputeColors[];
CDSequencer.ImplementCommand[$SaturationComm, SaturationComm, technology, doQueue];
CDSequencer.ImplementCommand[$ColorTool, ColorComm, technology, dontQueue];
CDCommandOpsExtras2.RegisterWithMenu[menu: $DisplayMenu, entry: Rope.Concat[technologyName, " 8 bit tool"], key: $ColorTooltech, tech: technology, queue: dontQueue];
[] ← Buttons.Create[
info: [name: Rope.Concat[technologyName, " colors"]],
proc: ResetAndCreateButton
];
Commander.Register[
key: Rope.Cat["CD", technologyName, "ColorRec"],
proc: ColorCommand,
doc: Rope.Concat[technologyName, " 8 bit color tool"]
];
END.