DIRECTORY Buttons USING [Button, ButtonProc, Create], ChoiceButtons USING [BuildEnumTypeSelection, ButtonList, EnumTypeRef, GetSelectedButton, SelectionNotifierProc, UpdateChoiceButtons], CIEViewer, ColorPatch, CNSColor USING [CNSFromCSL, CSLFromCNS, CSLChroma, CSLLightness, CSLSaturation, CSLFromHSL, HSLFromCSL], ColorToolViewer, ColorToolViewerExtras, Containers USING [Container, Create], Convert USING [RealFromRope], ImagerColor USING [ConstantColor, RGB, HSV, HSL, YIQ, HSVFromRGB, RGBFromHSV, HSLFromRGB, RGBFromHSL, YIQFromRGB, RGBFromYIQ, ColorFromAtom], ImagerDitheredDevice USING [ColorFromSpecialRGB], Terminal USING [Current, ChannelValue, ColorValue], ImagerColorMap USING [LoadEntries, MapEntry], Real USING [RoundC], IO USING [PutFR, real], Menus USING [Menu], MessageWindow USING [Append], CGColorWithCIE, Rope USING [Equal, ROPE], Sliders USING [Create, SetContents, SliderProc], Commander USING [CommandProc, Register], TiogaOps USING [InsertRope], VFonts USING [CharWidth], ViewerClasses USING [Column, Viewer, ViewerClass], ViewerOps USING [PaintViewer, SetOpenHeight, OpenIcon ], ViewerTools USING [MakeNewTextViewer, GetContents, SetContents], WindowManager USING [colorDisplayOn]; ColorToolViewerImpl: CEDAR PROGRAM IMPORTS Buttons, ChoiceButtons, CIEViewer, CNSColor, ColorPatch, Commander, Containers, Convert, ImagerColor, IO, MessageWindow, CGColorWithCIE, Rope, Sliders, TiogaOps, VFonts, ViewerOps, ViewerTools, WindowManager, ImagerColorMap, ImagerDitheredDevice, Terminal, Real EXPORTS ColorToolViewer, ColorToolViewerExtras = 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]; lastHandle: Handle _ NIL; --so the viewer can be manipulated by a program ColorPatchViewer: TYPE = ColorPatch.ColorPatchViewer; ColorPatchData: TYPE = ColorPatch.ColorPatchData; 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 rgb: RGBViewer, -- the RGB viewer's state hsv: HSVViewer, -- the HSV viewer's state hsl: HSLViewer, -- the HSL viewer's state yiq: YIQViewer, -- the YIQ viewer's state argyb: ARgYbViewer, -- the ARgYb viewer's state cns: CNSViewer, -- the CNS viewer's state menus: MenusViewer, -- the menu viewer's state colorPatch: ColorPatchViewer, -- the color patch viewer's state cie: CIEViewer.Viewer -- the CIE Viewer ]; GetRGBValue: PUBLIC PROC RETURNS [red,green,blue: REAL] = { data: ColorPatchData _ NARROW[lastHandle.colorPatch.data]; RETURN[red: data.rgb.R, green: data.rgb.G, blue: data.rgb.B]; }; 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]]]; }; GetSpecialColor: PUBLIC PROC RETURNS[ImagerColor.ConstantColor] = { ToByte: PROC[v: REAL] RETURNS[Terminal.ColorValue] = INLINE { RETURN[Real.RoundC[v*255]] }; patchData: ColorPatchData _ NARROW[lastHandle.colorPatch.data]; patchData.patchMapEntry.red _ ToByte[patchData.rgb.R]; patchData.patchMapEntry.green _ ToByte[patchData.rgb.G]; patchData.patchMapEntry.blue _ ToByte[patchData.rgb.B]; ImagerColorMap.LoadEntries[vt: Terminal.Current[], mapEntries: LIST[patchData.patchMapEntry], shared: FALSE]; RETURN[ImagerDitheredDevice.ColorFromSpecialRGB[ specialPixel: [patchData.patchMapEntry.mapIndex,null], rgb: patchData.rgb]]; }; MakeColorTool: Commander.CommandProc = { my: Handle _ NEW[ColorToolRec]; column: ViewerClasses.Column _ color; IF WindowManager.colorDisplayOn = FALSE THEN column _ left; my.outer _ Containers.Create[info: [ name: "Color Tool", iconic: TRUE, column: column, scrollable: TRUE ], paint: FALSE ]; MakeRGB[my]; MakeHSV[my]; MakeHSL[my]; MakeYIQ[my]; MakeARgYb[my]; MakeCNS[my]; MakeMenus[my]; MakeColorPatch[my]; MakeCIEViewer[my]; UpdateColorViewers[handle: my, color: [rgb[[initialRed, initialGreen, initialBlue]]]]; ViewerOps.SetOpenHeight[my.outer, my.height]; ViewerOps.OpenIcon[my.outer]; 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: ImagerColor.ColorFromAtom[$Red], color2: ImagerColor.ColorFromAtom[$Green], color3: ImagerColor.ColorFromAtom[$Blue], xOrigin: 200, yOrigin: 0 ]^; }; 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, xOrigin: 0, yOrigin: 0 ]^; }; 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, xOrigin: 0, yOrigin: 150 ]^; }; YIQViewer: TYPE = RECORD [ intensityText: ViewerClasses.Viewer _ NIL, inPhaseText: ViewerClasses.Viewer _ NIL, quadratureText: ViewerClasses.Viewer _ NIL, intensitySlider: ViewerClasses.Viewer _ NIL, inPhaseSlider: ViewerClasses.Viewer _ NIL, quadratureSlider: ViewerClasses.Viewer _ NIL ]; MakeYIQ: PROCEDURE [handle: Handle] = { [handle.yiq.intensityText, handle.yiq.inPhaseText, handle.yiq.quadratureText, handle.yiq.intensitySlider, handle.yiq.inPhaseSlider, handle.yiq.quadratureSlider] _ MakeColorSchemeViewer[ handle: handle, name: "YIQ", buttonProc: ComputeFromYIQ, sliderProc1: YIQIntensitySliderUpdate, sliderProc2: YIQInPhaseSliderUpdate, sliderProc3: YIQQuadratureSliderUpdate, xOrigin: 400, yOrigin: 0 ]^; }; ARgYbViewer: TYPE = RECORD [ achromaticText: ViewerClasses.Viewer _ NIL, redGreenText: ViewerClasses.Viewer _ NIL, yellowBlueText: ViewerClasses.Viewer _ NIL, achromaticSlider: ViewerClasses.Viewer _ NIL, redGreenSlider: ViewerClasses.Viewer _ NIL, yellowBlueSlider: ViewerClasses.Viewer _ NIL ]; MakeARgYb: PROCEDURE [handle: Handle] = { [handle.argyb.achromaticText, handle.argyb.redGreenText, handle.argyb.yellowBlueText, handle.argyb.achromaticSlider, handle.argyb.redGreenSlider, handle.argyb.yellowBlueSlider] _ MakeColorSchemeViewer[ handle: handle, name: "ARgYb", buttonProc: ComputeFromARgYb, sliderProc1: ARgYbAchromaticSliderUpdate, sliderProc2: ARgYbRedGreenSliderUpdate, sliderProc3: ARgYbYellowBlueSliderUpdate, xOrigin: 400, yOrigin: 150 ]^; }; MakeColorSchemeViewer: PROCEDURE [handle: Handle, name: Rope.ROPE, buttonProc: Buttons.ButtonProc, sliderProc1, sliderProc2, sliderProc3: Sliders.SliderProc, color1, color2, color3: ImagerColor.ConstantColor _ NIL, xOrigin, yOrigin: CARDINAL] RETURNS [ret: REF SixViewers] = { valueEntryWidth: CARDINAL = 8 * VFonts.CharWidth['0]; -- eight digits worth of width xPosition: CARDINAL _ xOrigin; yPosition: CARDINAL _ yOrigin; button: Buttons.Button; ret _ NEW[SixViewers]; yPosition _ yPosition + entryVSpace; button _ Buttons.Create[ info: [ name: name, wx: xPosition + entryHSpace, wy: yPosition, wh: entryHeight, parent: handle.outer, border: TRUE ], clientData: handle, proc: buttonProc, paint: FALSE ]; yPosition _ yPosition + entryHeight; ret.text1 _ ViewerTools.MakeNewTextViewer[info: [ parent: handle.outer, wx: xPosition + entryHSpace, wy: yPosition+2, ww: valueEntryWidth, wh: entryHeight, data: " ", scrollable: FALSE, border: FALSE ], paint: FALSE ]; ret.text2 _ ViewerTools.MakeNewTextViewer[info: [ parent: handle.outer, wx: ret.text1.wx + ret.text1.ww + entryHSpace, wy: yPosition+2, ww: valueEntryWidth, wh: entryHeight, data: " ", scrollable: FALSE, border: FALSE ], paint: FALSE ]; ret.text3 _ ViewerTools.MakeNewTextViewer[info: [ parent: handle.outer, wx: ret.text2.wx + ret.text2.ww + entryHSpace, wy: yPosition+2, ww: valueEntryWidth, wh: entryHeight, data: " ", scrollable: FALSE, border: FALSE ], paint: FALSE ]; yPosition _ yPosition + entryHeight + entryVSpace; ret.slider1 _ Sliders.Create[ info: [ parent: handle.outer, wx: xPosition + entryHSpace, wy: yPosition, ww: sliderWidth, wh: sliderHeight ], foreground: color1, clientData: handle, sliderProc: sliderProc1, paint: FALSE ]; ret.slider2 _ Sliders.Create[ info: [ parent: handle.outer, wx: ret.text1.wx + ret.text1.ww + entryHSpace, wy: yPosition, ww: sliderWidth, wh: sliderHeight ], foreground: color2, clientData: handle, sliderProc: sliderProc2, paint: FALSE ]; ret.slider3 _ Sliders.Create[ info: [ parent: handle.outer, wx: ret.text2.wx + ret.text2.ww + entryHSpace, wy: yPosition, ww: sliderWidth, wh: sliderHeight ], foreground: color3, clientData: handle, sliderProc: sliderProc3, paint: FALSE ]; yPosition _ yPosition + sliderHeight; handle.height _ MAX[handle.height, yPosition]; RETURN[ret]; }; 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 = 610; -- not really width, it's the max x allowed on the screen! xPosition: CARDINAL = 0; yPosition: CARDINAL _ 300; button: Buttons.Button; yPosition _ yPosition + entryVSpace; button _ Buttons.Create[ info: [ name: "CNS", wx: xPosition + entryHSpace, wy: yPosition, wh: entryHeight, parent: handle.outer, border: TRUE ], clientData: handle, proc: ComputeFromCNS, paint: FALSE ]; yPosition _ yPosition + entryHeight; handle.cns.saturationChoices _ ChoiceButtons.BuildEnumTypeSelection[ viewer: handle.outer, x: button.wx, y: yPosition, title: "Saturation:", buttonNames: CNSSaturations, default: "Vivid", borderOnButtons: FALSE, notifyClientProc: CNSSaturationUpdate, clientdata: handle, style: menuSelection, allInOneRow: TRUE ]; yPosition _ yPosition + entryHeight; handle.cns.lightnessChoices _ ChoiceButtons.BuildEnumTypeSelection[ viewer: handle.outer, x: button.wx, y: yPosition, title: "Lightness:", buttonNames: CNSLightnesses, default: "Medium", borderOnButtons: FALSE, notifyClientProc: CNSLightnessUpdate, clientdata: handle, style: menuSelection, allInOneRow: TRUE ]; yPosition _ yPosition + entryHeight; handle.cns.hueChoices _ ChoiceButtons.BuildEnumTypeSelection[ viewer: handle.outer, x: button.wx, y: yPosition, title: "Hue: ", buttonNames: CNSHues, borderOnButtons: FALSE, notifyClientProc: CNSHueUpdate, clientdata: handle, style: menuSelection, allInOneRow: FALSE, maxWidth: maxWidth ]; yPosition _ yPosition + 8*entryHeight + entryVSpace; handle.height _ MAX[handle.height, yPosition]; }; DitherChoices: ChoiceButtons.ButtonList _ LIST[ "True", "False" ]; ContrastChoices: ChoiceButtons.ButtonList _ LIST[ "None", "All", "RGB", "HSV", "HSL", "YIQ", "ARgYb" ]; ConsistencyCheckChoices: ChoiceButtons.ButtonList _ LIST[ "On", "Off" ]; InterpolationChoices: ChoiceButtons.ButtonList _ LIST[ "Left", "Right", "Stop", "Off" ]; MenusViewer: TYPE = RECORD [ ditherChoices: ChoiceButtons.EnumTypeRef, contrastChoices: ChoiceButtons.EnumTypeRef, interpolationChoices: ChoiceButtons.EnumTypeRef, consistencyCheckChoices: ChoiceButtons.EnumTypeRef ]; MakeMenus: PROCEDURE [handle: Handle] = { xPosition: CARDINAL _ 350; yPosition: CARDINAL _ 300; yPosition _ yPosition + entryVSpace; handle.menus.contrastChoices _ ChoiceButtons.BuildEnumTypeSelection[ viewer: handle.outer, x: xPosition, y: yPosition, title: "Contrast:", buttonNames: ContrastChoices, default: "None", borderOnButtons: FALSE, notifyClientProc: ContrastUpdate, clientdata: handle, style: menuSelection, allInOneRow: TRUE ]; yPosition _ yPosition + entryHeight; handle.menus.ditherChoices _ ChoiceButtons.BuildEnumTypeSelection[ viewer: handle.outer, x: xPosition, y: yPosition, title: "Dither:", buttonNames: DitherChoices, default: "False", borderOnButtons: FALSE, notifyClientProc: DitherUpdate, clientdata: handle, style: menuSelection, allInOneRow: TRUE ]; xPosition _ 480; -- terrible isn't it? handle.menus.consistencyCheckChoices _ ChoiceButtons.BuildEnumTypeSelection[ viewer: handle.outer, x: xPosition, y: yPosition, title: "Consist. Check:", buttonNames: ConsistencyCheckChoices, default: "Off", borderOnButtons: FALSE, notifyClientProc: ConsistencyCheckUpdate, clientdata: handle, style: menuSelection, allInOneRow: TRUE ]; xPosition _ 350; -- just as bad yPosition _ yPosition + entryHeight; handle.menus.interpolationChoices _ ChoiceButtons.BuildEnumTypeSelection[ viewer: handle.outer, x: xPosition, y: yPosition, title: "Interpolation:", buttonNames: InterpolationChoices, default: "Off", borderOnButtons: FALSE, notifyClientProc: InterpolationUpdate, clientdata: handle, style: menuSelection, allInOneRow: TRUE ]; yPosition _ yPosition + 8*entryHeight + entryVSpace; handle.height _ MAX[handle.height, yPosition]; }; MakeColorPatch: PROCEDURE [handle: Handle] = { xPosition: CARDINAL = 167; yPosition: CARDINAL _ 150; height: INTEGER = 150; width: INTEGER _ 200; yPosition _ yPosition + entryVSpace; handle.colorPatch _ ColorPatch.MakeColorPatch[parent: handle.outer, wx: xPosition + entryHSpace, wy: yPosition, width: width, height: height]; yPosition _ yPosition + height + entryVSpace; handle.height _ MAX[handle.height, yPosition]; }; ComputeFromRGB: Buttons.ButtonProc = { handle: Handle _ NARROW[clientData]; redValue: REAL _ GetColorValue[handle.rgb.redText]; greenValue: REAL _ GetColorValue[handle.rgb.greenText]; blueValue: REAL _ GetColorValue[handle.rgb.blueText]; UpdateColorViewers[handle: handle, color: [rgb[[redValue, greenValue, blueValue]]]]; IF shift THEN { StuffSelection[handle.rgb.redText, handle.rgb.greenText, handle.rgb.blueText]; }; }; RedSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [rgb[[value, patchData.rgb.G, patchData.rgb.B]]]]; }; GreenSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [rgb[[patchData.rgb.R, value, patchData.rgb.B]]]]; }; BlueSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [rgb[[patchData.rgb.R, patchData.rgb.G, value]]]]; }; ComputeFromHSV: Buttons.ButtonProc = { handle: Handle _ NARROW[clientData]; hueValue: REAL _ GetColorValue[handle.hsv.hueText]; saturationValue: REAL _ GetColorValue[handle.hsv.saturationText]; valueValue: REAL _ GetColorValue[handle.hsv.valueText]; UpdateColorViewers[handle: handle, color: [hsv[[hueValue, saturationValue, valueValue]]]]; IF shift THEN { StuffSelection[handle.hsv.hueText, handle.hsv.saturationText, handle.hsv.valueText]; }; }; HueSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [hsv[[value, patchData.hsv.S, patchData.hsv.V]]]]; }; SaturationSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [hsv[[patchData.hsv.H, value, patchData.hsv.V]]]]; }; ValueSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [hsv[[patchData.hsv.H, patchData.hsv.S, value]]]]; }; ComputeFromHSL: Buttons.ButtonProc = { handle: Handle _ NARROW[clientData]; hueValue: REAL _ GetColorValue[handle.hsl.hueText]; saturationValue: REAL _ GetColorValue[handle.hsl.saturationText]; lightnessValue: REAL _ GetColorValue[handle.hsl.lightnessText]; UpdateColorViewers[handle: handle, color: [hsl[[hueValue, saturationValue, lightnessValue]]]]; IF shift THEN { StuffSelection[handle.hsl.hueText, handle.hsl.saturationText, handle.hsl.lightnessText]; }; }; HSLHueSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [hsl[[value, patchData.hsl.S, patchData.hsl.L]]]]; }; HSLSaturationSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [hsl[[patchData.hsl.H, value, patchData.hsl.L]]]]; }; HSLLightnessSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [hsl[[patchData.hsl.H, patchData.hsl.S, value]]]]; }; GetColorValue: PROCEDURE [v: ViewerClasses.Viewer] RETURNS [value: REAL] = { rope: Rope.ROPE ~ ViewerTools.GetContents[v]; 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]; }; StuffSelection: PROC [v1, v2, v3: ViewerClasses.Viewer] ~ { TiogaOps.InsertRope[ViewerTools.GetContents[v1]]; TiogaOps.InsertRope[ViewerTools.GetContents[v2]]; TiogaOps.InsertRope[ViewerTools.GetContents[v3]]; }; ComputeFromYIQ: Buttons.ButtonProc = { handle: Handle _ NARROW[clientData]; intensityValue: REAL _ GetColorValue[handle.yiq.intensityText]; inPhaseValue: REAL _ GetColorValue[handle.yiq.inPhaseText]; quadratureValue: REAL _ GetColorValue[handle.yiq.quadratureText]; UpdateColorViewers[handle: handle, color: [yiq[[intensityValue, inPhaseValue, quadratureValue]]]]; IF shift THEN { StuffSelection[handle.yiq.intensityText, handle.yiq.inPhaseText, handle.yiq.quadratureText]; }; }; YIQIntensitySliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [yiq[[value, patchData.yiq.I, patchData.yiq.Q]]]]; }; YIQInPhaseSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [yiq[[patchData.yiq.Y, value, patchData.yiq.Q]]]]; }; YIQQuadratureSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [yiq[[patchData.yiq.Y, patchData.yiq.I, value]]]]; }; ComputeFromARgYb: Buttons.ButtonProc = { handle: Handle _ NARROW[clientData]; achromaticValue: REAL _ GetColorValue[handle.argyb.achromaticText]; redGreenValue: REAL _ GetColorValue[handle.argyb.redGreenText]; yellowBlueValue: REAL _ GetColorValue[handle.argyb.yellowBlueText]; UpdateColorViewers[handle: handle, color: [argyb[achromaticValue, redGreenValue, yellowBlueValue]]]; IF shift THEN { StuffSelection[handle.argyb.achromaticText, handle.argyb.redGreenText, handle.argyb.yellowBlueText]; }; }; ARgYbAchromaticSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [argyb[value, patchData.argybRg, patchData.argybYb]]]; }; ARgYbRedGreenSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [argyb[patchData.argybA, value, patchData.argybYb]]]; }; ARgYbYellowBlueSliderUpdate: Sliders.SliderProc = { handle: Handle _ NARROW[clientData]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; UpdateColorViewers[handle: handle, color: [argyb[patchData.argybA, patchData.argybRg, 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.CSLFromCNS[hue, saturation, lightness]; UpdateColorViewers[handle: handle, color: [csl[c, s, l]]]; }; CNSHueUpdate: ChoiceButtons.SelectionNotifierProc = { handle: Handle _ NARROW[clientdata]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; hue, saturation, lightness: Rope.ROPE; c: CNSColor.CSLChroma; s: CNSColor.CSLSaturation; l: CNSColor.CSLLightness; [hue, saturation, lightness] _ CNSColor.CNSFromCSL[patchData.cslC, patchData.cslS, patchData.cslL]; [c, s, l] _ CNSColor.CSLFromCNS[ name, saturation, lightness]; UpdateColorViewers[handle: handle, color: [csl[c, s, l]]]; }; CNSSaturationUpdate: ChoiceButtons.SelectionNotifierProc = { handle: Handle _ NARROW[clientdata]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; hue, saturation, lightness: Rope.ROPE; c: CNSColor.CSLChroma; s: CNSColor.CSLSaturation; l: CNSColor.CSLLightness; [hue, saturation, lightness] _ CNSColor.CNSFromCSL[patchData.cslC, patchData.cslS, patchData.cslL]; [c, s, l] _ CNSColor.CSLFromCNS[ hue, name, lightness]; UpdateColorViewers[handle: handle, color: [csl[c, s, l]]]; }; CNSLightnessUpdate: ChoiceButtons.SelectionNotifierProc = { handle: Handle _ NARROW[clientdata]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; hue, saturation, lightness: Rope.ROPE; c: CNSColor.CSLChroma; s: CNSColor.CSLSaturation; l: CNSColor.CSLLightness; [hue, saturation, lightness] _ CNSColor.CNSFromCSL[patchData.cslC, patchData.cslS, patchData.cslL]; [c, s, l] _ CNSColor.CSLFromCNS[ hue, saturation, name]; UpdateColorViewers[handle: handle, color: [csl[c, s, l]]]; }; DitherUpdate: ChoiceButtons.SelectionNotifierProc = { handle: Handle _ NARROW[clientdata]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; ditherRope: Rope.ROPE _ ChoiceButtons.GetSelectedButton[handle.menus.ditherChoices]; SELECT ditherRope FROM "True" => patchData.dither _ TRUE; "False" => patchData.dither _ FALSE; ENDCASE; ViewerOps.PaintViewer[viewer: handle.colorPatch, hint: client, clearClient: FALSE]; }; ConsistencyCheckUpdate: ChoiceButtons.SelectionNotifierProc = { handle: Handle _ NARROW[clientdata]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; consistencyCheckRope: Rope.ROPE _ ChoiceButtons.GetSelectedButton[handle.menus.consistencyCheckChoices]; redValue: REAL _ GetColorValue[handle.rgb.redText]; greenValue: REAL _ GetColorValue[handle.rgb.greenText]; blueValue: REAL _ GetColorValue[handle.rgb.blueText]; SELECT consistencyCheckRope FROM "On" => { patchData.consistencyCheck _ TRUE; UpdateColorViewers[handle: handle, color: [rgb[[redValue, greenValue, blueValue]]]]; }; "Off" => patchData.consistencyCheck _ FALSE; ENDCASE; }; InterpolationUpdate: ChoiceButtons.SelectionNotifierProc = { handle: Handle _ NARROW[clientdata]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; interpolationRope: Rope.ROPE _ ChoiceButtons.GetSelectedButton[handle.menus.interpolationChoices]; repaint: BOOLEAN _ FALSE; wasOff: BOOLEAN _ IF patchData.interpolationRequest = off THEN TRUE ELSE FALSE; SELECT interpolationRope FROM "Left" => { patchData.interpolationRequest _ left; IF wasOff THEN repaint _ TRUE; }; "Right" => { patchData.interpolationRequest _ right; IF wasOff THEN repaint _ TRUE; }; "Stop" => { patchData.interpolationRequest _ stop; IF wasOff THEN repaint _ TRUE; }; "Off" => { patchData.interpolationRequest _ off; repaint _ TRUE; }; ENDCASE; IF repaint THEN ViewerOps.PaintViewer[viewer: handle.colorPatch, hint: client, clearClient: FALSE]; }; ContrastUpdate: ChoiceButtons.SelectionNotifierProc = { handle: Handle _ NARROW[clientdata]; patchData: ColorPatchData _ NARROW[handle.colorPatch.data]; contrastRope: Rope.ROPE _ ChoiceButtons.GetSelectedButton[handle.menus.contrastChoices]; SELECT contrastRope FROM "All" => { patchData.rgbContrast _ TRUE; patchData.hsvContrast _ TRUE; patchData.hslContrast _ TRUE; patchData.yiqContrast _ TRUE; patchData.argybContrast _ TRUE; }; "None" => { patchData.rgbContrast _ FALSE; patchData.hsvContrast _ FALSE; patchData.hslContrast _ FALSE; patchData.yiqContrast _ FALSE; patchData.argybContrast _ FALSE; }; "RGB" => { patchData.rgbContrast _ TRUE; patchData.hsvContrast _ FALSE; patchData.hslContrast _ FALSE; patchData.yiqContrast _ FALSE; patchData.argybContrast _ FALSE; }; "HSV" => { patchData.rgbContrast _ FALSE; patchData.hsvContrast _ TRUE; patchData.hslContrast _ FALSE; patchData.yiqContrast _ FALSE; patchData.argybContrast _ FALSE; }; "HSL" => { patchData.rgbContrast _ FALSE; patchData.hsvContrast _ FALSE; patchData.hslContrast _ TRUE; patchData.yiqContrast _ FALSE; patchData.argybContrast _ FALSE; }; "YIQ" => { patchData.rgbContrast _ FALSE; patchData.hsvContrast _ FALSE; patchData.hslContrast _ FALSE; patchData.yiqContrast _ TRUE; patchData.argybContrast _ FALSE; }; "ARgYb" => { patchData.rgbContrast _ FALSE; patchData.hsvContrast _ FALSE; patchData.hslContrast _ FALSE; patchData.yiqContrast _ FALSE; patchData.argybContrast _ TRUE; }; ENDCASE; ViewerOps.PaintViewer[viewer: handle.colorPatch, hint: client, clearClient: FALSE]; }; ColorSpecification: TYPE = RECORD [ color: SELECT type: ColorType FROM hsv => [val: ImagerColor.HSV], hsl => [val: ImagerColor.HSL], yiq => [val: ImagerColor.YIQ], argyb => [a, rg, yb: REAL], rgb => [val: ImagerColor.RGB], cie => [x, y, Y: REAL], csl => [c: CNSColor.CSLChroma, s: CNSColor.CSLSaturation, l: CNSColor.CSLLightness], ENDCASE ]; ColorType: TYPE = {hsv, rgb, csl, hsl, yiq, argyb, cie}; UpdateColorViewers: PROCEDURE [handle: Handle, color: ColorSpecification] RETURNS [] = { UpdateColorValue: PROCEDURE [oldValue, newValue: REAL, textViewer, sliderViewer: ViewerClasses.Viewer] RETURNS [new: REAL] = { 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.data]; hsv: ImagerColor.HSV; rgb: ImagerColor.RGB; hsl: ImagerColor.HSL; yiq: ImagerColor.YIQ; a, rg, yb: REAL; chroma: CNSColor.CSLChroma; saturation: CNSColor.CSLSaturation; lightness: CNSColor.CSLLightness; cnsHue, cnsSaturation, cnsLightness: Rope.ROPE; WITH col: color SELECT FROM hsv => { hsv _ col.val; rgb _ ImagerColor.RGBFromHSV[hsv]; hsl _ ImagerColor.HSLFromRGB[rgb]; yiq _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; [a, rg, yb] _ CGColorWithCIE.RGBToARgYb[rgb.R, rgb.G, rgb.B]; [chroma, saturation, lightness] _ CNSColor.CSLFromHSL[hsl.H, hsl.S, hsl.L]; }; hsl => { hsl _ col.val; rgb _ ImagerColor.RGBFromHSL[hsl]; hsv _ ImagerColor.HSVFromRGB[rgb]; yiq _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; [a, rg, yb] _ CGColorWithCIE.RGBToARgYb[rgb.R, rgb.G, rgb.B]; [chroma, saturation, lightness] _ CNSColor.CSLFromHSL[hsl.H, hsl.S, hsl.L]; }; yiq => { yiq _ col.val; yiq.I _ yiq.I * 1.2 - 0.6; yiq.Q _ yiq.Q * 1.04 - 0.52; rgb _ ImagerColor.RGBFromYIQ[yiq]; rgb.R _ MIN[rgb.R,1]; rgb.G _ MIN[rgb.G,1]; rgb.B _ MIN[rgb.B,1]; rgb.R _ MAX[rgb.R,0]; rgb.G _ MAX[rgb.G,0]; rgb.B _ MAX[rgb.B,0]; IF patchData.consistencyCheck THEN yiq _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; hsv _ ImagerColor.HSVFromRGB[rgb]; hsl _ ImagerColor.HSLFromRGB[rgb]; [a, rg, yb] _ CGColorWithCIE.RGBToARgYb[rgb.R, rgb.G, rgb.B]; [chroma, saturation, lightness] _ CNSColor.CSLFromHSL[hsl.H, hsl.S, hsl.L]; }; argyb => { a _ col.a; rg _ col.rg; yb _ col.yb; [rgb.R, rgb.G, rgb.B] _ CGColorWithCIE.ARgYbToRGB[a, rg, yb]; rgb.R _ MIN[rgb.R,1]; rgb.G _ MIN[rgb.G,1]; rgb.B _ MIN[rgb.B,1]; rgb.R _ MAX[rgb.R,0]; rgb.G _ MAX[rgb.G,0]; rgb.B _ MAX[rgb.B,0]; IF patchData.consistencyCheck THEN [a, rg, yb] _ CGColorWithCIE.RGBToARgYb[rgb.R, rgb.G, rgb.B]; hsv _ ImagerColor.HSVFromRGB[rgb]; hsl _ ImagerColor.HSLFromRGB[rgb]; yiq _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; [chroma, saturation, lightness] _ CNSColor.CSLFromHSL[hsl.H, hsl.S, hsl.L]; }; rgb => { rgb _ col.val; hsv _ ImagerColor.HSVFromRGB[rgb]; hsl _ ImagerColor.HSLFromRGB[rgb]; yiq _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; [a, rg, yb] _ CGColorWithCIE.RGBToARgYb[rgb.R, rgb.G, rgb.B]; [chroma, saturation, lightness] _ CNSColor.CSLFromHSL[hsl.H, hsl.S, hsl.L]; }; cie => { [rgb.R, rgb.G, rgb.B] _ CGColorWithCIE.CIEToRGB[col.x,col.y,col.Y]; rgb.R _ MIN[rgb.R,1]; rgb.G _ MIN[rgb.G,1]; rgb.B _ MIN[rgb.B,1]; rgb.R _ MAX[rgb.R,0]; rgb.G _ MAX[rgb.G,0]; rgb.B _ MAX[rgb.B,0]; hsv _ ImagerColor.HSVFromRGB[rgb]; hsl _ ImagerColor.HSLFromRGB[rgb]; yiq _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; [a, rg, yb] _ CGColorWithCIE.RGBToARgYb[rgb.R, rgb.G, rgb.B]; [chroma, saturation, lightness] _ CNSColor.CSLFromHSL[hsl.H, hsl.S, hsl.L]; }; csl => { chroma _ col.c; saturation _ col.s; lightness _ col.l; [hsl.H, hsl.S, hsl.L] _ CNSColor.HSLFromCSL[ chroma, saturation, lightness]; rgb _ ImagerColor.RGBFromHSL[hsl]; hsv _ ImagerColor.HSVFromRGB[rgb]; yiq _ ImagerColor.YIQFromRGB[rgb]; yiq.I _ (yiq.I + 0.6) / 1.2; yiq.Q _ (yiq.Q + 0.52) / 1.04; [a, rg, yb] _ CGColorWithCIE.RGBToARgYb[rgb.R, rgb.G, rgb.B]; } ENDCASE; patchData.rgb.R _ UpdateColorValue[oldValue: patchData.rgb.R, newValue: rgb.R, textViewer: handle.rgb.redText, sliderViewer: handle.rgb.redSlider]; patchData.rgb.G _ UpdateColorValue[oldValue: patchData.rgb.G, newValue: rgb.G, textViewer: handle.rgb.greenText, sliderViewer: handle.rgb.greenSlider]; patchData.rgb.B _ UpdateColorValue[oldValue: patchData.rgb.B, newValue: rgb.B, textViewer: handle.rgb.blueText, sliderViewer: handle.rgb.blueSlider]; patchData.hsv.H _ UpdateColorValue[oldValue: patchData.hsv.H, newValue: hsv.H, textViewer: handle.hsv.hueText, sliderViewer: handle.hsv.hueSlider]; patchData.hsv.S _ UpdateColorValue[oldValue: patchData.hsv.S, newValue: hsv.S, textViewer: handle.hsv.saturationText, sliderViewer: handle.hsv.saturationSlider]; patchData.hsv.V _ UpdateColorValue[oldValue: patchData.hsv.V, newValue: hsv.V, textViewer: handle.hsv.valueText, sliderViewer: handle.hsv.valueSlider]; patchData.hsl.H _ UpdateColorValue[oldValue: patchData.hsl.H, newValue: hsl.H, textViewer: handle.hsl.hueText, sliderViewer: handle.hsl.hueSlider]; patchData.hsl.S _ UpdateColorValue[oldValue: patchData.hsl.S, newValue: hsl.S, textViewer: handle.hsl.saturationText, sliderViewer: handle.hsl.saturationSlider]; patchData.hsl.L _ UpdateColorValue[oldValue: patchData.hsl.L, newValue: hsl.L, textViewer: handle.hsl.lightnessText, sliderViewer: handle.hsl.lightnessSlider]; patchData.yiq.Y _ UpdateColorValue[oldValue: patchData.yiq.Y, newValue: yiq.Y, textViewer: handle.yiq.intensityText, sliderViewer: handle.yiq.intensitySlider]; patchData.yiq.I _ UpdateColorValue[oldValue: patchData.yiq.I, newValue: yiq.I, textViewer: handle.yiq.inPhaseText, sliderViewer: handle.yiq.inPhaseSlider]; patchData.yiq.Q _ UpdateColorValue[oldValue: patchData.yiq.Q, newValue: yiq.Q, textViewer: handle.yiq.quadratureText, sliderViewer: handle.yiq.quadratureSlider]; patchData.argybA _ UpdateColorValue[oldValue: patchData.argybA, newValue: a, textViewer: handle.argyb.achromaticText, sliderViewer: handle.argyb.achromaticSlider]; patchData.argybRg _ UpdateColorValue[oldValue: patchData.argybRg, newValue: rg, textViewer: handle.argyb.redGreenText, sliderViewer: handle.argyb.redGreenSlider]; patchData.argybYb _ UpdateColorValue[oldValue: patchData.argybYb, newValue: yb, textViewer: handle.argyb.yellowBlueText, sliderViewer: handle.argyb.yellowBlueSlider]; [cnsHue, cnsSaturation, cnsLightness] _ CNSColor.CNSFromCSL[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 patchData.consistencyCheck OR color.type#cie THEN { x,y,Y: REAL; [x,y,Y] _ CGColorWithCIE.RGBToCIE[rgb.R,rgb.G,rgb.B]; CIEViewer.SetContents[handle.cie, x,y,Y]; }; ViewerOps.PaintViewer[viewer: handle.colorPatch, hint: client, clearClient: FALSE]; }; Commander.Register[key: "ColorTool", proc: MakeColorTool, doc: "Create a color tool"]; END. .ColorToolViewerImpl.mesa Written by Darlene Plebon on June 24, 1983 11:14 am Last Edited by: Stone, June 9, 1986 11:18:16 am PDT Last Edited by: Beach, April 1, 1984 6:00:29 pm PST Rick Beach, October 25, 1985 8:40:58 pm PDT Avi Naiman, September 8, 1985 7:30:32 pm PDT hack to avoid an unsafe return The color naming scheme. The color patch reflecting the currently selected color. depend on the viewer contents having form: "d.dd " from the "%-5f" format in UpdateColorViewers IF newValue=CGColorWithCIE.undefined THEN RETURN[oldValue]; we have to protect ourselves from receiving back RGB values outside of the [0,1] range we have to protect ourselves from receiving back RGB values outside of the [0,1] range control precision problems Register a command that will create an instance of this tool. Κ φ– "Cedar" style˜code– "Cedar" stylešœ™K– "Cedar" stylešœ3™3K™3K™3K™+K™,—K™šΟk ˜ Kšœœ˜+Kšœœr˜…K˜ K˜ Kšœ œZ˜hKšœ˜Kšœ˜Kšœ œ˜%Kšœœ˜Kš œ œœœœY˜Jšœœ˜1Jšœ œ%˜3Jšœœ˜-Jšœœ ˜Kšœœ˜Kšœœ˜Kšœœ ˜Kšœ˜Kšœœ œ˜Kšœœ#˜0Kšœ œ˜(Kšœ œ˜Kšœœ ˜Kšœœ˜2Kšœ œ)˜8Kšœ œ/˜@Kšœœ˜%—K˜KšΠlnœœ˜"Kšœgœž˜ŽKšœ'˜.Kšœ˜Kšœ œΟc+˜HKšœ œŸ'˜DKšœ œ Ÿ+˜IKšœœŸ˜5Kšœ œŸ%˜BKšœœ Ÿ&˜EKšœ œ Ÿ'˜CKšœœ˜Kšœ œ˜K˜Kšœ œœG˜`Kšœ™KšœœŸ/˜JKšœœ˜5Kšœœ˜1Kšœœœ˜ šœœœ˜KšœœŸ%˜HKšœœ Ÿ0˜JKšœŸ˜.KšœŸ˜.KšœŸ˜/KšœŸ˜/KšœŸ˜3KšœŸ˜/KšœŸ˜2Kšœ Ÿ!˜AKšœŸ˜+Kšœ˜—K˜K˜š Οn œœœœœ˜;Kšœœ˜:Kšœ7˜=K˜—K˜š  œœœœo˜Kšœœ˜:KšœJ˜PK˜—K˜š  œœœœ˜3KšœG˜GK˜—K˜š  œœœp˜ˆKšœ]˜]K˜—K˜š œ œœ˜CIprocš  œœœœœœ˜[Kšœœ˜?Lšœ6˜6Lšœ8˜8Lšœ7˜7šœ2˜2Lšœ œ#œ˜:—šœ*˜0LšœL˜L—J˜J˜—š  œ˜(Kšœ œ˜K˜%Kšœ œœ˜;šœ$˜$Kšœ˜Kšœœ˜ Kšœ˜Kšœ œ˜Kšœœ˜—Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜K˜ K˜Kšœ˜K˜KšœV˜VKšœ-˜-Kšœ˜K˜Kšœ˜—K˜š œ˜%Kšœœ ˜$Kšœ8˜8Kšœ˜K˜—š  œ œ˜-šœ˜Kšœ˜K˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—K˜šœ œœ˜Kšœ œ˜$Kšœ"œ˜&Kšœ!œ˜&Kšœ"œ˜&Kšœ$œ˜(Kšœ#˜&Kšœ˜—K˜š œ œ˜'šœ˜Kšœ˜Kšœ ˜ Kšœ˜K˜K˜K˜K˜(K˜*K˜)K˜ K˜ Kšœ˜—Kšœ˜—K˜šœ œœ˜Kšœ œ˜$Kšœ'œ˜+Kšœ"œ˜&Kšœ"œ˜&Kšœ)œ˜-Kšœ$˜'Kšœ˜—K˜š œ œ˜'šœ©˜©Kšœ˜Kšœ ˜ Kšœ˜K˜K˜$K˜K˜ K˜ Kšœ˜—K˜—K˜šœ œœ˜Kšœ œ˜$Kšœ'œ˜+Kšœ&œ˜*Kšœ"œ˜&Kšœ)œ˜-Kšœ(˜+Kšœ˜—K˜š œ œ˜'šœ±˜±Kšœ˜Kšœ ˜ Kšœ˜K˜ K˜'K˜&K˜ K˜ Kšœ˜—K˜—K˜šœ œœ˜Kšœ&œ˜*Kšœ$œ˜(Kšœ'œ˜+Kšœ(œ˜,Kšœ&œ˜*Kšœ)˜,Kšœ˜—K˜š œ œ˜'šœΉ˜ΉKšœ˜Kšœ ˜ Kšœ˜K˜&K˜$Kšœ'˜'K˜ K˜ Kšœ˜—K˜K˜—šœ œœ˜Kšœ'œ˜+Kšœ%œ˜)Kšœ'œ˜+Kšœ)œ˜-Kšœ'œ˜+Kšœ)˜,Kšœ˜—K˜š  œ œ˜)šœΙ˜ΙKšœ˜Kšœ˜Kšœ˜K˜)K˜'Kšœ)˜)K˜ K˜ Kšœ˜—K˜—K˜š œ œœ‘œœœœ˜”KšœœŸ˜TKšœ œ ˜Kšœ œ ˜Kšœ˜Kšœœ ˜Kšœ$˜$šœ˜šœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœœ˜—Kšœ˜Kšœ˜Kšœœ˜—Kšœ$˜$šœ1˜1Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœœ˜Kšœœ˜—šœ1˜1Kšœ˜Kšœ.˜.Kšœ˜KšœŸ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœœ˜Kšœœ˜—šœ1˜1Kšœ˜Kšœ.˜.Kšœ˜KšœŸ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœœ˜Kšœœ˜—Kšœ2˜2šœ˜šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜K˜Kšœ˜Kšœ˜ Kšœ˜—šœ˜šœ˜Kšœ˜Kšœ.˜.Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜K˜Kšœ˜Kšœ˜ Kšœ˜—šœ˜šœ˜Kšœ˜Kšœ.˜.Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜K˜Kšœ˜Kšœ˜ Kšœ˜—Kšœ%˜%Kšœœ˜.Kšœ˜ K˜—K˜K™šœ$œ˜*Kšœ3˜3K˜>K˜˜>Kšœ:˜:K˜K˜—š œ)˜˜>Kšœ˜—Kšœ ˜K˜—Kšœœ˜;Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœ œ˜Kšœ˜Kšœ#˜#Kšœ!˜!Kšœ*œ˜/šœ œ˜šœ˜K˜Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ;˜;Kšœ=˜=KšœK˜KKšœ˜—šœ˜K˜Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ;˜;Kšœ=˜=KšœK˜KKšœ˜—šœ˜Kšœ˜K˜7Kšœ"˜"K™VKšœœœœ ˜AKšœœœœ ˜Ašœ˜"Kšœ"˜"—Kšœ;˜;Kšœ"˜"Kšœ"˜"Kšœ=˜=KšœK˜KKšœ˜—šœ ˜ Kšœ$˜$Kšœ=˜=K™VKšœœœœ ˜AKšœœœœ ˜Ašœ˜"Kšœ=˜=—Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ;˜;KšœK˜KKšœ˜—šœ˜K˜Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ;˜;Kšœ=˜=KšœK˜KK˜—šœ˜Kšœ@œ˜CKšŸ™Kšœœœœ ˜AKšœœœœ ˜AKšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ;˜;Kšœ=˜=KšœK˜KK˜—šœ˜Kšœ6˜6KšœL˜LKšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ;˜;Kšœ=˜=K˜—Kšœ˜—K˜K˜Kšœ”˜”Kšœ˜˜˜Kšœ–˜–Kšœ”˜”Kšœ’˜’Kšœ˜˜˜Kšœ”˜”Kšœ’˜’Kšœ ˜ Kšœ ˜ Kšœœ˜œKšœ’˜’Kšœ€˜€Kšœ£˜£Kšœ§˜§K˜Kšœ[˜[K˜šœœœ˜=Kšœ˜Kšœn˜nK˜—šœœ œ˜HKšœ˜Kšœ|˜|K˜—šœœœ˜FKšœ˜Kšœz˜zK˜—K˜šœœ˜4Kšœ˜Kšœœ˜ Kšœœ/˜5Kšœ&œ˜)K˜—KšœLœ˜SK˜—K™Kšœ=™=KšœV˜VK™Kšœ˜K˜K™K™—…—€±€