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 ANY _ NIL ]; 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; }; Create: PUBLIC PROCEDURE [info: ViewerClasses.ViewerRec _ [], sliderWidth, sliderHeight: CARDINAL, proc: CIEProc, clientData: REF ANY _ NIL, 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] = { 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. ΰ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 all values should be in the range 0..1 reinitializes the phosphor chromaticities Κ ˜Jšœ™Jšœ<™˜’Jšœ ˜—J˜Jšœœ ˜Jšœ œœœ˜7J˜EJšœ œœ ˜šœ œœ˜Jšœ˜JšœœΟc*˜NJšœž˜ Jšœœ˜"Jšœœ˜#Jšœœ˜#Jšœœ˜#Jšœœœž>˜LJšœ)œ˜-Jšœ$œ˜(Jšœœž8˜IJšœœž ˜,J˜Jšœ œœ˜J˜—Jšœ+œ˜BJšœ*œ˜DšΟbœ˜&Jšœœ ˜#Jšœœ6˜BJšœœ6˜BJšœœ6˜BJšœ˜J˜Jšœ:œ'˜bJ˜—šŸ œ)˜6Jšœœ ˜#Jšœœ˜ Jšœœ˜šœœ˜!Jšœ$˜$JšœY˜YJ˜—šœœ˜#Jšœ&˜&Jšœ[˜[J˜—Jšœœ/ž˜FJšœs˜sJšœ˜Jšœ˜J˜—šŸ œ)˜5Jšœœ ˜#šœœ˜$Jšœœ˜J˜J˜—Jšœœœ˜6J˜—Jšœ&™&šΟnœœ œAœœœœœœ˜ΡJšœ˜Jšœœ˜Jšœœ˜Jšœ˜Jšœ œ˜Jšœ œ˜Jšœœ˜!Jšœœ˜&Jšœ œ˜Jšœœž˜TJšœ˜Jšœ$˜$JšœY˜YJšœA˜Ašœœ˜Jšœ˜Jšœ ˜ JšœF˜FJšœœ˜ Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ ˜ —Jšœ*˜*šœ˜šœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœœ˜—Jšœ˜Jšœ˜Jšœ˜—Jšœ,˜,šœ-˜-Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ œ˜Jšœœ˜—šœ˜codešœ˜Jšœ˜Jšœ ˜ Jšœ%˜%Jšœ˜Jšœ˜Jšœ˜—J˜Jšœ˜Jšœ˜Jšœ˜—Jšœ-˜-šœ#˜#šœ˜Jšœ˜Jšœ ˜ Jšœ%˜%Jšœ˜Jšœ˜Jšœ˜ Jšœ˜—JšœT˜TJ˜ Jšœ˜—šœ-˜-Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ œ˜Jšœœ˜—Jšœ+˜+šœ-˜-Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ œ˜Jšœœ˜—Jšœ+˜+šœ-˜-Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ œ˜Jšœœ˜—Jšœ)˜)Jšœ4˜4šœ8˜8Jšœ˜Jšœ'˜'Jšœ˜J˜Jšœ˜J˜Jšœœ˜Jšœ ˜ Jšœ˜J˜Jšœ œ˜—šœ8˜8Jšœ˜Jšœ&˜&Jšœ˜J˜Jšœ˜J˜Jšœœ˜Jšœ˜Jšœ˜J˜Jšœ œ˜—Jšœž˜#Jšœ˜—š   œœ œœœœ˜LJšœ˜J˜/Jšœ$˜%J˜—š   œœ œœœ˜BJšœ˜Jšœœœœœ œ œ˜MJš œœœœœ˜!J˜—š  œœ œ/œ˜VJšœ)™)Jšœ˜Jšœ ˜JšœS˜SJšœW˜WJšœ,˜,Jšœx˜xJšœ˜Jšœ4˜4JšœS˜SJ˜—š œœœœ˜,Jšœœ œ ž*˜YJšœ9˜9Jšœ0ž˜PJšœD˜DJ˜—š œœœ˜0JšœC˜CJšœ3ž˜OJšœ+˜+Jšœ˜J˜—š  œœœ˜4JšœD˜DJšœD˜DJšœJ˜JJ˜—š  œœœœœ˜-Jšœœœ ˜%J˜—š œ!˜&Jšœ˜Jšœœ˜ Jšœ œ œœ˜+Jšœ#˜#Jšœœ,œ˜[Jšœ˜Jšœ˜J˜Jšœœc˜|J˜—š œ˜Jšœœ ˜#Jšœœ˜ Jšœ œœœ˜J˜JšœE˜EJ˜/JšœR˜RJšœ˜—šŸ œ˜"Jšœœ ˜#Jšœœ˜Jšœ˜—š   œ œ œœ œ˜DJ˜#šœ œ œ˜$Jšœ<œ˜BJšœ0œ˜7J˜ Jšœ˜—Jšœ˜J˜—J˜Jšœ˜J˜—…—%40.