PieViewersImpl.mesa
Michael Plass, November 2, 1982 10:56 am
Last Edited by: Beach, May 24, 1983 9:13 am
DIRECTORY
Graphics,
PieViewers,
Real,
RealFns,
ViewerOps,
ViewerClasses;
PieViewersImpl: CEDAR MONITOR
IMPORTS Graphics, 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;
pathStorage: Graphics.Path ← Graphics.NewPath[16];
PieViewerPaint: ENTRY ViewerClasses.PaintProc =
BEGIN ENABLE ANY => GOTO Quit;
d: REF DataRec ← NARROW[self.data];
diameter: REAL ← self.ww;
radius: REAL ← diameter/2;
path: Graphics.Path ← pathStorage;
Graphics.SetColor[context, Graphics.black];
Graphics.MoveTo[path, radius, radius];
Graphics.LineTo[path, radius, diameter-0.51];
ArcAround[path, radius, radius, TwoPi*d.amount/d.total];
Graphics.LineTo[path, radius, radius];
Graphics.DrawArea[context, path];
Graphics.SetColor[context, Graphics.white];
Graphics.MoveTo[path, radius, radius];
Graphics.LineTo[path, radius, diameter];
ArcAround[path, radius, radius, TwoPi*(d.amount/d.total-1)];
Graphics.LineTo[path, radius, radius];
Graphics.DrawArea[context, path];
EXITS Quit => {}
END;
TwoPi: REAL = 2*3.14159265;
Vec: TYPE = RECORD[x,y: REAL];
Abs: PROCEDURE [a: Vec] RETURNS [REAL] = INLINE
{RETURN[RealFns.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 [path: Graphics.Path, x, y: REAL, angle: REAL] =
BEGIN -- good for angles of less than about a quarter circle
init: Vec;
[init.x, init.y] ← Graphics.LastPoint[path];
init ← Sub[init, [x,y]];
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[[x,y], Add[init, Mul[init, [0,velocityRatio]]]];
b2: Vec ← Add[[x,y], Add[final, Mul[final, [0,-velocityRatio]]]];
final ← Add[[x,y], final];
Graphics.CurveTo[path, b1.x, b1.y, b2.x, b2.y, final.x, final.y];
END;
END;
MaxSmallArc: REAL = 3.14159265/2.0;
ArcAround: PROC [path: Graphics.Path, x, y: REAL, angle: REAL] =
BEGIN
delta: REALIF angle>0 THEN MaxSmallArc ELSE - MaxSmallArc;
WHILE ABS[angle]>MaxSmallArc DO
ShortArcAround[path, x, y, delta];
angle ← angle - delta;
ENDLOOP;
ShortArcAround[path, x, y, angle];
END;
pieViewer: ViewerClasses.ViewerClass ← NEW[ViewerClasses.ViewerClassRec ← [
paint: PieViewerPaint,
tipTable: NIL
]];
TRUSTED{ViewerOps.RegisterViewerClass[$PieViewer, pieViewer]}; -- plug in to Viewers
END.
Michael Plass, November 2, 1982 10:57 am. CEDARized.