CIEViewerImpl.mesa
Written by Maureen Stone on September 3, 1985 5:16:53 pm PDT
Last Edited by: Beach, February 13, 1984 1:58:37 pm PST

DIRECTORY
Buttons USING [Button, ButtonProc, Create],
ChoiceButtons USING [BuildEnumTypeSelection, ButtonList, EnumTypeRef,SelectionNotifierProc],
CIEViewer,
CIETriangle,
CGColorWithCIE,
Containers USING [Container, Create],
Convert USING [RealFromRope],
IO USING [PutFR, real],
MessageWindow USING [Append],
Rope USING [ROPE, Equal],
Sliders,
VFonts USING[CharWidth],
ViewerClasses USING [Viewer, ViewerRec],
ViewerOps USING [PaintViewer],
ViewerTools USING [MakeNewTextViewer, GetContents, SetContents, InhibitUserEdits];
CIEViewerImpl: CEDAR PROGRAM
IMPORTS Buttons, ChoiceButtons, CIETriangle, Containers, Convert, CGColorWithCIE, IO, MessageWindow, Rope, Sliders, VFonts, ViewerOps, ViewerTools
EXPORTS CIEViewer =
BEGIN OPEN CIEViewer;
CIEInit: TYPE=RECORD[xr,yr,xg,yg, xb,yb, whiteY: REAL];
globalData: CIEData; --hack. Need to hang this on the viewer somehow
CIEData: TYPE = REF CIEDataRec;
CIEDataRec: TYPE = RECORD [
cieInit: CIEInit,
triangle: CIETriangle.Viewer ← NIL, --the triangular slider, which is a viewer
slider: Sliders.Slider,  --for Y
xText: ViewerClasses.Viewer ← NIL,
yText: ViewerClasses.Viewer ← NIL,
YText: ViewerClasses.Viewer ← NIL,
zText: ViewerClasses.Viewer ← NIL,
x,y,Y: REAL,  --values for viewers. Cache for compare that prevents flicker
initChoices: ChoiceButtons.EnumTypeRef ← NIL,
YTrack: ChoiceButtons.EnumTypeRef ← NIL,
yTrack: BOOLEAN, --cached value of YTrack. Controls behavior of Y slider
maxY: REAL, --maximum luminance for this hue
proc: CIEProc,
clientData: REF ANYNIL
];
CIEInitChoices: ChoiceButtons.ButtonList ← LIST["Long", "Normal"];
YTrackChoices: ChoiceButtons.ButtonList ← LIST["Track Y", "Clip Y"];
ComputeFromCIE: Buttons.ButtonProc = {
data: CIEData ← NARROW[clientData];
xValue: REAL ← GetColorValue[ViewerTools.GetContents[data.xText]];
yValue: REAL ← GetColorValue[ViewerTools.GetContents[data.yText]];
YValue: REAL ← GetColorValue[ViewerTools.GetContents[data.YText]];
UpdateXY[data,xValue,yValue];
UpdateY[data, YValue];
data.proc[self: data.slider.parent, x: xValue, y: yValue, Y: YValue, clientData: data.clientData];
};
CIEInitUpdate: ChoiceButtons.SelectionNotifierProc = {
data: CIEData ← NARROW[clientdata];
x,y, Y: REAL;
xr,yr,xg,yg,xb,yb: REAL;
IF Rope.Equal[name,"Long"] THEN {
CGColorWithCIE.InitDefaultCIE[long];
[xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb] ← CGColorWithCIE.GetDefaultValues[long];
};
IF Rope.Equal[name,"Normal"] THEN {
CGColorWithCIE.InitDefaultCIE[normal];
[xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb] ← CGColorWithCIE.GetDefaultValues[normal];
};
[x,y,Y] ← CGColorWithCIE.RGBToCIE[r: 1, g: 1, b: 1]; --set it to white
CIETriangle.Reinitialize[cieTriangle: data.triangle, xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb, xw: x, yw: y];
UpdateXY[data, x,y];
UpdateY[data,Y];
};
YTrackUpdate: ChoiceButtons.SelectionNotifierProc = {
data: CIEData ← NARROW[clientdata];
IF Rope.Equal[name,"Track Y"] THEN {
data.yTrack ← TRUE;
UpdateY[data,data.maxY];
};
IF Rope.Equal[name,"Clip Y"] THEN data.yTrack ← FALSE;
};
all values should be in the range 0..1
Create: PUBLIC PROCEDURE [info: ViewerClasses.ViewerRec ← [], sliderWidth, sliderHeight: CARDINAL, proc: CIEProc, clientData: REF ANYNIL, maxY, initR, initG, initB: REAL ← 1] RETURNS [cieViewer: Viewer] = {
button: Buttons.Button;
leftX: CARDINAL ← 0;
topY: CARDINAL ← 0;
xInit,yInit,YInit: REAL;
entryHSpace: CARDINAL ← 10;
entryVSpace: CARDINAL ← 8;
xr,yr,xg,yg,xb,yb,xw,yw,Yw: REAL;
triangleSize: CARDINAL ← sliderHeight;
entryHeight: CARDINAL = 15;
valueEntryWidth: CARDINAL = 8 * VFonts.CharWidth['0]; -- eight digits worth of width
data: CIEData;
CGColorWithCIE.InitDefaultCIE[long];
[xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb] ← CGColorWithCIE.GetDefaultValues[long];
[xInit,yInit,YInit] ← CGColorWithCIE.RGBToCIE[initR,initG,initB];
data← NEW[CIEDataRec ← [
clientData: clientData,
proc: proc,
cieInit: [xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb, whiteY: Yw],
yTrack: TRUE,
x: xInit,
y: yInit,
Y: YInit,
maxY: maxY]];
cieViewer ← Containers.Create[info: info];
button ← Buttons.Create[
info: [
name: "CIE",
wx: leftX,
wy: topY,
wh: entryHeight,
parent: cieViewer,
border: TRUE ],
clientData: data,
proc: ComputeFromCIE
];
leftX ← button.wx + button.ww + entryHSpace;
data.YText ← ViewerTools.MakeNewTextViewer[ [
parent: cieViewer,
wx: leftX,
wy: topY,
ww: valueEntryWidth,
wh: entryHeight,
data: Format[YInit],
scrollable: FALSE,
border: FALSE ] ];
data.slider ← Sliders.Create[
info: [
parent: cieViewer,
wx: leftX,
wy: topY + entryHeight + entryVSpace,
ww: sliderWidth,
wh: sliderHeight
],
clientData: data,
sliderProc: CIESetY,
filterProc: CIEFilterY
];
leftX ← leftX+valueEntryWidth+2*entryHSpace;
data.triangle ← CIETriangle.Create[
info: [
parent: cieViewer,
wx: leftX,
wy: topY + entryHeight + entryVSpace,
ww: triangleSize,
wh: triangleSize,
border: TRUE
],
xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb, xw: xw, yw: yw, scale: triangleSize,
proc: NewXY
];
data.xText ← ViewerTools.MakeNewTextViewer[ [
parent: cieViewer,
wx: leftX,
wy: topY,
ww: valueEntryWidth,
wh: entryHeight,
data: Format[xInit],
scrollable: FALSE,
border: FALSE ] ];
leftX ← leftX+valueEntryWidth+entryHSpace;
data.yText ← ViewerTools.MakeNewTextViewer[ [
parent: cieViewer,
wx: leftX,
wy: topY,
ww: valueEntryWidth,
wh: entryHeight,
data: Format[yInit],
scrollable: FALSE,
border: FALSE ] ];
leftX ← leftX+valueEntryWidth+entryHSpace;
data.zText ← ViewerTools.MakeNewTextViewer[ [
parent: cieViewer,
wx: leftX,
wy: topY,
ww: valueEntryWidth,
wh: entryHeight,
data: Format[1-(xInit+yInit)],
scrollable: FALSE,
border: FALSE ] ];
ViewerTools.InhibitUserEdits[data.zText];
topY ← topY+2*entryHeight+sliderHeight+entryHSpace;
data.initChoices ← ChoiceButtons.BuildEnumTypeSelection[
viewer: cieViewer,
x: button.wx + button.ww + entryHSpace,
y: topY,
title: "Init:",
buttonNames: CIEInitChoices,
default: "Long",
borderOnButtons: TRUE,
notifyClientProc: CIEInitUpdate,
clientdata: data,
style: menuSelection,
allInOneRow: TRUE ];
data.initChoices ← ChoiceButtons.BuildEnumTypeSelection[
viewer: cieViewer,
x: data.initChoices.nextx+entryHSpace,
y: topY,
title: "Y Tracking:",
buttonNames: YTrackChoices,
default: "Track Y",
borderOnButtons: TRUE,
notifyClientProc: YTrackUpdate,
clientdata: data,
style: menuSelection,
allInOneRow: TRUE ];
globalData ← data; --temporary hack
};
GetContents: PUBLIC PROCEDURE [cieViewer: Viewer] RETURNS [x,y, Y: REAL] = {
data: CIEData ← globalData;
[x,y] ← CIETriangle.GetContents[data.triangle];
Y ← Sliders.GetContents[data.slider];
};
SetContents: PUBLIC PROCEDURE [cieViewer: Viewer, x,y,Y: REAL] = {
data: CIEData ← globalData;
IF NOT (x=0 AND y=0) AND NOT (x=data.x AND y=data.y) THEN UpdateXY[data,x,y];
IF Y#data.Y THEN UpdateY[data,Y];
};
Reinitialize: PUBLIC PROCEDURE [cieViewer: Viewer, xr,yr,xg,yg,xb,yb,whiteY: REAL] = {
reinitializes the phosphor chromaticities
cieData: CIEData ← globalData;
xw,yw,Yw: REAL;
cieData.cieInit ← [xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb, whiteY: whiteY];
CGColorWithCIE.InitCIE[xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb, whiteY: whiteY];
[xw,yw,Yw] ← CGColorWithCIE.RGBToCIE[1,1,1];
CIETriangle.Reinitialize[cieTriangle: cieData.triangle, xr: xr, yr: yr, xg: xg, yg: yg, xb: xb, yb: yb, xw: xw, yw: yw];
UpdateY[cieData, Yw];
ViewerOps.PaintViewer[viewer: cieViewer, hint: all];
cieData.proc[self: cieViewer, x: xw, y: yw, Y: Yw, clientData: cieData.clientData];
};
UpdateY: PROC[cieData: CIEData, Y: REAL] = {
Y ← CIEFilterY[value: Y, clientData: cieData]; --should the slider do this automatically?
Sliders.SetContents[slider: cieData.slider, contents: Y];
Y ← Sliders.GetContents[slider: cieData.slider]; --may be clipped by filter proc
ViewerTools.SetContents[viewer: cieData.YText, contents: Format[Y]];
};
UpdateXY: PROC [cieData: CIEData, x,y: REAL] = {
CIETriangle.SetContents[cieTriangle: cieData.triangle, x: x, y: y];
[x,y] ← CIETriangle.GetContents[cieData.triangle]; --may be clipped to triangle
cieData.maxY ← CGColorWithCIE.GetMaxY[x,y];
UpdateXYText[cieData, x, y];
};
UpdateXYText: PROC [cieData: CIEData, x,y: REAL] = {
ViewerTools.SetContents[viewer: cieData.xText, contents: Format[x]];
ViewerTools.SetContents[viewer: cieData.yText, contents: Format[y]];
ViewerTools.SetContents[viewer: cieData.zText, contents: Format[1-(x+y)]];
};
Format: PROC[v: REAL] RETURNS [Rope.ROPE] = {
RETURN[IO.PutFR["%-5f", IO.real[v]]];
};
NewXY: CIETriangle.CIETriangleProc = {
cieData: CIEData ← globalData;
maxY: REAL;
IF x=cieData.x AND y=cieData.y THEN RETURN;
maxY ← CGColorWithCIE.GetMaxY[x,y];
IF cieData.yTrack OR maxY < Sliders.GetContents[cieData.slider] THEN UpdateY[cieData,maxY];
UpdateXYText[cieData,x,y];
cieData.maxY ← maxY;
cieData.x ← x; cieData.y ← y;
cieData.proc[self: NARROW[self.parent], x: x, y: y, Y: Sliders.GetContents[cieData.slider], clientData: cieData.clientData];
};
CIESetY: Sliders.SliderProc = {
data: CIEData ← NARROW[clientData];
x,y: REAL;
IF value=data.Y THEN RETURN;
data.Y ← value;
ViewerTools.SetContents[viewer: data.YText, contents: Format[value]];
[x,y] ← CIETriangle.GetContents[data.triangle];
data.proc[x: x, y: y, Y: value, self: slider.parent, clientData: data.clientData];
};
CIEFilterY: Sliders.FilterProc = {
data: CIEData ← NARROW[clientData];
RETURN[MIN[value,data.maxY]];
};
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];
};
END.