PieViewersImpl.mesa
Copyright © 1982, 1983, 1984 Xerox Corporation. All rights reserved.
Michael Plass, November 2, 1982 10:56 am
Last Edited by: Beach, May 24, 1983 9:13 am
Doug Wyatt, September 5, 1984 3:45:51 pm PDT
DIRECTORY
Imager USING [black, Context, MaskFill, SetColor, VEC, white],
ImagerOps USING [ImagerFromGraphics],
ImagerPath USING [PathProc],
PieViewers USING [PieViewer],
Real USING [RoundI, SqRt],
RealFns USING [Cos, Sin, Tan],
ViewerClasses USING [PaintProc, Viewer, ViewerClass, ViewerClassRec],
ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass];
PieViewersImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerOps, Real, RealFns, ViewerOps
EXPORTS PieViewers
= BEGIN
PieViewer: TYPE = PieViewers.PieViewer;
DataRec: TYPE = RECORD [
total: REAL, -- what the entire circle is worth
amount: REAL, -- what amount is currently on
granularity: REAL -- display will not change if the new amount is of the same grain
];
Create: PUBLIC PROC [parent: ViewerClasses.Viewer, x, y: INTEGER ← 0, diameter: INTEGER ← 16, total: REAL ← 100, divisions: NAT ← 25]
RETURNS [pieViewer: PieViewer] = TRUSTED {
data: REF DataRec ← NEW[DataRec];
data.total ← total;
data.granularity ← total/divisions;
pieViewer ← ViewerOps.CreateViewer[flavor: $PieViewer, info: [parent: parent, wx: x, wy: y, ww: diameter, wh: diameter, data: data, border: FALSE], paint: FALSE];
Set[pieViewer, 0];
};
Set: PUBLIC PROC [pieViewer: PieViewer, amount: REAL] =
BEGIN ENABLE ANY => GOTO Quit;
d: REF DataRec ← NARROW[pieViewer.data];
IF amount=d.total OR amount=0 OR Real.RoundI[d.amount/d.granularity] # Real.RoundI[amount/d.granularity] THEN
BEGIN
d.amount ← amount;
TRUSTED{ViewerOps.PaintViewer[pieViewer, client, FALSE, $Update]};
END;
EXITS Quit => {}
END;
PieViewerPaint: ViewerClasses.PaintProc = BEGIN
imager: Imager.Context ~ ImagerOps.ImagerFromGraphics[context];
d: REF DataRec ← NARROW[self.data];
diameter: REAL ← self.ww;
radius: REAL ← diameter/2;
center: VEC ~ [radius, radius];
blackPart: ImagerPath.PathProc ~ {
p: VEC ~ [radius, diameter-0.51];
moveTo[center];
lineTo[p];
ArcAround[curveTo, p, center, TwoPi*d.amount/d.total];
lineTo[center];
};
whitePart: ImagerPath.PathProc ~ {
p: VEC ~ [radius, diameter];
moveTo[center];
lineTo[p];
ArcAround[curveTo, p, center, TwoPi*(d.amount/d.total-1)];
lineTo[center];
};
Imager.SetColor[imager, Imager.black];
Imager.MaskFill[imager, blackPart];
Imager.SetColor[imager, Imager.white];
Imager.MaskFill[imager, whitePart];
END;
TwoPi: REAL = 2*3.14159265;
VEC: TYPE = Imager.VEC;
Abs: PROCEDURE [a: VEC] RETURNS [REAL] = INLINE
{RETURN[Real.SqRt[a.x*a.x+a.y*a.y]]};
Mul: PROCEDURE [a: VEC, b: VEC] RETURNS [VEC] = INLINE
{RETURN[[(a.x*b.x - a.y*b.y), (a.x*b.y + a.y*b.x)]]}; -- complex product
Add: PROCEDURE [a: VEC, b: VEC] RETURNS [VEC] = INLINE
{RETURN[[a.x+b.x,a.y+b.y]]}; -- same as vector sum
Sub: PROCEDURE [a: VEC, b: VEC] RETURNS [VEC] = INLINE
{RETURN[[a.x-b.x,a.y-b.y]]}; -- same as vector difference
ShortArcAround: PROC [curveTo: PROC[p1, p2, p3: VEC], p0: VEC, center: VEC, angle: REAL]
RETURNS[VEC] =
BEGIN -- good for angles of less than about a quarter circle
init: VEC ← Sub[p0, center];
IF angle#0 THEN
BEGIN
final: VEC ← Mul[init, [RealFns.Cos[angle], RealFns.Sin[angle]]];
velocityRatio: REAL ← (4.0/3.0)*RealFns.Tan[angle/4];
b1: VEC ← Add[center, Add[init, Mul[init, [0,velocityRatio]]]];
b2: VEC ← Add[center, Add[final, Mul[final, [0,-velocityRatio]]]];
final ← Add[center, final];
curveTo[b1, b2, final];
RETURN[final];
END
ELSE RETURN[p0];
END;
MaxSmallArc: REAL = 3.14159265/2.0;
ArcAround: PROC [curveTo: PROC[p1, p2, p3: VEC], p0: VEC, center: VEC, angle: REAL] =
BEGIN
delta: REALIF angle>0 THEN MaxSmallArc ELSE - MaxSmallArc;
WHILE ABS[angle]>MaxSmallArc DO
p0 ← ShortArcAround[curveTo, p0, center, delta];
angle ← angle - delta;
ENDLOOP;
[] ← ShortArcAround[curveTo, p0, center, angle];
END;
pieViewer: ViewerClasses.ViewerClass ← NEW[ViewerClasses.ViewerClassRec ← [
paint: PieViewerPaint,
tipTable: NIL
]];
ViewerOps.RegisterViewerClass[$PieViewer, pieViewer]; -- plug in to Viewers
END.
Michael Plass, November 2, 1982 10:57 am. CEDARized.