ThymeViewers.mesa -- Some parts stolen from PseudoCursorsImpl.mesa
Last Edited by: SChen, May 20, 1985 4:10:53 pm PDT
DIRECTORY
Buttons USING [Button, ButtonProc, Create, SetDisplayStyle],
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, ChildYBound, Create],
Cursors USING [CursorArray],
FileNames USING [CurrentWorkingDirectory],
FS USING [Close, GetInfo, Open, OpenFile, Read],
Graphics USING [Context, DrawBox, Mark, Restore, Save, SetCP, SetPaintMode],
GraphicsOps USING [BitmapRef, BitmapRep, DrawBitmap],
IconManager USING [selectedIcon],
Icons USING [IconFlavor, IconFileFormat, IconRef, IconRep],
IO USING [Close, Flush, PutF, time],
Labels USING [Create, Label],
Menus USING [AppendMenuEntry, ChangeNumberOfLines, CreateMenu, CreateEntry,
GetLine, SetLine, MenuEntry
GetNumberOfLines, Menu, MenuLine, MenuProc],
MessageWindow USING [Append, Blink],
Rope USING [ROPE],
Rules USING [Create, Rule],
spGlobals USING[ConRec, DumpIt, FuncTable, Handle, Level2Model, ModelTable, NodeRec, NormalRun, RefConRec, RefNodeRec, RefR, RefUnReal, ResistorBody, ShowDetails, spFunctions, spModels, Stages, StopIt, ThymeToolRec, ToggleShowDetails, UnReal],
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, FetchProp, PaintViewer, RegisterViewerClass, RestoreViewer, SaveViewer, --SetMenu, --SetOpenHeight],
ViewerTools USING [GetContents, MakeNewTextViewer, SetSelection],
VM USING [AddressForPageNumber, Allocate, Free, Interval];
ThymeViewers: CEDAR MONITOR
IMPORTS Buttons, Commander, Containers, FileNames, FS, Graphics, GraphicsOps, IconManager, IO, Labels, Menus, MessageWindow, Rules, spGlobals, TiogaOps, TypeScript, ViewerEvents, ViewerIO, ViewerOps, VFonts, ViewerBLT, ViewerTools, VM
EXPORTS spGlobals = {
entryHeight: CARDINAL = 12;
entryVSpace: CARDINAL = 6;
entryHSpace: CARDINAL = 10;
msgViewerH: CARDINAL = 100;
destroyEvent: ViewerEvents.EventRegistration ← NIL;
MakeThyme: Commander.CommandProc = {
[] ← MakeThymeViewers[];
}; -- MakeThyme
MakeThymeViewers: PUBLIC PROC[wDir: Rope.ROPENIL]
RETURNS [handle: spGlobals.Handle ← NIL] = {
thymeMenus: Menus.Menu;
d: REF CursorData;
handle ← NEW[spGlobals.ThymeToolRec ← []];
thymeMenus ← MakeThymeMenus[handle];
TRUSTED{
handle.outer ← Containers.Create[
info: [
name: version,
file: LOOPHOLE[handle], -- sorry, no better place.
iconic: TRUE,
icon: private,
menu: thymeMenus,
column: left,
scrollable: FALSE],
paint: FALSE];
};
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];
d← NARROW[handle.progress.data];
d.bitMap ← idleCursorMap;
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.Blink[];
MessageWindow.Append[msg, TRUE];
}; -- BlinkMsg
main sub viewer
initialOutputName: Rope.ROPE = "<Output file name(s) will be set automatically.>";
MakeMainViewer: PROC [handle: spGlobals.Handle, workingDir: Rope.ROPENIL] = {
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 ← CreateCursor[
parent: handle.outer,
x: progressLabel.wx + progressLabel.ww + entryHSpace,
y: handle.height];
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: 10*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: 15*VFonts.StringWidth["M"],
wh: entryHeight,
border: FALSE],
paint: FALSE];
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];
};
}; -- InputPrompt
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 msg sub window
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, $ThymeToolData] = NIL
THEN ViewerOps.AddProp[handle.message, $ThymeToolData, 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
MyDestroy: ViewerEvents.EventProc = {
h: spGlobals.Handle ← NARROW[ViewerOps.FetchProp[viewer, $ThymeToolData]];
IF h=NIL THEN RETURN;
IF event=destroy AND before THEN {
h.msgStream.Close[];
h.outer.file ← NIL;
};
ViewerEvents.UnRegisterEventProc[proc: destroyEvent, event: destroy];
}; -- MyDestroy
ThymeViewerPaint: ViewerClasses.PaintProc = {
IF self.iconic THEN ThymeIconPaint[self, context, whatChanged, clear]
ELSE ThymeNormalPaint[self, context, whatChanged, clear];
}; -- ThymeViewerPaint
ThymeIconPaint: ViewerClasses.PaintProc = {
handle: spGlobals.Handle;
cursorData: REF CursorData;
mark: Graphics.Mark ← Graphics.Save[context];
TRUSTED{handle ← NARROW[LOOPHOLE[self.file]]};
cursorData ← NARROW[handle.progress.data];
IF whatChanged # $ThymeStatus THEN {
Graphics.SetCP[context, 0, iconH];
GraphicsOps.DrawBitmap[context, thymeIconBitmap, iconW, iconH];
};
Graphics.SetCP[context, 25, 44];
IF cursorData.invert THEN [] ← Graphics.SetPaintMode[context, invert]
ELSE [] ← Graphics.SetPaintMode[context, opaque];
GraphicsOps.DrawBitmap[context, cursorData.bitMap, 16, 16];
Graphics.Restore[context, mark];
IF IconManager.selectedIcon = self THEN {
[] ← Graphics.SetPaintMode[context, invert];
Graphics.DrawBox[context, [0, 0, iconW, iconW]];
};
}; -- ThymeIconPaint
ThymeNormalPaint: ViewerClasses.PaintProc ← NIL; -- will be assigned Containers PaintProc
thymeViewerClass: ViewerClasses.ViewerClass ← NEW [ViewerClasses.ViewerClassRec←
[paint: ThymeViewerPaint,
icon: private,
cursor: textPointer]];
Thyme icon bitmap
iconW: INTEGER = 64;
iconH: INTEGER = 64;
thymeIconBitmap: REF GraphicsOps.BitmapRep = CreateThymeIcon["Thyme.icons", 0];
CreateThymeIcon: PROC[file: Rope.ROPE ← "Thyme.icons", n: CARDINAL ← 0]
RETURNS [bitmap: REF GraphicsOps.BitmapRep ← NIL]=
TRUSTED { -- modified Icons.NewIconFromFile
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];
iconRef: Icons.IconRef;
FS.Read[file: fh, from: 0, nPages: pages, to: iconBase];
iconBase ← iconBase + (n*SIZE[Icons.IconFileFormat]);
iconRef ← NEW[Icons.IconRep ←
[iconBase.bits, iconBase.label, iconBase.invertLabel,
0--filler--, iconBase.lx, iconBase.ly, iconBase.lw, iconBase.lh]];
bitmap ← NEW[GraphicsOps.BitmapRep ← [iconRef, iconW/16, iconW, iconH]];
VM.Free[space];
FS.Close[fh];
}; -- CreateThymeIcon
cursors
CursorArray: TYPE= Cursors.CursorArray;
CursorData: TYPE= RECORD[
bitMap: GraphicsOps.BitmapRef ← NIL,
invert: BOOLFALSE];
idleCursorMap: GraphicsOps.BitmapRef= NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[600B, 1100B, 1100B, 600B,
600B, 3740B, 600B, 40602B,
60606B, 70616B, 74636B, 70616B,
54632B, 17770B, 7760B, 600B]],
raster: 1, width: 16, height: 16]
];
inputCursorMap: GraphicsOps.BitmapRef= NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[3740B, 37770B, 160176B, 17B,
24403B, 53500B, 137760B, 77770B,
137636B, 177767B, 173767B, 35754B,
13760B, 2500B, 0B, 0B]],
raster: 1, width: 16, height: 16]
];
bombCursorMap: GraphicsOps.BitmapRef= NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[30B, 140B, 200B, 700B,
600B, 700B, 3060B, 4010B,
4010B, 10004B, 10004B, 10004B,
4010B, 4010B, 3060B, 700B]],
raster: 1, width: 16, height: 16]
];
topoCursorMap: GraphicsOps.BitmapRef= NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[0B, 400B, 0B, 20410B,
10020B, 4440B, 2100B, 0B,
124052B, 0B, 2100B, 4440B,
10020B, 20410B, 0B, 400B]],
raster: 1, width: 16, height: 16]
];
runCursorMap: ARRAY [0..4) OF GraphicsOps.BitmapRef= [
NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[3700B, 14060B, 20410B, 41604B,
40404B, 100402B, 100402B, 100402B,
100002B, 100002B, 40004B, 40004B,
20010B, 14060B, 3700B, 0B]],
raster: 1, width: 16, height: 16]
],
NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[3700B, 14060B, 20010B, 40004B,
40004B, 100002B, 100022B, 100772B,
100022B, 100002B, 40004B, 40004B,
20010B, 14060B, 3700B, 0B]],
raster: 1, width: 16, height: 16]
],
NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[3700B, 14060B, 20010B, 40004B,
40004B, 100002B, 100002B, 100402B,
100402B, 100402B, 40404B, 41604B,
20410B, 14060B, 3700B, 0B]],
raster: 1, width: 16, height: 16]
],
NEW[GraphicsOps.BitmapRep ←
[base: NEW[CursorArray ←
[3700B, 14060B, 20010B, 40004B,
40004B, 100002B, 110002B, 137402B,
110002B, 100002B, 40004B, 40004B,
20010B, 14060B, 3700B, 0B]],
raster: 1, width: 16, height: 16]
]
];
CreateCursor: PROC [parent: ViewerClasses.Viewer, x, y: INTEGER ← 0]
RETURNS [cursor: ViewerClasses.Viewer] = TRUSTED {
cursorData: REF CursorData ← NEW[CursorData];
cursorData.bitMap ←
NEW[GraphicsOps.BitmapRep ←
[base: NIL, raster: 1, width: 16, height: 16]];
cursorData.newData ← TRUE;
Process.InitializeCondition[@cursorData.timeout, waitTime];
cursor ← ViewerOps.CreateViewer[
flavor: $ThymeCursor,
info: [
parent: parent,
wx: x, wy: y, ww: 16, wh: 16,
data: cursorData,
border: FALSE],
paint: FALSE];
}; -- CreateCursor
SetCursor: PUBLIC PROC [handle: spGlobals.Handle,
invert: BOOLFALSE] = {
ENABLE UNWIND => {};
d: REF CursorData;
IF handle = NIL THEN RETURN;
IF handle.progress = NIL THEN RETURN;
d← NARROW[handle.progress.data];
IF d = NIL THEN RETURN;
SELECT handle.stage FROM
idle => d.bitMap ← idleCursorMap;
input => d.bitMap ← inputCursorMap;
bomb => d.bitMap ← bombCursorMap;
topo => d.bitMap ← topoCursorMap;
run => d.bitMap ←
IF handle.vars = NIL THEN runCursorMap[0]
ELSE runCursorMap[handle.vars.runState];
ENDCASE =>
BlinkMsg["* Weird situation at SetCursor detected. Please inform Thyme implementor."];
d.invert ← invert;
IF handle.outer.iconic THEN
ViewerOps.PaintViewer[handle.outer, client, FALSE, $ThymeStatus]
ELSE ViewerOps.PaintViewer[handle.progress, client, FALSE, $ThymeStatus];
IF d.paint=NIL THEN TRUSTED{
Process.Detach[d.paint ← FORK ShowProgress[handle.progress]]};
ShowProgress[handle.progress];
}; -- SetCursor
waitTime: Process.Ticks ← Process.MsecToTicks[100];
ShowProgress: -- ENTRY -- PROC[viewer: ViewerClasses.Viewer] = {
ENABLE UNWIND=> {};
d: REF CursorData ← NARROW[viewer.data];
d.newData ← TRUE;
WHILE d.newData DO
d.newData ← FALSE;
TRUSTED{ViewerOps.PaintViewer[viewer, client, FALSE, $Update]};
WAIT d.timeout;
ENDLOOP;
d.paint ← NIL;
TRUSTED{ViewerOps.PaintViewer[viewer, client, FALSE, $Update]};
}; -- ShowProgress
ThymeCursorPaint: ViewerClasses.PaintProc = {
ctx: Graphics.Context ← context;
cursorData: REF CursorData ← NARROW[self.data];
mark: Graphics.Mark ← Graphics.Save[ctx];
Graphics.SetCP[ctx, 0, 16];
IF cursorData.invert THEN [] ← Graphics.SetPaintMode[ctx, invert]
ELSE [] ← Graphics.SetPaintMode[ctx, opaque];
GraphicsOps.DrawBitmap[ctx, cursorData.bitMap, 16, 16];
Graphics.Restore[ctx, mark];
}; -- ThymeCursorPaint
thymeCursorClass: ViewerClasses.ViewerClass ←
NEW[ViewerClasses.ViewerClassRec ← [
paint: ThymeCursorPaint,
tipTable: NIL]
];
global variables
version: PUBLIC Rope.ROPE← "Thyme - Cedar5.2 - May 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;
registrations:
-- ViewerOps.RegisterViewerClass[$ThymeViewer, thymeViewerClass];
ViewerOps.RegisterViewerClass[$ThymeCursor, thymeCursorClass];
Commander.Register[
key: "Thyme",
proc: MakeThyme,
doc: "Start an instance of the circuit simulator Thyme." ];
destroyEvent --
[] ← ViewerEvents.RegisterEventProc[proc: MyDestroy, event: destroy];
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.