IPToolImpl.mesa
Last edited by:
Michael Plass, March 20, 1984 1:17:24 pm PST
Doug Wyatt, April 9, 1984 1:12:38 pm PST
DIRECTORY
BasicTime USING [GMT],
Buttons USING [Button, ButtonProc, Create],
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, ChildYBound, Container, Create],
FS USING [ComponentPositions, ExpandName],
Icons USING [IconFlavor, NewIconFromFile],
Imager USING [Context, Create, NewPage, Reset, SpecialOp],
ImagerBridge USING [SetViewFromGraphicsContext],
ImagerPD USING [Hornet, PDFileDescription, PlateMaker, Puffin],
IO USING [Close, int, PutChar, PutF, PutFR, PutRope, rope, STREAM, time],
IP USING [State],
IPExtras USING [DoPage, OpenMaster, PageCount],
IPUtils USING [ToEncoded, ToWritten],
Loader USING [BCDBuildTime],
Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc],
Process USING [Pause, SecondsToTicks],
Rope USING [Concat, Find, ROPE, Substr],
Rules USING [Create, Rule],
ViewerClasses USING [PaintProc, Viewer, ViewerClass, ViewerClassRec],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass],
ViewerTools USING [MakeNewTextViewer, GetContents, SetContents, SetSelection],
ViewRec USING [ViewRef];
IPToolImpl: CEDAR MONITOR
LOCKS data USING data: Data
IMPORTS Buttons, Commander, Containers, FS, Icons, Imager, ImagerBridge, ImagerPD, IO, IPExtras, IPUtils, Loader, Menus, Process, Rope, Rules, ViewerIO, ViewerOps, ViewerTools, ViewRec = {
-- Here is the layout of the tool --
--========================================================================--
-- Interpress --
--========================================================================--
-- Load Show Next PDOptions Print PrintAll Write Read --
--========================================================================--
-- Master: Test.Interpress --
-- Written: Test.IPWritten --
--========================================================================--
-- Interpress Tool of March 31, 1983 --
-- Test.Interpress -> WTest.Interpress --
-- --
-- --
-- --
-- --
--========================================================================--
-- Here is the layout of a page viewer --
--========================================================================--
-- Test.Interpress, page 3 --
--========================================================================--
-- --
-- --
-- . . . --
-- --
--========================================================================--
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Viewer: TYPE = ViewerClasses.Viewer;
Button: TYPE = Buttons.Button;
Data: TYPE = REF DataRep;
DataRep: TYPE = MONITORED RECORD [ -- the data for a particular tool instance
outer: Containers.Container ← NIL, -- handle for the enclosing container
busy: BOOLFALSE,
height: NAT ← 0, -- height measured from the top of the container
logViewer: Viewer, -- contains error log
log: STREAM, -- output stream for writing to error log
masterButton: Button, -- Master: button
masterField: Viewer, -- contains name of Master file
writtenButton: Button, -- Written: button
writtenField: Viewer, -- contains name of Written file
pageButton: Button, -- Page: button
pageField: Viewer, -- contains page number
page: Viewer, -- viewer for showing a page
masterName: ROPE, -- name of current master
pageNumber: NAT, -- current page number
state: IP.State, -- state of the Interpress interpreter
display: Imager.Context, -- imager context for the display
pdOptions: ImagerPD.PDFileDescription ← NIL
];
Lock: ENTRY PROC[data: Data] RETURNS[BOOL] = {
IF data.busy THEN RETURN[FALSE]
ELSE RETURN[data.busy ← TRUE];
};
Unlock: ENTRY PROC[data: Data] = {
data.busy ← FALSE
};
lineHeight: CARDINAL = 15; -- how tall to make each line of items
lineLeading: CARDINAL = 2; -- vertical leading space between lines
totalWidth: CARDINAL = 444; -- width of the entire viewer
margin: CARDINAL = 8; -- left and right margins
entryHSpace: CARDINAL = 10; -- horizontal space between items in a line
MakeIPTool: Commander.CommandProc = { CreateTool[] };
CreateTool: PROC = {
data: Data = NEW[DataRep];
menu: Menus.Menu = MakeMenu[data];
buildTime: BasicTime.GMT ~ Loader.BCDBuildTime[CreateTool];
data.outer ← Containers.Create[[-- construct the outer container'
name: "Interpress Tool", -- name displayed in the caption
menu: menu,
iconic: FALSE,
column: right, -- initially in the right column
scrollable: FALSE
]];
build each (sub)viewer in turn
MakeFilePart[data];
MakeRule[data, 1];
MakeLogPart[data, 100];
data.page ← CreatePage[data];
data.log.PutF["Interpress Tool of %g\n", IO.time[buildTime]];
ViewerOps.PaintViewer[data.outer, all]; -- reflect above change
};
PageData: TYPE = REF PageDataRep;
PageDataRep: TYPE = RECORD[w: NAT]; -- instance data for Interpress viewers
CreatePage: PROC[data: Data] RETURNS[ViewerClasses.Viewer] = {
viewer: ViewerClasses.Viewer = ViewerOps.CreateViewer[
flavor: $Page,
info: [
name: "Interpress Page",
data: data,
iconic: FALSE,
column: left,
scrollable: FALSE
]
];
RETURN[viewer];
};
LongOperation: PROC[log: STREAM, n: NAT] = {
THROUGH [0..n) DO
log.PutChar['.];
Process.Pause[Process.SecondsToTicks[1]];
ENDLOOP;
};
MakeMenu: PROC[data: Data] RETURNS[Menus.Menu] = {
menu: Menus.Menu = Menus.CreateMenu[];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "Load",
proc: LoadProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "Show",
proc: ShowProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "Next",
proc: NextProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "PDOptions",
proc: PDOptionsProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "Print",
proc: PrintProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "PrintAll",
proc: PrintAllProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "Write",
proc: WriteProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "Read",
proc: ReadProc, clientData: data]
];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "LoadSelection",
proc: LoadSelectionProc, clientData: data]
];
RETURN[menu];
};
PaintPageViewer: PROC[data: Data] = {
page: Viewer ~ data.page;
page.name ← IO.PutFR["%g, page %g", IO.rope[data.masterName], IO.int[data.pageNumber]];
ViewerOps.PaintViewer[viewer: page, hint: all, whatChanged: $SetView];
call PaintViewer to update caption and set view for display context
IF page.iconic THEN RETURN;
data.state.imager ← data.display;
[] ← IPExtras.DoPage[data.state, data.pageNumber];
};
GetPDFileDescription: PROC[data: Data] RETURNS[ImagerPD.PDFileDescription] ~ {
IF data.pdOptions = NIL THEN RETURN [ImagerPD.Hornet[PDName[data.masterName]]]
ELSE RETURN [data.pdOptions];
};
PrintPage: PROC[data: Data] = {
log: STREAM ~ data.log;
self: IP.State ~ data.state;
masterName: ROPE ~ data.masterName;
page: NAT ~ data.pageNumber;
pd: Imager.Context ← NIL;
pdOptions: ImagerPD.PDFileDescription ~ GetPDFileDescription[data];
log.PutF["Writing page %g of %g to %g ...",
IO.int[page], IO.rope[masterName], IO.rope[pdOptions.fileName]];
self.imager ← pd ← Imager.Create[$PD, pdOptions];
[] ← IPExtras.DoPage[self, page];
[] ← Imager.SpecialOp[pd, $Close, NIL];
log.PutRope["done.\n"];
};
PrintAll: PROC[data: Data] = {
log: STREAM ~ data.log;
self: IP.State ~ data.state;
masterName: ROPE ~ data.masterName;
count: NAT ~ IPExtras.PageCount[self];
pd: Imager.Context ← NIL;
pdOptions: ImagerPD.PDFileDescription ~ GetPDFileDescription[data];
log.PutF["Writing %g to %g (%g pages) ...",
IO.rope[masterName], IO.rope[pdOptions.fileName], IO.int[count]];
self.imager ← pd ← Imager.Create[$PD, pdOptions];
FOR page: NAT IN[1..count] DO
log.PutF[" %g", IO.int[page]];
[] ← IPExtras.DoPage[self, page];
IF page<count THEN Imager.NewPage[pd];
ENDLOOP;
[] ← Imager.SpecialOp[pd, $Close, NIL];
log.PutRope[" done.\n"];
};
PDName: PROC[name: ROPE] RETURNS[ROPE] = {
fname: ROPE; cp: FS.ComponentPositions;
[fullFName: fname, cp: cp] ← FS.ExpandName[name];
RETURN[fname.Substr[len: cp.base.start+cp.base.length].Concat[".pd"]];
};
Extend: PROC[name: ROPE, ext: ROPE] RETURNS[ROPE] = {
RETURN[IF name.Find["."]<0 THEN name.Concat[ext] ELSE name];
};
LoadMaster: PROC[data: Data] = {
name: ROPE = ViewerTools.GetContents[data.masterField];
file: ROPE = Extend[name, ".Interpress"];
log: STREAM = data.log;
log.PutF["Loading %g...", IO.rope[file]];
data.display ← Imager.Create[$LFDisplay];
data.state ← IPExtras.OpenMaster[file, data.display];
log.PutRope["done.\n"];
data.state.log ← log;
data.masterName ← name;
data.pageNumber ← 1;
};
Do: PROC[proc: PROC[Data], data: Data] = {
IF Lock[data] THEN {
proc[data ! UNWIND => Unlock[data]];
Unlock[data];
};
};
LoadProc: Buttons.ButtonProc = {
Do[LoadMaster, NARROW[clientData]];
};
ShowProc: Menus.MenuProc = {
Do[PaintPageViewer, NARROW[clientData]];
};
viewRecBuggy: BOOLFALSE;
PDOptionsProc: Menus.MenuProc = {
SetPDOptions: PROC[data: Data] ~ {
fileName: ROPE ~ PDName[data.masterName];
new: ImagerPD.PDFileDescription ~ SELECT mouseButton FROM
red => ImagerPD.Hornet[fileName],
blue => ImagerPD.PlateMaker[fileName],
yellow => ImagerPD.Puffin[fileName],
ENDCASE => ImagerPD.Hornet[fileName];
IF mouseButton = blue THEN {
new.sResolution ← new.fResolution ← 1200;
new.imageSSize ← 13200;
new.imageFSize ← 10200;
};
IF data.pdOptions = NIL THEN {
data.pdOptions ← new;
IF NOT viewRecBuggy THEN [] ← ViewRec.ViewRef[agg: new, otherStuff: NIL, viewerInit: [name: "PD File Options", column: right]];
}
ELSE data.pdOptions^ ← new^;
};
Do[SetPDOptions, NARROW[clientData]];
};
PrintProc: Menus.MenuProc = {
Do[PrintPage, NARROW[clientData]];
};
PrintAllProc: Menus.MenuProc = {
Do[PrintAll, NARROW[clientData]];
};
NextProc: Menus.MenuProc = {
Next: PROC[data: Data] = {
n: NAT = data.pageNumber;
count: NAT = IPExtras.PageCount[data.state];
SELECT mouseButton FROM
red, yellow => {
IF n<count THEN {
data.pageNumber ← n+1;
PaintPageViewer[data];
};
};
blue => {
IF n>1 THEN {
data.pageNumber ← n-1;
PaintPageViewer[data];
};
};
ENDCASE;
};
Do[Next, NARROW[clientData]];
};
WriteProc: Menus.MenuProc = {
Write: PROC[data: Data] = {
master: ROPE = Extend[ViewerTools.GetContents[data.masterField], ".Interpress"];
written: ROPE = Extend[ViewerTools.GetContents[data.writtenField], ".Interpress"];
log: STREAM = data.log;
Dot: PROC = { log.PutChar['.] };
log.PutRope[IO.PutFR["%g -> %g ", IO.rope[master], IO.rope[written]]];
IPUtils.ToWritten[master, written, Dot];
log.PutRope["done\n"];
};
Do[Write, NARROW[clientData]];
};
ReadProc: Menus.MenuProc = {
Read: PROC[data: Data] = {
master: ROPE = Extend[ViewerTools.GetContents[data.masterField], ".Interpress"];
written: ROPE = Extend[ViewerTools.GetContents[data.writtenField], ".Interpress"];
log: STREAM = data.log;
Dot: PROC = { log.PutChar['.] };
log.PutRope[IO.PutFR["%g -> %g ", IO.rope[written], IO.rope[master]]];
IPUtils.ToEncoded[written, master, Dot];
log.PutRope["done\n"];
};
Do[Read, NARROW[clientData]];
};
LoadSelectionProc: Menus.MenuProc = {
LoadSelection: PROC[data: Data] = {
selection: ROPE = ViewerTools.GetSelectionContents[];
log: STREAM = data.log;
ViewerTools.SetContents[data.masterField, "Selection"];
log.PutRope[" Parsing selection ..."];
{ IPUtils.RopeToMaster[selection, "Selection.Interpress" ! ANY => GOTO Fail];
log.PutRope["ok\n"];
LoadMaster[data];
EXITS Fail => log.PutRope["failed\n"];
};
};
Do[LoadSelection, NARROW[clientData]];
};
MakeRule: PROC[data: Data, height: NAT] = {
rule: Rules.Rule ← Rules.Create[ [ -- create a horizontal rule to separate sections
parent: data.outer,
wy: data.height,
ww: data.outer.cw,
wh: height
]];
Containers.ChildXBound[data.outer, rule];
data.height ← rule.wy + rule.wh + lineLeading; -- spacing after rule
};
TSOpen: PROC[viewer: Viewer] RETURNS[STREAM] = {
in, out: STREAM;
[in: in, out: out] ← ViewerIO.CreateViewerStreams[name: NIL,
viewer: viewer, backingFile: NIL, editedStream: FALSE];
in.Close[];
RETURN[out];
};
MakeLogPart: PROC[data: Data, height: NAT] = {
viewer: Viewer = ViewerOps.CreateViewer[
flavor: $Typescript,
info: [parent: data.outer,
wx: 0, ww: totalWidth, wy: data.height, wh: height,
scrollable: TRUE, border: FALSE]
];
Containers.ChildXBound[data.outer, viewer];
Containers.ChildYBound[data.outer, viewer];
data.logViewer ← viewer;
data.log ← TSOpen[viewer]; -- open an output stream on the typescript
data.height ← viewer.wy + viewer.wh + lineLeading; -- spacing after typescript
};
buttonBorders: BOOLTRUE;
MakeFilePart: PROC[data: Data] = {
middle: NAT = totalWidth/2;
rightEdge: NAT = totalWidth;
x: NAT ← margin; -- current x
y: NAT ← data.height; -- current y
container: Viewer = data.outer;
AddButton: PROC[name: ROPE, proc: Buttons.ButtonProc] RETURNS[Button] = {
button: Button = Buttons.Create[
info: [parent: container, name: name,
wx: x, wy: y, wh: lineHeight,
border: buttonBorders],
proc: proc, clientData: data
];
x ← button.wx+button.ww+entryHSpace;
RETURN[button];
};
AddPrompt: PROC[name: ROPE, proc: Buttons.ButtonProc] RETURNS[Button] = {
button: Button = Buttons.Create[
info: [parent: container, name: name,
wx: x, wy: y, wh: lineHeight,
border: FALSE],
proc: proc, clientData: data
];
x ← button.wx+button.ww; -- no extra space
RETURN[button];
};
AddField: PROC[nextX: NAT] RETURNS[Viewer] = {
field: Viewer = ViewerTools.MakeNewTextViewer[
info: [parent: container,
wx: x, wy: y+1, ww: nextX-entryHSpace-x, wh: lineHeight,
scrollable: TRUE, border: FALSE]
];
x ← nextX;
RETURN[field];
};
NextLine: PROC = { y ← y+lineHeight+lineLeading; x ← margin; };
data.masterButton ← AddPrompt["Master:", MasterPrompt];
data.masterField ← AddField[rightEdge];
NextLine[];
data.writtenButton ← AddPrompt["Written:", WrittenPrompt];
data.writtenField ← AddField[rightEdge];
NextLine[];
data.height ← y;
};
MasterPrompt: Buttons.ButtonProc = {
data: Data = NARROW[clientData];
IF mouseButton=blue THEN ViewerTools.SetContents[data.masterField, NIL];
ViewerTools.SetSelection[data.masterField]; -- force the selection
};
WrittenPrompt: Buttons.ButtonProc = {
data: Data = NARROW[clientData];
IF mouseButton=blue THEN ViewerTools.SetContents[data.writtenField, NIL];
ViewerTools.SetSelection[data.writtenField]; -- force the selection
};
PagePrompt: Buttons.ButtonProc = {
data: Data = NARROW[clientData];
IF mouseButton=blue THEN ViewerTools.SetContents[data.pageField, NIL];
ViewerTools.SetSelection[data.pageField]; -- force the selection
};
PutLine: PROC[data: Data, rope: ROPE] = {
log: STREAM = data.log;
log.PutRope[rope];
log.PutChar['\n];
};
PaintPage: ViewerClasses.PaintProc = {
[self: Viewer, context: Graphics.Context, whatChanged: REF ANY, clear: BOOL]
data: Data = NARROW[self.data];
IF whatChanged=$SetView THEN {
display: Imager.Context ~ data.display;
ImagerBridge.SetViewFromGraphicsContext[display, context];
Imager.Reset[display];
};
};
pageIcon: Icons.IconFlavor = Icons.NewIconFromFile["Interpress.icons", 2];
pageClass: ViewerClasses.ViewerClass = NEW[ViewerClasses.ViewerClassRec ← [
paint: PaintPage, icon: pageIcon]];
Register the Interpress class of viewer with the Window Manager
ViewerOps.RegisterViewerClass[$Page, pageClass];
Register a command with the executive.
Commander.Register[key: "Interpress", proc: MakeIPTool,
doc: "Create an Interpress tool" ];
}.