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: REAL ← IF 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.