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
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 = {
public global variables
version: PUBLIC Rope.ROPE← "Thyme - Cedar6.0 - Oct 1985";
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.ROPENIL]
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.ROPENIL] = {
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
message viewer
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: INTFS.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: 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[
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: 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;
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.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
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