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
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 [ChildXBound, ChildYBound, Create],
Convert USING [CardFromRope, Error],
FileNames USING [CurrentWorkingDirectory],
FS USING [Close, EnumerateForNames, GetInfo, NameProc, Open, OpenFile, Read],
Icons USING [IconFlavor, IconFileFormat],
Imager USING [Context, DoSave, MaskBox, SetColor, SetXY],
ImagerBackdoor USING [DrawBits, invert],
IO USING [Close, Flush, int, PutF, PutFR, rope, time],
Labels USING [Create, Label],
List USING [DReverse],
Menus
USING [AppendMenuEntry, ChangeNumberOfLines, CreateMenu, CreateEntry,
GetLine, SetLine, MenuEntry
GetNumberOfLines, Menu, MenuLine, MenuProc],
MessageWindow USING [Append, Blink],
Rope USING [Equal, Fetch, Find, Length, ROPE, Substr],
Rules USING [Create, Rule],
spGlobals USING[BatchRun, ConRec, DumpIt, EchoInput, EnsureExtension, FuncTable, Handle, Level2Model, ModelTable, NodeRec, NormalRun, RefConRec, RefNodeRec, RefR, RefUnReal, ResistorBody, ShowDetails, spFunctions, spModels, SaveAll, Stages, StopIt, ThymeToolRec, ToggleEchoInput, ToggleSaveAll, ToggleShowDetails, UnReal],
TerminalDefs USING [Cursor],
TiogaOps USING [FindDef, FindText, FindWord, SearchDir],
TypeScript USING [Create, TS],
VFonts USING[CharWidth, StringWidth],
ViewerBLT USING[ChangeNumberOfLines],
ViewerClasses USING [PaintProc, Viewer, ViewerClass, ViewerClassRec],
ViewerEvents USING [EventProc, RegisterEventProc],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [AddProp, CreateViewer, EnumerateViewers, EnumProc, FetchProp, PaintViewer, RegisterViewerClass, RestoreViewer, SaveViewer, SetViewer, --SetMenu, --SetOpenHeight],
ViewerPrivate USING [selectedIcon],
ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection],
VM USING [AddressForPageNumber, Allocate, Free, Interval];
ThymeViewers:
CEDAR
MONITOR
IMPORTS Buttons, Commander, CommandTool, Containers, Convert, FileNames, FS, Imager, ImagerBackdoor, IO, Labels, List, Menus, MessageWindow, Rope, Rules, spGlobals, TiogaOps, TypeScript, ViewerEvents, ViewerIO, ViewerOps, VFonts, ViewerBLT, ViewerPrivate, ViewerTools, VM
EXPORTS spGlobals = {
version: PUBLIC Rope.ROPE← "Thyme - Cedar6.1 - June 1986";
refNodeRec: PUBLIC spGlobals.RefNodeRec= NEW[spGlobals.NodeRec];
refConRec: PUBLIC spGlobals.RefConRec= NEW[spGlobals.ConRec];
refR: PUBLIC spGlobals.RefR= NEW[spGlobals.ResistorBody];
refUnReal: PUBLIC spGlobals.RefUnReal= NEW[spGlobals.UnReal];
modelTable: PUBLIC spGlobals.ModelTable← NIL;
functionTable: PUBLIC spGlobals.FuncTable← NIL;
local constants
msgViewerH: CARDINAL = 100;
MakeThymeViewers:
PUBLIC
PROC[wDir: Rope.
ROPE ←
NIL]
RETURNS [handle: spGlobals.Handle ← NIL] = {
thymeMenus: Menus.Menu;
handle ← NEW[spGlobals.ThymeToolRec ← []];
thymeMenus ← MakeThymeMenus[handle];
TRUSTED{
handle.outer ← Containers.Create[
info: [
name: version,
iconic: TRUE,
icon: private,
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];
MakeMsgViewer[handle];
ViewerOps.SetOpenHeight[handle.outer, handle.height + msgViewerH];
ViewerOps.PaintViewer[handle.outer, all];
}; -- MakeThymeViewers
menus
MakeThymeMenus:
PROC[handle: spGlobals.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]
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[name: "TypeScriptMenus", proc: TypeScriptMenus,
clientData: handle]
];
typescript menus
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[
name: "Save",
proc: Save,
clientData: handle,
guarded: TRUE,
documentation: requestConfirmMsg],
line: 1
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[
name: "Reset",
proc: Reset,
clientData: handle,
guarded: TRUE,
documentation: requestConfirmMsg],
line: 1
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[name: "Find", proc: Find, clientData: handle],
line: 1
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[name: "Word", proc: Word, clientData: handle],
line: 1
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[name: "Def", proc: Def, clientData: handle],
line: 1
];
Menus.AppendMenuEntry[
menu: menu,
entry: Menus.CreateEntry[name: "FindError", proc: FindError, clientData: handle],
line: 1
];
}; -- MakeThymeMenus
Stop:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
spGlobals.StopIt[handle];
}; -- Stop
Run:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
spGlobals.NormalRun[handle];
}; -- Run
Dump:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
spGlobals.DumpIt[handle];
}; -- Dump
New: Menus.MenuProc = {
handle: spGlobals.Handle ← NARROW[clientData];
[]← MakeThymeViewers[ViewerTools.GetContents[handle.wDir]];
};
TypeScriptMenus:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
viewer: ViewerClasses.Viewer ← NARROW[parent];
menu: Menus.Menu ← viewer.menu;
numLines: Menus.MenuLine ← Menus.GetNumberOfLines[menu];
SELECT numLines
FROM
1 => {
Menus.SetLine[menu, 1, tsMenuEntry];
numLines ← numLines + 1;
};
2 => numLines ← numLines - 1;
ENDCASE => ERROR;
ViewerBLT.ChangeNumberOfLines[viewer, numLines];
}; -- TypeScriptMenus
Save:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
IF handle.simulation # NIL THEN MessageWindow.Append["Thyme.log could NOT be saved when a circuit is being simulated.", TRUE]
ELSE
IF handle.msgStream #
NIL
THEN {
handle.msgStream.PutF["\nSaved: %g\n", IO.time[]];
handle.msgStream.Flush[];
ViewerOps.SaveViewer[handle.message];
};
};
}; -- Save
Reset:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
IF handle.simulation # NIL THEN MessageWindow.Append["Thyme.log could NOT be reset when a circuit is being simulated.", TRUE]
ELSE
IF handle.msgStream #
NIL
THEN {
ViewerOps.RestoreViewer[handle.message];
handle.msgStream.PutF["File: Thyme.log\nCreated: %g\n", IO.time[]];
};
};
}; -- Reset
Find:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
IF handle.msgStream #
NIL
AND handle.message #
NIL
THEN {
dir: TiogaOps.SearchDir =
SELECT mouseButton
FROM
red => forwards, yellow => anywhere, ENDCASE => backwards;
case: BOOL = NOT shift;
found:
BOOL ← TiogaOps.FindText[
viewer: handle.message,
rope: NIL, -- automatically uses contents of primary selection
whichDir: dir,
which: primary,
case: case];
IF NOT found THEN BlinkMsg["Text not found."];
};
};
}; -- Find
Word:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
IF handle.msgStream #
NIL
AND handle.message #
NIL
THEN {
dir: TiogaOps.SearchDir =
SELECT mouseButton
FROM
red => forwards, yellow => anywhere, ENDCASE => backwards;
case: BOOL = NOT shift;
found:
BOOL ← TiogaOps.FindWord[
viewer: handle.message,
rope: NIL, -- automatically uses contents of primary selection
whichDir: dir,
which: primary,
case: case];
IF NOT found THEN BlinkMsg["Text not found."];
};
};
}; -- Word
Def:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
IF handle.msgStream #
NIL
AND handle.message #
NIL
THEN {
dir: TiogaOps.SearchDir =
SELECT mouseButton
FROM
red => forwards, yellow => anywhere, ENDCASE => backwards;
case: BOOL = NOT shift;
found:
BOOL ← TiogaOps.FindDef[
viewer: handle.message,
rope: NIL, -- automatically uses contents of primary selection
whichDir: dir,
which: primary,
case: case];
IF NOT found THEN BlinkMsg["Text not found."];
};
};
}; -- Def
FindError:
ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
IF handle.msgStream #
NIL
AND handle.message #
NIL
THEN {
dir: TiogaOps.SearchDir =
SELECT mouseButton
FROM
red => forwards, yellow => anywhere, ENDCASE => backwards;
case: BOOL = NOT shift;
found:
BOOL ← TiogaOps.FindText[
viewer: handle.message,
rope: "g Error ",
whichDir: dir,
which: primary,
case: case];
IF NOT found THEN BlinkMsg["Text not found."];
};
};
}; -- FindError
BlinkMsg:
PROC[msg: Rope.
ROPE] = {
MessageWindow.Append[msg, TRUE];
MessageWindow.Blink[];
}; -- BlinkMsg
MakeMainViewer:
PROC [handle: spGlobals.Handle, workingDir: Rope.
ROPE ←
NIL] = {
entryHeight: CARDINAL = 12;
entryVSpace: CARDINAL = 6;
entryHSpace: CARDINAL = 10;
initialOutputName: Rope.ROPE = "<Output file name(s) will be set automatically.>";
outLabel, progressLabel, timeLabel, stepLabel: Labels.Label;
wDirButton, inputButton: Buttons.Button;
openInput: 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,
scrollable: FALSE,
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,
border: FALSE],
paint: FALSE];
handle.showDetailsButton ← Buttons.Create[
info: [
name: "details:",
parent: handle.outer,
wx: handle.progress.wx + handle.progress.ww + entryHSpace + entryHSpace,
wy: handle.height,
wh: entryHeight + 3,
border: TRUE ],
clientData: handle,
proc: ShowDetailsProc,
paint: FALSE];
Buttons.SetDisplayStyle[handle.showDetailsButton,
IF spGlobals.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 spGlobals.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 spGlobals.SaveAll[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
handle.height ← handle.height + entryHeight + entryVSpace;
}; -- MakeMainViewer
DirPrompt: Buttons.ButtonProc = {
handle: spGlobals.Handle ← NARROW[clientData];
IF handle # NIL THEN ViewerTools.SetSelection[handle.wDir];
}; -- InputPrompt
InputPrompt: Buttons.ButtonProc = {
handle: spGlobals.Handle ← NARROW[clientData];
IF handle # NIL THEN ViewerTools.SetSelection[handle.input];
}; -- InputPrompt
ShowDetailsProc: Buttons.ButtonProc = {
force the selection into the user input field
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
spGlobals.ToggleShowDetails[handle];
Buttons.SetDisplayStyle[handle.showDetailsButton,
IF spGlobals.ShowDetails[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
IF
NOT spGlobals.ShowDetails[handle]
THEN {
ViewerTools.SetContents[handle.time, NIL];
ViewerTools.SetContents[handle.step, NIL];
};
};
}; -- InputPrompt
EchoInputProc: Buttons.ButtonProc = {
echo input when parsing
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
spGlobals.ToggleEchoInput[handle];
Buttons.SetDisplayStyle[handle.echoInputButton,
IF spGlobals.EchoInput[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
};
}; -- EchoInputProc
SaveAllProc: Buttons.ButtonProc = {
echo input when parsing
handle: spGlobals.Handle ← NARROW[clientData];
IF handle #
NIL
THEN {
spGlobals.ToggleSaveAll[handle];
Buttons.SetDisplayStyle[handle.saveAllButton,
IF spGlobals.SaveAll[handle] THEN $WhiteOnBlack ELSE $BlackOnWhite];
};
}; -- SaveAllProc
MakeMsgViewer:
PROC [handle: spGlobals.Handle] = {
divider
rule: Rules.Rule ← Rules.Create[
info: [
parent: handle.outer,
wy: handle.height,
ww: handle.outer.cw,
wh: 1],
paint: FALSE];
Containers.ChildXBound[handle.outer, rule];
handle.height← handle.height + 2;
the typescript
handle.message← TypeScript.Create[
info: [
parent: handle.outer,
wy: handle.height,
ww: handle.outer.cw,
wh: 800,
border: FALSE,
file: "Thyme.log"],
paint: FALSE
];
IF ViewerOps.FetchProp[handle.message, $ThymeHandle] = NIL
THEN ViewerOps.AddProp[handle.message, $ThymeHandle, handle];
[in: , out: handle.msgStream] ← ViewerIO.CreateViewerStreams[
name: "Thyme.log", viewer: handle.message, backingFile: "Thyme.log"];
IO.PutF[handle.msgStream, "File: Thyme.log\nCreated: %g\n", IO.time[]];
Containers.ChildXBound[handle.outer, handle.message];
Containers.ChildYBound[handle.outer, handle.message];
}; -- MakeMsgViewer
destroy proc
ThymeDestroy: ViewerEvents.EventProc = {
IF (event = destroy)
AND before
THEN {
h: spGlobals.Handle ← NARROW[ViewerOps.FetchProp[viewer, $ThymeHandle]];
IF h #
NIL
THEN {
OPEN h;
outer ← NIL;
wDir ← input ← NIL;
progress ← NIL; -- NOT nil'd for fear that ThymeIconPaint may be called after this.
output ← time ← step ← NIL;
message ← NIL;
msgStream.Flush[]; msgStream.Close[];
msgStream ← NIL;
showDetailsButton ← echoInputButton ← saveAllButton ← NIL;
checkProcess, simulation and vars should have been nil'd.
};
};
}; -- ThymeDestroy
painting
iconW: INTEGER = 64;
iconH: INTEGER = 64;
StatusBitmap: TYPE = REF StatusPattern;
StatusPattern: TYPE = TerminalDefs.Cursor; -- ARRAY [0..16) OF WORD
thymeIconBitmap: REF IconPattern;
IconPattern: TYPE = ARRAY [0..iconH*iconW/16) OF WORD;
idleBitmap, inputBitmap, bombBitmap, topoBitmap: StatusBitmap;
runBitmap: ARRAY [0..4) OF StatusBitmap;
ThymeViewerPaint: ViewerClasses.PaintProc = {
IF self.iconic THEN [] ← ThymeIconPaint[self, context, whatChanged, clear]
ELSE [] ← ThymeNormalPaint[self, context, whatChanged, clear];
}; -- ThymeViewerPaint
ThymeNormalPaint: ViewerClasses.PaintProc ← NIL; -- will be assigned Containers PaintProc
ThymeIconPaint: ViewerClasses.PaintProc = {
handle: spGlobals.Handle;
bitmap: StatusBitmap;
drawFace:
PROC = {
context.SetXY[[0, iconH]];
ImagerBackdoor.DrawBits[context: context, base:
LOOPHOLE[thymeIconBitmap],
wordsPerLine: iconW/16, sMin: 0, fMin: 0, sSize: iconH, fSize: iconW, tx: 0, ty: iconH];
};
drawStatus:
PROC = {
context.SetXY[[25, 39]];
ImagerBackdoor.DrawBits[context: context, base:
LOOPHOLE[bitmap],
wordsPerLine: 1, sMin: 0, fMin: 0, sSize: 15, fSize: 15, tx: 25, ty: 39];
};
invertProc:
PROC = {
context.SetColor[ImagerBackdoor.invert];
context.MaskBox[[0, 0, iconW, iconH]];
};
handle ← NARROW[ViewerOps.FetchProp[self, $ThymeHandle]];
bitmap ← NARROW[handle.progress.data];
IF whatChanged # $ThymeStatus THEN context.DoSave[drawFace];
context.DoSave[drawStatus];
IF ViewerPrivate.selectedIcon = self THEN context.DoSave[invertProc];
}; -- ThymeIconPaint
MakeBitmaps:
PROC[file: Rope.
ROPE ← "Thyme.icons"]=
TRUSTED {
iconRaster: INTEGER = 4;
fh: FS.OpenFile ← FS.Open[file];
pages: INT ← FS.GetInfo[fh].pages;
space: VM.Interval ← VM.Allocate[count: pages];
iconBase:
LONG
POINTER
TO Icons.IconFileFormat
←
VM.AddressForPageNumber[space.page];
cursorsBase:
LONG
POINTER
TO Icons.IconFileFormat
←
iconBase + SIZE[Icons.IconFileFormat];
MakeCursorBitmap:
PROC[offset:
INTEGER]
RETURNS [bitmap: StatusBitmap] =
TRUSTED{
bitmap ← NEW[StatusPattern];
FOR i:
INTEGER
IN [0..16)
DO
bitmap[i] ← cursorsBase.bits[offset + i * iconRaster];
ENDLOOP;
}; -- MakeBitmap
FS.Read[file: fh, from: 0, nPages: pages, to: iconBase];
thymeIconBitmap ← NEW[IconPattern ← iconBase.bits];
idleBitmap ← MakeCursorBitmap[0];
inputBitmap ← MakeCursorBitmap[1];
bombBitmap ← MakeCursorBitmap[2];
topoBitmap ← MakeCursorBitmap[3];
FOR ir:
CARDINAL
IN [0..4)
DO
runBitmap[ir] ← MakeCursorBitmap[16 * iconRaster + ir];
ENDLOOP;
VM.Free[space];
FS.Close[fh];
}; -- MakeBitmaps
SetCursor:
PUBLIC
PROC [handle: spGlobals.Handle] = {
ENABLE UNWIND => NULL;
d: REF ANY;
IF handle = NIL THEN RETURN;
IF handle.progress = NIL THEN RETURN;
SELECT handle.stage
FROM
idle => d ← idleBitmap;
input => d ← inputBitmap;
bomb => d ← bombBitmap;
topo => d ← topoBitmap;
run => d ←
IF handle.vars = NIL THEN runBitmap[0]
ELSE runBitmap[handle.vars.runState];
ENDCASE =>
BlinkMsg["* Weird situation at SetCursor detected. Please inform Thyme implementor."];
handle.progress.data ← d;
IF handle.outer.iconic
THEN
ViewerOps.PaintViewer[handle.outer, client, FALSE, $ThymeStatus]
ELSE ViewerOps.PaintViewer[handle.progress, client, FALSE, $ThymeStatus];
}; -- SetCursor
SetWorkingDirectory:
PUBLIC
PROC [wDir: Rope.
ROPE, handle: spGlobals.Handle] = {
ViewerOps.SetViewer[handle.wDir, wDir];
};
ThymeCursorPaint: ViewerClasses.PaintProc = {
ctx: Imager.Context ← context;
bitmap: StatusBitmap ← NARROW[self.data];
proc:
PROC = {
ctx.SetXY[[0, 16]];
ImagerBackdoor.DrawBits[context: ctx, base:
LOOPHOLE[bitmap],
wordsPerLine: 1, sMin: 0, fMin: 0, sSize: 15, fSize: 15, tx: 0, ty: 16];
};
ctx.DoSave[proc];
}; -- ThymeCursorPaint
thymeCursorClass: ViewerClasses.ViewerClass ←
NEW[ViewerClasses.ViewerClassRec ← [
paint: ThymeCursorPaint,
tipTable: NIL]
];
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: BOOL ← FALSE;
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[
spGlobals.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: spGlobals.Handle;
create: BOOL ← TRUE;
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;
spGlobals.BatchRun[handle, wDir, file.first];
RETURN[FALSE];
};
}; -- EnumThymeViewers
ViewerOps.EnumerateViewers[EnumThymeViewers];
IF create
THEN {
handle ← MakeThymeViewers[wDir];
spGlobals.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.
ROPE ←
NIL, allVersions:
BOOL ←
FALSE]
RETURNS [fileList: RopeList ←
NIL] = {
root, lastRoot: Rope.ROPE ← NIL;
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
MakeBitmaps[];
ViewerOps.RegisterViewerClass[$ThymeCursor, thymeCursorClass];
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];
build the library functions and models
START spGlobals.spModels;
START spGlobals.Level2Model;
START spGlobals.spFunctions;
}.
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