RPCEchoToolImpl.mesa
Hal Murray December 30, 1985 5:47:23 pm PST
Hal Murray, January 22, 1986 11:15:47 pm PST
DIRECTORY
Atom USING [GetPName],
BasicTime USING [GetClockPulses, GMT, Now, Period, Pulses, PulsesToMicroseconds],
Buttons USING [Button, ButtonProc, Create, Destroy, SetDisplayStyle],
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, ChildYBound, Create],
IO USING [Flush, PutF, PutRope, STREAM, Value],
Labels USING [Create],
Loader USING [BCDBuildTime],
Rope USING [ROPE],
RPCEcho USING [DoAtom, DoRope, Simple, SloshTenPages, SloshTenWords, PullPage, PushPage, SloshPage, Page, TenPages, TenWords],
RPCEchoRpcControl USING [ImportInterface, UnimportInterface],
Rules USING [Create],
TypeScript USING [ChangeLooks, Create],
ViewerClasses USING [Viewer],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [AddProp, ComputeColumn, CreateViewer, MoveViewer, OpenIcon, SetOpenHeight],
ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection];
RPCEchoToolImpl: CEDAR MONITOR
IMPORTS
Atom, BasicTime, Buttons, Commander, Containers, IO, Labels, Loader, RPCEcho, RPCEchoRpcControl, Rules, TypeScript, ViewerIO, ViewerOps, ViewerTools = {
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Viewer: TYPE = ViewerClasses.Viewer;
Viewer layout parameters
buttonHeight: INTEGER ← 0;
buttonWidth: INTEGER ← 0;
ClientData: TYPE = REF ClientDataRep;
ClientDataRep: TYPE = RECORD [
log: STREAMNIL,
in: STREAMNIL,
pleaseStop: BOOLEANFALSE,
target: Viewer ← NIL,
minDelay, maxDelay: INT ← 0,
delayHist: ARRAY DelayRange OF INTALL[0] ];
DelayRange: TYPE = {
d1, d1a, d2, d2a, d3, d3a, d4, d4a, d5, d5a, d6, d6a, d7, d7a, d8, d8a, d9, d9a,
d10, d14, d20, d28, d50, d70, d100, d140, d200, d280, d500, d700,
d1000, d1400, d2000, d2800, d5000, d7000, d10000, d14000, d20000, d28000, more};
delayTime: ARRAY DelayRange OF INT = [
d1: 1000, d1a: 1500, d2: 2000, d2a: 2500,
d3: 3000, d3a: 3500, d4: 4000, d4a: 4500,
d5: 5000, d5a: 5500, d6: 6000, d6a: 6500,
d7: 7000, d7a: 7500, d8: 8000, d8a: 8500,
d9: 9000, d9a: 9500,
d10: 10000, d14: 14000, d20: 20000, d28: 28000, d50: 50000, d70: 70000,
d100: 100000, d140: 140000, d200: 200000, d280: 280000, d500: 500000, d700: 700000,
d1000: 1000000, d1400: 1400000, d2000: 2000000, d2800: 2800000, d5000: 5000000, d7000: 7000000,
d10000: 10000000, d14000: 14000000, d20000: 20000000, d28000: 28000000, more: LAST[INT]];
global: ClientData ← NIL; -- debugging
Create: Commander.CommandProc = TRUSTED {
viewer, buttons, log: Viewer ← NIL;
data: ClientData ← NEW[ClientDataRep ← []];
global ← data;
viewer ← ViewerOps.CreateViewer [
flavor: $Container,
info: [name: "RPC EchoTool", column: right, iconic: TRUE, scrollable: FALSE]];
ViewerOps.AddProp[viewer, $RPCEcho, data];
{ -- Kludge to find Button size
temp: Buttons.Button = Buttons.Create[
info: [name: "Length:", parent: viewer, border: FALSE,
wx: 0, wy: 0],
proc: NIL, clientData: NIL, fork: FALSE, paint: FALSE];
buttonWidth ← temp.ww;
buttonHeight ← temp.wh;
Buttons.Destroy[temp]; };
log ← TypeScript.Create[
[name: "RPCEchoTool.log", wy: 27+4, parent: viewer, border: FALSE], FALSE];
[data.in, data.log] ← ViewerIO.CreateViewerStreams [
name: "RPCEchoTool.log", backingFile: "RPCEchoTool.log", viewer: log, editedStream: FALSE];
Containers.ChildXBound[viewer, log];
Containers.ChildYBound[viewer, log];
CreateButtons[data, viewer, log];
TypeScript.ChangeLooks[log, 'f];
IO.PutF[data.log, "RPC EchoTool of %G.\n", [time[Loader.BCDBuildTime[Create]]]];
ViewerOps.OpenIcon[viewer]; };
CreateButtons: ENTRY PROC[data: ClientData, parent, log: Viewer] = {
child: Viewer ← NIL;
kids: Viewer = Containers.Create[
info: [parent: parent, border: FALSE, scrollable: FALSE, wx: 0, wy: -9999, ww: 9999, wh: 0] ];
Containers.ChildXBound[parent, kids];
child ← MakeRule[kids, child];
child ← data.target ← MakeLabeledText[
parent: kids,
sibling: child,
name: "Target:",
data: "ME",
prev: data.target ];
child ← MakeRule[kids, child];
child ← MakeLabel[kids, child, "What: "];
child ← MakeButton[kids, child, data, "Stop", StopProc];
child ← MakeButton[kids, child, data, "Simple", DoSimple];
child ← MakeButton[kids, child, data, "10 Wds", DoTenWords];
child ← MakeButton[kids, child, data, "Pull", DoPull];
child ← MakeButton[kids, child, data, "Push", DoPush];
child ← MakeButton[kids, child, data, "Page", DoPage];
child ← MakeButton[kids, child, data, "10 Pgs", DoTenPages];
child ← MakeButton[kids, child, data, "Atom", DoAtom];
child ← MakeButton[kids, child, data, "Rope", DoRope];
child ← MakeRule[kids, child];
{
kidsY: INTEGER = 2;
kidsH: INTEGER = child.wy + child.wh + 2;
ViewerOps.MoveViewer[viewer: log, x: 0, y: kidsY + kidsH, w: log.ww, h: parent.ch - (kids.wy + kidsH), paint: FALSE];
ViewerOps.SetOpenHeight[parent, kidsY + kidsH + 12 * buttonHeight];
IF ~parent.iconic THEN ViewerOps.ComputeColumn[parent.column];
ViewerOps.MoveViewer[viewer: kids, x: kids.wx, y: kidsY, w: kids.ww, h: kidsH]; };
};
StopProc: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
data.pleaseStop ← TRUE; };
DoSimple: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting Simple test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
RPCEcho.Simple[];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
DoTenWords: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
tenWords: RPCEcho.TenWords;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting 10 word test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
tenWords ← RPCEcho.SloshTenWords[tenWords];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
DoPull: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
page: RPCEcho.Page;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting Pull Page test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
page ← RPCEcho.PullPage[];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
DoPush: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
page: RPCEcho.Page;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting Push Page test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
RPCEcho.PushPage[page];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
DoPage: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
page: RPCEcho.Page;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting Page test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
page ← RPCEcho.SloshPage[page];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
DoTenPages: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
pages: RPCEcho.TenPages;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting 10 Page test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
pages ← RPCEcho.SloshTenPages[pages];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
DoAtom: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting ATOM test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
RPCEcho.DoAtom[$Atom];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
DoRope: Buttons.ButtonProc = {
[parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE]
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
start, finish: BasicTime.GMT;
calls: INT ← 0;
InitDelayHist[data];
IO.PutRope[data.log, "\n\nStarting ROPE test...\n"];
data.pleaseStop ← FALSE;
start ← BasicTime.Now[];
RPCEchoRpcControl.ImportInterface[
interfaceName: [instance: ViewerTools.GetContents[data.target]] ];
UNTIL data.pleaseStop DO
callStart: BasicTime.Pulses ← BasicTime.GetClockPulses[];
callStop: BasicTime.Pulses;
RPCEcho.DoRope["Mumble foo, asdfasdfasdfasdfasd"];
callStop ← BasicTime.GetClockPulses[];
AddToDelayHist[data, BasicTime.PulsesToMicroseconds[callStop-callStart]];
calls ← calls.SUCC;
ENDLOOP;
TRUSTED { RPCEchoRpcControl.UnimportInterface[]; };
finish ← BasicTime.Now[];
BEGIN
callsPerSecond, msPerCall: REAL;
seconds: LONG CARDINAL ← BasicTime.Period[from: start, to: finish];
IF seconds = 0 THEN seconds ← 1;
callsPerSecond ← REAL[calls]/REAL[seconds];
IF calls = 0 THEN msPerCall ← 0
ELSE msPerCall ← 1000.0*seconds/calls;
IO.PutF[data.log, "%5G calls in %G seconds =>\n", [integer[calls]], [cardinal[seconds]]];
IO.PutF[data.log, "%8.2F calls/second.\n", [real[callsPerSecond]] ];
IO.PutF[data.log, "%8.2F ms/call.\n", [real[msPerCall]] ];
END;
PrintDelayHist[data, calls];
IO.Flush[data.log];
};
InitDelayHist: PROC [data: ClientData] = {
data.minDelay ← INT.LAST;
data.maxDelay ← INT.FIRST;
data.delayHist ← ALL[0]; };
AddToDelayHist: PROC [data: ClientData, micro: INT] = {
FOR d: DelayRange IN DelayRange DO -- Slow but clean
IF delayTime[d] < micro THEN LOOP;
data.delayHist[d] ← data.delayHist[d] + 1;
EXIT;
REPEAT FINISHED => ERROR;
ENDLOOP;
data.minDelay ← MIN[data.minDelay, micro];
data.maxDelay ← MAX[data.maxDelay, micro]; };
PrintDelayHist: PROC [data: ClientData, calls: INT] = {
total: INT ← 0;
IF calls = 0 THEN RETURN;
IO.PutF[data.log, " Incremental Cumulative Microseconds\n"];
FOR d: DelayRange IN DelayRange DO
IF data.delayHist[d] = 0 THEN LOOP;
total ← total + data.delayHist[d];
IO.PutF[data.log, "%8G", [integer[data.delayHist[d]]]];
IO.PutF[data.log, "%7.2F%%", [real[100.0*data.delayHist[d]/calls]]];
IO.PutF[data.log, "%8G", [integer[total]]];
IO.PutF[data.log, "%7.2F%%", [real[100.0*total/calls]]];
IO.PutF[data.log, "%9G\n", [integer[delayTime[d]]]];
ENDLOOP;
IO.PutF[data.log, "The min delay was %G microseconds.\n", [integer[data.minDelay]]];
IO.PutF[data.log, "The max delay was %G microseconds.\n", [integer[data.maxDelay]]]; };
MakeRule: PROC [parent, sibling: Viewer] RETURNS [child: Viewer] = {
child ← Rules.Create[
info: [parent: parent, border: FALSE,
wy: IF sibling = NIL THEN 0 ELSE sibling.wy + sibling.wh + 2, wx: 0, ww: parent.ww, wh: 1],
paint: FALSE ];
Containers.ChildXBound[parent, child]; };
MakeButton: PROC [parent, sibling: Viewer, data: REF ANY, name: ROPE, proc: Buttons.ButtonProc] RETURNS[child: Viewer] = {
child ← Buttons.Create[
info: [name: name, parent: parent, border: TRUE,
wy: sibling.wy, wx: sibling.wx + buttonWidth - 1, ww: buttonWidth],
proc: proc,
clientData: data,
fork: TRUE,
paint: FALSE]; };
SelectorProc: TYPE = PROC [parent: Viewer, clientData: REF, value: ATOM];
Selector: TYPE = REF SelectorRec;
SelectorRec: TYPE = RECORD [
value: REF ATOM,
change: PROC [parent: Viewer, clientData: REF, value: ATOM],
clientData: REF,
buttons: LIST OF Buttons.Button,
values: LIST OF ATOM ];
MakeSelector: PROC
[name: ROPE, values: LIST OF ATOM, init: REF ATOMNIL, change: SelectorProc ← NIL, clientData: REFNIL, parent: Viewer, x, y: INTEGER]
RETURNS [child: Viewer] = {
selector: Selector ← NEW [SelectorRec ← [
value: IF init # NIL THEN init ELSE NEW [ATOM ← values.first],
change: change,
clientData: clientData,
buttons: NIL,
values: values ] ];
last: LIST OF Buttons.Button ← NIL;
child ← Labels.Create[info: [name: name, parent: parent, border: FALSE, wx: x, wy: y] ];
FOR a: LIST OF ATOM ← values, a.rest UNTIL a = NIL DO
child ← Buttons.Create[
info: [name: Atom.GetPName[a.first], parent: parent, border: TRUE, wx: child.wx + child.ww + 2, wy: child.wy],
proc: SelectorHelper, clientData: selector, fork: TRUE, paint: TRUE];
IF last = NIL THEN last ← selector.buttons ← CONS[first: child, rest: NIL]
ELSE { last.rest ← CONS[first: child, rest: NIL]; last ← last.rest };
IF a.first = selector.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack];
ENDLOOP; };
SelectorHelper: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
self: Buttons.Button = NARROW[parent];
selector: Selector = NARROW[clientData];
buttons: LIST OF Buttons.Button ← selector.buttons;
FOR a: LIST OF ATOM ← selector.values, a.rest UNTIL a = NIL DO
IF self = buttons.first THEN {
selector.value^ ← a.first;
IF selector.change # NIL THEN selector.change[self.parent, selector.clientData, a.first];
Buttons.SetDisplayStyle[buttons.first, $WhiteOnBlack]; }
ELSE Buttons.SetDisplayStyle[buttons.first, $BlackOnWhite];
buttons ← buttons.rest;
ENDLOOP; };
BoolProc: TYPE = PROC [parent: Viewer, clientData: REF, value: BOOL];
Bool: TYPE = REF BoolRec;
BoolRec: TYPE = RECORD [
value: REF BOOL,
change: BoolProc,
clientData: REF,
button: Viewer ];
MakeBool: PROC
[name: ROPE, init: REF BOOL, change: BoolProc ← NIL, clientData: REFNIL, parent: Viewer, x, y: INTEGER]
RETURNS [child: Viewer] = {
bool: Bool ← NEW [BoolRec ← [
value: IF init # NIL THEN init ELSE NEW [BOOLTRUE],
change: change,
clientData: clientData,
button: NIL ] ];
child ← Buttons.Create[
info: [name: name, parent: parent, border: TRUE, wx: x, wy: y],
proc: BoolHelper, clientData: bool, fork: TRUE, paint: TRUE];
bool.button ← child;
IF bool.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; };
BoolHelper: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
self: Buttons.Button = NARROW[parent];
bool: Bool = NARROW[clientData];
bool.value^ ← ~bool.value^;
IF bool.value^ THEN Buttons.SetDisplayStyle[bool.button, $WhiteOnBlack]
ELSE Buttons.SetDisplayStyle[bool.button, $BlackOnWhite];
IF bool.change # NIL THEN bool.change[self.parent, bool.clientData, bool.value^]; };
MakeLabel: PROC [parent, sibling: Viewer, name: ROPE] RETURNS [child: Viewer] = {
child ← Labels.Create[
info: [name: name, parent: parent, border: FALSE,
wy: sibling.wy + sibling.wh + (IF sibling.class.flavor = $Button THEN -1 ELSE 2),
wx: 2],
paint: FALSE ]; };
MakeLabeledText: PROC [
parent, sibling: Viewer, name, data: ROPE, prev: Viewer, newline: BOOLTRUE] RETURNS [child: Viewer] = {
x: INTEGER = IF newline THEN 2 ELSE sibling.wx + sibling.ww + 10;
y: INTEGER = IF newline THEN sibling.wy + sibling.wh + 1 ELSE sibling.wy;
child ← ViewerTools.MakeNewTextViewer[
info: [parent: parent, wh: buttonHeight, ww: 999, scrollable: TRUE,
data: IF prev = NIL THEN data ELSE ViewerTools.GetContents[prev],
border: FALSE,
wx: x + buttonWidth + 2, wy: y],
paint: FALSE ];
Containers.ChildXBound[parent, child];
[] ← Buttons.Create[
info: [name: name, parent: parent, wh: buttonHeight, border: FALSE, wx: x, wy: y],
proc: LabeledTextProc, clientData: child, fork: FALSE, paint: FALSE];
RETURN[child]; };
LabeledTextProc: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
text: Viewer = NARROW[clientData];
SELECT mouseButton FROM
red => ViewerTools.SetSelection[text, NIL];
yellow => NULL;
blue => { ViewerTools.SetContents[text, NIL]; ViewerTools.SetSelection[text, NIL] };
ENDCASE => ERROR; };
Commander.Register["RPCEchoTool", Create, "Simple RPC Tests."];
Commander.Register["RPCEchoToolImpl", Create, "Simple RPC Tests."]; -- Debugging hack
}.