CMos8BitColors.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Monier, September 24, 1984 9:55:48 pm PDT
Last Edited by: Jacobi, October 29, 1984 5:46:54 pm PST
Last Edited by: Jacobi, April 11, 1985 11:22:28 am PST
DIRECTORY
Buttons,
CD,
CDColors,
CDIO,
CDMenus,
CDSequencer,
CMos,
ColorMap,
ColorWorld,
Commander,
Containers,
Convert,
GraphicsBasic,
GraphicsColor,
Icons,
Labels,
MessageWindow,
Process,
Real,
Rope,
Sliders,
Terminal,
TerminalIO,
UserProfile,
ViewerOps,
ViewerClasses,
WindowManager;
CMos8BitColors: CEDAR PROGRAM
IMPORTS Buttons, CDColors, CDIO, CDMenus, CDSequencer, CMos, ColorMap, ColorWorld, Commander, Containers, Convert, Icons, Labels, MessageWindow, Process, Real, Rope, Sliders, Terminal, TerminalIO, UserProfile, ViewerOps, WindowManager =
BEGIN
--**Patterns**************************************
Init8Patterns: Buttons.ButtonProc =
--all parameter are discarded
BEGIN
green1: CARDINAL = 1;
green2: CARDINAL = 2;
blue: CARDINAL = 4;
pinktr: CARDINAL = 8;
red: CARDINAL = 16;
yellow: CARDINAL = 32;
black: CARDINAL = 255;
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, back];
END;
Full8: PROC[color: CARDINAL] RETURNS [b: REF CDColors.Brick] =
BEGIN
RETURN[Checker8[color, color]]
END;
CDColors.DefineColor[CMos.ndif, Full8[green1], bit8];
CDColors.DefineColor[CMos.pdif, Full8[green2], bit8];
CDColors.DefineColor[CMos.met, Full8[blue], bit8];
CDColors.DefineColor[CMos.met2, Full8[pinktr], bit8];
CDColors.DefineColor[CMos.pol, Full8[red], bit8];
CDColors.DefineColor[CMos.nwel, Full8[yellow], bit8];
CDColors.DefineColor[CMos.cut, Full8[black], bit8];
CDColors.DefineColor[CMos.cut2, Checker8[black, blue], bit8];
CDColors.DefineColor[CMos.bur, Checker8[black, 0], bit8];
CDColors.DefineColor[CMos.nwelCont, Checker8[green2, blue], bit8];
CDColors.DefineColor[CMos.pwelCont, Checker8[green1, blue], bit8];
CDColors.DefineColor[CMos.ovg, Checker8[blue, pinktr], bit8];
CDColors.DefineColor[CMos.pwel, NEW[CDColors.Brick ← [4, 0, 0, 0]], bit8];
CDColors.DefineColor[CMos.imp, NEW[CDColors.Brick←[14, 14, 0, 0]], bit8];
CDColors.DefineColor[CD.backGround, NEW[CDColors.Brick ← [8, 0, 256*8, 0]], bit8];
CDColors.DefineColor[CD.highLightError, NEW[CDColors.Brick ← [255, 0, 0, 0]], bit8];
CDColors.DefineColor[CD.highLightShade, NEW[CDColors.Brick←[0, 255,0 , 255]], bit8];
DefineDimmer8[CMos.ndif, green1];
DefineDimmer8[CMos.pdif, green2];
DefineDimmer8[CMos.met, blue];
DefineDimmer8[CMos.met2, pinktr];
DefineDimmer8[CMos.pol, red];
DefineDimmer8[CMos.nwel, yellow];
DefineDimmer8[CMos.cut, black];
DefineDimmer8[CMos.cut2, black];
-- no change for bur, nwelCont, pwelCont, and ovgc for this background
END;
--**end patterns**************************************
numberOfColors: INT = 8;
chanelColor: INT = 7;
backgroundColor: INT = 6;
backgroundColor2: INT = 5; --nWell
Color: TYPE = RECORD[r, g, b, weight: REAL ← 0];
ColorDescRec: TYPE = ARRAY [0..numberOfColors) OF Color;
ColorDesc: TYPE = REF ColorDescRec;
color: ColorDesc = NEW[ColorDescRec];
-- 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.
indLayer: INT ← 1;
previndLayer: 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 = "cmos 8 bit color editor";
ColorModeIs8: PROC [] RETURNS [BOOL] = INLINE
BEGIN
virtual: Terminal.Virtual = Terminal.Current[];
RETURN [virtual.hasColorDisplay AND ~virtual.GetColorMode[].full AND virtual.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;
color[layer].weight ← 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;
IF indLayer-1 = chanelColor THEN RETURN; -- channel hack
Labels.Set[my.potarColor[layer].value, Convert.RopeFromInt[Real.Fix[value*100]]];
SELECT layer FROM
0 => color[indLayer-1].r ← value;
1 => color[indLayer-1].g ← value;
2 => color[indLayer-1].b ← value;
ENDCASE=> ERROR;
ComputeColors[];
END;
ResetButton: Buttons.ButtonProc =
BEGIN
Init8Patterns[parent: parent, clientData: clientData];
ResetMapButton[parent: parent, clientData: clientData];
END;
ResetAndCreateButton: Buttons.ButtonProc =
BEGIN
viewer: ViewerClasses.Viewer ← ViewerOps.FindViewer[caption];
IF viewer=NIL THEN {
IF ColorWorld.HasMode[8] 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 ← color[layer].weight;
Sliders.SetContents[my.coefLayer[layer].bar, 0];
Sliders.SetContents[my.coefLayer[layer].bar, w];
Labels.Set[my.coefLayer[layer].value,
  Convert.RopeFromInt[Real.Fix[color[layer].weight*100]]];
ENDLOOP;
ButtonProcLayerInternal[0, my];
END;
--ResetMapButton
IF Check8BitMode[] THEN {
SetUserColor[];
ComputeColors[];
IF clientData#NIL THEN UpdateAllSliders[NARROW[clientData, Handle]];
};
END;
ButtonProcLayer: Buttons.ButtonProc =
BEGIN
data: DataForSpecialProc ← NARROW[clientData];
IF Check8BitMode[] THEN {
IF data.layer = chanelColor THEN RETURN; -- (transistor channel hack)
ButtonProcLayerInternal[data.layer, data.my];
}
END;
ButtonProcLayerInternal: PROC[layer: CARDINAL, my: Handle] =
BEGIN
SetPotar: PROC[layer: CARDINAL, my: Handle] =
BEGIN
IF layer = chanelColor THEN RETURN; -- channel hack
Sliders.SetContents[my.potarColor[0].bar, color[layer].r];
Sliders.SetContents[my.potarColor[1].bar, color[layer].g];
Sliders.SetContents[my.potarColor[2].bar, color[layer].b];
Labels.Set[my.potarColor[0].value, Convert.RopeFromInt[Real.Fix[color[layer].r*100]]];
Labels.Set[my.potarColor[1].value, Convert.RopeFromInt[Real.Fix[color[layer].g*100]]];
Labels.Set[my.potarColor[2].value, Convert.RopeFromInt[Real.Fix[color[layer].b*100]]];
END;
-- ButtonProcLayerInternal
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;
CreateAnInstance: PROC[] =
--create an icon of the tool;
--does not change any color setup at initialization of the tool
BEGIN
nameLayerButton: ARRAY [0..numberOfColors) OF Rope.ROPE
← ["n+", "p+", "m1", "m2", "pol", "nW", "sub", "tr"];
nameColorSlider: ARRAY [0..3) OF Rope.ROPE ← ["R", "G", "B"];
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;
firstButtonY: CARDINAL = 10;
buttonDY: CARDINAL = 15;
interButtonY: CARDINAL = 3;
buttonX: CARDINAL = coefX+numberOfColors*coefDeltaX+8;
buttonDX: CARDINAL = 80;
firstSliderY: CARDINAL = 10;
sliderDY: CARDINAL = 20;
interSliderY: CARDINAL = 5;
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];
IF ~ColorModeIs8[] THEN
TerminalIO.WriteRope["The cmos 8 bit color tool works only after you put 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 indLayer: INT IN [0..numberOfColors) DO
wInit: REAL ← color[indLayer].weight;
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]]
]; 
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 ← Sliders.Create[
info: [
name: nameLayerButton[indLayer],
iconic: TRUE,
parent: my.outer,
wx: coefX+indLayer*coefDeltaX,
wy: coefBarY,
wh: - 5, --guardY
ww: coefDX,
border: TRUE],
sliderProc: UpdateWeightSlider,
orientation: vertical,
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 all",
wx: buttonX,
wy: firstButtonY,
wh: buttonDY,
ww: buttonDX,
parent: my.outer,
border: TRUE],
proc: ResetButton,
clientData: my,
fork: TRUE
]; 
[] ← Buttons.Create[
info: [name: "reset map",
wx: buttonX,
wy: firstButtonY+buttonDY+interButtonY,
wh: buttonDY,
ww: buttonDX,
parent: my.outer,
border: TRUE],
proc: ResetMapButton,
clientData: my,
fork: TRUE
]; 
[] ← Buttons.Create[
info: [name: "reset pattern",
wx: buttonX,
wy: firstButtonY+2*(buttonDY+interButtonY),
wh: buttonDY,
ww: buttonDX,
parent: my.outer,
border: TRUE],
fork: TRUE,
proc: Init8Patterns
]; 
-- create sliders for rgb colors
FOR iColor: CARDINAL IN [0..3) DO
cInit: REALSELECT iColor FROM
0 => color[indLayer-1].r,
1 => color[indLayer-1].g,
2 => color[indLayer-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
valueLayer: CARDINAL ← 1;
IF Check8BitMode[] THEN {
indLayer ← TerminalIO.RequestSelection[
label: "Layers",
choice: LIST["n-diff", "p-diff", "met1", "met2", "poly", "nWell", "substrate", "channel", "from profile"]
];
IF indLayer = 0 THEN RETURN[];
IF indLayer <= numberOfColors 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[];
color[indLayer-1].weight ← Real.Float[valueLayer-1]/10;
END
ELSE SetUserColor[];
ComputeColors[];
};
END;
ComputeColors: PROC[] =
--takes a color setting (weights and rgb values) and sets up the device
BEGIN
SetMap: PROC[index: CARDINAL, color: Color] = {
ColorMap.SetRGBColor[index, color.r, color.g, color.b]
};
Adjust: 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+color[ind].weight*color[ind].r,
c1.g+color[ind].weight*color[ind].g,
c1.b+color[ind].weight*color[ind].b,
c1.weight+color[ind].weight]
};
c: Color;
backgnd: CARDINAL;
IF ~ColorModeIs8[] 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 ← [0, 0, 0, 0];
-- compute the weighted sum of colors
IF i0=1 THEN {c ← ComposeColor[c, 0]};
IF i1=1 THEN {c ← ComposeColor[c, 1]};
IF i2=1 THEN {c ← ComposeColor[c, 2]};
IF i3=1 THEN {c ← ComposeColor[c, 3]};
IF i4=1 THEN {c ← ComposeColor[c, 4]};
backgnd ← (IF i5=1 THEN backgroundColor2 ELSE backgroundColor);
c ← ComposeColor[c, backgnd];
IF c.weight=0 THEN c ← color[backgnd]
ELSE c ← [c.r/c.weight, c.g/c.weight, c.b/c.weight, c.weight];
-- force yellow on transistors
IF i0+i1+i4=2 THEN {
c.r ← Adjust[c.r, color[chanelColor].weight];
c.g ← Adjust[c.g, color[chanelColor].weight];
c.b ← Adjust[c.b, -color[chanelColor].weight]
};
-- detect forbidden overlaps and display them white
IF i0+i1=2 OR i0+i5=2 THEN c ← [1, 1, 1, 0];
SetMap[32*i5+16*i4+8*i3+4*i2+2*i1+i0, c];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
SetMap[index: 64, color: color[6]];    -- [background]
SetMap[index: 128, color: [r:1, g:1, b:0]];   -- [channels]
SetMap[index: 255, color: [r:0, g:0, b:0]];   -- [black]
SetMap[index: 254, color: [r:1, g:0, b:0]];   -- [pure red]
SetMap[index: 253, color: [r:0, g:1, b:0]];   -- [pure green]
SetMap[index: 252, color: [r:0, g:0, b:1]];   -- [pure blue]
SetMap[index: 251, color: [r:1, g:1, b:0]];   -- [pure yellow]
[] ← Terminal.SetColorCursorPresentation[Terminal.Current[], onesAreWhite];
END;
SetUserColor: PUBLIC PROC [] =
--makes a default color setup; reads user profile
--does not set up the device
BEGIN
color[0].weight ← Real.Float[UserProfile.Number[key: "Chipndale.green1Weight", default: 100]]/100;
color[0].r ← Real.Float[UserProfile.Number[key: "Chipndale.green1.r", default: 0]]/100;
color[0].g ← Real.Float[UserProfile.Number[key: "Chipndale.green1.g", default: 100]]/100;
color[0].b ← Real.Float[UserProfile.Number[key: "Chipndale.green1.b", default: 0]]/100;
color[1].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.green2Weight", default: 100]]/100;
color[1].r ← Real.Float[UserProfile.Number[key: "Chipndale.green2.r", default: 0]]/100;
color[1].g ← Real.Float[UserProfile.Number[key: "Chipndale.green2.g", default: 100]]/100;
color[1].b ← Real.Float[UserProfile.Number[key: "Chipndale.green2.b", default: 0]]/100;
color[2].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.blueWeight", default: 50]]/100;
color[2].r ← Real.Float[UserProfile.Number[key: "Chipndale.blue.r", default: 0]]/100;
color[2].g ← Real.Float[UserProfile.Number[key: "Chipndale.blue.g", default: 0]]/100;
color[2].b ← Real.Float[UserProfile.Number[key: "Chipndale.blue.b", default: 100]]/100;
color[3].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.pinkWeight", default: 50]]/100;
color[3].r ← Real.Float[UserProfile.Number[key: "Chipndale.pink.r", default: 70]]/100;
color[3].g ← Real.Float[UserProfile.Number[key: "Chipndale.pink.g", default: 40]]/100;
color[3].b ← Real.Float[UserProfile.Number[key: "Chipndale.pink.b", default: 70]]/100;
color[4].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.redWeight", default: 100]]/100;
color[4].r ← Real.Float[UserProfile.Number[key: "Chipndale.red.r", default: 100]]/100;
color[4].g ← Real.Float[UserProfile.Number[key: "Chipndale.red.g", default: 20]]/100;
color[4].b ← Real.Float[UserProfile.Number[key: "Chipndale.red.b", default: 0]]/100;
color[5].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.yellowWeight", default: 30]]/100;
color[5].r ← Real.Float[UserProfile.Number[key: "Chipndale.yellow.r", default: 60]]/100;
color[5].g ← Real.Float[UserProfile.Number[key: "Chipndale.yellow.g", default: 70]]/100;
color[5].b ← Real.Float[UserProfile.Number[key: "Chipndale.yellow.b", default: 40]]/100;
color[6].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.backgndWeight", default: 30]]/100;
color[6].r ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.r", default: 40]]/100;
color[6].g ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.g", default: 50]]/100;
color[6].b ← Real.Float[UserProfile.Number[key: "Chipndale.backgnd.b", default: 50]]/100;

color[chanelColor].weight ←
Real.Float[UserProfile.Number[key: "Chipndale.channelWeight", default: 30]]/100;
END;
CDCmosColorCommand: Commander.CommandProc =
BEGIN
CreateAnInstance[];
END;
CmosColorComm: PROC [comm: CDSequencer.Command] =
BEGIN
CreateAnInstance[];
END;
Init8Patterns[NIL];
SetUserColor[];
ComputeColors[];
CDSequencer.ImplementCommand[$SaturationComm, SaturationComm, CMos.cmos, doQueue];
CDSequencer.ImplementCommand[$ColorTool, CmosColorComm, CMos.cmos, dontQueue];
CDMenus.CreateEntry[$DisplayMenu, "cmos 8 bit tool", $ColorTool];
[] ← Buttons.Create[info: [name: "cmos colors"], proc: ResetAndCreateButton];
Commander.Register[
 key: "CDCmosColor",
 proc: CDCmosColorCommand,
 doc: "cmos 8 bit color tool"
 ];
END.