ThymeViewers.mesa
Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Last Edited by: Jacobi June 10, 1986 6:55:47 pm PDT
Last Edited by: Neil Gunther June 24, 1986 6:57:58 pm PDT
Barth, July 8, 1988 10:48:53 am PDT
Christian Le Cocq April 29, 1987 10:26:50 am PDT
Pradeep Sindhu April 29, 1986 0:45:42 am PDT
Sweetsun Chen, April 26, 1986 7:30:58 pm PST
Christian Jacobi, June 10, 1986 6:54:59 pm PDT
DIRECTORY
Buttons USING [Button, ButtonProc, Create, SetDisplayStyle],
Commander USING [CommandProc, Register],
CommandTool USING [ParseToList],
Containers USING [Create],
Convert USING [CardFromRope, Error],
FileNames USING [CurrentWorkingDirectory],
FS USING [EnumerateForNames, NameProc],
Icons USING [IconFlavor, NewIconFromFile],
IO USING [Close, Flush, int, PutF, PutFR, rope],
Labels USING [Create, Label],
List USING [DReverse],
Menus USING [AppendMenuEntry, ChangeNumberOfLines, CreateMenu, CreateEntry, Menu, MenuProc],
Rope USING [Equal, Fetch, Find, Length, ROPE, Substr],
ThymeGlobals USING[BatchRun, ConRec, DumpIt, EchoInput, EnsureExtension, FuncTable, Handle, ModelTable, NodeRec, NormalRun, RefConRec, RefNodeRec, RefR, RefUnReal, ResistorBody, ShowDetails, SaveAll, Stages, StopIt, ThymeToolRec, ToggleEchoInput, ToggleSaveAll, ToggleShowDetails, UnReal],
TerminalIO USING [TOS],
VFonts USING[CharWidth, StringWidth],
ViewerClasses USING [Viewer, ViewerClass, ViewerClassRec],
ViewerEvents USING [EventProc, RegisterEventProc],
ViewerOps USING [AddProp, EnumerateViewers, EnumProc, FetchProp, PaintViewer, SetViewer, SetOpenHeight],
ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection];
ThymeViewers: CEDAR MONITOR
IMPORTS
Buttons,
Commander,
CommandTool,
Containers,
Convert,
FileNames,
FS,
Icons,
IO,
Labels,
List,
Menus,
Rope,
TerminalIO,
ThymeGlobals,
ViewerEvents,
ViewerOps,
VFonts,
ViewerTools
EXPORTS
ThymeGlobals
= {
public global variables
version: PUBLIC Rope.ROPE← "NewThyme - Cedar6.1 - January 1987";
refNodeRec: PUBLIC ThymeGlobals.RefNodeRec= NEW[ThymeGlobals.NodeRec];
refConRec: PUBLIC ThymeGlobals.RefConRec= NEW[ThymeGlobals.ConRec];
refR: PUBLIC ThymeGlobals.RefR= NEW[ThymeGlobals.ResistorBody];
refUnReal: PUBLIC ThymeGlobals.RefUnReal= NEW[ThymeGlobals.UnReal];
modelTable: PUBLIC ThymeGlobals.ModelTable← NIL;
functionTable: PUBLIC ThymeGlobals.FuncTable← NIL;
MakeThymeViewers: PUBLIC PROC[wDir: Rope.ROPENIL] RETURNS [handle: ThymeGlobals.Handle ← NIL] = {
thymeMenus: Menus.Menu;
handle ← NEW[ThymeGlobals.ThymeToolRec ← []];
thymeMenus ← MakeThymeMenus[handle];
handle.outer ← Containers.Create[
info: [
name: version,
iconic: TRUE,
icon: Icons.NewIconFromFile["Thyme.icons", 0],
menu: thymeMenus,
column: left,
scrollable: FALSE],
paint: FALSE];
IF ViewerOps.FetchProp[handle.outer, $ThymeHandle] = NIL THEN ViewerOps.AddProp[handle.outer, $ThymeHandle, handle];
IF ThymeNormalPaint = NIL THEN ThymeNormalPaint ← handle.outer.class.paint;
handle.outer.class.paint ← ThymeViewerPaint;
Menus.ChangeNumberOfLines[thymeMenus, 1];
MakeMainViewer[
handle: handle,
workingDir: IF wDir = NIL THEN FileNames.CurrentWorkingDirectory[] ELSE wDir];
handle.msgStream ← TerminalIO.TOS[];
ViewerOps.SetOpenHeight[handle.outer, handle.height];
ViewerOps.PaintViewer[handle.outer, all];
}; -- MakeThymeViewers
menus
MakeThymeMenus: PROC[handle: ThymeGlobals.Handle] RETURNS[menu: Menus.Menu] = {
requestConfirmMsg: Rope.ROPE = "Please confirm by clicking at it again.";
menu ← Menus.CreateMenu[];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[
name: "Stop",
proc: Stop,
clientData: handle,
guarded: TRUE,
documentation: requestConfirmMsg]
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[
name: "Dump",
proc: Dump,
clientData: handle,
guarded: TRUE,
documentation: requestConfirmMsg]
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[name: "Run", proc: Run, clientData: handle]
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[name: "New", proc: New, clientData: handle]
];
}; -- MakeThymeMenus
Stop: ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: ThymeGlobals.Handle ← NARROW[clientData];
ThymeGlobals.StopIt[handle];
}; -- Stop
Run: ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: ThymeGlobals.Handle ← NARROW[clientData];
ThymeGlobals.NormalRun[handle];
}; -- Run
Dump: ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: ThymeGlobals.Handle ← NARROW[clientData];
ThymeGlobals.DumpIt[handle];
}; -- Dump
New: Menus.MenuProc = {
handle: ThymeGlobals.Handle ← NARROW[clientData];
[] ← MakeThymeViewers[ViewerTools.GetContents[handle.wDir]];
};
MakeMainViewer: PROC [handle: ThymeGlobals.Handle, workingDir: Rope.ROPENIL] = {
entryHeight: CARDINAL = 12;
entryVSpace: CARDINAL = 6;
entryHSpace: CARDINAL = 10;
initialOutputName: Rope.ROPE = "<Output file name(s) will be set automatically.>";
outLabel, timeLabel, stepLabel: Labels.Label;
wDirButton, inputButton: Buttons.Button;
initialInputName: Rope.ROPE = "<Specify input file name here.>";
handle.height ← handle.height + entryVSpace;
working directory
wDirButton ← Buttons.Create[
info: [
name: "Working Directory:",
parent: handle.outer,
wy: handle.height + 2,
wh: entryHeight, -- default the width so that it will be computed for us
border: FALSE ],
clientData: handle,
proc: DirPrompt,
paint: FALSE];
handle.wDir ← ViewerTools.MakeNewTextViewer[
info: [
parent: handle.outer,
wx: wDirButton.wx + wDirButton.ww + entryHSpace,
wy: handle.height,
ww: 80*VFonts.CharWidth['M],
wh: entryHeight + 2,
data: workingDir,
border: FALSE],
paint: FALSE];
handle.height ← handle.height + entryHeight + entryVSpace;
input file
inputButton ← Buttons.Create[
info: [
name: "Input File:",
parent: handle.outer,
wy: handle.height + 2,
wh: entryHeight,
border: FALSE ],
clientData: handle,
proc: InputPrompt,
paint: FALSE];
handle.input ← ViewerTools.MakeNewTextViewer[
info: [
parent: handle.outer,
wx: inputButton.wx + inputButton.ww + entryHSpace,
wy: handle.height,
ww: 80*VFonts.CharWidth['M],
wh: entryHeight + 2,
data: initialInputName,
scrollable: FALSE,
border: FALSE],
paint: FALSE];
handle.height ← handle.height + entryHeight + entryVSpace;
output file
outLabel ← Labels.Create[
info: [
name: "Output File:",
parent: handle.outer,
wy: handle.height,
border: FALSE ],
paint: FALSE];
handle.output ← Labels.Create[
info: [
name: initialOutputName,
parent: handle.outer,
wx: VFonts.StringWidth["Output File:"] + entryHSpace,
wy: handle.height + 2,
ww: 80*VFonts.CharWidth['W],
wh: entryHeight,
border: FALSE],
paint: FALSE];
handle.height ← handle.height + entryHeight + entryVSpace;
progress cursor
progressLabel ← Labels.Create[
info: [name: "Progress:", parent: handle.outer, wy: handle.height, border: FALSE ],
paint: FALSE];
handle.progress ← ViewerOps.CreateViewer[
flavor: $ThymeCursor,
info: [
parent: handle.outer,
wx: progressLabel.wx + progressLabel.ww + entryHSpace,
wy: handle.height,
ww: 16,
wh: 16,
data: idleBitmap,
data: NIL,
border: FALSE],
paint: FALSE];
handle.showDetailsButton ← Buttons.Create[
info: [
name: "details:",
parent: handle.outer,
wx: handle.progress.wx + handle.progress.ww + entryHSpace + entryHSpace,
wx: entryHSpace + entryHSpace,
wy: handle.height,
wh: entryHeight + 3,
border: TRUE ],
clientData: handle,
proc: ShowDetailsProc,
paint: FALSE];
Buttons.SetDisplayStyle[handle.showDetailsButton,
IF ThymeGlobals.ShowDetails[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
timeLabel ← Labels.Create[
info: [
name: "time:",
parent: handle.outer,
wx: handle.showDetailsButton.wx + handle.showDetailsButton.ww + entryHSpace,
wy: handle.height + 2,
wh: entryHeight,
border: FALSE ],
paint: FALSE];
handle.time ← Labels.Create[
info: [
parent: handle.outer,
wx: timeLabel.wx + timeLabel.ww + entryHSpace,
wy: handle.height + 2,
ww: 8*VFonts.StringWidth["M"],
wh: entryHeight,
border: FALSE],
paint: FALSE];
stepLabel ← Labels.Create[
info: [
name: "step:",
parent: handle.outer,
wx: handle.time.wx + handle.time.ww + entryHSpace,
wy: handle.height + 2,
wh: entryHeight,
border: FALSE ],
paint: FALSE];
handle.step ← Labels.Create[
info: [
parent: handle.outer,
wx: stepLabel.wx + stepLabel.ww + entryHSpace,
wy: handle.height + 2,
ww: 8*VFonts.StringWidth["M"],
wh: entryHeight,
border: FALSE],
paint: FALSE];
echo input switch
handle.echoInputButton ← Buttons.Create[
info: [
name: "Echo input",
parent: handle.outer,
wx: handle.step.wx + handle.step.ww + entryHSpace,
wy: handle.height,
wh: entryHeight + 3,
border: TRUE ],
clientData: handle,
proc: EchoInputProc,
paint: FALSE];
Buttons.SetDisplayStyle[handle.echoInputButton,
IF ThymeGlobals.EchoInput[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
saveAll switch
handle.saveAllButton ← Buttons.Create[
info: [
name: "Save All",
parent: handle.outer,
wx: handle.echoInputButton.wx + handle.echoInputButton.ww + entryHSpace,
wy: handle.height,
wh: entryHeight + 3,
border: TRUE ],
clientData: handle,
proc: SaveAllProc,
paint: FALSE];
Buttons.SetDisplayStyle[handle.saveAllButton,
IF ThymeGlobals.SaveAll[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
handle.height ← handle.height + entryHeight + entryVSpace;
}; -- MakeMainViewer
DirPrompt: Buttons.ButtonProc = {
handle: ThymeGlobals.Handle ← NARROW[clientData];
IF handle # NIL THEN ViewerTools.SetSelection[handle.wDir];
}; -- InputPrompt
InputPrompt: Buttons.ButtonProc = {
handle: ThymeGlobals.Handle ← NARROW[clientData];
IF handle # NIL THEN ViewerTools.SetSelection[handle.input];
}; -- InputPrompt
ShowDetailsProc: Buttons.ButtonProc = {
force the selection into the user input field
handle: ThymeGlobals.Handle ← NARROW[clientData];
IF handle # NIL THEN {
ThymeGlobals.ToggleShowDetails[handle];
Buttons.SetDisplayStyle[handle.showDetailsButton,
IF ThymeGlobals.ShowDetails[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
IF NOT ThymeGlobals.ShowDetails[handle] THEN {
ViewerTools.SetContents[handle.time, NIL];
ViewerTools.SetContents[handle.step, NIL];
};
};
}; -- InputPrompt
EchoInputProc: Buttons.ButtonProc = {
echo input when parsing
handle: ThymeGlobals.Handle ← NARROW[clientData];
IF handle # NIL THEN {
ThymeGlobals.ToggleEchoInput[handle];
Buttons.SetDisplayStyle[handle.echoInputButton,
IF ThymeGlobals.EchoInput[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
};
}; -- EchoInputProc
SaveAllProc: Buttons.ButtonProc = {
echo input when parsing
handle: ThymeGlobals.Handle ← NARROW[clientData];
IF handle # NIL THEN {
ThymeGlobals.ToggleSaveAll[handle];
Buttons.SetDisplayStyle[handle.saveAllButton,
IF ThymeGlobals.SaveAll[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
};
}; -- SaveAllProc
message viewer
destroy proc
ThymeDestroy: ViewerEvents.EventProc = {
IF (event = destroy) AND before THEN {
h: ThymeGlobals.Handle ← NARROW[ViewerOps.FetchProp[viewer, $ThymeHandle]];
IF h # NIL THEN {OPEN h;
outer ← NIL;
wDir ← input ← NIL;
output ← time ← step ← NIL;
IF msgStream#NIL THEN {
msgStream.Flush[];
msgStream.Close[];
msgStream ← NIL;
};
showDetailsButton ← echoInputButton ← saveAllButton ← NIL;
};
};
}; -- ThymeDestroy
painting
ThymeViewerPaint: ViewerClasses.PaintProc = {
IF ~self.iconic THEN [] ← ThymeNormalPaint[self, context, whatChanged, clear];
}; -- ThymeViewerPaint
ThymeNormalPaint: ViewerClasses.PaintProc ← NIL; -- will be assigned Containers PaintProc
SetWorkingDirectory: PUBLIC PROC [wDir: Rope.ROPE, handle: ThymeGlobals.Handle] = {
ViewerOps.SetViewer[handle.wDir, wDir];
};
RopeList: TYPE = LIST OF Rope.ROPE;
MakeThyme: Commander.CommandProc = {
argList: RopeList;
length: NAT;
msg ← NIL;
[argList, length] ← CommandTool.ParseToList[cmd];
IF length <= 0 THEN [] ← MakeThymeViewers[]
ELSE {
wDir: Rope.ROPE ← FileNames.CurrentWorkingDirectory[];
nCircuits: NAT ← 0;
maxCircuits: NAT ← 12;
allVersions: BOOLFALSE;
FOR arg: RopeList ← argList, arg.rest UNTIL arg = NIL OR msg # NIL DO
IF arg.first.Fetch[0] = '- THEN {
IF arg.first.Length[] >= 2 THEN SELECT arg.first.Fetch[1] FROM
'A, 'a => allVersions ← TRUE;
'H, 'h => allVersions ← FALSE;
IN ['0..'9] => {
max: NAT ← Convert.CardFromRope[arg.first.Substr[1]
! Convert.Error => max ← maxCircuits]; -- don't change it
maxCircuits ← max;
};
ENDCASE; -- simply ignors illegal switches
}
ELSE {
fileList: RopeList ← FileListFromPattern[
ThymeGlobals.EnsureExtension[arg.first, "thy"], wDir, allVersions];
IF fileList = NIL THEN msg ← "No such file."
ELSE FOR file: RopeList ← fileList, file.rest UNTIL file = NIL OR msg # NIL DO
IF nCircuits >= maxCircuits THEN msg ← IO.PutFR[
"Note: max. %g circuits for each command. You may change it by a switch.",
IO.int[maxCircuits]]
ELSE {
handle: ThymeGlobals.Handle;
create: BOOLTRUE;
EnumThymeViewers: ViewerOps.EnumProc = {
handle ← NARROW[ViewerOps.FetchProp[v, $ThymeHandle]];
IF handle = NIL THEN RETURN;
IF NOT handle.outer.inhibitDestroy THEN {
cmd.out.PutF[" Forking simulation of %g ....\n", IO.rope[file.first]];
create ← FALSE;
ThymeGlobals.BatchRun[handle, wDir, file.first];
RETURN[FALSE];
};
}; -- EnumThymeViewers
ViewerOps.EnumerateViewers[EnumThymeViewers];
IF create THEN {
handle ← MakeThymeViewers[wDir];
ThymeGlobals.BatchRun[handle, wDir, file.first];
cmd.out.PutF[" Forking simulation of %g ....\n", IO.rope[file.first]];
};
};
nCircuits ← nCircuits + 1;
ENDLOOP;
};
ENDLOOP;
};
}; -- GraphFiles
FileListFromPattern: PROC [pattern, wDir: Rope.ROPENIL, allVersions: BOOLFALSE] RETURNS [fileList: RopeList ← NIL] = {
root, lastRoot: Rope.ROPENIL;
LinkIt: FS.NameProc -- PROC [fullFName] RETURNS [continue: BOOL] -- = {
excl: INT ← fullFName.Find["!"];
continue ← TRUE;
IF ~allVersions THEN {
root ← fullFName.Substr[0, excl];
IF root.Equal[lastRoot, FALSE] THEN {
fileList.first ← fullFName;
RETURN;
};
lastRoot ← root;
};
fileList ← CONS[fullFName, fileList];
}; -- LinkIt
FS.EnumerateForNames[pattern, LinkIt, wDir];
TRUSTED {fileList ← LOOPHOLE[List.DReverse[LOOPHOLE[fileList]]]};
}; -- FileListFrom
Commander.Register[
key: "Thyme",
proc: MakeThyme,
doc: "Syntax: Thyme [switch(es)] <file name(s)>
Start instance(s) of the circuit simulator Thyme.
switches:
-a all versions, -h highest version only, -# start at most # instances." ];
[] ← ViewerEvents.RegisterEventProc[proc: ThymeDestroy, event: destroy, before: TRUE];
}.
CHANGE LOG
Chen, June 12, 1984 11:21:28 am PDT, created.
Chen, May 14, 1985 8:05:48 pm PDT, implemented custom icon that shows status.
Chen, July 19, 1985 2:59:06 pm PDT, => Cedar6.0. (Cedar Graphics -> Imager, etc.)
Christian Jacobi, June 10, 1986 6:55:20 pm PDT, Messages blink only afterwards