ColorToolViewerImpl.mesa
Written by Darlene Plebon on June 24, 1983 11:14 am
Last Edited by: Stone, April 9, 1985 5:31:27 pm PST
Last Edited by: Beach, April 1, 1984 6:00:29 pm PST
DIRECTORY
Buttons USING [Button, ButtonProc, Create],
ChoiceButtons USING [BuildEnumTypeSelection, ButtonList, EnumTypeRef, GetSelectedButton, SelectionNotifierProc, UpdateChoiceButtons],
CIEViewer,
CNSColor USING [CSLToCNS, CNSToCSL, CSLChroma, CSLLightness, CSLSaturation, CSLToHSL, HSLToCSL, medium, red, vivid],
ColorMap USING [GetIndex, SetRGBColor],
ColorToolViewer,
Containers USING [Container, Create],
Convert USING [RealFromRope],
Graphics USING [Box, Context, DrawBox, GetBounds, SetColor],
GraphicsBasic USING [Color],
GraphicsColor USING [RGBToColor, red, green, blue],
IO USING [PutFR, real],
Menus USING [Menu],
MessageWindow USING [Append],
CGColorWithCIE,
Rope USING [Equal, ROPE],
Sliders USING [Create, SetContents, SliderProc, sliderGray],
Commander USING [CommandProc, Register],
UserProfile,
VFonts USING [CharWidth],
ViewerClasses USING [Column, PaintProc, Viewer, ViewerClass, ViewerClassRec, DestroyProc],
ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass, SetOpenHeight ],
ViewerTools USING [MakeNewTextViewer, GetContents, SetContents],
WindowManager USING [colorDisplayOn, ScreenPos, StartColorViewers, StopColorViewers];
ColorToolViewerImpl: CEDAR PROGRAM
IMPORTS Buttons, ChoiceButtons, CIEViewer, CNSColor, ColorMap, Commander, Containers, Convert, Graphics, GraphicsColor, IO, MessageWindow, CGColorWithCIE, Rope, Sliders, UserProfile, VFonts, ViewerOps, ViewerTools, WindowManager
EXPORTS ColorToolViewer =
BEGIN
entryHeight: CARDINAL = 15;  -- how tall to make each line of text items
entryVSpace: CARDINAL = 8;   -- vertical leading space between lines
entryHSpace: CARDINAL = 10;   -- horizontal space between items in a line
columnSpacing: INTEGER = 20; -- space between columns
sliderWidth: CARDINAL = 20;  -- width of all sliders in color tool
sliderHeight: CARDINAL = 102;  -- height of all sliders in color tool
initialRed: REAL = 0.75;    -- initial color values for color patch
initialGreen: REAL = 0.75;
initialBlue: REAL = 0.2;
SixViewers: TYPE=RECORD[text1, text2, text3, slider1, slider2, slider3: ViewerClasses.Viewer];
--hack to avoid an unsafe return
lastHandle: Handle ← NIL;  --so the viewer can be manipulated by a program
Handle: TYPE = REF ColorToolRec;
ColorToolRec: TYPE = RECORD [
outer: Containers.Container ← NIL, -- handle for the enclosing container
height: CARDINAL ← 0,     -- height measured from the top of the container
height2: CARDINAL ← 0,    -- height of second column from top of the container
rgb: RGBViewer,      -- the RGB viewer's state
hsv: HSVViewer,      -- the HSV viewer's state
hsl: HSLViewer,       -- the HSL viewer's state
cns: CNSViewer,       -- the CNS viewer's state
colorPatch: ColorPatchViewer,   -- the color patch viewer's state
cie: CIEViewer.Viewer     -- the CIE Viewer (a REF not a RECORD)
];
GetRGBValue: PUBLIC PROC RETURNS [red,green,blue: REAL] = {
data: ColorPatchData ← NARROW[lastHandle.colorPatch.data];
RETURN[red: data.rgbR, green: data.rgbG, blue: data.rgbB];
};
GetCSLValue: PUBLIC PROC RETURNS[cslChroma: CNSColor.CSLChroma, cslSaturation: CNSColor.CSLSaturation, cslLightness: CNSColor.CSLLightness] = {
data: ColorPatchData ← NARROW[lastHandle.colorPatch.data];
RETURN[cslChroma: data.cslC, cslSaturation: data.cslS, cslLightness: data.cslL];
};
SetRGBValue: PUBLIC PROC [red,green,blue: REAL] = {
UpdateColorViewers[handle: lastHandle, color: [rgb[red,green,blue]]];
};
SetCSLValue: PUBLIC PROC [cslChroma: CNSColor.CSLChroma, cslSaturation: CNSColor.CSLSaturation, cslLightness: CNSColor.CSLLightness] = {
UpdateColorViewers[handle: lastHandle, color: [csl[cslChroma, cslSaturation, cslLightness]]];
};
MakeColorTool: Commander.CommandProc = {
my: Handle ← NEW[ColorToolRec];
column: ViewerClasses.Column ← color;
IF WindowManager.colorDisplayOn = FALSE THEN column ← left;
my.outer ← Containers.Create[ [
name: "Color Tool",
iconic: FALSE,
column: column,
scrollable: FALSE ] ];
MakeRGB[my];
MakeHSV[my];
MakeHSL[my];
MakeOnOffButtons[my];
MakeCNS[my];
MakeColorPatch[my];
MakeCIEViewer[my];
ViewerOps.SetOpenHeight[my.outer, my.height];
UpdateColorViewers[handle: my, color: [rgb[initialRed, initialGreen, initialBlue]]];
lastHandle ← my;
};
ComputeFromCIE: CIEViewer.CIEProc = {
handle: Handle ← NARROW[clientData];
UpdateColorViewers[handle: handle, color: [cie[x,y,Y]]];
};
MakeCIEViewer: PROCEDURE [handle: Handle] = {
handle.cie ← CIEViewer.Create[
info: [name: "ColorToolCIE"],
sliderWidth: sliderWidth,
sliderHeight: 2*sliderHeight,
clientData: handle,
proc: ComputeFromCIE,
maxY: 1,
initR: initialRed,
initG: initialGreen,
initB: initialBlue ];
};
RGBViewer: TYPE = RECORD [
redText: ViewerClasses.Viewer ← NIL,
greenText: ViewerClasses.Viewer ← NIL,
blueText: ViewerClasses.Viewer ← NIL,
redSlider: ViewerClasses.Viewer ← NIL,
greenSlider: ViewerClasses.Viewer ← NIL,
blueSlider: ViewerClasses.Viewer ← NIL
];
MakeRGB: PROCEDURE [handle: Handle] = {
[handle.rgb.redText, handle.rgb.greenText, handle.rgb.blueText, handle.rgb.redSlider, handle.rgb.greenSlider, handle.rgb.blueSlider] ← MakeColorSchemeViewer[
handle: handle,
name: "RGB",
buttonProc: ComputeFromRGB,
sliderProc1: RedSliderUpdate,
sliderProc2: GreenSliderUpdate,
sliderProc3: BlueSliderUpdate,
color1: GraphicsColor.red,
color2: GraphicsColor.green,
color3: GraphicsColor.blue
]^;
};
HSVViewer: TYPE = RECORD [
hueText: ViewerClasses.Viewer ← NIL,
saturationText: ViewerClasses.Viewer ← NIL,
valueText: ViewerClasses.Viewer ← NIL,
hueSlider: ViewerClasses.Viewer ← NIL,
saturationSlider: ViewerClasses.Viewer ← NIL,
valueSlider: ViewerClasses.Viewer ← NIL
];
MakeHSV: PROCEDURE [handle: Handle] = {
[handle.hsv.hueText, handle.hsv.saturationText, handle.hsv.valueText, handle.hsv.hueSlider, handle.hsv.saturationSlider, handle.hsv.valueSlider] ← MakeColorSchemeViewer[
handle: handle,
name: "HSV",
buttonProc: ComputeFromHSV,
sliderProc1: HueSliderUpdate,
sliderProc2: SaturationSliderUpdate,
sliderProc3: ValueSliderUpdate
]^;
};
HSLViewer: TYPE = RECORD [
hueText: ViewerClasses.Viewer ← NIL,
saturationText: ViewerClasses.Viewer ← NIL,
lightnessText: ViewerClasses.Viewer ← NIL,
hueSlider: ViewerClasses.Viewer ← NIL,
saturationSlider: ViewerClasses.Viewer ← NIL,
lightnessSlider: ViewerClasses.Viewer ← NIL
];
MakeHSL: PROCEDURE [handle: Handle] = {
[handle.hsl.hueText, handle.hsl.saturationText, handle.hsl.lightnessText, handle.hsl.hueSlider, handle.hsl.saturationSlider, handle.hsl.lightnessSlider] ← MakeColorSchemeViewer[
handle: handle,
name: "HSL",
buttonProc: ComputeFromHSL,
sliderProc1: HSLHueSliderUpdate,
sliderProc2: HSLSaturationSliderUpdate,
sliderProc3: HSLLightnessSliderUpdate
]^;
};
MakeColorSchemeViewer: PROCEDURE [handle: Handle, name: Rope.ROPE, buttonProc: Buttons.ButtonProc, sliderProc1, sliderProc2, sliderProc3: Sliders.SliderProc, color1, color2, color3: GraphicsBasic.Color ← Sliders.sliderGray] RETURNS [ret: REF SixViewers] = {
valueEntryWidth: CARDINAL = 8 * VFonts.CharWidth['0]; -- eight digits worth of width
button: Buttons.Button;
ret ← NEW[SixViewers];
handle.height ← handle.height + entryVSpace;
button ← Buttons.Create[
info: [
name: name,
wy: handle.height,
wh: entryHeight,
parent: handle.outer,
border: TRUE ],
clientData: handle,
proc: buttonProc ];
ret.text1 ← ViewerTools.MakeNewTextViewer[ [
parent: handle.outer,
wx: button.wx + button.ww + entryHSpace,
wy: handle.height+2,
ww: valueEntryWidth,
wh: entryHeight,
data: " ",
scrollable: FALSE,
border: FALSE ] ];
ret.text2 ← ViewerTools.MakeNewTextViewer[ [
parent: handle.outer,
wx: ret.text1.wx + ret.text1.ww + entryHSpace,
wy: handle.height+2,
ww: valueEntryWidth,
wh: entryHeight,
data: " ",
scrollable: FALSE,
border: FALSE ] ];
ret.text3 ← ViewerTools.MakeNewTextViewer[ [
parent: handle.outer,
wx: ret.text2.wx + ret.text2.ww + entryHSpace,
wy: handle.height+2,
ww: valueEntryWidth,
wh: entryHeight,
data: " ",
scrollable: FALSE,
border: FALSE ] ];
handle.height ← handle.height + entryHeight + entryVSpace;
ret.slider1 ← Sliders.Create[
info: [
parent: handle.outer,
wx: button.wx + button.ww + entryHSpace,
wy: handle.height,
ww: sliderWidth,
wh: sliderHeight
],
foreground: color1,
clientData: handle,
sliderProc: sliderProc1
];
ret.slider2 ← Sliders.Create[
info: [
parent: handle.outer,
wx: ret.text1.wx + ret.text1.ww + entryHSpace,
wy: handle.height,
ww: sliderWidth,
wh: sliderHeight
],
foreground: color2,
clientData: handle,
sliderProc: sliderProc2
];
ret.slider3 ← Sliders.Create[
info: [
parent: handle.outer,
wx: ret.text2.wx + ret.text2.ww + entryHSpace,
wy: handle.height,
ww: sliderWidth,
wh: sliderHeight
],
foreground: color3,
clientData: handle,
sliderProc: sliderProc3
];
handle.height ← handle.height + sliderHeight + entryVSpace;
RETURN[ret];
};
The color naming scheme.
CNSHues: ChoiceButtons.ButtonList ← LIST[
"Red", "OrangishRed", "RedOrange", "ReddishOrange",
"Orange", "YellowishOrange", "OrangeYellow", "OrangishYellow",
"Yellow", "GreenishYellow", "YellowGreen", "YellowishGreen",
"Green", "BluishGreen", "GreenBlue", "GreenishBlue",
"Blue", "PurplishBlue", "BluePurple", "BluishPurple",
"Purple", "ReddishPurple", "PurpleRed", "PurplishRed",
"BrownishRed", "RedBrown", "ReddishBrown",
"Brown", "YellowishBrown", "BrownYellow", "BrownishYellow",
"Black", "Gray", "White"
];
CNSLightnesses: ChoiceButtons.ButtonList ← LIST[
"VeryDark", "Dark", "Medium", "Light", "VeryLight"
];
CNSSaturations: ChoiceButtons.ButtonList ← LIST[
"Grayish", "Moderate", "Strong", "Vivid"
];
CNSViewer: TYPE = RECORD [
saturationChoices: ChoiceButtons.EnumTypeRef,
lightnessChoices: ChoiceButtons.EnumTypeRef,
hueChoices: ChoiceButtons.EnumTypeRef
];
MakeCNS: PROCEDURE [handle: Handle] = {
maxWidth: CARDINAL = 625;
button: Buttons.Button;
handle.height2 ← handle.height2 + entryVSpace;
button ← Buttons.Create[
info: [
name: "CNS",
wx: handle.rgb.blueText.wx + handle.rgb.blueText.ww + columnSpacing,
wy: handle.height2,
wh: entryHeight,
parent: handle.outer,
border: TRUE ],
clientData: handle,
proc: ComputeFromCNS ];
handle.cns.saturationChoices ← ChoiceButtons.BuildEnumTypeSelection[
viewer: handle.outer,
x: button.wx + button.ww + entryHSpace,
y: handle.height2,
title: "Saturation:",
buttonNames: CNSSaturations,
default: "Vivid",
borderOnButtons: FALSE,
notifyClientProc: CNSSaturationUpdate,
clientdata: handle,
style: menuSelection,
allInOneRow: TRUE ];
handle.height2 ← handle.height2 + entryHeight;
handle.cns.lightnessChoices ← ChoiceButtons.BuildEnumTypeSelection[
viewer: handle.outer,
x: button.wx + button.ww + entryHSpace,
y: handle.height2,
title: "Lightness:",
buttonNames: CNSLightnesses,
default: "Medium",
borderOnButtons: FALSE,
notifyClientProc: CNSLightnessUpdate,
clientdata: handle,
style: menuSelection,
allInOneRow: TRUE ];
handle.height2 ← handle.height2 + entryHeight;
handle.cns.hueChoices ← ChoiceButtons.BuildEnumTypeSelection[
viewer: handle.outer,
x: button.wx + button.ww + entryHSpace,
y: handle.height2,
title: "Hue:",
buttonNames: CNSHues,
borderOnButtons: FALSE,
notifyClientProc: CNSHueUpdate,
clientdata: handle,
style: menuSelection,
allInOneRow: FALSE,
maxWidth: maxWidth ];
handle.height2 ← handle.height2 + 8*entryHeight + entryVSpace;
};
The color patch reflecting the currently selected color.
ColorPatchViewer: TYPE = RECORD [viewer: ViewerClasses.Viewer ← NIL];
ColorPatchData: TYPE = REF ColorPatchDataRec;
ColorPatchDataRec: TYPE = RECORD [
index: CARDINAL ← 51,  -- color map index
hasWrongIndex: BOOLEANTRUE,
rgbR: REAL ← 1.0,
rgbG: REAL ← 1.0,
rgbB: REAL ← 0.0,
hsvH: REAL ← 0.0,
hsvS: REAL ← 0.0,
hsvV: REAL ← 0.0,
hslH: REAL ← 0.0,
hslS: REAL ← 0.0,
hslL: REAL ← 0.0,
xCIE: REAL ← 0.0,
yCIE: REAL ← 0.0,
cslC: CNSColor.CSLChroma ← CNSColor.red,
cslS: CNSColor.CSLSaturation ← CNSColor.vivid,
cslL: CNSColor.CSLLightness ← CNSColor.medium
];
MakeColorPatch: PROCEDURE [handle: Handle] = {
height: INTEGER = 50;
width: INTEGER ← 400;
instanceData: ColorPatchData ← NEW[ColorPatchDataRec];
handle.height2 ← handle.height2 + entryVSpace;
handle.colorPatch.viewer ← ViewerOps.CreateViewer[
flavor: $ColorPatch,
info: [
parent: handle.outer,
wx: handle.rgb.blueText.wx + handle.rgb.blueText.ww + columnSpacing,
wy: handle.height2,
ww: width,
wh: height,
data: instanceData,
scrollable: FALSE]
];
handle.height2 ← handle.height2 + height + entryVSpace;
};
PaintColorPatch: ViewerClasses.PaintProc = {
box: Graphics.Box ← Graphics.GetBounds[context];
patchData: ColorPatchData ← NARROW[self.data];
color: GraphicsBasic.Color ← GraphicsColor.RGBToColor[r: patchData.rgbR, g: patchData.rgbG, b: patchData.rgbB];
ColorMap.SetRGBColor[index: patchData.index, r: patchData.rgbR, g: patchData.rgbG, b: patchData.rgbB];
Repaint the color patch only if Viewers cleared it or
last time we had the wrong color map index
IF clear OR patchData.hasWrongIndex THEN {
patchData.hasWrongIndex ←
ColorMap.GetIndex[r: color.r, g: color.g, b: color.b] # patchData.index;
Graphics.SetColor[context, color];
Graphics.DrawBox[context, box];
};
};
DestroyColorPatch: ViewerClasses.DestroyProc = {};
MakeOnOffButtons: PROCEDURE [handle: Handle] = {
onButton, offButton: Buttons.Button;
handle.height ← handle.height + entryVSpace;
onButton ← Buttons.Create[
info: [
name: "Color On",
wy: handle.height,
wh: entryHeight,
parent: handle.outer,
border: TRUE ],
clientData: handle,
proc: TurnOnColorDisplay ];
offButton ← Buttons.Create[
info: [
name: "Color Off",
wy: handle.height,
wx: onButton.wx + onButton.ww + entryHSpace,
wh: entryHeight,
parent: handle.outer,
border: TRUE ],
clientData: handle,
proc: TurnOffColorDisplay ];
handle.height ← handle.height + entryHeight + entryVSpace;
};
TurnOnColorDisplay: Buttons.ButtonProc = {
IF WindowManager.colorDisplayOn = FALSE THEN {
sideToken: Rope.ROPE ~ UserProfile.Token["ColorDisplay.Side", "left"];
bppToken: Rope.ROPE ~ UserProfile.Token["ColorDisplay.BitsPerPoint", "8"];
WindowManager.StartColorViewers[
screenPos: SELECT TRUE FROM
sideToken.Equal["left"] => left,
sideToken.Equal["right"] => right,
ENDCASE => left,
bitsPerPixel: SELECT TRUE FROM
bppToken.Equal["1"] => 1,
bppToken.Equal["2"] => 2,
bppToken.Equal["4"] => 4,
bppToken.Equal["8"] => 8,
bppToken.Equal["24"] => 24,
ENDCASE => 8];
};
ColorMap.SetRGBColor[index: 1, r: 1.0, g: 1.0, b: 1.0]
};
TurnOffColorDisplay: Buttons.ButtonProc = {
WindowManager.StopColorViewers[];
};
ComputeFromRGB: Buttons.ButtonProc = {
handle: Handle ← NARROW[clientData];
redValue: REAL ← GetColorValue[ViewerTools.GetContents[handle.rgb.redText]];
greenValue: REAL ← GetColorValue[ViewerTools.GetContents[handle.rgb.greenText]];
blueValue: REAL ← GetColorValue[ViewerTools.GetContents[handle.rgb.blueText]];
UpdateColorViewers[handle: handle, color: [rgb[redValue, greenValue, blueValue]]];
};
RedSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [rgb[value, patchData.rgbG, patchData.rgbB]]];
};
GreenSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [rgb[patchData.rgbR, value, patchData.rgbB]]];
};
BlueSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [rgb[patchData.rgbR, patchData.rgbG, value]]];
};
ComputeFromHSV: Buttons.ButtonProc = {
handle: Handle ← NARROW[clientData];
hueContents: Rope.ROPE ← ViewerTools.GetContents[handle.hsv.hueText];
saturationContents: Rope.ROPE ← ViewerTools.GetContents[handle.hsv.saturationText];
valueContents: Rope.ROPE ← ViewerTools.GetContents[handle.hsv.valueText];
hueValue: REAL ← GetColorValue[hueContents];
saturationValue: REAL ← GetColorValue[saturationContents];
valueValue: REAL ← GetColorValue[valueContents];
UpdateColorViewers[handle: handle, color: [hsv[hueValue, saturationValue, valueValue]]];
};
HueSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [hsv[value, patchData.hsvS, patchData.hsvV]]];
};
SaturationSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [hsv[patchData.hsvH, value, patchData.hsvV]]];
};
ValueSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [hsv[patchData.hsvH, patchData.hsvS, value]]];
};
ComputeFromHSL: Buttons.ButtonProc = {
handle: Handle ← NARROW[clientData];
hueContents: Rope.ROPE ← ViewerTools.GetContents[handle.hsl.hueText];
saturationContents: Rope.ROPE ← ViewerTools.GetContents[handle.hsl.saturationText];
lightnessContents: Rope.ROPE ← ViewerTools.GetContents[handle.hsl.lightnessText];
hueValue: REAL ← GetColorValue[hueContents];
saturationValue: REAL ← GetColorValue[saturationContents];
lightnessValue: REAL ← GetColorValue[lightnessContents];
UpdateColorViewers[handle: handle, color: [hsv[hueValue, saturationValue, lightnessValue]]];
};
HSLHueSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [hsl[value, patchData.hslS, patchData.hslL]]];
};
HSLSaturationSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [hsl[patchData.hslH, value, patchData.hslL]]];
};
HSLLightnessSliderUpdate: Sliders.SliderProc = {
handle: Handle ← NARROW[clientData];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
UpdateColorViewers[handle: handle, color: [hsl[patchData.hslH, patchData.hslS, value]]];
};
GetColorValue: PROCEDURE [rope: Rope.ROPE] RETURNS [value: REAL] = {
value ← Convert.RealFromRope[rope];
IF value > 1.0 OR value < 0.0 THEN {
MessageWindow.Append[message: "Invalid value ", clearFirst: TRUE];
MessageWindow.Append[message: rope, clearFirst: FALSE];
value ← 1.0;
};
RETURN[value];
};
ComputeFromCNS: Buttons.ButtonProc = {
handle: Handle ← NARROW[clientData];
c: CNSColor.CSLChroma;
s: CNSColor.CSLSaturation;
l: CNSColor.CSLLightness;
hue: Rope.ROPE ← ChoiceButtons.GetSelectedButton[handle.cns.hueChoices];
saturation: Rope.ROPE ← ChoiceButtons.GetSelectedButton[handle.cns.saturationChoices];
lightness: Rope.ROPE ← ChoiceButtons.GetSelectedButton[handle.cns.lightnessChoices];
[c, s, l] ← CNSColor.CNSToCSL[hue, saturation, lightness];
UpdateColorViewers[handle: handle, color: [csl[c, s, l]]];
};
CNSHueUpdate: ChoiceButtons.SelectionNotifierProc = {
handle: Handle ← NARROW[clientdata];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
hue, saturation, lightness: Rope.ROPE;
c: CNSColor.CSLChroma;
s: CNSColor.CSLSaturation;
l: CNSColor.CSLLightness;
[hue, saturation, lightness] ← CNSColor.CSLToCNS[patchData.cslC, patchData.cslS, patchData.cslL];
[c, s, l] ← CNSColor.CNSToCSL[ name, saturation, lightness];
UpdateColorViewers[handle: handle, color: [csl[c, s, l]]];
};
CNSSaturationUpdate: ChoiceButtons.SelectionNotifierProc = {
handle: Handle ← NARROW[clientdata];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
hue, saturation, lightness: Rope.ROPE;
c: CNSColor.CSLChroma;
s: CNSColor.CSLSaturation;
l: CNSColor.CSLLightness;
[hue, saturation, lightness] ← CNSColor.CSLToCNS[patchData.cslC, patchData.cslS, patchData.cslL];
[c, s, l] ← CNSColor.CNSToCSL[ hue, name, lightness];
UpdateColorViewers[handle: handle, color: [csl[c, s, l]]];
};
CNSLightnessUpdate: ChoiceButtons.SelectionNotifierProc = {
handle: Handle ← NARROW[clientdata];
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
hue, saturation, lightness: Rope.ROPE;
c: CNSColor.CSLChroma;
s: CNSColor.CSLSaturation;
l: CNSColor.CSLLightness;
[hue, saturation, lightness] ← CNSColor.CSLToCNS[patchData.cslC, patchData.cslS, patchData.cslL];
[c, s, l] ← CNSColor.CNSToCSL[ hue, saturation, name];
UpdateColorViewers[handle: handle, color: [csl[c, s, l]]];
};
ColorSpecification: TYPE = RECORD [
color: SELECT type: ColorType FROM
hsv => [h, s, v: REAL],
hsl => [h, s, l: REAL],
rgb => [r, g, b: REAL],
cie => [x, y, Y: REAL],
csl => [c: CNSColor.CSLChroma, s: CNSColor.CSLSaturation, l: CNSColor.CSLLightness],
ENDCASE
];
ColorType: TYPE = {hsv, rgb, csl, hsl, cie};
UpdateColorViewers: PROCEDURE [handle: Handle, color: ColorSpecification] RETURNS [] = {
UpdateColorValue: PROCEDURE [oldValue, newValue: REAL, textViewer, sliderViewer: ViewerClasses.Viewer] RETURNS [new: REAL] = {
IF newValue=CGColorWithCIE.undefined THEN RETURN[oldValue];
IF newValue # oldValue THEN {
ViewerTools.SetContents[viewer: textViewer, contents: IO.PutFR["%-5f", IO.real[newValue]]];
Sliders.SetContents[slider: sliderViewer, contents: newValue];
};
RETURN[newValue];
};
patchData: ColorPatchData ← NARROW[handle.colorPatch.viewer.data];
h, s, v: REAL;
r, g, b: REAL;
hl,sl,l: REAL;
chroma: CNSColor.CSLChroma;
saturation: CNSColor.CSLSaturation;
lightness: CNSColor.CSLLightness;
cnsHue, cnsSaturation, cnsLightness: Rope.ROPE;
WITH col: color SELECT FROM
hsv => {
h ← col.h; s ← col.s; v ← col.v;
[r, g, b] ← CGColorWithCIE.HSVToRGB[h, s, v];
[hl, sl, l] ← CGColorWithCIE.RGBToHSL[r, g, b];
[chroma, saturation, lightness] ← CNSColor.HSLToCSL[hl, sl, l];
};
hsl => {
hl ← col.h; sl ← col.s; l ← col.l;
[r, g, b] ← CGColorWithCIE.HSLToRGB[hl, sl, l];
[h, s, v] ← CGColorWithCIE.RGBToHSV[r, g, b];
[chroma, saturation, lightness] ← CNSColor.HSLToCSL[hl, sl, l];
};
rgb => {
r ← col.r; g ← col.g; b ← col.b;
[h, s, v] ← CGColorWithCIE.RGBToHSV[ r, g, b ];
[hl, sl, l] ← CGColorWithCIE.RGBToHSL[r, g, b];
[chroma, saturation, lightness] ← CNSColor.HSLToCSL[hl, sl, l];
};
cie => {
[r,g,b] ← CGColorWithCIE.CIEToRGB[col.x,col.y,col.Y];
r ← MIN[r,1]; g ← MIN[g,1]; b ← MIN[b,1]; --control precision problems
r ← MAX[r,0]; g ← MAX[g,0]; b ← MAX[b,0];
[h, s, v] ← CGColorWithCIE.RGBToHSV[ r, g, b ];
[hl, sl, l] ← CGColorWithCIE.RGBToHSL[r, g, b];
[chroma, saturation, lightness] ← CNSColor.HSLToCSL[hl, sl, l];
};
csl => {
chroma ← col.c; saturation ← col.s; lightness ← col.l;
[hl, sl, l] ← CNSColor.CSLToHSL[ chroma, saturation, lightness];
[r, g, b] ← CGColorWithCIE.HSLToRGB[hl, sl, l];
[h, s, v] ← CGColorWithCIE.RGBToHSV[r, g, b];
}
ENDCASE;
patchData.rgbR ← UpdateColorValue[oldValue: patchData.rgbR, newValue: r,
textViewer: handle.rgb.redText, sliderViewer: handle.rgb.redSlider];
patchData.rgbG ← UpdateColorValue[oldValue: patchData.rgbG, newValue: g,
textViewer: handle.rgb.greenText, sliderViewer: handle.rgb.greenSlider];
patchData.rgbB ← UpdateColorValue[oldValue: patchData.rgbB, newValue: b,
textViewer: handle.rgb.blueText, sliderViewer: handle.rgb.blueSlider];
patchData.hsvH ← UpdateColorValue[oldValue: patchData.hsvH, newValue: h,
textViewer: handle.hsv.hueText, sliderViewer: handle.hsv.hueSlider];
patchData.hsvS ← UpdateColorValue[oldValue: patchData.hsvS, newValue: s,
textViewer: handle.hsv.saturationText, sliderViewer: handle.hsv.saturationSlider];
patchData.hsvV ← UpdateColorValue[oldValue: patchData.hsvV, newValue: v,
textViewer: handle.hsv.valueText, sliderViewer: handle.hsv.valueSlider];
patchData.hslH ← UpdateColorValue[oldValue: patchData.hslH, newValue: hl,
textViewer: handle.hsl.hueText, sliderViewer: handle.hsl.hueSlider];
patchData.hslS ← UpdateColorValue[oldValue: patchData.hslS, newValue: sl,
textViewer: handle.hsl.saturationText, sliderViewer: handle.hsl.saturationSlider];
patchData.hslL ← UpdateColorValue[oldValue: patchData.hslL, newValue: l,
textViewer: handle.hsl.lightnessText, sliderViewer: handle.hsl.lightnessSlider];
[cnsHue, cnsSaturation, cnsLightness] ← CNSColor.CSLToCNS[chroma, saturation, lightness];
IF patchData.cslC # chroma AND ~Rope.Equal[cnsHue, ""] THEN {
patchData.cslC ← chroma;
ChoiceButtons.UpdateChoiceButtons[viewer: handle.outer, enumTypeInfo: handle.cns.hueChoices, newName: cnsHue];
};
IF patchData.cslS # saturation AND ~Rope.Equal[cnsSaturation, ""] THEN {
patchData.cslS ← saturation;
ChoiceButtons.UpdateChoiceButtons[viewer: handle.outer, enumTypeInfo: handle.cns.saturationChoices, newName: cnsSaturation];
};
IF patchData.cslL # lightness AND ~Rope.Equal[cnsLightness, ""] THEN {
patchData.cslL ← lightness;
ChoiceButtons.UpdateChoiceButtons[viewer: handle.outer, enumTypeInfo: handle.cns.lightnessChoices, newName: cnsLightness];
};
IF color.type#cie THEN {
x,y,Y: REAL;
[x,y,Y] ← CGColorWithCIE.RGBToCIE[r,g,b];
CIEViewer.SetContents[handle.cie, x,y,Y];
};
ViewerOps.PaintViewer[viewer: handle.colorPatch.viewer, hint: client, clearClient: FALSE];
};
colorPatchClass is a record containing the procedures and data common to all ColorPatch viewer instances (class record).
colorPatchClass: ViewerClasses.ViewerClass ←
NEW[ViewerClasses.ViewerClassRec ← [paint: PaintColorPatch, destroy: DestroyColorPatch]];
Register a command that will create an instance of this tool.
Commander.Register[key: "ColorTool", proc: MakeColorTool, doc: "Create a color tool"];
Register the ColorPatch class of viewer with the Window Manager
ViewerOps.RegisterViewerClass[$ColorPatch, colorPatchClass];
END.
Edited on April 1, 1984 6:00:30 pm PST, by Beach
changes to: ColorPatchDataRec to add hasWrongIndex field, PaintColorPatch to repaint the color patch with the graphics package only when it was cleared by Viewers or when it previously had been painted with the wrong color map index value, DIRECTORY, TurnOnColorDisplay, END