DIRECTORY
Atom USING [PutPropOnList],
CD USING [Design, Layer, LayerKey, Number, Position, Rect, undefLayer],
CDBasics USING [SizeOfRect],
CDCommandOps USING [DoWithResource],
CDLayers USING [CurrentLayer],
CDOps USING [BoundingBox],
CDPanel USING [DefineButton, DefineNewLine, DefineRopeEntry, FromDisplayRope],
CDProperties USING [PutDesignProp, RegisterProperty],
CDSequencer USING [Command, ImplementCommand, UseAbortFlag],
CDValue USING [RegisterKey, Store],
CDViewer USING [ViewerList, ViewersOf, VisibleRect],
Commander USING [CommandProc, Handle, Register],
CommandTool USING [NextArgument],
CStitching USING [NewTesselation, Tesselation, FindTile],
Imager USING [metersPerPoint, Rectangle],
IO USING [atom, GetBool, GetInt, GetReal, int, PutF, PutFR, real, RIS, rope],
MessageWindow USING [Append, Blink, Clear],
Nectarine USING [DoInterpress, invalidPrinter, Print],
Real USING [Fix, Float, Round],
Rope USING [ActionType, Cat, Equal, IsEmpty, Map, ROPE],
RopeFile USING [Create],
RuntimeError USING [UNCAUGHT],
SafeStorage USING [GetCanonicalReferentType, Type],
SweepCollectableStorage USING [EnumerateCollectableStorage, InfoProc],
TEditDocument USING [Selection],
TEditInputOps USING [Break, CallWithLocks],
TerminalIO USING [PutF, PutRope],
TextNode USING [Ref],
TiogaAccess USING [Create, GetInternalProp, Put, TiogaChar, Writer, WriteSelection, WriteViewer],
UserProfile USING [Token],
ViewerClasses USING [Viewer],
ViewerOps USING [BlinkIcon, CreateViewer];
~
BEGIN
OPEN Real;
masterKey: ATOM ~ $Nectarine;
whatKey: ATOM ~ $NectarineWhat;
whereKey: ATOM ~ $NectarineWhere;
copiesKey: ATOM ~ $NectarineCopies;
scaleKey: ATOM ~ $NectarineScale;
monoLayerKey: ATOM ~ $NectarineMonoLayer;
CSTile: SafeStorage.Type;
ROPE: TYPE ~ Rope.ROPE;
lastPrint:
RECORD [ip:
ROPE, key:
ATOM, q:
INT, l:
BOOL, w: Imager.Rectangle];
This global variable is used to implement the Redo command.
maxHoldedArea: REF Imager.Rectangle ← NIL;
NectarineCommand:
PROC [comm: CDSequencer.Command] ~
BEGIN
Called by ChipNDale upon activation of the command.
abort: REF BOOL ← NEW [BOOL ← FALSE];
DoIt:
PROC [comm: CDSequencer.Command] ~
BEGIN
Protected procedure.
what: ROPE ~ CDPanel.FromDisplayRope [comm.design, whatKey];
where: ROPE ~ CDPanel.FromDisplayRope [comm.design, whereKey];
howMany: INT ← 0; -- number of copies
scale: REAL ← 0.0; -- lambda in millimetres
monoLayer: BOOL ← FALSE; -- only the layer of interset will be printed
layerOfInterest: CD.Layer ← CD.undefLayer;
cropKey, printKey: ATOM;
masterName: ROPE ← NIL;
usedField: Imager.Rectangle;
rollPaperDeviceHint: REF Imager.Rectangle ← NIL;
The exception: the user does not know what he is doing (may be he is just nervous).
IF where.Equal ["Explain", FALSE] THEN {ExplainGoals []; RETURN};
Interpret what.
SELECT
TRUE
FROM
what.Equal ["Design", FALSE] => cropKey ← $NectarineAll;
what.Equal ["Wysiwyg", FALSE] => cropKey ← $NectarineWysiwyg;
what.Equal ["Selection", FALSE] => cropKey ← $NectarineSel;
ENDCASE =>
BEGIN
TerminalIO.PutRope ["Unknown cropping option.\n"]; ERROR ABORTED
END;
Interpret where.
SELECT
TRUE
FROM
where.Equal ["ColorVersatec",
FALSE] =>
BEGIN
ImportantMessage ["Are you sure you did not want to use the printer server 'PeachExpand' (see doc)?"];
printKey ← $NColorVersatec
END;
where.Equal ["Color400", FALSE] => printKey ← $NColor400;
where.Equal ["Raven300", FALSE] => printKey ← $NRaven300;
where.Equal ["Raven384", FALSE] => printKey ← $NRaven384;
where.Equal ["Bw400", FALSE] => printKey ← $NBw400;
where.Equal ["Versatec", FALSE] => printKey ← $NVersatec;
where.Equal ["PlateMaker", FALSE] => printKey ← $NPlateMaker;
where.Equal ["Tioga doc", FALSE] => printKey ← $NPasteInTioga;
where.Equal ["IP only", FALSE] => printKey ← $NmasterOnly;
where.Equal ["hold", FALSE] => printKey ← $Nhold;
where.Equal ["PeachExpand",
FALSE] =>
BEGIN
TerminalIO.PutRope ["I will create an Interpress master, which I will use to produce a PD file. I will then send it to the expansion server to create a bitmap, and from there I will send it to the color Versatec. You will have to delete the temporary files manually.\n"];
printKey ← $NPeachExpand
END;
ENDCASE => {TerminalIO.PutRope ["Unknown printer.\n"]; ERROR ABORTED};
Interpret how many.
BEGIN
r: ROPE ~ CDPanel.FromDisplayRope [comm.design, copiesKey];
This is a hack to work around a bug in CDPanel: the initialization of the defaults is spurious.
IF r.IsEmpty THEN howMany ← 1
ELSE howMany ← IO.GetInt [IO.RIS [r] ! RuntimeError.UNCAUGHT => {howMany ← 1; CONTINUE}]
END;
Interpret scale (lambda in millimetres).
BEGIN
r: ROPE ~ CDPanel.FromDisplayRope [comm.design, scaleKey];
This is a hack to work around a bug in CDPanel: the initialization of the defaults is spurious.
IF r.IsEmpty THEN scale ← 0.0
ELSE scale ← IO.GetReal [IO.RIS [r] ! RuntimeError.UNCAUGHT => {scale ← 0.0; CONTINUE}];
IF (scale # 0.0) THEN TerminalIO.PutF ["Fixed scale = %g mm.\n", IO.real [scale]]
ELSE TerminalIO.PutRope ["Will scale to fit page.\n"]
END;
Interpretate necessity to print only one layer.
BEGIN
r: ROPE ~ CDPanel.FromDisplayRope [comm.design, monoLayerKey];
This is a hack to work around a bug in CDPanel: the initialization of the defaults is spurious.
IF r.IsEmpty THEN monoLayer ← FALSE
ELSE monoLayer ← IO.GetBool [IO.RIS [r] ! RuntimeError.UNCAUGHT => {monoLayer ← FALSE; CONTINUE}];
IF monoLayer
THEN
BEGIN
layerOfInterest ← CDLayers.CurrentLayer [comm.design];
TerminalIO.PutF ["Will print only the current layer (%g).\n", IO.atom [CD.LayerKey [layerOfInterest]]]
END
END;
Create an Interpress master if necessary.
IF (masterName.IsEmpty [])
THEN
BEGIN
cW: CD.Rect; -- ChipNDale window
l: CD.Number ~ comm.design.technology.lambda;
SELECT cropKey
FROM
$NectarineAll => cW ← CDOps.BoundingBox [comm.design];
$NectarineSel =>
BEGIN
size: CD.Position;
cW ← CDOps.BoundingBox [comm.design, TRUE];
size ← CDBasics.SizeOfRect [cW];
IF (size.x <= 0)
OR (size.y <= 0)
THEN
BEGIN
TerminalIO.PutRope ["You do not have a selection in this design !\n"];
ERROR ABORTED
END
END;
$NectarineWysiwyg =>
BEGIN
viewers: CDViewer.ViewerList = CDViewer.ViewersOf [comm.design];
goodViewer: ViewerClasses.Viewer;
good: INT ← 0;
IF (viewers =
NIL)
THEN
BEGIN
TerminalIO.PutRope ["You do not see anything of this design !\n"];
ERROR ABORTED
END;
FOR v: CDViewer.ViewerList ← viewers, v.rest
WHILE v #
NIL
DO
IF NOT v.first.iconic THEN {goodViewer ← v.first; good ← good.SUCC}
ENDLOOP;
SELECT good
FROM
0 => {TerminalIO.PutRope ["You do not see anything !\n"]; ERROR ABORTED};
> 1 => TerminalIO.PutRope ["WARNING: you see more than one viewer. I pick one at random\n"];
ENDCASE => NULL;
cW ← CDViewer.VisibleRect [goodViewer]
END;
ENDCASE => ERROR;
The following is not a hack. In schematics the cells may have a border. On the screen this border is one pixel wide, but with Interpress we have to specify a concrete width in millimetres. We choose to make it ¼ l wide. If the border has a width, it takes some finite amount of space on the paper. It would be natural to use this space inside the cell. However, the designers exploit the fact that on the screen the border has no width and put text flush to the border. In order to preserve such text, Nectarine is forced to print the border outside the cell. This means, that the border can now be outside the field on the medium. This is why here we cheat and increase the window by l on each side.
cW ← [x1: cW.x1 - l, x2: cW.x2 + l, y1: cW.y1 - l, y2: cW.y2 + l];
IF ((cropKey = $NectarineAll)
AND (scale # 0.0)
AND ((printKey = $NmasterOnly)
OR (printKey = $NRaven300)
OR (printKey = $NRaven384)
OR (printKey = $NPlateMaker)))
THEN
BEGIN
currentWindow: CD.Rect;
medium: Imager.Rectangle ~ [x: 0.0, y: 0.0, w: 215.9, h: 279.4]; -- in mm
field: Imager.Rectangle ~ [x: medium.x + 10.0, y: medium.y + 10.0, w: medium.w - 20.0, h: medium.h - 20.0]; -- in mm
windowW: INTEGER ~ Round [field.w / scale] * l; -- in cd units
windowH: INTEGER ~ Round [field.h / scale] * l; -- in cd units
totalWidth: REAL ~ Float [cW.x2 - cW.x1] / l * scale; -- in mm
totalHeight: REAL ~ Float [cW.y2 - cW.y1] / l * scale; -- in mm
columns: INTEGER ← Fix [totalWidth / field.w]; -- Fix truncates
rows: INTEGER ← Fix [totalHeight / field.h]; -- Fix truncates
IF (cW.x1 + windowW * columns < cW.x2) THEN columns ← columns.SUCC;
IF (cW.y1 + windowH * rows < cW.y2) THEN rows ← rows.SUCC;
TerminalIO.PutF ["Nectarine will break the design in %g A pages.\n", IO.int [columns*rows]];
currentWindow ← [x1 ~ cW.x1, y1 ~ cW.y2 - windowH, x2 ~ cW.x1 + windowW, y2 ~ cW.y2];
FOR i:
INTEGER
IN [0 .. rows)
DO
FOR j:
INTEGER
IN [0 .. columns)
DO
masterName ← Nectarine.DoInterpress [design: comm.design,
chipNDaleWindow: currentWindow,
clip: TRUE,
onlySel: FALSE,
layer: layerOfInterest,
singleLayer: monoLayer,
lambda: scale,
firstPage: ((i = 0) AND (j = 0)) OR ((printKey = $Nhold) AND (maxHoldedArea = NIL)),
lastPage: ((i = rows - 1) AND (j = columns - 1) AND (printKey # $Nhold)),
abortFlag: abort].masterName;
currentWindow.x1 ← currentWindow.x2;
currentWindow.x2 ← currentWindow.x2 + windowW
ENDLOOP;
currentWindow.x1 ← cW.x1; currentWindow.x2 ← cW.x1 + windowW;
currentWindow.y2 ← currentWindow.y1;
currentWindow.y1 ← currentWindow.y1 - windowH
ENDLOOP;
usedField ← [x: 0, y: 0, w: 0, h: -1] -- w > h
END
ELSE [masterName, usedField] ← Nectarine.DoInterpress [design: comm.design,
chipNDaleWindow: cW,
clip: (cropKey = $NectarineWysiwyg) OR (cropKey = $NectarineSel),
onlySel: (cropKey = $NectarineSel),
layer: layerOfInterest, singleLayer: monoLayer,
lambda: scale,
firstPage: (maxHoldedArea = NIL),
lastPage: (printKey # $Nhold),
abortFlag: abort];
IF (printKey = $Nhold)
THEN
BEGIN
IF (maxHoldedArea = NIL) THEN maxHoldedArea ← NEW [Imager.Rectangle ← usedField]
ELSE
BEGIN
I know, I could write this more succinctly, but this is more readable and speed is not an issue here.
x1: REAL ~ MAX [maxHoldedArea.x + maxHoldedArea.w, usedField.x + usedField.w];
y1: REAL ~ MAX [maxHoldedArea.y + maxHoldedArea.h, usedField.y + usedField.h];
maxHoldedArea.x ← MIN [maxHoldedArea.x, usedField.x];
maxHoldedArea.y ← MIN [maxHoldedArea.y, usedField.y];
maxHoldedArea.w ← x1 - maxHoldedArea.x;
maxHoldedArea.h ← y1 - maxHoldedArea.y
END
END
ELSE
BEGIN
IF (maxHoldedArea # NIL) THEN {usedField ← maxHoldedArea^; maxHoldedArea ← NIL}
END;
CDProperties.PutDesignProp [comm.design, masterKey, masterName]
END; -- create Interpress master
Print if asked to do so.
lastPrint ← [ip: masterName, key: printKey, q: howMany, l: (scale = 0.0), w: usedField]; -- for Redo
SELECT printKey
FROM
$NmasterOnly => NULL;
$NPasteInTioga => Paste [masterName, usedField];
$Nhold => TerminalIO.PutRope ["Nectarine is holding the result in a buffer until `where' no longer is `hold'.\n"];
ENDCASE =>
BEGIN
IF (usedField.h > usedField.w)
THEN
rollPaperDeviceHint ← NEW [Imager.Rectangle ← usedField];
[] ← Nectarine.Print [masterName, printKey, howMany, (scale = 0.0), rollPaperDeviceHint
! Nectarine.invalidPrinter => ERROR]
END;
TerminalIO.PutRope ["Design unlocked by Nectarine.\n"]
END; -- DoIt
CDSequencer.UseAbortFlag [comm.design, abort];
[] ← CDCommandOps.DoWithResource [DoIt, comm, $Nectarine]
You would probably expect here a direct call of Nectarine, since the implementation is reentrant. However, I wanted to avoid two print commands on the same design, because this would force me to implement a file name manager and to place on the user the burden of descrying it. What I really wanted to do was to prevent multiple calls on the same design, but to allow parallel calls on different designs. Unfortunately, currently there are no provisions for this in ChipNDale: resources are global to ChipNDale and there are none local to designs (at least as long as you imperatively need a lightweight abort capability). Surely I could implement a hack, but there are no hacks in Nectarine.
END; -- NectarineCommand
Paste:
PROC [name:
ROPE, bb: Imager.Rectangle, newViewer:
BOOL ←
FALSE] ~
BEGIN
Pastes the Interpress master in file name and with bounding box bb at the current Tioga selection. The appropriate scaling is being implemented in Tioga and in TiogaToInterpress.
I misteri della vita e della morte.
master: ROPE ~ RopeFile.Create [name]; -- the Interpress master desguised as a rope
document: TiogaAccess.Writer ← TiogaAccess.Create []; -- a working area Tioga doc
vanillaChar: TiogaAccess.TiogaChar = [0, 0C, ALL [FALSE], NIL, TRUE, FALSE, 0, NIL];
dummy, ip, caption: TiogaAccess.TiogaChar ← vanillaChar;
space: REAL ~ 8.0 * Imager.metersPerPoint * 1000.0; -- in mm
topCalcRope: ROPE; -- for postfix property calculating top leading and ident
PutRope:
PROC [r:
ROPE, attr: TiogaAccess.TiogaChar] ~
BEGIN
Writes into document the characters in r using the attributes of the sample character attr.
PutChar: Rope.ActionType ~ {attr.char ← c; document.Put [attr]};
[] ← Rope.Map [base: r, action: PutChar]
END; -- PutRope
PutProp:
PROC [char: TiogaAccess.TiogaChar, prop:
ATOM, val:
ROPE]
RETURNS [TiogaAccess.TiogaChar] ~
BEGIN
Safely attaches a property with key prop and value val to the character char.
char.propList ← Atom.PutPropOnList [propList: char.propList, prop: prop, val: TiogaAccess.GetInternalProp [prop, val]];
RETURN [char]
END; -- PutProp
Stuff:
PROC [root: TextNode.Ref, tSel:TEditDocument.Selection] ~
BEGIN
Takes the working area Tioga document document and stuffs it into the current selection.
IF newViewer
THEN
BEGIN
repository: ViewerClasses.Viewer ← ViewerOps.CreateViewer [$Text];
document.WriteViewer [repository]; ViewerOps.BlinkIcon [repository, 0]
END
ELSE {TEditInputOps.Break []; TiogaAccess.WriteSelection [document]}
END; -- Stuff
Insert block node containing a CR. Why???
dummy.endOfNode ← TRUE; PutRope ["\n", dummy];
Insert an artworkFigure node, with a postfix prop for lead and ident, bounds and with Artwork containing the IP master. The node contains a rope which becomes visible when ArtworkInterpress is off.
dummy.endOfNode ← FALSE; dummy.looks['n] ← TRUE;
PutRope ["[Artwork node; type 'ArtworkInterpress on' to command tool]", dummy];
ip.char ← '\n; ip.endOfNode ← TRUE; ip.deltaLevel ← 1;
ip.format ← $artworkFigure; -- it is an artwork node
ip ← PutProp [ip, $Postfix, IO.PutFR ["%g mm topLeading %g mm topIndent %g mm bottomLeading", IO.real [bb.y+bb.h+space], IO.real [bb.y+bb.h+space], IO.real [-bb.y+space/2.0]]]; -- margin in the document
topCalcRope ← IO.PutFR ["%g the lineLength .mul %g .add", IO.real [bb.h/bb.w], IO.real [space]];
ip ← PutProp [ip, $Postfix, IO.PutFR ["%g topLeading %g topIndent %g mm bottomLeading",
IO.rope [topCalcRope], IO.rope [topCalcRope], IO.real [space/2.0]]]; -- margin in the document
ip ← PutProp [ip, $Bounds, IO.PutFR ["%g mm xmin %g mm ymin %g mm xmax %g mm ymax", IO.real [bb.x], IO.real [bb.y], IO.real [bb.x+bb.w], IO.real [bb.y+bb.h]]]; -- set the bounding box
ip ← PutProp [ip, $Artwork, "Interpress"]; -- the artwork type is "Interpress"
ip ← PutProp [ip, $Interpress, master]; -- the Interpress master desguised as a rope
ip ← PutProp [ip, $Fit, "TRUE"]; -- fit the figure to the margins of the sibling node
document.Put [ip];
Insert a nested artworkCaption node with a hint rope.
caption.looks['i] ← TRUE; caption.looks['o] ← TRUE; -- should be in the style
PutRope ["Insert caption here", caption];
caption.char ← 0C; caption.format ← $artworkCaption; caption.endOfNode ← TRUE;
document.Put [caption];
Take the contents of document and stuff it into the current Tioga selection. If there is no selection, nothing happens.
TEditInputOps.CallWithLocks [Stuff]
END; -- Paste
Registations:
PROC [] ~
BEGIN
defaultCrops: LIST OF ROPE ~ LIST ["Design", "Selection", "Wysiwyg"];
defaultPrinters: LIST OF ROPE ~ LIST ["Explain", "Tioga doc", "Raven300", "Raven384", "Bw400", "Versatec", "PeachExpand", "ColorVersatec", "Color400", "PlateMaker", "IP only", "hold"];
bool: LIST OF ROPE ~ LIST ["No", "Yes"];
[] ← CDProperties.RegisterProperty [masterKey, masterKey];
CDValue.RegisterKey [key: whatKey, registrationKey: masterKey];
CDValue.RegisterKey [key: whereKey, registrationKey: masterKey];
CDValue.RegisterKey [key: copiesKey, registrationKey: masterKey];
CDValue.RegisterKey [key: scaleKey, registrationKey: masterKey];
CDValue.RegisterKey [key: monoLayerKey, registrationKey: masterKey];
CDValue.Store [key: whatKey, value: defaultCrops];
CDValue.Store [key: whereKey, value: defaultPrinters];
CDValue.Store [key: copiesKey, value: "1"];
CDValue.Store [key: scaleKey, value: "0.0"];
CDValue.Store [key: monoLayerKey, value: bool];
CDPanel.DefineButton [name: "Nectarine", border: TRUE, command: $NectarineCmd];
CDPanel.DefineRopeEntry [cdValueKey: whatKey, button: "What:", width: 60, editable: FALSE];
CDPanel.DefineRopeEntry [cdValueKey: whereKey, button: "Where:", width: 90, editable: FALSE];
CDPanel.DefineRopeEntry [cdValueKey: copiesKey, button: "Copies:", width: 30];
CDPanel.DefineRopeEntry [cdValueKey: scaleKey, button: " in mm:", width: 60];
CDPanel.DefineNewLine [];
CDPanel.DefineRopeEntry [cdValueKey: monoLayerKey, button: "Current layer only:", width: 60, editable: FALSE];
CDPanel.DefineNewLine [];
CDSequencer.ImplementCommand [key: $NectarineCmd, proc: NectarineCommand, queue: doQueue];
Commander.Register [key: "NCount", proc: Count, doc: "Counts corner stitching tiles"];
Commander.Register [key: "NRedo", proc: Redo, doc: "Syntax: NRedo <goal>. Redoes the last Nectarine Print command on the same Interpress master but with the newly specified goal. The goal must be one of those specified in the <where> field of the Nectarine line in the ChipNDale control panel. Default: the same as the last time around."]
END; -- Registrations
Count: Commander.CommandProc ~
BEGIN
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
PerObject: SweepCollectableStorage.InfoProc ~
BEGIN
[type: SafeStorage.Type, size: INT, object: LONG CARDINAL] RETURNS [continue: BOOLEAN]
IF type = CODE [CStitching.Tesselation] THEN tessCount ← tessCount + 1
ELSE IF type = CSTile THEN tileCount ← tileCount + 1;
RETURN [TRUE]
END; -- PerObject
tessCount: INT ← 0;
tileCount: INT ← 0;
TRUSTED { SweepCollectableStorage.EnumerateCollectableStorage [PerObject] };
cmd.out.PutF ["tesselations = %g\n", IO.int [tessCount]];
cmd.out.PutF ["tiles = %g\n", IO.int [tileCount]]
END; -- Count
Redo: Commander.CommandProc ~
BEGIN
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
Syntax: NRedo <goal>. Redoes the last Print command on the same Interpress master but on the newly specified goal. The goal must be one of those specified in the <where> field of the Nectarine line in the ChipNDale control panel. Default: the same as the last time around.
where: ROPE ~ CommandTool.NextArgument [cmd];
savedKey: ATOM ~ lastPrint.key;
IF lastPrint.ip.IsEmpty []
THEN
BEGIN
result ← $Failure; msg ← "No Interpress master cached !";
RETURN
END;
IF
NOT where.IsEmpty []
THEN lastPrint.key
← SELECT
TRUE
FROM
where.Equal ["ColorVersatec", FALSE] => $NColorVersatec,
where.Equal ["Color400", FALSE] => $NColor400,
where.Equal ["Raven300", FALSE] => $NRaven300,
where.Equal ["Raven384", FALSE] => $NRaven384,
where.Equal ["Hornet", FALSE] => $NRaven384,
where.Equal ["Bw400", FALSE] => $NBw400,
where.Equal ["Versatec", FALSE] => $NVersatec,
where.Equal ["PlateMaker", FALSE] => $NPlateMaker,
where.Equal ["Tioga", FALSE] => $NPasteInTioga,
where.Equal ["Tioga doc", FALSE] => $NPasteInTioga,
where.Equal ["Paste", FALSE] => $NPasteInTioga,
where.Equal ["Stuff", FALSE] => $NPasteInTioga,
where.Equal ["IP only", FALSE] => $NmasterOnly,
where.Equal ["IP", FALSE] => $NmasterOnly,
where.Equal ["PeachExpand", FALSE] => $NPeachExpand,
where.Equal ["hold", FALSE] => $Nhold,
ENDCASE => $cacca;
SELECT lastPrint.key
FROM
$NmasterOnly => msg ← lastPrint.ip;
$NPasteInTioga =>
BEGIN
The problem here is that now the input focus is in the Command Tool viewer, which surely is not the one into which the poor user wanted to paste his image. Therefore, a new Tioga viewer is created and used as a temporary repository for the image.
Paste [lastPrint.ip, lastPrint.w, TRUE];
msg ← "Image deposed in temporary blinking iconic Tioga viewer."
END;
$cacca =>
BEGIN
lastPrint.key ← savedKey; result ← $Failure; msg ← cmd.procData.doc
END;
ENDCASE =>
BEGIN
rollPaperDeviceHint: REF Imager.Rectangle ← NIL;
IF (lastPrint.w.h > lastPrint.w.w)
THEN
rollPaperDeviceHint ← NEW [Imager.Rectangle ← lastPrint.w];
[] ← Nectarine.Print [lastPrint.ip, lastPrint.key, lastPrint.q, lastPrint.l, rollPaperDeviceHint
! Nectarine.invalidPrinter => {result ← $Failure; msg ← cmd.procData.doc}]
END
END; -- Redo
ExplainGoals:
PROC [] ~
BEGIN
Upon popular demand, we explain the entries in the Where menu.
Plop:
PROC [plup, plip, plap:
ROPE] ~
BEGIN
Plaps plop for plop at plip.
TerminalIO.PutRope [plup.Cat [": print on ", UserProfile.Token [Rope.Cat ["Nectarine.", plup], plip]]];
TerminalIO.PutRope [Rope.Cat [", a ", plap, " printer.\n"]]
END; -- Plop
TerminalIO.PutRope ["The following goals are available for the output:\n"];
TerminalIO.PutRope ["PeachExpand: expand the PD file on "];
TerminalIO.PutRope [UserProfile.Token ["Nectarine.PeachExpand", "Kearsarge"]];
TerminalIO.PutRope [" and send it to "];
TerminalIO.PutRope [UserProfile.Token ["Nectarine.ColorVersatec", "Sleepy"]];
TerminalIO.PutRope [".\n"];
TerminalIO.PutRope ["Tioga doc: copy in the Tioga document at the caret.\n"];
Plop ["Raven300", "Quoth", "black & white XNS Interpress"];
Plop ["Raven384", "your disk", "black & white Press"];
Plop ["Bw400", "MtFuji", "black & white thermal"];
Plop ["Versatec", "Sleepy", "black & white Versatec"];
Plop ["ColorVersatec", "Sleepy", "colour Versatec"];
Plop ["Color400", "MtFuji", "colour thermal"];
Plop ["PlateMaker", "your disk", "Erie"];
TerminalIO.PutRope ["Explain: jot down this explanation.\n"];
TerminalIO.PutRope ["hold: perform only the algorithmic part and store the result in a buffer. The next time 'where' parameter is different from 'hold', prepend to it this buffer and create a multi-page Interpress master.\n\n"];
END; -- ExplainGoals
ImportantMessage:
PROC [msg:
ROPE] ~
BEGIN
Writes a message in the ChipNDale terminal viewer and in the Message Window at the top of the LF screen and makes it blink.
TerminalIO.PutRope [msg]; TerminalIO.PutRope ["\n"];
MessageWindow.Clear []; MessageWindow.Append [msg]; MessageWindow.Blink []
END; -- ImportantMessage
CSTile ← SafeStorage.GetCanonicalReferentType [CStitching.NewTesselation[].FindTile[[0,0]]];
Registations [];
TerminalIO.PutRope ["Nectarine package loaded.\n"];
ExplainGoals []