DIRECTORY TrcStandardClasses, Abutters USING [Create, QuaViewer, vanilla], AIS USING [Error, Histogram, OpenFile, ReadHistogram], Buttons USING [ButtonProc, Create], ChoiceButtons USING [BuildTextPrompt, PromptDataRef], FS USING [Error, FileInfo], IO USING [GetAtom, GetCedarTokenRope, GetCard, GetReal, PutF, PutRope, TokenKind], KnobAttach USING [Attach, Create, KnobAttachViewer], Labels USING [Create, Label], MessageWindow USING [Append, Blink], RealFns USING [Tan], RealOps USING [RoundC], Rope USING [ROPE, Concat, Equal, Length, Substr], Sliders USING [Create, Slider, SliderProc], Trc, --USING Lots! UserProfile USING [Boolean, Number], ViewerClasses USING [Viewer], ViewerOps USING [MoveViewer], ViewerTools USING [GetContents]; TrcStandardClassesImpl: CEDAR PROGRAM IMPORTS Abutters, AIS, Buttons, ChoiceButtons, FS, IO, KnobAttach, Labels, MessageWindow, RealFns, RealOps, Rope, Sliders, Trc, UserProfile, ViewerOps, ViewerTools EXPORTS TrcStandardClasses ~ BEGIN OPEN TrcStandardClasses; IdentityFcn: Trc.Fcn = { RETURN [a]; }; IdentityBlockFcn: Trc.BlockFcn = UNCHECKED { FOR k: NAT IN [0 .. count) DO to[k] _ from[k]; ENDLOOP; }; identityClass: Trc.Class ~ NEW[Trc.ClassRep _ [ flavor: $Identity, fcn: IdentityFcn, blockFcn: IdentityBlockFcn, copy: Trc.DefaultCopy, pickle: Trc.DefaultPickle, depickle: Trc.DefaultDepickle, background: Trc.DefaultBackground, notify: Trc.DefaultNotify, control: Trc.DefaultControl ]]; NewIdentityTrc: PUBLIC PROC RETURNS [trc: TRC] ~ { trc _ NEW[Trc.TRCRep _ [ class: identityClass, instance: NIL ]]; }; ChainInstance: TYPE ~ REF ChainInstanceRep; ChainInstanceRep: TYPE ~ RECORD [SEQUENCE n: NAT OF ChainElement]; ChainElement: TYPE ~ RECORD [ trc: TRC, listenerReg: REF _ NIL --So we can detach ourselves ]; ChainFcn: Trc.Fcn = { instance: ChainInstance ~ NARROW[trc.instance]; b _ a; FOR k: NAT IN [0..instance.n) DO b _ Trc.ApplyFcn[instance[k].trc, b]; ENDLOOP; }; ChainBlockFcn: Trc.BlockFcn = UNCHECKED { instance: ChainInstance ~ NARROW[trc.instance]; IF instance.n=0 THEN ERROR; --It's gotta have SOMETHING in it... Trc.ApplyBlockFcn[trc: instance[0].trc, from: from, to: to, count: count]; FOR k: NAT IN [1..instance.n) DO Trc.ApplyBlockFcn[trc: instance[k].trc, from: to, to: to, count: count]; --In place change ENDLOOP; }; ChainPickleProc: Trc.PickleProc = { instance: ChainInstance ~ NARROW[trc.instance]; newIndentation: ROPE ~ Rope.Concat[indentation, "\t"]; IO.PutF[stream: stream, format: " %g", v1: [cardinal[instance.n]]]; FOR k: NAT IN [0..instance.n) DO IO.PutF[stream: stream, format: "\n%g%g ", v1: [rope[indentation]], v2: [atom[instance[k].trc.class.flavor]]]; Trc.Pickle[trc: instance[k].trc, stream: stream, indentation: newIndentation]; ENDLOOP; }; ChainDepickleProc: Trc.DepickleProc = { nElements: NAT ~ IO.GetCard[stream: stream]; instance: ChainInstance ~ NEW[ChainInstanceRep[nElements]]; trc _ NEW[Trc.TRCRep _ [ class: chainClass, instance: instance ]]; FOR k: NAT IN [0..instance.n) DO flavor: ATOM ~ IO.GetAtom[stream: stream]; class: Trc.Class ~ Trc.ClassFromFlavor[flavor: flavor]; instance[k].trc _ Trc.Depickle[class, stream]; instance[k].listenerReg _ Trc.InstallListener[trc: instance[k].trc, listener: [ChainListener, trc]]; ENDLOOP; }; ChainBackgroundProc: Trc.BackgroundProc = { instance: ChainInstance ~ NARROW[trc.instance]; FOR k: NAT IN [0..instance.n) DO Trc.PaintBackground[trc: instance[k].trc, context: context, rectangle: rectangle, whatChanged: $Chain]; ENDLOOP; }; ChainListener: Trc.ListenerProc = { chain: TRC ~ NARROW[listenerData]; Trc.NotifyListeners[trc: chain]; }; chainClass: Trc.Class ~ NEW[Trc.ClassRep _ [ flavor: $Chain, fcn: ChainFcn, copy: Trc.DefaultCopy, blockFcn: ChainBlockFcn, pickle: ChainPickleProc, depickle: ChainDepickleProc, notify: Trc.DefaultNotify, control: NIL, background: ChainBackgroundProc ]]; NewChainTrc: PUBLIC PROC [dependents: LIST OF TRC] RETURNS [trc: TRC] ~ { NElements: PROC [list: LIST OF TRC] RETURNS [count: NAT _ 0] ~ { FOR each: LIST OF TRC _ list, each.rest UNTIL each=NIL DO count _ count+1; ENDLOOP; }; nElements: NAT ~ NElements[dependents]; instance: ChainInstance ~ NEW[ChainInstanceRep[nElements]]; trc _ NEW[Trc.TRCRep _ [ class: chainClass, instance: instance ]]; FOR k: NAT IN [0..nElements) DO instance[k].trc _ dependents.first; instance[k].listenerReg _ Trc.InstallListener[trc: instance[k].trc, listener: [ChainListener, trc]]; dependents _ dependents.rest; ENDLOOP; }; ReplaceNthTrcInChain: PUBLIC PROC [chain, new: TRC, n: NAT, notify: BOOL _ TRUE] ~ { instance: ChainInstance ~ NARROW[chain.instance]; Trc.DeinstallListener[registration: instance[n].listenerReg]; instance[n].trc _ new; instance[n].listenerReg _ Trc.InstallListener[trc: instance[n].trc, listener: [ChainListener, chain]]; IF notify THEN Trc.NotifyListeners[trc: chain]; }; ChainInfo: PUBLIC PROC [chain: TRC] RETURNS [n: NAT] ~ { instance: ChainInstance ~ NARROW[chain.instance]; RETURN [instance.n] }; GetNthTrcInChain: PUBLIC PROC [chain: TRC, n: NAT] RETURNS [trc: TRC] ~ { instance: ChainInstance ~ NARROW[chain.instance]; RETURN [instance[n].trc]; }; ExtendChain: PUBLIC PROC [chain: TRC, newLinks: NAT _ 1, atPosition: NAT _ NAT.LAST] ~ { instance: ChainInstance ~ NARROW[chain.instance]; newInstance: ChainInstance ~ NEW[ChainInstanceRep[instance.n+newLinks]]; IF atPosition > instance.n THEN atPosition _ instance.n; FOR k: NAT IN [0 .. instance.n) DO newInstance[IF k KnobAttach.Attach[viewer: kav, whichKnob: left, paint: FALSE]; 1 => KnobAttach.Attach[viewer: kav, whichKnob: right, paint: FALSE]; ENDCASE; label _ Labels.Create[ info: [name: title, wx: slider.wx + slider.ww + margin, wy: thisY, parent: viewer, border: FALSE], paint: FALSE]; maxX _ MAX[maxX, label.wx+label.ww]; thisY _ thisY + slider.wh + margin; }; margin: INTEGER ~ 8; sliderHeight: INTEGER ~ 12; thisY: INTEGER _ margin; index: NAT _ 0; instance: ParmInstance; instance _ GetParmInstance[trc]; info.scrollable _ FALSE; viewer _ Abutters.Create[viewerFlavor: Abutters.vanilla, info: info, paint: FALSE].QuaViewer[]; FOR each: LIST OF Parm _ NARROW[trc.class.classData], each.rest UNTIL each=NIL DO initialValueInt: INT _ UserProfile.Number[key: Rope.Concat["Trc.InitialParameter.", each.first.name], default: INT.LAST]; initialValue: REAL ~ IF initialValueInt=INT.LAST THEN instance[index] ELSE REAL[initialValueInt]/100.0; MakeSliderWithTitle[title: each.first.name, index: index, initialValue: initialValue]; index _ index+1; ENDLOOP; ViewerOps.MoveViewer[viewer: viewer, x: viewer.wx, y: viewer.wy, w: maxX+margin, h: thisY, paint: paint]; }; ParmSliderProc: Sliders.SliderProc = { data: ControlSliderData ~ NARROW[clientData]; instance: ParmInstance ~ NARROW[data.trc.instance]; IF instance[data.index]#value THEN { --This avoids some extra paints instance[data.index] _ value; Trc.NotifyListeners[trc: data.trc]; }; }; NElementsInParmList: PROC [list: LIST OF Parm] RETURNS [count: NAT _ 0] ~ { FOR each: LIST OF Parm _ list, each.rest UNTIL each=NIL DO count _ count+1; ENDLOOP; }; IndexIntoParmList: PROC [name: ROPE, parms: LIST OF Parm] RETURNS [index: NAT _ 0] ~ { FOR each: LIST OF Parm _ parms, each.rest UNTIL each=NIL DO IF Rope.Equal[s1: name, s2: each.first.name] THEN RETURN; index _ index+1; ENDLOOP; ERROR; }; CreateParametricSubclass: PUBLIC PROC [flavor: ATOM, fcn: Trc.Fcn, blockFcn: Trc.BlockFcn, parms: LIST OF Parm, register: BOOL _ TRUE] RETURNS [class: Trc.Class] ~ { class _ NEW[Trc.ClassRep _ [ flavor: flavor, fcn: fcn, blockFcn: blockFcn, copy: Trc.DefaultCopy, pickle: ParmPickleProc, depickle: ParmDepickleProc, notify: Trc.DefaultNotify, background: Trc.DefaultBackground, control: ParmBuildControlViewerProc, classData: parms ]]; IF register THEN Trc.RegisterClass[class: class]; }; EnumerateRegisteredParametricClasses: PUBLIC PROC [proc: Trc.ClassEnumProc] ~ { CheckForParametrics: Trc.ClassEnumProc ~ { IF class.classData#NIL AND ISTYPE[class.classData, LIST OF Parm] THEN RETURN [proc[class]]; }; Trc.EnumerateRegisteredClasses[CheckForParametrics]; }; NewParametricTrc: PUBLIC PROC [class: Class] RETURNS [trc: TRC] ~ { parms: LIST OF Parm _ NARROW[class.classData]; n: NAT ~ NElementsInParmList[parms]; instance: ParmInstance ~ NEW[ParmInstanceRep[n]]; trc _ NEW[Trc.TRCRep _ [ class: class, instance: instance ]]; FOR k: NAT IN [0..n) DO instance[k] _ parms.first.initialValue; parms _ parms.rest; ENDLOOP; }; p: REAL _ 3.141592653589793238462643383279; LinearFcn: Trc.Fcn = { brightness: NAT ~ 0; contrast: NAT ~ 1; instance: ParmInstance ~ GetParmInstance[trc]; slope: REAL ~ RealFns.Tan[(p/2)*instance[contrast]]; intercept: REAL ~ (slope+1)*instance[brightness]-slope; RETURN [slope*a + intercept]; }; LinearBlockFcn: Trc.BlockFcn = UNCHECKED { brightness: NAT ~ 0; contrast: NAT ~ 1; instance: ParmInstance ~ GetParmInstance[trc]; slope: REAL ~ RealFns.Tan[(p/2.0001)*instance[contrast]]; --Get close to, but not quite, vertical intercept: REAL ~ (slope+1)*instance[brightness]-slope; FOR k: NAT IN [0..count) DO to[k] _ slope*from[k] + intercept; ENDLOOP; }; linearClass: Class ~ CreateParametricSubclass[ flavor: $Linear, fcn: LinearFcn, blockFcn: LinearBlockFcn, parms: LIST[["Brightness"], ["Contrast"]] ]; midtoneClass: Trc.Class ~ CreateParametricSubclass[flavor: $Midtone, fcn: MidtoneFcn, blockFcn: MidtoneBlockFcn, parms: LIST [["Brightness"], ["Contrast"], ["Midtone"], ["Low Midtone"], ["High Midtone"]]]; RAY: TYPE ~ RECORD [x, y, m: REAL _ 0.0]; CalcMidtoneParms: PROC [instance: ParmInstance] RETURNS [points: ARRAY [0..5) OF RAY] ~ INLINE { Interpolate: PROC [p1, p2: RAY, dy: REAL] RETURNS [p: RAY] ~ INLINE { RETURN [[x: (p1.x+p2.x)*0.5, y: p1.y + dy*(p2.y-p1.y)]]; }; brightness: NAT ~ 0; contrast: NAT ~ 1; midtone: NAT ~ 2; loMidtone: NAT ~ 3; hiMidtone: NAT ~ 4; slope: REAL ~ RealFns.Tan[(p/2.001)*instance[contrast]]; intercept: REAL ~ (slope+1)*instance[brightness]-slope; points[0] _ IF intercept<0 THEN [x: -intercept/slope, y: 0.0] ELSE [x: 0, y: intercept]; points[4] _ IF slope+intercept>1.0 THEN [x: (1.0-intercept)/slope, y: 1.0] ELSE [x: 1.0, y: slope+intercept]; points[2] _ Interpolate[points[0], points[4], instance[midtone]]; points[1] _ Interpolate[points[0], points[2], instance[loMidtone]]; points[3] _ Interpolate[points[2], points[4], instance[hiMidtone]]; FOR k: NAT IN [0..4) DO IF points[k].x 0.0, a (a-points[0].x)*points[0].m+points[0].y, a (a-points[1].x)*points[1].m+points[1].y, a (a-points[2].x)*points[2].m+points[2].y, a (a-points[3].x)*points[3].m+points[3].y, ENDCASE => 1.0 ]; }; MidtoneBlockFcn: Trc.BlockFcn = UNCHECKED { points: ARRAY [0..5) OF RAY ~ CalcMidtoneParms[GetParmInstance[trc]]; FOR k: NAT IN [0..count) DO to[k] _ CalcMidtoneValue[points, from[k]]; ENDLOOP; }; MidtoneFcn: Trc.Fcn = { points: ARRAY [0..5) OF RAY ~ CalcMidtoneParms[GetParmInstance[trc]]; RETURN [CalcMidtoneValue[points, a]]; }; BilinearFunction: PROC [sslope, sintercept, hslope, hintercept, a: REAL] RETURNS [answer: REAL] ~ INLINE { RETURN [(1-a)*(sslope*a + sintercept) + a*(hslope*a + hintercept)] }; BilinearFcn: Trc.Fcn = { sbrightness: NAT ~ 0; scontrast: NAT ~ 1; hbrightness: NAT ~ 2; hcontrast: NAT ~ 3; instance: ParmInstance ~ GetParmInstance[trc]; sslope: REAL ~ RealFns.Tan[(p/2)*instance[scontrast]]; sintercept: REAL ~ (sslope+1)*instance[sbrightness]-sslope; hslope: REAL ~ RealFns.Tan[(p/2)*instance[hcontrast]]; hintercept: REAL ~ (hslope+1)*instance[hbrightness]-hslope; RETURN [BilinearFunction[sslope, sintercept, hslope, hintercept, a]]; }; BilinearBlockFcn: Trc.BlockFcn = UNCHECKED { sbrightness: NAT ~ 0; scontrast: NAT ~ 1; hbrightness: NAT ~ 2; hcontrast: NAT ~ 3; instance: ParmInstance ~ GetParmInstance[trc]; sslope: REAL ~ RealFns.Tan[(p/2)*instance[scontrast]]; sintercept: REAL ~ (sslope+1)*instance[sbrightness]-sslope; hslope: REAL ~ RealFns.Tan[(p/2)*instance[hcontrast]]; hintercept: REAL ~ (hslope+1)*instance[hbrightness]-hslope; FOR k: NAT IN [0..count) DO to[k] _ BilinearFunction[sslope, sintercept, hslope, hintercept, from[k]]; ENDLOOP; }; bilinearClass: Class ~ CreateParametricSubclass[ flavor: $Bilinear, fcn: BilinearFcn, blockFcn: BilinearBlockFcn, parms: LIST[["Shadow Brightness"], ["Shadow Contrast"], ["Hilight Brightness"], ["Hilight Contrast"]] ]; SliderValueToSlope: PROC [value: REAL] RETURNS [slope: REAL] ~ INLINE { RETURN [RealFns.Tan[(p/2)*value]]; }; AffectedSliderValue: PROC [basic, affector: REAL] RETURNS [affected: REAL] ~ INLINE { RETURN [IF affector > 0.5 THEN affector*(2-basic-basic) + basic + basic - 1 ELSE affector*(basic+basic) ]; }; SetUpQuadFunction: PROC [instance: ParmInstance] RETURNS [coeff0, coeff1, coeff2: REAL] ~ INLINE { brightness: NAT ~ 0; contrast: NAT ~ 1; shadowContrast: NAT ~ 2; hilightContrast: NAT ~ 3; slope0: REAL ~ SliderValueToSlope[AffectedSliderValue[instance[contrast], instance[shadowContrast]]]; slope1: REAL ~ SliderValueToSlope[AffectedSliderValue[instance[contrast], instance[hilightContrast]]]; coeff1 _ slope0; coeff2 _ (slope1 - slope0)/2.0; coeff0 _ instance[brightness] - coeff2/3.0 - coeff1/2.0; }; QuadFunction: PROC [a, coeff0, coeff1, coeff2: REAL] RETURNS [b: REAL] ~ INLINE { RETURN [coeff2*a*a + coeff1*a + coeff0] }; QuadFcn: Trc.Fcn = { coeff0, coeff1, coeff2: REAL; [coeff0, coeff1, coeff2] _ SetUpQuadFunction[NARROW[trc.instance, ParmInstance]]; RETURN [QuadFunction[a, coeff0, coeff1, coeff2]] }; QuadBlockFcn: Trc.BlockFcn = UNCHECKED { coeff0, coeff1, coeff2: REAL; [coeff0, coeff1, coeff2] _ SetUpQuadFunction[NARROW[trc.instance, ParmInstance]]; FOR k: NAT IN [0..count) DO to[k] _ QuadFunction[from[k], coeff0, coeff1, coeff2]; ENDLOOP; }; quadClass: Class ~ CreateParametricSubclass[ flavor: $Quadratic, fcn: QuadFcn, blockFcn: QuadBlockFcn, parms: LIST[["Brightness"], ["Contrast"], ["Shadow Contrast"], ["Hilight Contrast"]] ]; AISInstance: TYPE ~ REF AISInstanceRep; AISInstanceRep: TYPE ~ RECORD [ SEQUENCE n: NAT OF REAL ]; EqualizeFunction: PROC [instance: AISInstance, a: REAL] RETURNS [result: REAL] ~ INLINE { SELECT TRUE FROM a < 0.0 => RETURN [0]; a >= 1.0 => RETURN [1]; ENDCASE => { index: NAT ~ RealOps.RoundC[a*instance.n, [round: rm]]; --Round down! RETURN [instance[index]]; }; }; EqualizeFcn: Trc.Fcn = { instance: AISInstance ~ NARROW[trc.instance]; RETURN [EqualizeFunction[instance, a]]; }; EqualizeBlockFcn: Trc.BlockFcn = UNCHECKED { instance: AISInstance ~ NARROW[trc.instance]; FOR k: NAT IN [0..count) DO to[k] _ EqualizeFunction[instance, from[k]]; ENDLOOP; }; EqualizePickleProc: Trc.PickleProc = { instance: AISInstance ~ NARROW[trc.instance]; IO.PutF[stream: stream, format: " %g ", v1: [cardinal[instance.n]]]; FOR k: NAT IN [0 .. instance.n) DO IF k MOD 8=0 THEN IO.PutF[stream: stream, format: "\n%g", v1: [rope[indentation]]]; IO.PutF[stream: stream, format: "%g ", v1: [real[instance[k]]]]; ENDLOOP; IO.PutRope[self: stream, r: "\n"]; }; EqualizeDepickleProc: Trc.DepickleProc = { nElements: NAT ~ IO.GetCard[stream: stream]; instance: AISInstance ~ NEW[AISInstanceRep[nElements]]; trc _ NEW[Trc.TRCRep _ [ class: equalizeClass, instance: instance ]]; FOR k: NAT IN [0..instance.n) DO instance[k] _ IO.GetReal[stream]; ENDLOOP; }; EqualizeBuildControlViewerProc: Trc.BuildControlViewerProc = { button: ViewerClasses.Viewer; margin: NAT ~ 4; pdr: ChoiceButtons.PromptDataRef; IF trc.instance=NIL THEN { --Instantiate something for new viewer instance: AISInstance; trc.instance _ instance _ NEW[AISInstanceRep[1]]; instance[0] _ 0; }; viewer _ Abutters.Create[viewerFlavor: Abutters.vanilla, info: info, paint: FALSE].QuaViewer[]; pdr _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: 0, y: 0, title: "AIS File:", clientdata: trc]; button _ Buttons.Create[info: [name: "Load!", wy: pdr.textViewer.wh + margin, border: TRUE, parent: viewer], proc: EqualizeLoadHistogramProc, clientData: pdr, documentation: "Click again to compute TRC from Histogram", guarded: TRUE, paint: FALSE]; ViewerOps.MoveViewer[viewer: viewer, x: viewer.wx, y: viewer.wy, w: viewer.ww, h: button.wy + button.wh + margin, paint: paint]; }; Complain: PROC [msg: ROPE] ~ { MessageWindow.Append[message: msg, clearFirst: TRUE]; MessageWindow.Blink[]; }; EqualizeLoadHistogramProc: Buttons.ButtonProc = { ComputeHistoSum: PROC [h: AIS.Histogram] RETURNS [sum: INT _ 0] ~ { FOR k: NAT IN [0..h.length) DO sum _ sum+h[k]; ENDLOOP; }; pdr: ChoiceButtons.PromptDataRef ~ NARROW[clientData]; trc: TRC ~ NARROW[pdr.clientdata]; instance: AISInstance; fileName: ROPE _ ViewerTools.GetContents[pdr.textViewer]; histo: AIS.Histogram; sum, runningSum: INT _ 0; fileName _ FS.FileInfo[name: fileName ! FS.Error => { Complain["File name not found."]; GOTO Fail; };].fullFName; histo _ AIS.ReadHistogram[f: AIS.OpenFile[name: fileName ! AIS.Error => {Complain["Not an AIS file."]; GOTO Fail}] ! AIS.Error => {Complain["AIS file does not have a histogram."]; GOTO Fail}]; IF histo=NIL THEN {Complain["AIS file does not have a histogram."]; GOTO Fail}; sum _ ComputeHistoSum[histo]; trc.instance _ instance _ NEW[AISInstanceRep[histo.length]]; FOR k: NAT IN [0 .. instance.n) DO runningSum _ runningSum + histo[k]; instance[k] _ REAL[runningSum]/REAL[sum]; ENDLOOP; Trc.NotifyListeners[trc: trc]; EXITS Fail => NULL; }; equalizeClass: Class ~ NEW[Trc.ClassRep _ [ flavor: $Equalize, fcn: EqualizeFcn, blockFcn: EqualizeBlockFcn, copy: Trc.DefaultCopy, pickle: EqualizePickleProc, depickle: EqualizeDepickleProc, notify: Trc.DefaultNotify, background: Trc.DefaultBackground, control: EqualizeBuildControlViewerProc ]]; Trc.RegisterClass[identityClass]; Trc.RegisterClass[chainClass]; Trc.RegisterClass[equalizeClass]; END. ΚTrcStandardClassesImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Eric Nickell, January 25, 1987 5:52:05 am PST Identity Class [trc: TRC, a: REAL] RETURNS [b: REAL] [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT] Chain Class [trc: TRC, a: REAL] RETURNS [b: REAL] [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT] [trc: TRC, stream: STREAM, indentation: ROPE _ NIL] [class: Trc.Class, stream: STREAM] RETURNS [trc: TRC] [trc: TRC, context: Imager.Context, rectangle: ImagerTransformation.Rectangle] [trc: TRC, listenerData: REF ANY] Shouldn't need to NotifyListeners, as this should have not affected any data which comes out. Parametric Sublasses [trc: TRC, stream: STREAM, indentation: ROPE _ NIL] [class: Trc.Class, stream: STREAM] RETURNS [trc: TRC] [trc: TRC, info: ViewerClasses.ViewerRec] RETURNS [viewer: ViewerClasses.Viewer] [slider: Sliders.Slider, reason: Sliders.Reason, value: Sliders.NormalizedSliderValue, clientData: REF ANY _ NIL] [trc: TRC, a: REAL] RETURNS [b: REAL] [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT] [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT] [trc: TRC, a: REAL] RETURNS [b: REAL] [trc: TRC, a: REAL] RETURNS [b: REAL] [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT] Typically, one might have a single slider which affects a group of values ganged together, but each value has its own affector to tweak that value. If the affector~0.5, then affected=basic. Otherwise an affector in the range [0 .. 0.5] to map affected to the range [0 .. basic], while an affector in the range [0.5 .. 1.0] will map affected to the range [basic .. 1.0]. [trc: TRC, a: REAL] RETURNS [b: REAL] [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT] AIS Classes [trc: TRC, a: REAL] RETURNS [b: REAL] [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT] [trc: TRC, stream: STREAM, indentation: ROPE _ NIL] [class: Trc.Class, stream: STREAM] RETURNS [trc: TRC] [trc: TRC, info: ViewerClasses.ViewerRec] RETURNS [viewer: ViewerClasses.Viewer] [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] Registration Κ7₯˜™Icodešœ Οmœ1™K˜šžœ)žœ:ž˜lK–[base: ROPE]˜FK–[stream: STREAM]šœ9žœ˜LKšžœ˜—K˜Kšžœžœžœ˜!K˜—–T -- [trc: TRC, info: ViewerClasses.ViewerRec] RETURNS [viewer: ViewerClasses.Viewer]šœžœžœ˜3šœžœžœ˜%Kšœ žœ˜ Kšœž˜ Kšœ˜——š ’œžœžœžœžœ˜LKšžœžœžœ5˜MKšžœžœ˜K˜—˜:Kš‘P™PKšœžœ˜"Kšœžœ˜š ’œžœ žœ žœžœ˜KKšœ!˜!K–/[string: ROPE, font: ImagerFont.Font _ NIL]šœ˜K˜Kšœžœ2˜Ošœ˜Kšœ‚˜‚Jšœ˜J˜Jšœ˜Jšœ˜Jšœž˜ J˜—šœ˜KšœS˜SJšœ˜J˜Jšœ˜Jšœž˜ J˜—–&[key: ROPE, default: BOOL _ FALSE]š žœ:žœžœžœžœŸ%˜K–a[viewer: KnobAttach.KnobAttachViewer, whichKnob: KnobAttach.Attachment, paint: BOOL _ TRUE]šœ<žœ˜CK–a[viewer: KnobAttach.KnobAttachViewer, whichKnob: KnobAttach.Attachment, paint: BOOL _ TRUE]šœ=žœ˜DKšžœ˜—Kšœržœ žœ˜ˆKšœžœ˜$Jšœ#˜#K˜—K–™[info: ViewerClasses.ViewerRec _ [class: NIL, wx: 0, wy: 0, ww: 0, wh: 0, cx: 0, cy: 0, cw: 0, ch: 0, lock: [process: PROCESS#0B, count: 0B (0)], tipTable: NIL, name: NIL, file: NIL, label: NIL, menu: NIL, icon: 177777B?, column: left, caption: FALSE, scrollable: TRUE, hscrollable: FALSE, iconic: TRUE, border: TRUE, newVersion: FALSE, newFile: FALSE, visible: TRUE, offDeskTop: FALSE, destroyed: FALSE, init: FALSE, saveInProgress: FALSE, inhibitDestroy: FALSE, guardDestroy: FALSE, paintingWedged: FALSE, ...], paint: BOOL _ TRUE]šœžœ˜Kšœžœ˜Kšœžœ ˜Kšœžœ˜Kšœ˜K˜Kšœ ˜ K˜Kšœžœ˜K–β[saveChildren: BOOL _ FALSE, info: ViewerClasses.ViewerRec _ [class: NIL, wx: 0, wy: 0, ww: 0, wh: 0, cx: 0, cy: 0, cw: 0, ch: 0, lock: [process: PROCESS#0B, count: 0B (0)], tipTable: NIL, name: NIL, file: NIL, label: NIL, menu: NIL, icon: 177777B?, column: left, caption: FALSE, scrollable: TRUE, hscrollable: FALSE, iconic: TRUE, border: TRUE, newVersion: FALSE, newFile: FALSE, visible: TRUE, offDeskTop: FALSE, destroyed: FALSE, init: FALSE, saveInProgress: FALSE, inhibitDestroy: FALSE, guardDestroy: FALSE, paintingWedged: FALSE, spare0: FALSE, spare1: FALSE, spare2: FALSE, spare3: FALSE, spare4: FALSE, spare5: FALSE, spare6: FALSE, position: 0, openHeight: 0, link: NIL, parent: NIL, sibling: NIL, child: NIL, props: NIL, data: NIL], paint: BOOL _ TRUE]šœLžœ˜_š žœžœžœžœ!žœžœž˜QK–![key: ROPE, default: INT _ 0]šœžœ[žœžœ˜yKšœžœžœžœžœžœžœžœ˜gK˜VK˜Kšžœ˜—K–n[viewer: ViewerClasses.Viewer, x: INTEGER, y: INTEGER, w: INTEGER, h: INTEGER, paint: BOOL _ TRUE]˜iK˜—–u -- [slider: Sliders.Slider, reason: Sliders.Reason, value: Sliders.NormalizedSliderValue, clientData: REF ANY _ NIL]˜&Kš‘q™qK–"[trc: TRC, fork: BOOL _ FALSE]šœžœ ˜-Kšœžœ˜3šžœžœŸ˜DK˜Kšœ#˜#Kšœ˜—K˜—–[list: LIST OF REF ANY]š ’œžœžœžœžœ žœ ˜Kš žœžœžœžœžœž˜:K˜Kšžœ˜—K˜—š’œžœžœ žœžœžœ žœ ˜Vš žœžœžœžœžœž˜;K–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šžœ+žœžœ˜9K˜Kšžœ˜—Kšžœ˜K˜—š’œžœžœ žœ/žœžœžœžœžœ˜₯šœžœ˜K˜K˜ K˜K˜K˜K˜Kšœ˜Kšœ"˜"K˜$K˜K˜—K–-[class: Trc.Class, fillNILs: BOOL _ TRUE]šžœ žœ!˜1K˜—š’$œž œ˜Ošœ*˜*Kšžœžœžœžœžœžœžœžœ˜[Kšœ˜—Kšœ4˜4K˜—š ’œžœžœžœžœ˜CKšœžœžœžœ˜.Kšœžœ˜$Kšœžœ˜1šœžœ˜Kšœ ˜ Kšœ˜K˜—šžœžœžœž˜K˜'K˜Kšžœ˜—K˜—K˜JšΟgœžœ$˜+–) -- [trc: TRC, a: REAL] RETURNS [b: REAL]˜Kš‘%™%Kšœ žœ˜Kšœ žœ˜Kšœžœ˜.Kšœžœ£œ˜4Kšœ žœ(˜7Kšžœ˜K˜—–F -- [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT]šœž œ˜*Kš‘B™BKšœ žœ˜Kšœ žœ˜Kšœžœ˜.Kšœžœ£œŸ'˜aKšœ žœ(˜7šžœžœžœ ž˜Kšœ"˜"Kšžœ˜—K˜—šœ.˜.K˜K˜K˜Kšœžœ˜)Kšœ˜—M–}[flavor: ATOM, fcn: Trc.Fcn, blockFcn: Trc.BlockFcn, parms: LIST OF TrcStandardClasses.Parm, register: BOOL _ TRUE]šœxžœQ˜ΝK–) -- [trc: TRC, a: REAL] RETURNS [b: REAL]šžœžœžœ žœ˜)š’œžœžœ žœžœžœžœ˜`š’ œžœ žœžœžœžœžœ˜EKšžœ2˜8K˜—Kš Πos Ρkos€₯€₯€₯€₯€˜aKšœžœ£œ€œ˜8Kšœ žœ€ œ˜7Kšœ žœ žœžœ˜XKšœ žœžœ$žœ˜mKšœ7€œ˜AKšœ7€ œ˜CKšœ7€ œ˜Cšžœžœžœž˜KšžœžœF˜gKšžœ˜—K˜K˜—–F -- [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT]š’œžœ žœžœžœžœžœžœžœ˜Zšžœžœžœž˜K˜K˜9Kšœ9˜9Kšœ9˜9Kšœ9˜9Kšžœ˜Kšœ˜—K˜—š’œž œ˜+Kš‘B™BKš œžœžœžœžœ˜Ešžœžœžœ ž˜Kšœ*˜*Kšžœ˜—K˜—šœ˜Kš‘%™%Kš œžœžœžœžœ˜EKšžœ˜%K˜—–) -- [trc: TRC, a: REAL] RETURNS [b: REAL]š ’œžœ-žœžœ žœžœ˜jKšžœ<˜BK˜—˜Kš‘%™%Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜.Kšœžœ£œ˜6Kšœ žœ+˜;Kšœžœ£œ˜6Kšœ žœ+˜;Kšžœ?˜EK˜—–F -- [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT]šœ!ž œ˜,Kš‘B™BKšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜.Kšœžœ£œ˜6Kšœ žœ+˜;Kšœžœ£œ˜6Kšœ žœ+˜;šžœžœžœ ž˜KšœJ˜JKšžœ˜—K˜—šœ0˜0K˜K˜K˜KšœžœZ˜eKšœ˜—š ’œžœ žœžœ žœžœ˜GKšžœ£œ ˜"K˜—š ’œžœžœžœ žœžœ˜UK™σšžœžœ˜Kšžœ-˜1Kšžœ˜Kšœ˜—K˜—š ’œžœžœžœžœ˜bKšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜KšœžœY˜eKšœžœZ˜fKšœ˜Kšœ˜Kšœ8˜8K˜—–) -- [trc: TRC, a: REAL] RETURNS [b: REAL]š ’ œžœžœžœžœžœ˜QKšžœ!˜'K˜—˜Kš‘%™%Kšœžœ˜Kšœ-žœ˜QKšžœ*˜0K˜—–F -- [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT]šœž œ˜(Kš‘B™BKšœžœ˜Kšœ-žœ˜Qšžœžœžœ ž˜Kšœ6˜6Kšžœ˜—K˜—šœ,˜,K˜K˜ K˜KšœžœI˜TKšœ˜—K˜K˜—™ šœ žœžœ˜'šœžœžœ˜Kšžœžœžœž˜Kšœ˜——–) -- [trc: TRC, a: REAL] RETURNS [b: REAL]š ’œžœžœžœ žœžœ˜Yšžœžœž˜Kšœ žœ˜Kšœ žœ˜šžœ˜ Kšœžœ.Ÿ ˜EKšžœ˜Kšœ˜——K˜—˜Kš‘%™%Kšœžœ˜-Kšžœ!˜'K˜—–F -- [trc: TRC, from: Trc.UnsafeTable, to: Trc.UnsafeTable, count: NAT]šœ!ž œ˜,Kš‘B™BKšœžœ˜-šžœžœžœ ž˜Kšœ,˜,Kšžœ˜—K˜—–7 -- [trc: TRC, stream: STREAM, indentation: ROPE _ NIL]˜&Kš‘3™3Kšœžœ˜-K–―[stream: STREAM, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šžœB˜Dšžœžœžœž˜"K–―[stream: STREAM, format: ROPE _ NIL, v1: IO.Value _ [null[]], v2: IO.Value _ [null[]], v3: IO.Value _ [null[]], v4: IO.Value _ [null[]], v5: IO.Value _ [null[]]]šžœžœžœžœ?˜SKšžœ?˜AKšžœ˜—K–elf: STREAM, r: ROPE]šžœ ˜"K˜—–9 -- [class: Trc.Class, stream: STREAM] RETURNS [trc: TRC]˜*Kš‘5™5Kšœ žœžœ˜,Kšœžœ˜7šœžœ˜Kšœ˜Kšœ˜K˜—šžœžœžœž˜ Kšœžœ˜!Kšžœ˜—K˜—–T -- [trc: TRC, info: ViewerClasses.ViewerRec] RETURNS [viewer: ViewerClasses.Viewer]šœ>˜>Kš‘P™PK–™[info: ViewerClasses.ViewerRec _ [class: NIL, wx: 0, wy: 0, ww: 0, wh: 0, cx: 0, cy: 0, cw: 0, ch: 0, lock: [process: PROCESS#0B, count: 0B (0)], tipTable: NIL, name: NIL, file: NIL, label: NIL, menu: NIL, icon: 177777B?, column: left, caption: FALSE, scrollable: TRUE, hscrollable: FALSE, iconic: TRUE, border: TRUE, newVersion: FALSE, newFile: FALSE, visible: TRUE, offDeskTop: FALSE, destroyed: FALSE, init: FALSE, saveInProgress: FALSE, inhibitDestroy: FALSE, guardDestroy: FALSE, paintingWedged: FALSE, ...], paint: BOOL _ TRUE]˜Kšœžœ˜K˜!šžœžœžœŸ&˜BK˜Kšœžœ˜1K˜Kšœ˜—K–β[saveChildren: BOOL _ FALSE, info: ViewerClasses.ViewerRec _ [class: NIL, wx: 0, wy: 0, ww: 0, wh: 0, cx: 0, cy: 0, cw: 0, ch: 0, lock: [process: PROCESS#0B, count: 0B (0)], tipTable: NIL, name: NIL, file: NIL, label: NIL, menu: NIL, icon: 177777B?, column: left, caption: FALSE, scrollable: TRUE, hscrollable: FALSE, iconic: TRUE, border: TRUE, newVersion: FALSE, newFile: FALSE, visible: TRUE, offDeskTop: FALSE, destroyed: FALSE, init: FALSE, saveInProgress: FALSE, inhibitDestroy: FALSE, guardDestroy: FALSE, paintingWedged: FALSE, spare0: FALSE, spare1: FALSE, spare2: FALSE, spare3: FALSE, spare4: FALSE, spare5: FALSE, spare6: FALSE, position: 0, openHeight: 0, link: NIL, parent: NIL, sibling: NIL, child: NIL, props: NIL, data: NIL], paint: BOOL _ TRUE]šœLžœ˜_K–«[viewer: ViewerClasses.Viewer, x: CARDINAL _ 0B (0), y: CARDINAL _ 0B (0), title: ROPE, default: ROPE _ NIL, font: ImagerFont.Font _ NIL, textViewerWidth: INTEGER, clientdata: REF ANY _ NIL, notify: ChoiceButtons.SelectionNotifierProc, permit: ChoiceButtons.PromptPermissionProc]˜eK–Ώ[info: ViewerClasses.ViewerRec _ [class: NIL, wx: 0, wy: 0, ww: 0, wh: 0, cx: 0, cy: 0, cw: 0, ch: 0, lock: [process: PROCESS#0B, count: 0B (0)], tipTable: NIL, name: NIL, file: NIL, label: NIL, menu: NIL, icon: 177777B?, column: left, caption: FALSE, scrollable: TRUE, hscrollable: FALSE, iconic: TRUE, border: TRUE, newVersion: FALSE, newFile: FALSE, visible: TRUE, offDeskTop: FALSE, destroyed: FALSE, init: FALSE, saveInProgress: FALSE, inhibitDestroy: FALSE, guardDestroy: FALSE, paintingWedged: FALSE, ...], proc: Buttons.ButtonProc, clientData: REF ANY _ NIL, fork: BOOL _ TRUE, font: ImagerFont.Font _ NIL, documentation: REF ANY _ NIL, guarded: BOOL _ FALSE, paint: BOOL _ TRUE]šœVžœŠžœ žœ˜ψK–n[viewer: ViewerClasses.Viewer, x: INTEGER, y: INTEGER, w: INTEGER, h: INTEGER, paint: BOOL _ TRUE]˜€K˜—š’œžœžœ˜K–-[message: ROPE, clearFirst: BOOL _ FALSE]šœ/žœ˜5K–[]˜K˜—–‚ -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE]šœ1˜1Kš‘~™~š ’œžœžœ žœžœ ˜Cšžœžœžœž˜K˜Kšžœ˜—K˜—Kšœ#žœ ˜6Kšœžœžœ˜"K˜K– [viewer: ViewerClasses.Viewer]šœ žœ+˜9Kšœžœ ˜Kšœžœ˜K˜–[name: ROPE, wantedCreatedTime: GMT _ --{UnknownError[sig: 3304B, msg: 177777B]}--, remoteCheck: BOOL _ TRUE, wDir: ROPE _ NIL]šœ žœ(˜5Kšœ!˜!Kšžœ˜ Kšœ˜—K–([name: ROPE, write: BOOLEAN _ FALSE]š œžœžœžœ)žœ žœ<žœ˜ΐKšžœžœžœ3žœ˜OK˜Kšœžœ˜<šžœžœžœž˜"K˜#Kšœžœ žœ˜)Kšžœ˜—K–"[trc: TRC, fork: BOOL _ FALSE]˜Kšžœ žœ˜K˜—šœžœ˜+K˜K˜Kšœ˜K˜K˜K˜Kšœ˜Kšœ"˜"Kšœ'˜'K˜—K˜K˜—™ Kšœ!˜!K˜Kšœ!˜!—K˜Kšžœ˜—…—Qθ’W