QuickViewerExampleImpl.mesa - Rudimentary Imager exerciser
Authored by Frank Crow
Last Edited by: Crow, February 7, 1986 5:33:27 pm PST
DIRECTORY
RealFns    USING [Cos, Sin],
QuickViewer   USING [DrawInViewer, BuildViewer],
Imager    USING [Context, Color, Font, DoSaveAll, SetColor, black, white,
        MaskVector, PathProc, MaskFill, MaskRectangle, SetFont, SetXY,
        ShowRope, Rectangle, SetStrokeWidth, SetStrokeEnd,
        SetStrokeJoint],
ImagerColor   USING [ColorFromRGB],
ImagerFont   USING [Find, Scale],
ImagerBackdoor  USING [GetBounds],
Vector2    USING [VEC],
Rope     USING [ROPE, Cat],
MessageWindow  USING [Append];
QuickViewerExampleImpl: CEDAR PROGRAM
IMPORTS RealFns, QuickViewer, Imager, ImagerBackdoor, ImagerColor, ImagerFont,
   Rope, MessageWindow
~ BEGIN
drawMode: ATOM;            -- type of object to draw
ShapeRec: TYPE ~ RECORD[ color: Imager.Color, drawMode: ATOM, place: Vector2.VEC ];
DisplayList: TYPE ~ RECORD[ SEQUENCE length: NAT OF ShapeRec ];
displayList: REF DisplayList ← NEW[ DisplayList[32] ];     -- display list of shapes
displayListPtr: NAT ← 0;
size: REAL ← 20.;           -- size of objects (radius or side length)
currentColor: Imager.Color ← Imager.black;
currentFont: Imager.Font ← NIL;
displayContext: Imager.Context ← NIL;
Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ { RETURN[number * number]; };
Init: PROCEDURE [] ~ {
displayContext ← QuickViewer.BuildViewer[
LIST[$Boxes, $Circles, $Octagons, $Xs, $Black, $White, $Red, $Green, $Blue, $Puce, $Spiral],
ReDraw,
ShutDown,
MenuHit,
"QuickViewerExample"
];
};
This will be called whenever the mouse is moved or a button is pushed
MenuHit: PROCEDURE[bttn: ATOM, x, y: REAL, ctrl, shift: BOOL] ~ { 
keys: Rope.ROPE;
SELECT TRUE FROM
ctrl AND shift => keys ← "ctrl-shift";
ctrl    => keys ← "ctrl";
shift    => keys ← "shift";
ENDCASE   => keys ← NIL;
SELECT bttn FROM
$Boxes, $Circles, $Xs, $Octagons => drawMode ← bttn;
$Black => currentColor ← ImagerColor.ColorFromRGB[ [ R: 0.0, G: 0.0, B: 0.0 ] ];
$White => currentColor ← ImagerColor.ColorFromRGB[ [ R: 1.0, G: 1.0, B: 1.0 ] ];
$Red  => currentColor ← ImagerColor.ColorFromRGB[ [ R: 1.0, G: 0.0, B: 0.0 ] ];
$Green => currentColor ← ImagerColor.ColorFromRGB[ [ R: 0.0, G: 1.0, B: 0.0 ] ];
$Blue  => currentColor ← ImagerColor.ColorFromRGB[ [ R: 0.0, G: 0.0, B: 1.0 ] ];
$Puce  => currentColor ← ImagerColor.ColorFromRGB[ [ R: 0.5, G: 0.2, B: 0.4 ] ];
$Spiral => DrawSpiral[];
$LeftButton, $LeftHeld => {
    displayList[displayListPtr] ← [currentColor, drawMode, [x, y] ];
    SELECT drawMode FROM
    $Xs  => DrawX[displayList[displayListPtr].place, size];
    $Boxes => DrawBox[displayList[displayListPtr].place, size];
    $Circles => DrawCircle[displayList[displayListPtr].place, size];
    $Octagons => DrawOct[displayList[displayListPtr].place, size];
    ENDCASE;
    displayListPtr ← displayListPtr + 1;
    IF displayListPtr = displayList.length THEN { -- get longer display list
    newList: REF DisplayList ← NEW[ DisplayList[displayList.length + 32] ];
    FOR i: NAT IN [0..displayListPtr) DO newList[i] ← displayList[i]; ENDLOOP;
    displayList ← newList;
    };
    };
$MiddleButton => ShowRope[ x, y, Rope.Cat["MiddleButton ", keys] ];
$RightButton => ShowRope[ x, y, Rope.Cat["RightButton ", keys] ];
$MiddleHeld  => ShowRope[ x, y, Rope.Cat["MiddleHeld ", keys] ];
$RightHeld  => ShowRope[ x, y, Rope.Cat["RightHeld ", keys] ];
ENDCASE;
};
This will be called when the viewer is changed
ReDraw:  PROCEDURE [context: Imager.Context] ~ { 
savedColor: Imager.Color ← currentColor;
proc: PROC ~ {                -- erase viewport first
Imager.SetColor[context, Imager.white];         -- set color to white
Imager.MaskRectangle[context, ImagerBackdoor.GetBounds[context]]; -- fill screen
};
Imager.DoSaveAll[context, proc];
FOR i: NAT IN [0..displayListPtr) DO
currentColor ← displayList[i].color;
SELECT displayList[i].drawMode FROM
$Xs  => DrawX[displayList[i].place, size];
$Boxes => DrawBox[displayList[i].place, size];
$Circles => DrawCircle[displayList[i].place, size];
$Octagons => DrawOct[displayList[i].place, size];
ENDCASE;
ENDLOOP;
currentColor ← savedColor;
};
This will be called when the viewer is destroyed
ShutDown: PROCEDURE [] ~ {
MessageWindow.Append["QuickViewerExample Exited",TRUE];    -- say goodbye
};
An example using direct calls on the imager (Callback from Viewers is handled internally)
DrawSpiral: PROC [] ~ {
screen: Imager.Rectangle ← ImagerBackdoor.GetBounds[displayContext];
oldPt: Vector2.VEC ← [screen.w/2.0, screen.h/2.0];
Imager.SetStrokeWidth[displayContext, 10.0];
Imager.SetStrokeEnd[displayContext, round];
Imager.SetStrokeJoint[displayContext, mitered];
Imager.SetColor[displayContext, currentColor];
FOR i: NAT IN [0..3000] DO
newPt: Vector2.VEC ← [
i/10.0 * RealFns.Sin[i/40.0] + screen.w/2.0 ,
i/10.0 * RealFns.Cos[i/40.0] + screen.h/2.0
];
Imager.MaskVector[displayContext, oldPt, newPt];
oldPt ← newPt;
ENDLOOP;
};
The following are examples using callback from the Viewers package
DrawX: PROC [controlPoint: Vector2.VEC, leg: REAL] ~ {
DoDrawX: PROC [context: Imager.Context] ~ {
Imager.SetColor[context, currentColor];
Imager.MaskVector[
context,
[controlPoint.x - leg, controlPoint.y - leg],
[controlPoint.x + leg, controlPoint.y + leg]
];
Imager.MaskVector[
context,
[controlPoint.x - leg, controlPoint.y + leg],
[controlPoint.x + leg, controlPoint.y - leg]
];
};
QuickViewer.DrawInViewer[DoDrawX];  -- ask the viewer procs to call you back
};
DrawBox: PROC [controlPoint: Vector2.VEC, side: REAL] ~ {
DoDrawBox: PROC [context: Imager.Context] ~ {
Path: Imager.PathProc ~ {
moveTo[[controlPoint.x - side, controlPoint.y - side]];
lineTo[[controlPoint.x + side, controlPoint.y - side]];
lineTo[[controlPoint.x + side, controlPoint.y + side]];
lineTo[[controlPoint.x - side, controlPoint.y + side]];
lineTo[[controlPoint.x - side, controlPoint.y - side]];
};
Imager.SetColor[context, currentColor];
Imager.MaskFill[context, Path];
};
QuickViewer.DrawInViewer[DoDrawBox];  -- ask the viewer procs to call you back
};
DrawCircle: PROC [controlPoint: Vector2.VEC, radius: REAL] ~ {
DoDrawCircle: PROC [context: Imager.Context] ~ {
Path: Imager.PathProc ~ {
x, y, theta: REAL ← 0.;
moveTo[[controlPoint.x + radius, controlPoint.y]];
UNTIL theta > 2*3.1416 DO
x ← radius * RealFns.Cos[theta] + controlPoint.x;
y ← radius * RealFns.Sin[theta] + controlPoint.y;
lineTo[[x, y]];
theta ← theta + 3.1416 / 12.;
ENDLOOP;
};
Imager.SetColor[context, currentColor];
Imager.MaskFill[context, Path];
};
QuickViewer.DrawInViewer[DoDrawCircle];  -- ask the viewer procs to call you back
};
DrawOct: PROC [controlPoint: Vector2.VEC, radius: REAL] ~ { -- draw an octagon
DoDrawOct: PROC [context: Imager.Context] ~ {
Path: Imager.PathProc ~ {
x, y, theta: REAL ← 0.;
moveTo[[controlPoint.x + radius , controlPoint.y - radius/3.]];
lineTo[[controlPoint.x + radius , controlPoint.y + radius/3.]];
lineTo[[controlPoint.x + radius/3., controlPoint.y + radius]];
lineTo[[controlPoint.x - radius/3., controlPoint.y + radius]];
lineTo[[controlPoint.x - radius, controlPoint.y + radius/3.]];
lineTo[[controlPoint.x - radius, controlPoint.y - radius/3.]];
lineTo[[controlPoint.x - radius/3., controlPoint.y - radius]];
lineTo[[controlPoint.x + radius/3., controlPoint.y - radius]];
lineTo[[controlPoint.x + radius, controlPoint.y - radius/3.]];
};
Imager.SetColor[context, currentColor];
Imager.MaskFill[context, Path];
};
QuickViewer.DrawInViewer[DoDrawOct];  -- ask the viewer procs to call you back
};
ShowRope: PROC[x, y: REAL, rope: Rope.ROPE] ~ {
DoShowRope: PROC[context: Imager.Context] ~ {
IF currentFont = NIL THEN {
currentFont ← ImagerFont.Find["Xerox/Pressfonts/TimesRoman-MRR"];
currentFont ← ImagerFont.Scale[currentFont, 12.0];
};
Imager.SetColor[context, currentColor];
Imager.SetFont[context, currentFont];
Imager.SetXY[context, [x, y]];
Imager.ShowRope[context, rope];
};
QuickViewer.DrawInViewer[DoShowRope];  -- ask the viewer procs to call you back
};
Init[];
END.