PEViewerImpl.mesa
Last Edited by Plebon, August 23, 1983 4:17 pm
Routines to manage the Path Editor viewer. These routines are essentially Frank Crow's Quick Viewer with a few improvements.
DIRECTORY
Atom USING [GetPName],
Containers USING [Container, Create, ChildXBound, ChildYBound],
Graphics USING [Context, Mark, Save, white, GetBounds, SetColor, DrawBox, Restore, Translate],
InputFocus USING [ReleaseButtons],
Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc],
PEViewer,
Process USING [Detach],
Real USING [FixI],
Rope USING [ROPE],
TIPUser USING [InstantiateNewTIPTable,TIPScreenCoords],
ViewerClasses USING [Viewer, ViewerClass, ViewerClassRec, NotifyProc, PaintProc, DestroyProc, ScrollProc],
ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass],
WindowManager USING [RestoreCursor];
PEViewerImpl: CEDAR MONITOR
IMPORTS Atom, Containers, Graphics, InputFocus, Menus, Process, Real, TIPUser, ViewerOps, WindowManager
EXPORTS PEViewer =
BEGIN OPEN PEViewer;
entryHeight: CARDINAL = 12;   -- height of a line of items in a menu
entryVSpace: CARDINAL = 3;   -- vertical leading between lines
entryHSpace: CARDINAL = 8;    -- horizontal space between items on a line
PathViewerData: TYPE = REF PathViewerDataRec;
PathViewerDataRec: TYPE = RECORD [
outer: Containers.Container ← NIL,
viewer: ViewerClasses.Viewer,
xTranslation, yTranslation: REAL ← 0.,
xLeft, xRight, yBottom, yTop: REAL ← 0.,
buttonPasserState: ButtonPasserState ← alive,
inputEvent: ATOM,
newEventArrival: CONDITION,
gotANewHit: BOOLEANFALSE,
controlPointX, controlPointY: REAL ← 0.,
redrawProc: RedrawProc,  -- name of procedure for redrawing on window resizing, etc.
buttonProc: ButtonProc,   -- name of procedure for acting on button pushes
quitProc: QuitProc,    -- name of procedure for cleaning up on exit
clientData: REF ANY
];
ButtonPasserState: TYPE = {alive, dying, dead};
MenuData: TYPE = REF MenuDataRec;
MenuDataRec: TYPE = RECORD [
menuButton: ATOM,
pathViewerData: PathViewerData
];
BuildViewer: PUBLIC PROCEDURE [name: Rope.ROPE, menuLabels: LIST OF MenuLabelRec, clientData: REF ANY, redrawProc: RedrawProc, quitProc: QuitProc, buttonProc: ButtonProc] RETURNS [pathViewer: ViewerClasses.Viewer] = {
This routine makes a viewer with the supplied name and menu labels. The supplied redrawProc is called when the screen must be redrawn (because the viewer changes size, etc.). The supplied quitProc is called to clean up on program termination (which occurs when the viewer is destroyed.
menu: Menus.Menu ← Menus.CreateMenu[];
pathViewerData: PathViewerData ← NEW[PathViewerDataRec ← [redrawProc: redrawProc, buttonProc: buttonProc, quitProc: quitProc, clientData: clientData]];
Menus.AppendMenuEntry[     -- enter "erase" button
menu: menu,
entry: Menus.CreateEntry[
name: "Erase",
proc: Erase,
clientData: pathViewerData,
documentation: "Erase the viewer"
]
];
Menus.AppendMenuEntry[     -- enter "<" button
menu: menu,
entry: Menus.CreateEntry[
name: "<",
proc: RollLeft,
clientData: pathViewerData,
documentation: "Roll image to left"
]
];
Menus.AppendMenuEntry[     -- enter ">" button
menu: menu,
entry: Menus.CreateEntry[
name: ">",
proc: RollRight,
clientData: pathViewerData,
documentation: "Roll image to right"
]
];
FOR menuLabels ← menuLabels, menuLabels.rest UNTIL menuLabels = NIL DO
Menus.AppendMenuEntry[     -- enter menu buttons 
menu: menu,
entry: Menus.CreateEntry[
name: Atom.GetPName[menuLabels.first.label],
proc: MenuHit,
clientData: NEW[MenuDataRec ← [
menuButton: menuLabels.first.label,
pathViewerData: pathViewerData
] ],
documentation: "",
guarded: menuLabels.first.guarded
]
];
ENDLOOP;
pathViewerData.outer ← Containers.Create[ [
name: name,
menu: menu,
iconic: TRUE,
column: left,
scrollable: FALSE
] ];                     
pathViewerData.viewer ← ViewerOps.CreateViewer[
flavor: $PEViewer,
info: [
parent: pathViewerData.outer,
wx: 0, wy: 0,        -- position WRT parent
ww: pathViewerData.outer.ww,  -- CHildXBound below
wh: pathViewerData.outer.wh,   -- CHildXBound below
data: pathViewerData,     -- describes the current scene
scrollable: TRUE
]
];
Constrain the graphics area to lie in viewer space left over after menu, etc. are drawn.    
Containers.ChildXBound[pathViewerData.outer, pathViewerData.viewer];
Containers.ChildYBound[pathViewerData.outer, pathViewerData.viewer];
ViewerOps.PaintViewer[pathViewerData.outer, all];
pathViewerData.xTranslation ← pathViewerData.yTranslation ← 0.;
pathViewerData.xLeft ← pathViewerData.yBottom ← 0.;
pathViewerData.xRight ← pathViewerData.viewer.ww;
pathViewerData.yTop ← pathViewerData.viewer.wh;
TRUSTED {Process.Detach[FORK ButtonPasser[pathViewerData]];};
RETURN [pathViewerData.viewer];
};
DrawInViewer: PUBLIC PROCEDURE [pathViewer: ViewerClasses.Viewer, drawProc: DrawProc] = {
This routine calls the PaintProc to draw in the viewer.
doDrawProc: REF DrawProc ← NIL;
IF pathViewer # NIL THEN {
TRUSTED {doDrawProc ← NEW[DrawProc ← drawProc];};
ViewerOps.PaintViewer[
viewer: pathViewer,
hint: client,
whatChanged: doDrawProc,
clearClient: FALSE
];
};
};
PaintProc: ViewerClasses.PaintProc = {
This routine repaints the screen with updates.
pathViewerData: PathViewerData ← NARROW[self.data];
x,y: REAL;
x ← pathViewerData.xTranslation;
y ← pathViewerData.yTranslation;
IF whatChanged = NIL THEN {
Graphics.Translate[context, x, y];
pathViewerData.redrawProc[pathViewerData.clientData];
}
ELSE {
Graphics.Translate[context, x, y];
NARROW[whatChanged, REF DrawProc]^[context];
};
}; 
Erase: Menus.MenuProc = {
This routine erases the contents the the graphics viewer.
DoErase: PROC [context: Graphics.Context] = {
mark: Graphics.Mark ← Graphics.Save[context];
Graphics.SetColor[context, Graphics.white];
Graphics.DrawBox[context, Graphics.GetBounds[context]];
Graphics.Restore[context,mark];
};
pathViewerData: PathViewerData ← NARROW[clientData];
DrawInViewer[pathViewerData.viewer, DoErase];
};
RollLeft: Menus.MenuProc = {
This routine moves the image to the left in the graphics viewer. 
pathViewerData: PathViewerData ← NARROW[clientData];
pathViewerData.xTranslation ← pathViewerData.xTranslation - 64;
pathViewerData.redrawProc[clientData: pathViewerData.clientData];
};
RollRight: Menus.MenuProc = {
This routine moves the image to the right in the graphics viewer. 
pathViewerData: PathViewerData ← NARROW[clientData];
pathViewerData.xTranslation ← pathViewerData.xTranslation + 64;
pathViewerData.redrawProc[clientData: pathViewerData.clientData];
};
MenuHit: Menus.MenuProc = {
This routine handles client menu item hits.
menuData: MenuData ← NARROW[clientData];
ButtonMonitor[menuData.pathViewerData, menuData.menuButton];
};
ButtonMonitor: ENTRY PROCEDURE [pathViewerData: PathViewerData, event: ATOM] = {
This routine stores a button event and notifies the button passing process.
pathViewerData.inputEvent ← event;
pathViewerData.gotANewHit ← TRUE;
NOTIFY pathViewerData.newEventArrival;
};
ButtonPasser: PROCEDURE [pathViewerData: PathViewerData] = {
This process monitors button events.
WHILE pathViewerData.buttonPasserState = alive DO
IF GotAButtonHit[pathViewerData] THEN pathViewerData.buttonProc[pathViewerData.clientData, pathViewerData.inputEvent, pathViewerData.controlPointX, pathViewerData.controlPointY];
ENDLOOP;
pathViewerData.buttonPasserState ← dead;
};
GotAButtonHit: ENTRY PROCEDURE [pathViewerData: PathViewerData] RETURNS [gotAHit: BOOLEAN] = {
This routine waits for notification of an event, and determines if the event is a button hit.
IF ~pathViewerData.gotANewHit THEN WAIT pathViewerData.newEventArrival;
gotAHit ← pathViewerData.gotANewHit;
pathViewerData.gotANewHit ← FALSE;
};
NotifyProc: ViewerClasses.NotifyProc = {
This routine responds to input events (from the TIP table).
ENABLE UNWIND => { InputFocus.ReleaseButtons[]; WindowManager.RestoreCursor[]; };
pathViewerData: PathViewerData ← NARROW[self.data];
FOR list: LIST OF REF ANY ← input, list.rest UNTIL list = NIL DO
WITH list.first SELECT FROM
x: ATOM => ButtonMonitor[pathViewerData, x];
z: TIPUser.TIPScreenCoords => {
OPEN pathViewerData;
controlPointX ← z.mouseX - xTranslation;
controlPointY ← z.mouseY - yTranslation;
Expand work area if clicked outside existing bounds.
IF controlPointX > xRight THEN xRight ← controlPointX
ELSE IF controlPointX < xLeft THEN xLeft ← controlPointX;
IF controlPointY > yTop THEN yTop ← controlPointY
ELSE IF controlPointY < yBottom THEN yBottom ← controlPointY;
};
ENDCASE => ERROR;
ENDLOOP;
};
DestroyProc: ViewerClasses.DestroyProc = {
This routine cleans up when the viewer is destroyed.
pathViewerData: PathViewerData ← NARROW[self.data];
DestroyButtonPasser[pathViewerData];
IF pathViewerData.quitProc # NIL THEN pathViewerData.quitProc[pathViewerData.clientData];
pathViewerData.viewer ← NIL;
pathViewerData.outer ← NIL;
};
DestroyButtonPasser: ENTRY PROCEDURE [pathViewerData: PathViewerData] = {
This routine causes the button passer process to kill itself.
pathViewerData.buttonPasserState ← dying;
NOTIFY pathViewerData.newEventArrival;
};
ScrollProc: ViewerClasses.ScrollProc = {
This routine handles scrollbar mouse hits.
pathViewerData: PathViewerData ← NARROW[self.data];
SELECT op FROM
up => {
pathViewerData.yTranslation ← pathViewerData.yTranslation + amount;
pathViewerData.redrawProc[clientData: pathViewerData.clientData];
};
down => {
pathViewerData.yTranslation ← pathViewerData.yTranslation - amount;
pathViewerData.redrawProc[clientData: pathViewerData.clientData];
};
thumb => {
pathViewerData.yTranslation ← - (pathViewerData.yBottom + (1. - amount/100.) * (pathViewerData.yTop - pathViewerData.yBottom));
pathViewerData.redrawProc[clientData: pathViewerData.clientData];
};
query => {
OPEN pathViewerData;
RETURN [Real.FixI[100. - (-yTranslation + self.ch - yBottom) * 100. / (yTop - yBottom)], Real.FixI[100. - (-yTranslation - yBottom) * 100. / (yTop - yBottom)]];
};
ENDCASE;
};
Init: PROCEDURE [] = {
This routine starts up the viewer.
pathViewerClass: ViewerClasses.ViewerClass;
pathViewerClass ← NEW[ViewerClasses.ViewerClassRec ← [
paint: PaintProc,
notify: NotifyProc,
destroy: DestroyProc,
scroll: ScrollProc,
tipTable: TIPUser.InstantiateNewTIPTable["PEViewer.TIP"],
icon: document
] ];
ViewerOps.RegisterViewerClass[$PEViewer, pathViewerClass];
};
Init[];
END.