<> <> <> DIRECTORY Controls, ControlsPrivate, Convert, Imager, ImagerOps, Real, Rope, ViewerClasses, ViewerOps, ViewerTools; ControlsFunctionImpl: CEDAR MONITOR IMPORTS ControlsPrivate, Convert, Imager, ImagerOps, Real, Rope, ViewerOps, ViewerTools EXPORTS Controls, ControlsPrivate ~ BEGIN OPEN Controls; <> Function: TYPE ~ REF FunctionRep; FunctionRep: TYPE ~ RECORD [ vMul: REAL _ 0.0, -- (private) value multiplier screenValues: IntegerSequence _ NIL, -- (private) screen function values p0, p1: Pos _ [0, 0] -- (private) mouse interpolates ]; <> NewFunction: PUBLIC PROC [control: Control] ~ { function: Function _ NEW[FunctionRep]; IF control.type # function THEN RETURN; control.functionRef _ function; IF control.values = NIL THEN { control.values _ NEW[RealSequenceRep[control.w]]; FOR i: NAT IN[0..control.values.length) DO control.values[i] _ control.min; ENDLOOP; }; IF control.values.length < control.w THEN { temp: RealSequence _ NEW[RealSequenceRep[control.w]]; FOR i: NAT IN[0..control.values.length) DO temp[i] _ control.values[i]; ENDLOOP; control.values _ temp; }; function.screenValues _ NEW[IntegerSequenceRep[control.w]]; }; ResetFunction: PUBLIC PROC [control: Control, repaint: BOOL _ TRUE] ~ { IF control.type = function THEN { FOR i: NAT IN[0..control.values.length) DO control.values[i] _ control.min; ENDLOOP; IF repaint THEN ViewerOps.PaintViewer[control.viewer, client, FALSE, NIL]; }; }; SetFunctionValues: PUBLIC PROC [ control: Control, values: RealSequence, repaint: BOOL _ TRUE] ~ { control.values _ values; IF repaint THEN ViewerOps.PaintViewer[control.viewer, client, FALSE, NIL]; }; <<>> GetFunctionValues: PUBLIC PROC [control: Control] RETURNS [RealSequence] ~ { RETURN[control.values]; }; <> NotifyFunction: PUBLIC PROC [control: Control] ~ { SetInterpolates[control]; IF control.mouse.state # up THEN ViewerOps.PaintViewer[control.viewer, client, FALSE, control] ELSE ControlsPrivate.MaybeForkControlProc[control]; }; SetInterpolates: PROC [control: Control] ~ { mouse: Mouse _ control.mouse; function: Function _ NARROW[control.functionRef]; SELECT mouse.state FROM down => SELECT mouse.button FROM left, middle => function.p0 _ function.p1 _ [mouse.x, mouse.y]; right => { -- straight lines function.p0 _ function.p1; function.p1 _ [mouse.x, mouse.y]; }; ENDCASE => NULL; held => SELECT mouse.button FROM left, middle => { -- freestyle function.p0 _ function.p1; function.p1 _ [mouse.x, mouse.y]; }; right => -- straight lines function.p1 _ [mouse.x, mouse.y]; ENDCASE => NULL; ENDCASE => NULL; }; <> PaintFunction: PUBLIC ViewerClasses.PaintProc ~ { control: Control _ NARROW[self.data]; Action: PROC ~ { IF whatChanged = NIL THEN PaintInit[context, control, self.ww, self.wh] ELSE PaintUpdate[context, control]; }; ImagerOps.DoWithBuffer[context, Action, 0, 0, self.ww, self.wh]; }; PaintInit: PROC [context: Context, control: Control, w, h: INTEGER] ~ { function: Function _ NARROW[control.functionRef]; IF function = NIL THEN RETURN; Imager.SetColor[context, Imager.white]; Imager.MaskRectangleI[context, 0, 0, w, h]; Imager.SetColor[context, Imager.black]; function.vMul _ IF h = 0 THEN 1.0 ELSE (control.max-control.min)/Real.Float[h-3]; FOR x: NAT IN[0..control.values.length) DO y: INTEGER _ function.screenValues[x] _ Real.RoundI[(control.values[x]-control.min)/function.vMul]; Imager.MaskRectangleI[context, x, y, 1, 1]; ENDLOOP; }; PaintUpdate: PROC [context: Context, control: Control] ~ { UpdateOne: PROC [x: INTEGER, y, value: REAL, report: BOOL] ~ { control.values[x] _ value; Imager.MaskRectangleI[context, x, function.screenValues[x] _ Real.Round[y], 1, 1]; IF report AND control.status # NIL THEN { ViewerTools.SetContents[control.status, Rope.Concat[Convert.FtoRope[value, 3], " "]]; ViewerOps.PaintViewer[control.status, client]; }; }; y: REAL; x0, x1: INTEGER; function: Function _ NARROW[control.functionRef]; IF function = NIL THEN RETURN; IF function.p1.x > function.p0.x THEN {x0 _ function.p0.x; x1 _ function.p1.x; y _ function.p0.y} ELSE {x0 _ function.p1.x; x1 _ function.p0.x; y _ function.p1.y}; Imager.SetColor[context, Imager.white]; FOR x: NAT IN[x0..x1] DO Imager.MaskRectangleI[context, x, function.screenValues[x], 1, 1]; ENDLOOP; Imager.SetColor[context, Imager.black]; IF x0 = x1 THEN UpdateOne[x0, y, control.min+function.vMul*y, TRUE] ELSE { value: REAL _ control.min+function.vMul*y; dy: REAL _ Real.Float[function.p1.y-function.p0.y]/(function.p1.x-function.p0.x); dValue: REAL _ function.vMul*dy; FOR x: NAT IN[x0..x1] DO UpdateOne[x, y, value, x = x1]; value _ value+dValue; y _ y+dy; ENDLOOP; }; }; END.