CDSil8BitColors.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,
CDSil,
ColorMap,
Commander,
Containers,
Convert,
GraphicsBasic,
GraphicsColor,
Icons,
Labels,
Process,
Real,
Rope,
Sliders,
Terminal,
TerminalIO,
ViewerOps;
CDSil8BitColors: CEDAR PROGRAM
IMPORTS Buttons, CDColors, CDIO, CDMenus, CDSequencer, CDSil, ColorMap, Commander, Containers, Convert, Icons, Labels, Process, Real, Rope, Sliders, Terminal, TerminalIO, ViewerOps =
BEGIN
--**Patterns**************************************
Init8Patterns: Buttons.ButtonProc =
--all parameter are discarded
BEGIN
standard: CARDINAL = 1;
green: CARDINAL = 2;
blue: CARDINAL = 4;
pinktr: CARDINAL = 8;
red: CARDINAL = 16;
yellow: CARDINAL = 32;
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[CDSil.xneutral, Full8[standard], bit8];
CDColors.DefineColor[CDSil.xgreen, Full8[green], bit8];
CDColors.DefineColor[CDSil.xcyan, Full8[blue], bit8];
CDColors.DefineColor[CDSil.xpink, Full8[pinktr], bit8];
CDColors.DefineColor[CDSil.xred, Full8[red], bit8];
CDColors.DefineColor[CDSil.xyellow, Full8[yellow], 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[CDSil.xneutral, standard];
DefineDimmer8[CDSil.xgreen, green];
DefineDimmer8[CDSil.xcyan, blue];
DefineDimmer8[CDSil.xpink, pinktr];
DefineDimmer8[CDSil.xred, red];
DefineDimmer8[CDSil.xyellow, yellow];
END;
--**end patterns**************************************
numberOfColors: INT = 7;
backgroundColor: INT = 6;
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. standard 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
];
ColorMode8: 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 ← ColorMode8[];
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 ~ColorMode8[] 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 ~ColorMode8[] THEN RETURN;
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 =
--Resets color map;
--does not touch patterns
BEGIN
UpdateAllSliders: PROC [my: Handle] =
BEGIN
w: Sliders.NormalizedSliderValue;
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;
--ResetButton
IF Check8BitMode[] THEN {
SetUserColor[];
ComputeColors[];
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, 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
← ["blk", "grn", "blu", "pin", "red", "yel", "bck"];
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;
caption: Rope.ROPE = "ChiPencil 8 bit color editor";
my: Handle = NEW[AdjustColorRec];
IF ~ColorMode8[] THEN
TerminalIO.WriteRope["The 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 map",
wx: buttonX,
wy: firstButtonY,
wh: buttonDY,
ww: buttonDX,
parent: my.outer,
border: TRUE],
proc: ResetButton,
clientData: my,
fork: TRUE
]; 
[] ← Buttons.Create[
info: [name: "reset pattern",
wx: buttonX,
wy: firstButtonY+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;
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;
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 ← [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]};
IF i5=1 THEN {c ← ComposeColor[c, 5]};
c ← ComposeColor[c, backgroundColor];
IF c.weight=0 THEN c ← color[backgroundColor]
ELSE c ← [c.r/c.weight, c.g/c.weight, c.b/c.weight, c.weight];
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:0, g:0, b:0]];   -- [channels]
SetMap[index: 255, color: [r:1, g:1, b:1]];   -- [white]
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 ← 1;
color[0].r ← 0;
color[0].g ← 0;
color[0].b ← 0;
color[1].weight ← 1;
color[1].r ← 0;
color[1].g ← 1;
color[1].b ← 0;
color[2].weight ← 1;
color[2].r ← 0;
color[2].g ← 0;
color[2].b ← 1;
color[3].weight ← 1;
color[3].r ← 0.7;
color[3].g ← 0.4;
color[3].b ← 0.7;
color[4].weight 𡤁
color[4].r ← 1;
color[4].g ← 0;
color[4].b ← 0;
color[5].weight ← 1;
color[5].r ← 1;
color[5].g ← 1;
color[5].b ← 0;
color[6].weight ← 0;
color[6].r ← 0.4;
color[6].g ← 0.5;
color[6].b ← 0.5;
END;
CDSilColorCommand: Commander.CommandProc =
BEGIN
CreateAnInstance[];
END;
CDSilColorComm: PROC [comm: CDSequencer.Command] =
BEGIN
CreateAnInstance[];
END;
Init8Patterns[NIL];
SetUserColor[];
ComputeColors[];
CDSequencer.ImplementCommand[$SilColorTool, CDSilColorComm, CDSil.cdsil, dontQueue];
CDMenus.CreateEntry[$DisplayMenu, "sil 8 bit tool", $SilColorTool];
Commander.Register[
 key: "CDSilColor",
 proc: CDSilColorCommand,
 doc: "cd sil 8 bit color tool"
 ];
END.