-- Pupwatch: Display

-- [Indigo]<Grapevine>PupWatch>Cedar>FunnyDisplay.mesa

-- Andrew Birrell August 26, 1983 1:45 pm

DIRECTORY
Ascii   USING[ CR ],
Buttons,
Containers,
Graphics,
GraphicsOps USING[ DrawText ],
Labels  USING[ Create ],
LookerDefs USING[ DoAction, InputAction, NewPriority, ShowBroadcast],
PrincOpsUtils  USING[ LongCOPY ],
Process  USING[ Detach, Priority, priorityBackground, priorityNormal ],
Rope   USING[ ROPE ],
VFonts  USING[ EstablishFont, GraphicsFont],
ViewerClasses,
ViewerOps,
ViewerTools;

FunnyDisplay: MONITOR
IMPORTS Buttons, Containers, Graphics, GraphicsOps, Labels, LookerDefs, PrincOpsUtils, Process, VFonts, ViewerOps, ViewerTools
EXPORTS LookerDefs =

BEGIN

font: Graphics.FontRef = VFonts.GraphicsFont[VFonts.EstablishFont["Helvetica",8]];

fontMax: REAL = Graphics.FontBox[font].ymax;
fontMin: REAL = Graphics.FontBox[font].ymin;
topPos: REAL = fontMax;

myViewer: ViewerClasses.Viewer;
pause, fast, slow, hostText, bYes, bNo, normal, back, small, big: ViewerClasses.Viewer;

line: REF TEXT = NEW[TEXT[600]];
xPos: REAL ← 0.0;
yPos: REAL ← topPos; -- offset from top of text area --

DisplayChar: PUBLIC PROC[c: CHARACTER] =
BEGIN
IF c = Ascii.CR
THEN BEGIN
SendNow[]; xPos ← 0.0; yPos ← yPos + (fontMax-fontMin);
END
ELSE { line[line.length] ← c; line.length ← line.length+1 };
END;

DisplayMultiple: PUBLIC PROC[
desc: LONG DESCRIPTOR FOR PACKED ARRAY OF CHARACTER] =
BEGIN
amount: CARDINAL = MIN[line.maxLength-line.length, LENGTH[desc]];
IF line.length MOD 2 = 0
THEN PrincOpsUtils.LongCOPY[from: BASE[desc],
to: LOOPHOLE[line,LONG POINTER]+SIZE[TEXT[0]]+line.length/2,
nwords: (amount+1)/2]
ELSE FOR i: CARDINAL IN [0..amount) DO line[line.length+i] ← desc[i] ENDLOOP;
line.length ← line.length + amount;
END;

GetLength: PUBLIC PROC[r: Rope.ROPE] RETURNS[ length: REAL] =
BEGIN
xw, yw: REAL;
[xw, yw] ← Graphics.RopeWidth[font, r];
RETURN[xw]
END;

SetPos: PUBLIC PROC[pos: REAL] =
{ SendNow[]; xPos ← pos };

SendNow: PUBLIC PROC =
{ ViewerOps.PaintViewer[myViewer, client, FALSE, line]; line.length ← 0 };

Clear: PUBLIC PROC =
BEGIN
ViewerOps.PaintViewer[myViewer, client, FALSE, $Clear];
END;

WriteTitle: PUBLIC PROC[r: Rope.ROPE] =
BEGIN
myViewer.parent.name ← r;
ViewerOps.PaintViewer[myViewer.parent, caption, FALSE, NIL];
END;

myClass: ViewerClasses.ViewerClass = NEW[ViewerClasses.ViewerClassRec ←[
  paint: MyPaint,
  destroy: MyDestroy,
  icon: tool ] ];

screenLines: CARDINAL ← 0;

ScreenLines: PUBLIC ENTRY PROC RETURNS[CARDINAL] =
{ RETURN[screenLines] };

MyPaint: ENTRY ViewerClasses.PaintProc = TRUSTED
-- self: Viewer, context: Graphics.Context, whatChanged: REF ANY, clear: BOOLEAN
BEGIN
bounds: Graphics.Box = Graphics.GetBounds[context];
IF whatChanged = NIL
THEN BEGIN
yPos ← topPos;
screenLines ← 0;
BEGIN
tempY: REAL ← topPos;
WHILE bounds.ymax - tempY + fontMin >= bounds.ymin
DO screenLines ← screenLines+1; tempY ← tempY + (fontMax-fontMin) ENDLOOP;
END;
RETURN
END;
WITH whatChanged SELECT FROM
text: REF TEXT =>
BEGIN
IF bounds.ymax - yPos + fontMin < bounds.ymin THEN yPos ← topPos;
IF xPos = 0.0 -- start of a new line --
THEN BEGIN
yBase: REAL =
IF bounds.ymax - yPos + fontMin - (fontMax-fontMin) < bounds.ymin
THEN topPos
ELSE yPos + (fontMax-fontMin);
Graphics.SetColor[context, Graphics.white];
Graphics.DrawBox[context,
[xmin: bounds.xmin, ymin: bounds.ymax - yBase + fontMin,
xmax: bounds.xmax, ymax: bounds.ymax - yBase + fontMax] ];
Graphics.SetColor[context, Graphics.black];
END;
Graphics.SetCP[context, bounds.xmin + xPos, bounds.ymax - yPos];
GraphicsOps.DrawText[self: context, text: text, font: font];
xPos ← Graphics.GetCP[context].x - bounds.xmin;
END;
x: ATOM => SELECT x FROM
$Clear =>
BEGIN
Graphics.SetColor[context, Graphics.white];
Graphics.DrawBox[context,
[xmin: bounds.xmin, ymin: bounds.ymin,
xmax: bounds.xmax, ymax: bounds.ymax - topPos + fontMax] ];
xPos ← 0.0;
yPos ← topPos;
END;
ENDCASE => NULL;
ENDCASE => NULL;
END;

MyDestroy: ViewerClasses.DestroyProc = TRUSTED
-- self: Viewer
BEGIN
Process.Detach[FORK LookerDefs.DoAction[[stop[]]] ];
END;

active: ATOM = $WhiteOnBlack;

Create: PROC RETURNS[text: ViewerClasses.Viewer] =
-- returns viewer which is the non-scrolling text area --
BEGIN
outer: ViewerClasses.Viewer = Containers.Create[
info: [name: "Pupwatch", column: right, scrollable: FALSE, iconic: TRUE]];
child: ViewerClasses.Viewer ← CreateChildren[outer];
Buttons.SetDisplayStyle[fast, active, FALSE];
Buttons.SetDisplayStyle[back, active, FALSE];
Buttons.SetDisplayStyle[bNo, active, FALSE];
Buttons.SetDisplayStyle[small, active, FALSE];
text ← ViewerOps.CreateViewer[
flavor: $Pupwatch,
info: [parent: outer, scrollable: FALSE, border: FALSE, wx: 2, wy: child.wy + child.wh + 2]];
Containers.ChildXBound[outer, text];
Containers.ChildYBound[outer, text];
END;

CreateChildren: PROC[v: ViewerClasses.Viewer] RETURNS[child: ViewerClasses.Viewer] =
BEGIN
SimpleButton: PROC[name: Rope.ROPE, action: LookerDefs.InputAction] =
BEGIN
child ← Buttons.Create[
info: [name: name, parent: v, border: TRUE,
wx: IF child = NIL THEN 2 ELSE 2+child.wx+child.ww,
wy: IF child = NIL THEN 1 ELSE child.wy],
proc: DoSimpleAction,
clientData: NEW[LookerDefs.InputAction ← action],
fork: TRUE];
END;
child ← NIL;
SimpleButton["Continue", [pauseContinue[]]]; pause ← child;
SimpleButton["Fast", [fast[]]]; fast ← child;
SimpleButton["Slow", [slow[]]]; slow ← child;
SimpleButton["Replay", [replay[]]];
SimpleButton["Write log", [writeLog[]]];
child ← Buttons.Create[
info: [name: "New host", parent: v, border: TRUE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoHost, fork: TRUE];
child ← Buttons.Create[
info: [name: " Host: ", parent: v, border: FALSE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoHostPrompt, fork: FALSE];
hostText ← ViewerTools.MakeNewTextViewer[
info: [parent: v, scrollable: FALSE, border: FALSE,
wx: 2+child.wx+child.ww, wy: child.wy,
ww: v.cw-(2+child.wx+child.ww), wh: child.wh]];
Containers.ChildXBound[v, hostText];
child ← Labels.Create[
info: [name: "Broadcasts:", parent: v, border: FALSE,
wx: 2, wy: child.wy + child.wh + 2]];
child ← bYes ← Buttons.Create[
info: [name: "yes", parent: v, border: TRUE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoBroadcast, fork: TRUE];
child ← bNo ← Buttons.Create[
info: [name: "no", parent: v, border: TRUE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoBroadcast, fork: TRUE];
child ← Labels.Create[
info: [name: " Priority:", parent: v, border: FALSE,
wx: 2+child.wx+child.ww, wy: child.wy]];
child ← normal ← Buttons.Create[
info: [name: "normal", parent: v, border: TRUE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoPriority, fork: TRUE];
child ← back ← Buttons.Create[
info: [name: "background", parent: v, border: TRUE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoPriority, fork: TRUE];
child ← Labels.Create[
info: [name: " PktSize:", parent: v, border: FALSE,
wx: 2+child.wx+child.ww, wy: child.wy]];
child ← small ← Buttons.Create[
info: [name: "small", parent: v, border: TRUE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoSize, fork: TRUE];
child ← big ← Buttons.Create[
info: [name: "big", parent: v, border: TRUE,
wx: 2+child.wx+child.ww, wy: child.wy],
proc: DoSize, fork: TRUE];
END;

NotePausing: PUBLIC ENTRY PROC[nowPausing: BOOLEAN] =
BEGIN
Buttons.ReLabel[pause, IF nowPausing THEN "Continue" ELSE "Pause"];
END;

DoSimpleAction: Buttons.ButtonProc = TRUSTED
-- parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
BEGIN
LookerDefs.DoAction[NARROW[clientData, REF LookerDefs.InputAction]^];
END;

isSlow: BOOLEANFALSE;

NoteSlow: PUBLIC ENTRY PROC[nowSlow: BOOLEAN] =
BEGIN
Buttons.SetDisplayStyle[IF isSlow THEN slow ELSE fast, $BlackOnWhite];
isSlow ← nowSlow;
Buttons.SetDisplayStyle[IF isSlow THEN slow ELSE fast, active];
END;

DoHost: Buttons.ButtonProc = TRUSTED
-- parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
BEGIN
LookerDefs.DoAction[[newHost[ViewerTools.GetContents[hostText]]]];
END;

DoHostPrompt: Buttons.ButtonProc = TRUSTED
-- parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
BEGIN
text: ViewerClasses.Viewer = hostText;
SELECT mouseButton FROM
red => ViewerTools.SetSelection[text, NIL];
blue => { ViewerTools.SetContents[text, NIL]; ViewerTools.SetSelection[text, NIL] };
yellow => NULL;
ENDCASE => ERROR;
END;

DoBroadcast: Buttons.ButtonProc = TRUSTED
-- parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
BEGIN
viewer: Buttons.Button = NARROW[parent];
Buttons.SetDisplayStyle[bYes, IF viewer = bYes THEN active ELSE $BlackOnWhite];
Buttons.SetDisplayStyle[bNo, IF viewer = bNo THEN active ELSE $BlackOnWhite];
LookerDefs.ShowBroadcast[viewer = bYes];
END;

DoPriority: Buttons.ButtonProc = TRUSTED
-- parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
BEGIN
viewer: Buttons.Button = NARROW[parent];
Buttons.SetDisplayStyle[normal, IF viewer = normal THEN active ELSE $BlackOnWhite];
Buttons.SetDisplayStyle[back, IF viewer = back THEN active ELSE $BlackOnWhite];
LookerDefs.NewPriority[IF viewer = normal THEN Process.priorityNormal
ELSE Process.priorityBackground];
END;

DoSize: Buttons.ButtonProc = TRUSTED
-- parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL
BEGIN
viewer: Buttons.Button = NARROW[parent];
Buttons.SetDisplayStyle[small, IF viewer = small THEN active ELSE $BlackOnWhite];
Buttons.SetDisplayStyle[big, IF viewer = big THEN active ELSE $BlackOnWhite];
LookerDefs.DoAction[[pktSize[big: viewer = big]]];
END;


ViewerOps.RegisterViewerClass[$Pupwatch, myClass];

myViewer ← Create[];

LookerDefs.DoAction[[start[]]];

END.