-- TJaMGraphicsViewer.mesa
-- Last change by Bill Paxton, October 5, 1982 3:19 pm
-- Last change by McGregor, June 15, 1982 10:05 am
-- Last Edited by: Stone,
March 28, 1983 4:21 pm

DIRECTORY
Graphics,
GraphicsOps,
CGVector,
GL USING [ Start],
Rope USING [Concat],
InputFocus USING [CaptureButtons, ReleaseButtons],
Real USING [RoundI],
Spline USING [New],
TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords],
Cursors USING [SetCursor],
WindowManager USING [RestoreCursor],
Menus USING [Menu, MenuProc, CreateEntry, CreateMenu, InsertMenuEntry],
ViewerClasses USING [Viewer, ViewerClass, ViewerClassRec, NotifyProc],
ViewerOps USING [DestroyViewer, RegisterViewerClass, CreateViewer],
JaMTypeScript USING [GetTypeScript, NotifyBeforeDestroy, SetMouseProc, DoAtom, DoButton],
JaMOps USING [SetAbort, defaultFrame, RegisterExplicit, PushReal, PopBoolean],
TJaMGraphics,
TJaMGraphicsInfo,
TJaMGraphicsContexts,
UserTerminal USING [BlinkDisplay];

TJaMGraphicsViewer: MONITOR
LOCKS info USING info:TJaMGraphicsInfo.Info
IMPORTS Graphics, Real, JaMTypeScript, TJaMGraphicsInfo, Rope,
 UserTerminal, InputFocus, TIPUser, Cursors, Menus, ViewerOps, WindowManager,
 Spline, JaMOps, GraphicsOps, TJaMGraphics, GL, TJaMGraphicsContexts
EXPORTS TJaMGraphics, TJaMGraphicsInfo, TJaMGraphicsContexts =
BEGIN OPEN TJaMGraphicsInfo, J: JaMOps, G: Graphics, E: GraphicsOps,
Vector: CGVector, TJaMGraphics, TDC: TJaMGraphicsContexts;

jamGraphicsClass: ViewerClasses.ViewerClass ← NEW[ViewerClasses.ViewerClassRec ← [
 paint: TJaMGraphicsInfo.Paint,
 notify: InputNotify,
 destroy: AboutToDestroy,
 tipTable: TIPUser.InstantiateNewTIPTable["JaMGraphics.TIP"]
 ]];

JReloadTIP: PROC [frame: Frame] = { ReloadTIP[] };

ReloadTIP: PUBLIC PROC = {
 jamGraphicsClass.tipTable ← TIPUser.InstantiateNewTIPTable["JaMGraphics.TIP"] };

JGetViewer: PROC [frame: Frame] = {
tool: ViewerClasses.Viewer ← JaMTypeScript.GetTypeScript[frame];
IF tool=NIL THEN RETURN; -- error
[] ← Create[frame,tool];
};

InitGL: PROC RETURNS[Graphics.Context] = {RETURN[GL.Start[NIL]]};
Create: PUBLIC PROC [
frame: Frame, typescript: ViewerClasses.Viewer, iconic: BOOLEANFALSE]
RETURNS [viewer: ViewerClasses.Viewer] = {
info: Info;
menu: Menus.Menu;
bmw,bmh: CARDINAL;
{ -- extra block to make info defined in scope of UNWIND
ENABLE UNWIND => -- something went wrong while creating the viewer
IF viewer#NIL THEN DestroyViewer[viewer] ELSE IF info#NIL THEN ForgetInfo[frame];
IF (info ← GetInfo[frame]) # NIL THEN RETURN;
info ← CreateInfo[frame];
info.path ← G.NewPath[];
[bmw,bmh] ← GetBitmapSize[];
info.bitmap ← E.NewBitmap[bmw,bmh];
info.spline ← Spline.New[];
info.font ← E.DefaultFont[];
info.text ← NEW[TEXT[256]];
menu ← Menus.CreateMenu[];
Menus.InsertMenuEntry[menu, Menus.CreateEntry["Reset", Reset]];
Menus.InsertMenuEntry[menu, Menus.CreateEntry["Mouse", CaptureFocusButton]];
Menus.InsertMenuEntry[menu, Menus.CreateEntry["Interrupt", InterruptButton]];
viewer ← ViewerOps.CreateViewer[flavor: $JaMGraphics, info: [data: info,
 name: Rope.Concat[typescript.name,"Graphics "], menu: menu, iconic: iconic, scrollable: FALSE]];
info.viewer ← viewer;
info.typescript ← typescript;
info.vdc ← NIL; info.vinitdc ← NIL; info.venabled ← TRUE;
TDC.AddContext[frame: frame, init: InitGL,name: $GList, enabled: FALSE, initOnErase: TRUE];
info.gl ← NIL; info.drawGL ← FALSE;
JaMTypeScript.NotifyBeforeDestroy[typescript,JDestroyViewer];
}};

Reset: Menus.MenuProc = TRUSTED {
viewer: ViewerClasses.Viewer ← NARROW[parent];
frame: Frame ← NARROW[viewer.data,Info].frame;
InitDC[frame]; JErase[frame] };

CaptureFocusButton: Menus.MenuProc = TRUSTED {
viewer: ViewerClasses.Viewer ← NARROW[parent];
info: Info ← NARROW[viewer.data];
frame: Frame ← info.frame;
JCaptureButtons[frame] };

InterruptButton: Menus.MenuProc = TRUSTED {
viewer: ViewerClasses.Viewer ← NARROW[parent];
info: Info ← NARROW[viewer.data];
frame: Frame ← info.frame;
J.SetAbort[frame,TRUE];
SetPlace[info,0,0];
SetBug[info,0,0] };

JDestroyViewer: PROCEDURE [frame: Frame] = { -- returns true if already have a viewer for this frame
info: Info ← GetInfo[frame];
IF info = NIL THEN RETURN;
DestroyViewer[info.viewer];
};

DestroyViewer: PROC [viewer: ViewerClasses.Viewer] = {
AboutToDestroy[viewer];
ViewerOps.DestroyViewer[viewer];
};

AboutToDestroy: SAFE PROC [self: ViewerClasses.Viewer] = TRUSTED {
info: Info ← NARROW[self.data];
ForgetInfo[info.frame];
};

JCaptureButtons: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
InputFocus.CaptureButtons[info.viewer.class.notify, info.viewer.tipTable, info.viewer];
info.capturedButtons ← TRUE;
Cursors.SetCursor[textPointer] };

JReleaseButtons: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
InputFocus.ReleaseButtons[];
WindowManager.RestoreCursor;
info.capturedButtons ← FALSE };

InitDC: PROCEDURE [frame: Frame] = {
info: Info ← GetInfo[frame];
IF info.venabled THEN info.vdc ← G.CopyContext[info.vinitdc];
FOR l: TDC.DCList ← info.dcList, l.next UNTIL l=NIL DO
  IF l.enabled THEN l.dc ← l.init[];
  ENDLOOP;
info.gl ← NIL;
};

JErase: PROCEDURE [frame: Frame] = {
 info: Info ← GetInfo[frame];
 paint: TDC.GProc ={
  mark: G.Mark ← G.Save[dc];
  G.SetColor[dc, G.white];
  G.DrawBox[dc,G.GetBounds[dc]];
  G.Restore[dc,mark];
  };
 Painter[paint,frame];
FOR l: TDC.DCList ← info.dcList, l.next UNTIL l=NIL DO
   IF l.initOnErase AND l.enabled THEN l.dc ← l.init[];
   ENDLOOP;
 info.gl ← NIL;
 };

EnableViewer: PUBLIC PROC [frame: Frame] = {
 info: Info ← GetInfo[frame];
 info.venabled ← TRUE;
 };

DisableViewer: PUBLIC PROC [frame: Frame] = {
 info: Info ← GetInfo[frame];
 info.venabled ← FALSE;
 };

KeepGL: PUBLIC PROC [frame: Frame] = {
 info: Info ← GetInfo[frame];
 b: BOOLEANJ.PopBoolean[frame.opstk];
FOR l: TDC.DCList ← info.dcList, l.next UNTIL l=NIL DO
  IF l.name=$GList THEN l.enabled ← b;
  ENDLOOP;
IF b=FALSE THEN {info.drawGL ← FALSE; info.gl ← NIL};
 };

DoRefresh: PUBLIC PROC [frame: Frame] = {
 info: Info ← GetInfo[frame];
 b: BOOLEANJ.PopBoolean[frame.opstk];
IF b=TRUE THEN {FOR l: TDC.DCList ← info.dcList, l.next UNTIL l=NIL DO
  IF l.name=$GList THEN l.enabled ← b;  --must have an active GList to use it for refresh
  ENDLOOP;
  }
ELSE info.gl ← NIL; --destroy old list
 info.drawGL ← b;
 };

MouseToUser: PROCEDURE[frame: Frame, x,y:REAL] = {
J.PushReal[frame.opstk,x]; J.PushReal[frame.opstk,y];
};

ViewerMouse: PUBLIC PROCEDURE[frame: Frame, click: BOOLEAN] RETURNS[x,y: INTEGER] = {
rx, ry: REAL;
[rx, ry] ← RealViewerMouse[frame, click];
x ← Real.RoundI[x]; y ← Real.RoundI[y] };

RealViewerMouse: PUBLIC PROCEDURE[frame: Frame, click: BOOLEAN] RETURNS[x,y: REAL] = {
info: Info ← GetInfo[frame];
IF info=NIL THEN RETURN [0,0];
IF click THEN [x,y] ← GetBug[info] ELSE [x,y] ← GetPlace[info];
};

GetBug: ENTRY PROC [info: Info] RETURNS[x,y: REAL] = { OPEN info;
ENABLE UNWIND => NULL;
bugflag ← FALSE;
UNTIL viewer.destroyed OR bugflag DO WAIT bugged ENDLOOP;
IF viewer.destroyed THEN x ← y ← 0
ELSE { x ← bugX; y ← bugY; bugflag ← FALSE };
};

SetBug: PUBLIC ENTRY PROC [info: Info, x,y: REAL] = { OPEN info;
ENABLE UNWIND => NULL;
bugflag ← TRUE; bugX ← x; bugY ← y;
NOTIFY bugged };

GetPlace: ENTRY PROC [info: Info] RETURNS[x,y: REAL] = { OPEN info;
ENABLE UNWIND => NULL;
mouseflag ← FALSE;
UNTIL viewer.destroyed OR mouseflag DO WAIT mouse ENDLOOP;
IF viewer.destroyed THEN x ← y ← 0
ELSE { x ← mouseX; y ← mouseY; mouseflag ← FALSE };
};

SetPlace: PUBLIC ENTRY PROC [info: Info, x,y: REAL] = { OPEN info;
ENABLE UNWIND => NULL;
mouseflag ← TRUE; mouseX ← x; mouseY ← y; NOTIFY mouse;
};

--[self: ViewerClasses.Viewer, input: LIST OF REF ANY]
InputNotify: PUBLIC ViewerClasses.NotifyProc = TRUSTED {
Do: PROC [button: ATOM] = {
JaMTypeScript.DoButton[NARROW[self.data,Info].typescript,button,x,y] };
ReleaseButtons: PROC = {
 info: Info ← NARROW[self.data];
IF ~info.capturedButtons THEN RETURN;
 InputFocus.ReleaseButtons[];
info.capturedButtons ← FALSE };
AdjustCoords: PROC = {
 info: Info ← NARROW[self.data];
IF ~info.capturedButtons THEN -- get screen coordinates
  [x, y] ← Graphics.UserToWorld[info.vinitdc, mx, my]
ELSE { x ← mx; y ← my }; -- already in screen coordinates
 [x, y] ← Graphics.WorldToUser[info.vdc, x, y]; -- convert using current dc
 };
mx, my: INTEGER;
x, y: REAL;
Place: PROC = { SetPlace[NARROW[self.data,Info],x,y] };
FOR l: LIST OF REF ANY ← input, l.rest UNTIL l = NIL DO
WITH l.first SELECT FROM
z: ATOM => SELECT z FROM
  $RedDown, $CtrlRedDown, $ShiftRedDown, $CtrlShiftRedDown => {
   SetBug[NARROW[self.data,Info],x,y]; Place[]; Do[z] };
  $YellowDown, $CtrlYellowDown, $ShiftYellowDown, $CtrlShiftYellowDown,
   $BlueDown, $CtrlBlueDown, $ShiftBlueDown, $CtrlShiftBlueDown,
   $Track, $CtrlTrack, $ShiftTrack, $CtrlShiftTrack => Do[z];
  $RedUp, $CtrlRedUp, $ShiftRedUp, $CtrlShiftRedUp,
   $YellowUp, $CtrlYellowUp, $ShiftYellowUp, $CtrlShiftYellowUp,
   $BlueUp, $CtrlBlueUp, $ShiftBlueUp, $CtrlShiftBlueUp => { Do[z]; ReleaseButtons[] }; 
  $Place => Place[];
  ENDCASE => JaMTypeScript.DoAtom[NARROW[self.data,Info].typescript,z];
z: TIPUser.TIPScreenCoords => { [mx, ----, my] ← z^; AdjustCoords[] };
ENDCASE => UserTerminal.BlinkDisplay;
ENDLOOP;
};

Init: PROC = {
frame: Frame ← J.defaultFrame;
[] ← JaMTypeScript.SetMouseProc[MouseToUser];
ViewerOps.RegisterViewerClass[$JaMGraphics, jamGraphicsClass];
J.RegisterExplicit[frame,".erase"L,JErase];
J.RegisterExplicit[frame,".initdc"L,InitDC];
J.RegisterExplicit[frame,".destroyviewer"L,JDestroyViewer];
J.RegisterExplicit[frame,".getviewer"L,JGetViewer];
J.RegisterExplicit[frame,".capturebuttons"L,JCaptureButtons];
J.RegisterExplicit[frame,".releasebuttons"L,JReleaseButtons];
J.RegisterExplicit[frame,".reloadTIP"L,JReloadTIP];
J.RegisterExplicit[frame,".enableviewer"L,EnableViewer];
J.RegisterExplicit[frame,".disableviewer"L,DisableViewer];
J.RegisterExplicit[frame,".keepgl"L,KeepGL];
J.RegisterExplicit[frame,".dorefresh"L,DoRefresh];
};

Init;

END...