CDSil8BitColors.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Jacobi, October 24, 1985 1:08:33 pm PDT
gbb, September 13, 1985 11:23:28 am PDT
DIRECTORY
Basics USING [BITAND, BITSHIFT],
Buttons USING [Button, ButtonProc, Create, SetDisplayStyle],
CD USING [backGround, ContextFilter, FetchTechnology, highLightError, highLightShade, Layer, Technology],
CDColors USING [Brick, DefineColor],
CDIO USING [GetWorkingDirectory],
CDMenus USING [CreateEntry],
CDSequencer USING [Command, CommandProc, CommDescriptor, FetchCommand, ImplementCommand],
CDSil USING [cdsil, xaqua, xblue, xbrown, xcyan, xgreen, xlime, xmagenta, xneutral, xorange, xpink, xred, xsmoke, xturquise, xultraviolet, xviolet, xwhite, xyellow],
CDValue USING [Fetch],
Commander USING [CommandProc, Handle, Register],
Containers USING [ChildXBound, ChildYBound, Container, Create],
Convert USING [RopeFromInt],
Imager USING [Context],
ImagerColor USING [ColorFromRGB],
ImagerColorMap USING [LoadEntries, MapEntry],
ImagerDitherContext USING [MapEntries, SetDitherMap],
ImagerTerminal USING [BWContext, ColorContext],
InterminalBackdoor USING [terminal],
Icons USING [NewIconFromFile],
Labels USING [Create, Label, Set],
MessageWindow USING [Append],
Process USING [Detach],
Real USING [Fix, Float, RoundI],
Rope USING [Cat, Concat, Equal, ROPE],
Sliders USING [Create, NormalizedSliderValue, SetContents, Slider, SliderProc],
Terminal USING [GetColorMode, LegalColorMode, SetColorCursorPresentation, Virtual],
TerminalIO USING [RequestSelection, WriteRope],
UserProfile USING [Boolean, Number, Token],
ViewerClasses USING [Viewer],
ViewerOps USING [FindViewer, OpenIcon, PaintViewer, SetOpenHeight],
ViewerPrivate USING [ContextCreatorProc, SetCreator],
WindowManager USING [ScreenPos, StartColorViewers];
CDSil8BitColors: CEDAR PROGRAM
IMPORTS Basics, Buttons, CD, CDColors, CDIO, CDMenus, CDSequencer, CDSil, CDValue, Commander, Containers, Convert, Icons, ImagerColor, 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
comm: REF READONLY CDSequencer.CommDescriptor ← CDSequencer.FetchCommand[$ColorDisplayMenuC, technology];
IF comm#NIL AND comm.p#NIL THEN comm.p[NIL];
END;
--**end color device**************************************
ColorRec: TYPE = RECORD [r, g, b, w: REAL ← 0, name: Rope.ROPENIL];
--w is a weight; 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 ← CDSil.cdsil;
technologyName: Rope.ROPE ← technology.name;
numberOfColors: INT = 8; -- background and "primary" colors
numberOfNormalColors: INT = 7; -- without background
numberOfTotalColors: INT = 18;
mapRange: TYPE = [0 .. numberOfTotalColors);
myMap: ARRAY mapRange OF RECORD [l: CD.Layer, c: ColorRec] = [
[CD.backGround, [r: 0.49, g: 0.62, b: 0.62, w: 0.05, name: "Sub"]],
[CDSil.xred, [r: 1, g: 0, b: 0, w: 0.75, name: "Red"]],
[CDSil.xgreen, [r: 0, g: 1, b: 0, w: 0.75, name: "Green"]],
[CDSil.xblue, [r: 0, g: 0, b: 1, w: 0.75, name: "Blue"]],
[CDSil.xcyan, [r: 0, g: 1, b: 1, w: 0.75, name: "Cyan"]],
[CDSil.xmagenta, [r: 1, g: 0, b: 1, w: 0.75, name: "Magenta"]],
[CDSil.xyellow, [r: 1, g: 1, b: 0, w: 0.75, name: "Yellow"]],
[CDSil.xwhite, [r: 1, g: 1, b: 1, w: 1, name: "White"]],
[CDSil.xaqua, [r: 0.42, g: 0.92, b: 0.55, w: 0.75, name: "Aqua"]],
[CDSil.xturquise, [r: 0.42, g: 0.70, b: 0.92, w: 0.75, name: "Turquoise"]],
[CDSil.xbrown, [r: 0.25, g: 0.12, b: 0.08, w: 0.75, name: "DarkBrown"]],
[CDSil.xviolet, [r: 0.45, g: 0.25, b: 0.75, w: 0.75, name: "Violet"]],
[CDSil.xultraviolet, [r: 0.13, g: 0.0, b: 0.33, w: 0.75, name: "Ultraviolet"]],
[CDSil.xorange, [r: 0.64, g: 0.2752, b: 0.16, w: 0.75, name: "Orange"]], -- we prefer our orange
[CDSil.xsmoke, [r: 0.50, g: 0.50, b: 0.50, w: 0.75, name: "Smoke"]], -- grey
[CDSil.xlime, [r: 0.39, g: 0.75, b: 0.25, w: 0.75, name: "Lime"]],
[CDSil.xpink, [r: 0.90 , g: 0.45, b: 0.55, w: 0.75, name: "Pink"]], -- we need a bit more red and less green in it
[CDSil.xneutral, [r: 0, g: 0, b: 0, w: 0.75, name: "Neutral"]]]; -- Black
-- Order is important !!!
Set colour map: each of the eight elements sets the RGB colour to corresponding to a given bit in the pattern.
cDefaults: REF ColorDescRep ← NEW [ColorDescRep ← [
myMap[0].c, myMap[1].c, myMap[2].c, myMap[3].c, myMap[4].c, myMap[5].c, myMap[6].c, myMap[7].c
]];
"Auxiliary" colours
neutral: ColorRec = myMap[17].c; -- Black
violet: ColorRec = myMap[11].c;
darkBrown: ColorRec = myMap[10].c;
orange myMap[13].c; we prefer our orange
lime: ColorRec = myMap[15].c;
turquoise: ColorRec = myMap[9].c;
aqua: ColorRec = myMap[8].c;
ultraviolet: ColorRec = myMap[12].c;
pink: ColorRec = myMap[16].c; we need a bit more red and less green in it
pink: ColorRec = myMap[16].c;
smoke: ColorRec = myMap[14].c; -- Grey
Colour mixtures
red: CARDINAL = 1;
green: CARDINAL = 2;
blue: CARDINAL = 4;
cyan: CARDINAL = 8;
magenta: CARDINAL = 16;
yellow: CARDINAL = 32;
white: CARDINAL = 64;
fakeAqua: CARDINAL = green+cyan; -- 10
fakeTurquoise: CARDINAL = blue + cyan; -- 12
fakeBrown: CARDINAL = green+magenta; -- 18
fakeViolet: CARDINAL = cyan+magenta; -- 24
fakeUltraviolet: CARDINAL = blue + cyan + magenta; -- 28
orange: CARDINAL = red+yellow; -- 33 this orange is better than the one used by Sil
fakeSmoke: CARDINAL = blue+yellow; -- 36
fakeLime: CARDINAL = cyan+yellow; -- 40
fakePink: CARDINAL = magenta + white; -- 80
fakeBlack: CARDINAL = white-1;
Init8Patterns: Buttons.ButtonProc =
--all parameter are discarded
BEGIN
Pixels in a dither:
1 2
3 4
5 6
7 8
Each pixel has 8 bits, one for every element in the table cDefaults.
pixel1: CARDINAL = 1;
pixel3: CARDINAL = 256;
Dithers
Mixture: PROC [col: CARDINAL] RETURNS [REF CDColors.Brick] ~ BEGIN
Full colour
RETURN [Dither1to1 [col, col]]
END; -- Dither1to0
Dither1to1: PROC [col1, col2: CARDINAL ← white] RETURNS [REF CDColors.Brick] ~ BEGIN
Dither 1 to 1
RETURN [NEW [CDColors.Brick ← [col1*pixel1+col2*pixel3, col2*pixel1+col1*pixel3, col1*pixel1+col2*pixel3, col2*pixel1+col1*pixel3]]]
END; -- Dither1to1
Dither1to3: PROC [col1, col2: CARDINAL] RETURNS [REF CDColors.Brick] ~ BEGIN
Dither 1 to 3
RETURN [NEW [CDColors.Brick ← [col1*pixel1+col2*pixel3, col2*pixel1+col2*pixel3, col1*pixel1+col2*pixel3, col2*pixel1+col2*pixel3]]]
END; -- Dither1to3
Dither2to1to1to4: PROC [col1, col2, col3, col4: CARDINAL] RETURNS [REF CDColors.Brick] ~ BEGIN
Dither 4 to 2 to 1 to 1
RETURN [NEW [CDColors.Brick ← [col1*pixel1+col4*pixel3, col4*pixel1+col2*pixel3, col1*pixel1+col4*pixel3, col4*pixel1+col3*pixel3]]]
END; -- Dither2to1to1to4
Lighten: PROC[l: CD.Layer, color: CARDINAL] =
BEGIN
CDColors.DefineColor [l, Dither1to1[color], bit8, pushedOut];
END;
CDColors.DefineColor[CDSil.xneutral, Mixture[fakeBlack], bit8];
CDColors.DefineColor[CDSil.xred, Mixture[red], bit8];
CDColors.DefineColor[CDSil.xyellow, Mixture[yellow], bit8];
CDColors.DefineColor[CDSil.xgreen, Mixture[green], bit8];
CDColors.DefineColor[CDSil.xcyan, Mixture[cyan], bit8];
CDColors.DefineColor[CDSil.xviolet, Mixture[fakeViolet], bit8];
CDColors.DefineColor[CDSil.xmagenta, Mixture[magenta], bit8];
CDColors.DefineColor[CDSil.xwhite, Mixture[white], bit8];
CDColors.DefineColor[CDSil.xbrown, Mixture[fakeBrown], bit8];
CDColors.DefineColor[CDSil.xorange, Mixture[orange], bit8];
CDColors.DefineColor[CDSil.xlime, Mixture[fakeLime], bit8];
CDColors.DefineColor[CDSil.xturquise, Mixture[fakeTurquoise], bit8];
CDColors.DefineColor[CDSil.xaqua, Mixture[fakeAqua], bit8];
CDColors.DefineColor[CDSil.xultraviolet, Mixture[fakeUltraviolet], bit8];
CDColors.DefineColor[CDSil.xpink, Mixture[fakePink], bit8];
CDColors.DefineColor[CDSil.xsmoke, Mixture[fakeSmoke], bit8];
CDColors.DefineColor[CDSil.xblue, Mixture[blue], 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];
Lighten[CDSil.xneutral, fakeBlack];
Lighten[CDSil.xred, red];
Lighten[CDSil.xyellow, yellow];
Lighten[CDSil.xgreen, green];
Lighten[CDSil.xcyan, cyan];
Lighten[CDSil.xviolet, fakeViolet];
Lighten[CDSil.xmagenta, magenta];
Lighten[CDSil.xwhite, white];
Lighten[CDSil.xbrown, fakeBrown];
Lighten[CDSil.xorange, orange];
Lighten[CDSil.xlime, fakeLime];
Lighten[CDSil.xturquise, fakeTurquoise];
Lighten[CDSil.xaqua, fakeAqua];
Lighten[CDSil.xultraviolet, fakeUltraviolet];
Lighten[CDSil.xpink, fakePink];
Lighten[CDSil.xsmoke, fakeBlack];
Lighten[CDSil.xblue, blue];
HackContextColors[];
END;
SetupSpecials: PROC [] =
BEGIN
specials2 ← LIST [
[x: fakeAqua + 1, c: aqua],
[x: fakeTurquoise + 1, c: turquoise],
[x: fakeBrown + 1, c: darkBrown],
[x: fakeViolet + 1, c: violet],
[x: fakeUltraviolet + 1, c: ultraviolet],
[x: fakeSmoke + 1, c: smoke],
[x: fakeLime + 1, c: lime],
[x: fakePink, c: pink],
[x: fakeBlack, c: neutral]];
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: 253, c: [0, 0, 0, 1]],
[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;
HackContextColors: PROC [] =
BEGIN
WITH CDValue.Fetch[boundTo: NIL, key: $ContextFilter] SELECT FROM
rcf: REF CD.ContextFilter =>
FOR i: mapRange IN mapRange DO
rcf[myMap[i].l] ← ImagerColor.ColorFromRGB [
rgb: [R: myMap[i].c.r, G: myMap[i].c.g, B: myMap[i].c.b],
calibration: NIL]
ENDLOOP;
ENDCASE => NULL
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[];
IF UserProfile.Boolean[
key: Rope.Cat["ChipNDale.", technologyName, ".StartColorMap8"],
default: CD.FetchTechnology[$cmos]=NIL
AND CD
.FetchTechnology[$cmosB]=NIL
AND CD
.FetchTechnology[$nmos]=NIL
] THEN ComputeColors[];
CDSequencer.ImplementCommand[$SaturationComm, SaturationComm, technology, doQueue];
CDSequencer.ImplementCommand[$ColorTool, ColorComm, technology, dontQueue];
CDMenus.CreateEntry[$DisplayMenu, Rope.Concat[technologyName, " 8 bit tool"], $ColorTool];
[] ← 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.