ControlsFunctionImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, July 2, 1992 6:10 pm PDT
DIRECTORY Controls, ControlsPrivate, Convert, Imager, Real, Rope, ViewerClasses, ViewerOps, ViewerTools;
ControlsFunctionImpl: CEDAR MONITOR
IMPORTS ControlsPrivate, Convert, Imager, Real, Rope, ViewerOps, ViewerTools
EXPORTS Controls, ControlsPrivate
~ BEGIN
Types
Context:     TYPE ~ Imager.Context;
Control:     TYPE ~ Controls.Control;
IntegerPair:    TYPE ~ Controls.IntegerPair;
IntegerSequence:   TYPE ~ Controls.IntegerSequence;
IntegerSequenceRep: TYPE ~ Controls.IntegerSequenceRep;
Mouse:     TYPE ~ Controls.Mouse;
RealSequence:   TYPE ~ Controls.RealSequence;
RealSequenceRep:  TYPE ~ Controls.RealSequenceRep;
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:        IntegerPair ¬ []   -- (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 < CARD16[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;
control.values.length ¬ control.w;
};
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 RequestPaint[control, FALSE, NIL];
};
};
SetFunctionValues: PUBLIC PROC [
control: Control, values: RealSequence, repaint: BOOL ¬ TRUE] ~ {
control.values ¬ values;
IF repaint THEN RequestPaint[control, FALSE, NIL];
};
GetFunctionValues: PUBLIC PROC [control: Control] RETURNS [RealSequence] ~ {
RETURN[control.values];
};
Function Notification
NotifyFunction: PUBLIC PROC [control: Control, mouse: Mouse] ~ {
control.mouse ¬ mouse;
SetInterpolates[control];
IF control.mouse.state # up
THEN RequestPaint[control, 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.pos;
right => {            -- straight lines
function.p0 ¬ function.p1;
function.p1 ¬ mouse.pos;
};
ENDCASE => NULL;
held => SELECT mouse.button FROM
left, middle => {           -- freestyle
function.p0 ¬ function.p1;
function.p1 ¬ mouse.pos;
};
right =>             -- straight lines
function.p1 ¬ mouse.pos;
ENDCASE => NULL;
ENDCASE => NULL;
};
Function Painting
RequestPaint: PROC [control: Control, clearClient: BOOL, whatChanged: REF ANY] ~ {
ViewerOps.PaintViewer[control.viewer, client, clearClient, whatChanged];
IF control.status # NIL THEN {
value: REAL ~ control.values[NARROW[control.functionRef, Function].p1.x];
ViewerTools.SetContents[control.status, Rope.Concat[Convert.FtoRope[value, 3], " "]];
ViewerOps.PaintViewer[control.status, client];
};
};
PaintFunction: PUBLIC ViewerClasses.PaintProc ~ {
PaintUpdate: PROC ~ {
UpdateOne: PROC [x: INTEGER, y, value: REAL] ~ { 
control.values[x] ¬ value;
Imager.MaskRectangleI[context, x, function.screenValues[x] ¬ Real.Round[y], 1, 1];
};
y: REAL;
x0, x1: INTEGER;
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]
ELSE {
value: REAL ¬ control.min+function.vMul*y;
dy: REAL ¬ (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];
value ¬ value+dValue;
y ¬ y+dy;
ENDLOOP;
};
};
PaintInit: PROC ~ {
Imager.SetColor[context, Imager.black];
function.vMul ¬ IF self.wh = 0 THEN 1.0 ELSE (control.max-control.min)/(self.wh-3.0);
FOR x: NAT IN[0..control.values.length) DO
y: INTEGER ¬ function.screenValues[x] ¬
Real.Round[(control.values[x]-control.min)/function.vMul];
Imager.MaskRectangleI[context, x, y, 1, 1];
ENDLOOP;
};
control: Control ¬ NARROW[self.data];
function: Function ¬ NARROW[control.functionRef];
IF function = NIL THEN RETURN;
IF whatChanged = NIL
THEN Imager.DoWithBuffer[context, PaintInit, 0, 0, self.ww, self.wh, Imager.white]
ELSE PaintUpdate[];
};
END.