-- 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: BOOLEAN ← FALSE;
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.