ControlsSliderDialImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, February 24, 1987 4:42:40 pm PST
DIRECTORY Controls, ControlsPrivate, Convert, Draw2d, Imager, ImagerOps, Real, RealFns, ViewerClasses, ViewerOps, ViewerTools;
ControlsSliderDialImpl: CEDAR MONITOR
IMPORTS ControlsPrivate, Convert, Draw2d, Imager, ImagerOps, Real, RealFns, ViewerOps, ViewerTools
EXPORTS Controls, ControlsPrivate
~ BEGIN
OPEN Controls;
Slider/Dial Type Definitions
SliderDial:   TYPE ~ REF SliderDialRec;
SliderDialRec:  TYPE ~ RECORD [
t:       REAL ← 0.0,      -- parametric pos'n (0~min, 1~max)
tPrev:      REAL ← 0.0,      -- (private) previous t
detents:     DetentList ← NIL,    -- list of detents
detented:     BOOLFALSE,     -- (private) true if control detented
detentedPrev:   BOOLFALSE,     -- (private) true if was detented
taper:      SliderTaper ← lin,    -- lin, log, or exponential slider
cx, cy, rad:    REAL ← 0.0      -- center and radius of dial
];
Initialization
NewSliderDial: PUBLIC PROC [control: Control] ~ {
sliderDial: SliderDial ← NEW[SliderDialRec ← [detents: control.detents, taper: control.taper]];
control.sliderDialRef ← sliderDial;
FOR d: DetentList ← sliderDial.detents, d.rest WHILE d # NIL DO
d.first.t ← (d.first.value-control.min)/(control.max-control.min);
ENDLOOP;
IF control.max # control.min THEN {
sliderDial.t ←(control.init-control.min)/(control.max-control.min);
IF control.taper = log THEN sliderDial.t ← sliderDial.t*sliderDial.t;
IF control.taper = exp THEN sliderDial.t ← Real.SqRt[sliderDial.t];
};
control.value ← control.init;
sliderDial.rad ← MIN[control.w, control.h]/2-1;
sliderDial.cx ← control.w/2;
sliderDial.cy ← sliderDial.cx-1;
};
Notification
NotifySliderDial: PUBLIC PROC [control: Control] ~ {
IF ControlsPrivate.ControlProcBusy[control] THEN RETURN;
ComputeControlTandValue[control, control.mouse.x, control.mouse.y];
ViewerOps.PaintViewer[control.viewer, client, FALSE, control];
ControlsPrivate.ForkControlProc[control];
};
Reading/Writing
SetSliderDialValue: PUBLIC PROC [control: Control, value: REAL, repaint: BOOLTRUE] ~ {
sliderDial: SliderDial ← NARROW[control.sliderDialRef];
sliderDial.detentedPrev ← sliderDial.detented;
sliderDial.detented ← FALSE;
control.valuePrev ← control.value;
control.value ← value;
sliderDial.tPrev ← sliderDial.t;
sliderDial.t ← (control.value-control.min)/(control.max-control.min);
SELECT sliderDial.taper FROM
log => sliderDial.t ← sliderDial.t*sliderDial.t;
exp => sliderDial.t ← Real.SqRt[sliderDial.t];
ENDCASE;
IF repaint THEN ViewerOps.PaintViewer[control.viewer, client, FALSE, control];
};
GetSliderDialValue: PUBLIC PROC [control: Control] RETURNS [REAL] ~ {
RETURN[control.value];
};
Painting
PaintSliderDial: PUBLIC ViewerClasses.PaintProc ~ {
control: Control ← NARROW[self.data];
sliderDial: SliderDial ← NARROW[control.sliderDialRef];
Action: PROC ~ {
IF control.w = 0 THEN control.w ← control.viewer.cw;
IF control.h = 0 THEN control.h ← control.viewer.ch;
IF whatChanged = NIL AND control.type = dial
THEN Draw2d.Circle[context, [sliderDial.cx, sliderDial.cy], sliderDial.rad, FALSE];
UnTick[context, control];
FOR detents: DetentList ← sliderDial.detents, detents.rest WHILE detents # NIL DO
Tick[context, control, detents.first.t, FALSE, 1];
ENDLOOP;
Tick[context, control, sliderDial.t, sliderDial.detented, 2];
sliderDial.detentedPrev ← sliderDial.detented;
IF control.status # NIL THEN {
ViewerTools.SetContents[control.status,
Convert.FtoRope[control.value, IF control.truncate THEN 0 ELSE 3]];
ViewerOps.PaintViewer[control.status, client];
};
};
IF sliderDial # NIL THEN ImagerOps.DoWithBuffer[context, Action, 0, 0, self.ww, self.wh];
};
UnTick: PUBLIC PROC[context: Context, control: Control] ~ {
sliderDial: SliderDial ← NARROW[control.sliderDialRef];
Imager.SetColor[context, Imager.white];
Tick[context, control, sliderDial.tPrev, sliderDial.detentedPrev, 2];
Imager.SetColor[context, Imager.black];
};
Tick: PUBLIC PROC [
context: Context, control: Control, t: REAL, detent: BOOLFALSE, width: NAT ← 1] ~ {
SELECT control.type FROM
vSlider => {
y: REAL ← control.h*t;
Imager.MaskRectangle[context, [0, y-width/2, control.w, width]];
IF detent THEN Draw2d.Square[context, [control.w/2, y], 3.0];
};
hSlider => {
x: REAL ← control.w*t;
Imager.MaskRectangle[context, [x-width/2, 0, width, control.h]];
IF detent THEN Draw2d.Square[context, [x+1, control.h/2-1], 3.0];
};
dial => {
sliderDial: SliderDial ← NARROW[control.sliderDialRef]; 
rad: REAL ← sliderDial.rad-3;
deg: REAL ← 360.0*t;
Imager.SetStrokeWidth[context, width];
Imager.MaskVector[context, [sliderDial.cx+rad*RealFns.CosDeg[deg], sliderDial.cy+rad*RealFns.SinDeg[deg]], [sliderDial.cx, sliderDial.cy]];
IF detent THEN Draw2d.Circle[context, [sliderDial.cx, sliderDial.cy], 3.0, TRUE];
};
ENDCASE => NULL;
};
ComputeControlTandValue: PROC [control: Control, x, y: INTEGER] ~ {
ComputeControlT[control, x, y];
ComputeControlValue[control];
};
ComputeControlT: PROC [control: Control, x, y: INTEGER] ~ {
sliderDial: SliderDial ← NARROW[control.sliderDialRef];
sliderDial.tPrev ← sliderDial.t;
SELECT control.type FROM
vSlider => sliderDial.t ← REAL[y]/REAL[control.h-3];
hSlider => sliderDial.t ← REAL[x]/REAL[control.w-3];
dial => {
sliderDial.t ← RealFns.ArcTan[y-sliderDial.cy, x-sliderDial.cx]/(2.0*3.1415926535);
IF y-sliderDial.cy < 0.0 THEN sliderDial.t ← sliderDial.t+1.0;
};
ENDCASE => NULL;
sliderDial.t ← MIN[1.0, MAX[0.0, sliderDial.t]];
};
ComputeControlValue: PROC [control: Control] ~ {
sliderDial: SliderDial ← NARROW[control.sliderDialRef];
control.valuePrev ← control.value;
sliderDial.detented ← FALSE;
IF sliderDial.detents = NIL THEN {
tt: REALSELECT sliderDial.taper FROM
log => Real.SqRt[sliderDial.t],
exp => sliderDial.t*sliderDial.t,
ENDCASE => sliderDial.t;
control.value ← (1.0-tt)*control.min+tt*control.max;
}
ELSE {
grain: REAL ~ 0.02;
t0, t1, value0, value1: REAL ← 0.0;
FOR d: DetentList ← sliderDial.detents, d.rest WHILE d # NIL DO
t: REAL ← d.first.t;
IF ABS[sliderDial.t-t] < grain THEN {
sliderDial.t ← t; control.value ← d.first.value; sliderDial.detented ← TRUE;
EXIT;
};
IF t > sliderDial.t THEN EXIT;
ENDLOOP;
IF NOT sliderDial.detented
THEN control.value ← (1.0-sliderDial.t)*control.min+sliderDial.t*control.max;
};
IF control.truncate THEN control.value ← Real.Round[control.value];
};
END.