ControlsFunctionImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, October 8, 1986 9:55:24 pm PDT
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 Definitions
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
];
Function Initialization/Reading/Setting
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: BOOLTRUE] ~ {
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: BOOLTRUE] ~ {
control.values ← values;
IF repaint THEN ViewerOps.PaintViewer[control.viewer, client, FALSE, NIL];
};
GetFunctionValues: PUBLIC PROC [control: Control] RETURNS [RealSequence] ~ {
RETURN[control.values];
};
Function Notification
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;
};
Function Painting
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.