CDBWVersatecImpl:
CEDAR
MONITOR
IMPORTS Atom, CD, CDApplications, CDBasics, CDCallSpecific, CDEvents, CDExtras, CDIO, CDMenus, CDViewer, CDOps, CDProperties, CDSequencer, CornerStitching, FS, Graphics, GraphicsOps, IO, Menus, Process, Real, STPStreams, TerminalIO, VFonts, ViewerOps
EXPORTS =
BEGIN
maxScanLineWidth: CARDINAL = 7040; -- the wide-bed Versatec
scanLineWidth: CARDINAL ← maxScanLineWidth;
maxPatchHeight: CARDINAL = 144; -- fits in 64k
stippleRepeat: CARDINAL = 16;
Nibble: TYPE = [0..16);
ScanLine: TYPE = PACKED ARRAY [0..0) OF WORD;
ScanLineInNibbles: TYPE = PACKED ARRAY [0..0) OF Nibble;
CodedScanLine:
TYPE =
RECORD [
codeWordCount: CARDINAL ← 0,
codeWords: REF CodeWords ];
CodeWords: TYPE = PACKED ARRAY [0..maxScanLineWidth) OF CodeWord;
CodeWord:
TYPE =
MACHINE
DEPENDENT
RECORD [
repeats (0: 0..3): [1..16],
pattern (0: 4..7): Nibble];
textures: ARRAY CD.Layer OF REF GraphicsOps.Texture ← ALL[NIL];
outLine: BOOL ← TRUE;
skipLayers: BOOL ← FALSE;
allBlack: BOOL ← FALSE;
handleSignalNames: BOOL ← TRUE;
PlotStateRef: TYPE = REF PlotState;
PlotState:
TYPE =
RECORD [
text: REF CornerStitching.Tesselation ← NIL,
tes: ARRAY CD.Layer OF REF CornerStitching.Tesselation ← ALL[NIL],
bitmap: GraphicsOps.BitmapRef ← NIL,
vPatch, context: Graphics.Context ← NIL,
scale: REAL ← 1.0, -- pixels per CD.DesignNumber
totalPlotClip, bandClip:
CD.DesignRect ← [0, 0, 0, 0],
rectangles in design space touching all geometry in the plot, or this band
texture: GraphicsOps.Texture ← ALL[0]
];
currentFlavor: ViewerClasses.ViewerFlavor = $ChipndaleVersatecPlot;
Init:
ENTRY
PROC ~ {
menu: Menus.Menu = Menus.CreateMenu[];
Menus.AppendMenuEntry[menu: menu,
entry: Menus.CreateEntry[name: "AbortPlot", proc: AbortProc, guarded: TRUE]];
CDEvents.RegisterEventProc[$Abort, AbortEvent];
ViewerOps.RegisterViewerClass[flavor: currentFlavor,
class: NEW[ViewerClasses.ViewerClassRec ← [paint: PaintVersatecStripe, menu: menu]]];
CDSequencer.ImplementCommand[a: $VPlotLocal, p: PlotDesignToLocalFile, queue: doQueue];
CDSequencer.ImplementCommand[a: $VPlotPlotter, p: PlotDesignToPlotter, queue: doQueue];
CDSequencer.ImplementCommand[a: $VPlot, p: PlotDesignToAny, queue: doQueue];
CDSequencer.ImplementCommand[a: $VersatecBWPlot, p: PlotDesignToAny, queue: doQueue];
CDMenus.CreateEntry[menu: $HardCopyMenu, entry: "BW Versatec Plot", key: $VersatecBWPlot];
signalFont ← VFonts.GraphicsFont[VFonts.EstablishFont[family: "Helvetica", size: 18, bold: TRUE]];
TerminalIO.WriteRope["ChipNDale BW Versatec plotter loaded\n"];
TerminalIO.WriteRope[" ..use the hardcopy command for plotting..\n"];
};
PlotDesignToAny:
ENTRY
PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
n:
CARDINAL ← TerminalIO.RequestSelection[
label: "Versatec Plot",
choice: LIST[" plotter", " local", " read name"]
];
SELECT n
FROM
1 => PlotDesign[c: c, to: plotter];
2 => PlotDesign[c: c, to: localFile];
3 => PlotDesign[c: c, to: requestFilename];
ENDCASE => TerminalIO.WriteRope["skipped\n"];
END;
PlotDesignToLocalFile:
ENTRY
PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
PlotDesign[c: c, to: localFile];
END;
PlotDesignToPlotter:
ENTRY
PROC [ c: CDSequencer.Command ] =
BEGIN ENABLE UNWIND => NULL;
PlotDesign[c: c, to: plotter];
END;
signalFont: Graphics.FontRef ← NIL;
viewer: ViewerClasses.Viewer ← NIL;
plotter: Rope.ROPE ← "vice";
plotFileToSpool: Rope.ROPE ← "[vice]<sysdir>plot.bits";
plotFileOnPlotter: Rope.ROPE ← "<sysdir>plot.bits";
plotFileOnLocalMachine: Rope.ROPE ← "///chipndale/tem/plot.bits";
latestPlotFile: Rope.ROPE ← NIL;
spoolToPlotter: BOOL ← TRUE;
abortPlot: BOOL ← FALSE;
designIfAbort: CD.Design ← NIL;
AssignTextures:
PROC [usedLayers:
REF
PACKED
ARRAY
CD.Layer
OF
BOOL] =
BEGIN
IF allBlack
THEN {
black: REF GraphicsOps.Texture ← NEW[GraphicsOps.Texture←ALL[0FFH]];
FOR l:
CD.Layer
IN
CD.Layer
DO
-- assign textures to used layers
textures[l] ← black;
ENDLOOP;
}
ELSE {
textureNo: CARDINAL ← 0;
FOR l:
CD.Layer
IN
CD.Layer
DO
-- assign textures to used layers
IF usedLayers[l]
THEN {
textures[l] ← Texture[textureNo];
textureNo ← textureNo+1
}
ELSE textures[l] ← NIL;
ENDLOOP;
}
END;
PlotDesign:
INTERNAL
PROC [ c: CDSequencer.Command, to: {localFile, plotter, requestFilename}] =
BEGIN
s: IO.STREAM ← NIL;
plotClip: CD.DesignRect;
strips: [1..100];
IF ~outLine
OR skipLayers
OR allBlack
OR ~handleSignalNames
THEN
TerminalIO.WriteRope["**WARNING, colors set up different from default\n"];
SELECT TerminalIO.RequestSelection["Plot",
LIST["complete design", "rectangle"]]
FROM
2 => {
plotClip ← CDBasics.ToRect[c.pos, c.sPos];
TerminalIO.WriteRope["plot rectangle\n"];
};
ENDCASE => {
plotClip ← CDExtras.BoundingBox[c.design];
TerminalIO.WriteRope["plot all\n"];
};
strips ← TerminalIO.RequestInt["How many vertical strips in the plot? "];
BEGIN
ENABLE
{ -- for ERRORs
UNWIND => {s ← AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]};
};
design: CD.Design = c.design;
dr: CD.DrawRef = CD.CreateDrawRef[design];
scale:
REAL =
MIN[32.0/
CD.lambda, (
REAL[scanLineWidth]+
REAL[scanLineWidth-100]*(strips-1))/(plotClip.x2-plotClip.x1)];
---Center the x range of the selected area of the design on the plotter bed, with at most 32 pixels per lambda. If multiple strips are called for, overlap adjacent ones by 100 pixels.
patchHeight:
CARDINAL = stippleRepeat*((
MIN[maxPatchHeight,
CARDINAL[Real.Fix[50*
CD.lambda*scale]]]+stippleRepeat-1)/stippleRepeat);
--divisible by stippleRepeat, so that textures work out
bitmap: GraphicsOps.BitmapRef = GraphicsOps.NewBitmap[width: scanLineWidth, height: patchHeight];
ps: PlotStateRef = NEW[ PlotState ← [
text: CornerStitching.NewTesselation[],
scale: scale,
totalPlotClip: plotClip,
bitmap: bitmap,
vPatch: GraphicsOps.NewContextFromBitmap[bitmap]] ];
usedLayers: REF PACKED ARRAY CD.Layer OF BOOL ← NIL;
abortPlot ← FALSE;
designIfAbort ← design;
TerminalIO.WriteRope["Starting Versatec plot "];
TRUSTED {Process.SetPriority[Process.priorityBackground]};
viewer ← ViewerOps.FindViewer["Versatec Stripe"];
IF viewer #
NIL
AND viewer.class.flavor # currentFlavor
THEN
{ViewerOps.DestroyViewer[viewer]; viewer ← NIL};
IF viewer=
NIL
THEN
BEGIN
viewer ← ViewerOps.CreateViewer[flavor: currentFlavor,
info: [name: "Versatec Stripe", iconic: FALSE, openHeight: patchHeight+ViewerSpecs.menuHeight]];
END;
viewer.data ← ps;
dr.minimalSize ← 0;
dr.drawRect ← dr.saveRect ← NoteLayer;
dr.contextFilter ← NEW[CD.ContextFilter←ALL[[doit: TRUE]]];
dr.drawContext ← CheckDrawContext;
dr.devicePrivate ← usedLayers;
dr.interestClip ← CDBasics.universe;
dr.devicePrivate ← usedLayers ← NEW[PACKED ARRAY CD.Layer OF BOOL ← ALL[FALSE]];
CDOps.DrawDesign[design, dr]; -- mark used layers
AssignTextures[usedLayers];
dr.drawRect ← dr.saveRect ← NoteRectangle;
dr.contextFilter ← NIL;
dr.devicePrivate ← ps;
SELECT to
FROM
localFile =>
BEGIN
TerminalIO.WriteRope["onto """];
s ← FS.StreamOpen[plotFileOnLocalMachine, create];
TerminalIO.WriteRope[plotFileOnLocalMachine];
TerminalIO.WriteRope[""""];
s.SetLength[0];
latestPlotFile ← plotFileOnLocalMachine;
END;
requestFilename =>
BEGIN
r: Rope.ROPE ← CDIO.MakeName[TerminalIO.RequestRope["to file ? > "], "bits"];
TerminalIO.WriteRope["onto """];
s ← FS.StreamOpen[r, create];
TerminalIO.WriteRope[r];
TerminalIO.WriteRope[""""];
s.SetLength[0];
latestPlotFile ← r;
END;
plotter =>
BEGIN
TerminalIO.WriteRope["onto plotter "];
[self: s] ← STPStreams.OpenSTP[host: plotter, fileName: plotFileOnPlotter, accessOptions: create];
latestPlotFile ← NIL;
END;
ENDCASE => ERROR;
TRUSTED {
s.PutChar[LOOPHOLE[scanLineWidth/256, CHARACTER]];
s.PutChar[
LOOPHOLE[scanLineWidth
MOD 256]];
send the length of a scan line to the Versatec
IF handleSignalNames
THEN {
TerminalIO.WriteRope["\n.. found "];
TerminalIO.WriteInt[CDCallSpecific.CallForAll[design: design, whatElse: LookForSignalName, x: ps]];
TerminalIO.WriteRope[" top-layer signal names "];
};
SendWhiteBar[s: s];
SendBlackBar[s: s];
FOR strip:
INT
IN [0..strips)
DO
clip: CD.DesignRect = [
x1: plotClip.x1+strip*((plotClip.x2-plotClip.x1)/strips),
y1: plotClip.y1,
x2: plotClip.x1+(strip+1)*((plotClip.x2-plotClip.x1)/strips)+Real.Fix[100./scale]+1,
y2: plotClip.y2];
FOR topLine:
INT ← 0, topLine+patchHeight
WHILE topLine<Real.Fix[scale*(clip.y2-clip.y1)]
DO
x, y, x1, y1, x2, y2: REAL;
dc: CD.DesignRect;
IF abortPlot
THEN
GOTO AbortPlot;
[] ← ps.vPatch.SetPaintMode[opaque];
ps.vPatch.SetColor[Graphics.white];
ps.vPatch.DrawBox[[xmin: 0, ymin: 0, xmax: scanLineWidth, ymax: patchHeight]];
clear the bitmap
[] ← ps.vPatch.SetPaintMode[transparent];
ps.vPatch.SetColor[Graphics.black];
ps.context ← ps.vPatch.CopyContext[];
ps.context.Scale[sx: scale, sy: scale];
[dx: x, dy: y] ← Graphics.Map[sc: ps.vPatch, dc: ps.context,
sx: scanLineWidth/2, sy: topLine+patchHeight-1];
ps.context.Translate[tx: x-(clip.x2+clip.x1)/2, ty: y-clip.y2];
ps.context.ClipBox[box: [xmin: clip.x1, ymin: clip.y1, xmax: clip.x2, ymax: clip.y2]];
clip to the user-specified design rectangle
[dx: x1, dy: y1] ← Graphics.Map[sc: ps.vPatch, dc: ps.context, sx: -1, sy: -1];
[dx: x2, dy: y2] ← Graphics.Map[sc: ps.vPatch, dc: ps.context,
sx: scanLineWidth, sy: patchHeight];
dc ← CDBasics.NormalizeRect[[x1: Real.Fix[x1], y1: Real.Fix[y1], x2: Real.Fix[x2], y2: Real.Fix[y2]]];
ps.bandClip ← dr.interestClip ← [x1:
MAX[plotClip.x1, dc.x1-1], y1:
MAX[plotClip.y1, dc.y1-1], x2:
MIN[plotClip.x2, dc.x2+1], y2:
MIN[plotClip.y2, dc.y2+1]];
rectangle in design space that ChipNDale can use to clip its recursive drawing
CDViewer.ShowArrow[design: design,
pos: [x: (dr.interestClip.x1+dr.interestClip.x2)/2, y: (dr.interestClip.y1+dr.interestClip.y2)/2]];
FOR l:
CD.Layer
IN
CD.Layer
DO
IF ps.tes[l]#NIL THEN CornerStitching.ChangeRect[plane: ps.tes[l], rect: CDBasics.universe, newValue: NIL];
ENDLOOP;
CDOps.DrawDesign[design, dr]; -- build tesselations of the relevant design rectangle
AnalyzeTesselations[ps];
[] ← ps.vPatch.SetPaintMode[opaque];
[] ← ps.text.EnumerateArea[rect: ps.totalPlotClip, perTile: PaintASignalName, data: ps];
ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: topLine=0];
for debugging and to pacify the user
SendBitmap[s: s, bitmap: ps.bitmap];
s.Flush[];
TerminalIO.WriteRope["."];
ENDLOOP;
TerminalIO.WriteRope["*"];
SendBlackBar[s: s];
ENDLOOP;
SendWhiteBar[s: s];
s.Close[];
IF to # plotter AND spoolToPlotter THEN SpoolFileToPlotter[latestPlotFile];
designIfAbort ← NIL;
TerminalIO.WriteRope["finished\n"];
EXITS
AbortPlot => {s ← AbortFile[s]; TerminalIO.WriteRope[" ** plot aborted ** "]; abortPlot ← FALSE};
END;
END;
CheckDrawContext:
PROC [pr:
CD.DrawRef, proc:
CD.DrawContextLayerProc, ob:
CD.ObPtr, pos:
CD.DesignPosition, orient:
CD.Orientation, layer:
CD.Layer] =
BEGIN
IF pr.contextFilter#
NIL
AND pr.contextFilter[layer].doit
THEN {
pr.contextFilter[layer].doit ← FALSE;
TerminalIO.WriteRope[" "];
TerminalIO.WriteRope[CDOps.Info[ob]];
TerminalIO.WriteRope[" (and maybe others) is not rectilinear and will not appear on plot.\n"];
}
END;
NoteLayer:
PROC [ r:
CD.DesignRect, l:
CD.Layer, pr:
CD.DrawRef ] =
BEGIN
ps: REF PACKED ARRAY CD.Layer OF BOOL = NARROW[pr.devicePrivate];
ps[l] ← TRUE;
END;
NoteRectangle:
PROC [ r:
CD.DesignRect, l:
CD.Layer, pr:
CD.DrawRef ] =
BEGIN
ps: PlotStateRef = NARROW[pr.devicePrivate];
IF CDBasics.NonEmpty[r]
THEN {
IF ps.tes[l]=
NIL
THEN {
IF skipLayers
AND
CDProperties.GetPropFromLayer[l, $DrawMeOnBWVersatec]#$DrawMeOnBWVersatec THEN RETURN;
ps.tes[l] ← CornerStitching.NewTesselation[];
};
ps.tes[l].ChangeRect[rect: r, newValue: $covered];
};
END;
AnalyzeTesselations:
PROC [ ps: PlotStateRef ] =
BEGIN
FOR l:
CD.Layer
IN
CD.Layer
DO
IF ps.tes[l]#
NIL
THEN {
ps.texture ← textures[l]^;
[] ← ps.tes[l].EnumerateArea[rect: ps.bandClip, perTile: ProcessTile, data: ps, backgroundValue: $none];
};
ENDLOOP;
END;
ProcessTile:
PROCEDURE [tile: CornerStitching.TilePtr, data:
REF
ANY]
=
-- CornerStitching.PerTileProc --
BEGIN -- only called on covered tiles
t: CornerStitching.TilePtr;
ps: PlotStateRef = NARROW[data];
tileValue: REF = tile.Value;
IF tileValue = $covered
THEN {
r: CD.DesignRect = tile.Area;
GraphicsOps.DrawTexturedBox[self: ps.context, box: [xmin: r.x1, ymin: r.y1, xmax: r.x2, ymax: r.y2], texture: ps.texture];
};
IF outLine
THEN {
--Put lines at boundaries with regions of other color
FOR t ← tile.NEastNeighbour, t.WSouthNeighbour
WHILE tile.SouthEdge<t.NorthEdge
DO
--going south along east edge of tile
IF t.Value#tileValue
THEN {
ps.context.SetCP[x: tile.EastEdge, y: MAX[tile.SouthEdge, t.SouthEdge]];
ps.context.DrawTo[x: tile.EastEdge, y: MIN[tile.NorthEdge, t.NorthEdge]];
};
ENDLOOP;
FOR t ← tile.ENorthNeighbour, t.SWestNeighbour
WHILE tile.WestEdge<t.EastEdge
DO
--going west along north edge of tile
IF t.Value#tileValue
THEN {
ps.context.SetCP[x: MAX[tile.WestEdge, t.WestEdge], y: tile.NorthEdge];
ps.context.DrawTo[x: MIN[tile.EastEdge, t.EastEdge], y: tile.NorthEdge];
};
ENDLOOP;
};
END;
SignalValueRef: TYPE = REF SignalValue;
SignalValue: TYPE = RECORD [s: Rope.ROPE];
LookForSignalName:
PROC [ design:
CD.Design, aptr:
CD.ApplicationPtr, x:
REF ]
RETURNS [done:
BOOL←
TRUE, removeMe:
BOOL←
FALSE, include:
CD.ApplicationList←
NIL,
repaintMe:
BOOL←
FALSE, repaintInclude:
BOOL←
FALSE]
-- CDCallSpecific.CallProc -- =
BEGIN
This area needs considerable improvement. The ultimate goal is to find a place to put the signal name where it will not be confused with any other geometry (than the named piece, or continuations on the same layer) or signal name.
GetSignalName:
PROC [signal:
REF]
RETURNS [s: Rope.
ROPE] =
BEGIN
WITH signal
SELECT
FROM
atom: ATOM => s ← Atom.GetPName[atom];
rope: Rope.ROPE => s ← rope;
ENDCASE => s ← "?";
END;
ps: PlotStateRef = NARROW[x];
r: CD.DesignRect = CDBasics.Intersection[ps.totalPlotClip, CDApplications.ARectO[aptr]];
signal: REF = CDProperties.GetProp[from: aptr, prop: $SignalName];
IF signal #
NIL
AND CDBasics.NonEmpty[r]
THEN
BEGIN
signalValue: SignalValueRef = NEW[SignalValue ← [s: GetSignalName[signal]]];
others: LIST OF REF CornerStitching.Region = NARROW[ps.text.EnumerateArea[rect: r]];
ps.text.ChangeRect[rect: r, newValue: signalValue];
FOR other:
LIST
OF
REF CornerStitching.Region ← others, other.rest
WHILE other#
NIL
DO
ps.text.ChangeRect[rect: other.first.rect, newValue: other.first.value];
ENDLOOP;
END
ELSE done ← FALSE;
END;
PaintASignalName:
PROC [tile: CornerStitching.TilePtr, data:
REF
ANY] =
CornerStitching.PerTileProc --
BEGIN
ps: PlotStateRef = NARROW[data];
textContext: Graphics.Context = ps.vPatch.CopyContext[];
signalValue: SignalValueRef = NARROW[tile.Value[]];
dx, dy, xmin, xmax, ymin, ymax: REAL;
r: CD.DesignRect = CDBasics.Intersection[tile.Area, ps.totalPlotClip];
ctr: CD.DesignPosition = Center[r];
[dx: dx, dy: dy] ← Graphics.Map[sc: ps.context, dc: ps.vPatch,
sx: ctr.x, sy: ctr.y];
[xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] ← Graphics.RopeBox[font: signalFont, rope: signalValue.s];
textContext.Translate[tx: dx-(xmax+xmin)/2, ty: dy-(ymax+ymin)/2]; -- centers the text in r
IF ((xmax-xmin)>(ymax-ymin)) # ((r.x2-r.x1)>(r.y2-r.y1))
THEN
textContext.Rotate[270];
textContext.SetColor[Graphics.white];
textContext.DrawBox[[xmin: -2, ymin: -2, xmax: xmax-xmin+2, ymax: ymax-ymin+2]];
leave a two-scan-line white patch all around
textContext.SetColor[Graphics.black];
textContext.SetCP[x: 0, y: 0];
textContext.DrawRope[rope: signalValue.s, font: signalFont];
END;
Center:
PROC [ r:
CD.Rect ]
RETURNS [
CD.Position ] =
{RETURN[[x: (r.x1+r.x2)/2, y: (r.y1+r.y2)/2]]};
SendWhiteBar:
PROC [ s:
IO.
STREAM, lines:
CARDINAL ← 40 ] =
{SendBar[s, 0, lines]};
SendBlackBar:
PROC [ s:
IO.
STREAM, lines:
CARDINAL ← 20 ] =
{SendBar[s, 15, lines]};
SendBar:
PROC [ s:
IO.
STREAM, pattern: Nibble, lines:
CARDINAL ] =
BEGIN
scanLineNibbles: CARDINAL = scanLineWidth/4;
FOR j:
CARDINAL
IN [0..lines)
DO
FOR i:
CARDINAL
IN [0..(scanLineNibbles+15)/16)
DO
TRUSTED {s.PutChar[LOOPHOLE[CodeWord[repeats: MIN[16, scanLineNibbles-16*i], pattern: pattern]]]};
ENDLOOP;
ENDLOOP;
END;
SendBitmap:
PROC [ s:
IO.
STREAM, bitmap: GraphicsOps.BitmapRef ] =
BEGIN
csl: REF CodedScanLine = NEW[CodedScanLine ← [codeWords: NEW[CodeWords]]];
FOR i:
CARDINAL
IN [0..bitmap.height)
DO
-- send to the Versatec
TRUSTED {
EncodeScanLine[sl: LOOPHOLE[LOOPHOLE[bitmap.base, INT]+INT[bitmap.raster]*i, LONG POINTER TO ScanLine], bitWidth: bitmap.width, csl: csl];
s.UnsafePutBlock[[base: LOOPHOLE[csl.codeWords], startIndex: 0,
count: csl.codeWordCount]];
}
ENDLOOP;
END;
EncodeScanLine:
PROC [ sl:
LONG
POINTER
TO ScanLine, bitWidth:
CARDINAL, csl:
REF CodedScanLine ] =
TRUSTED BEGIN
size: CARDINAL ← 0;
scanLineInNibbles: LONG POINTER TO ScanLineInNibbles = LOOPHOLE[sl];
scanLineNibbles: CARDINAL = (bitWidth+3)/4;
i: CARDINAL ← 0;
WHILE i<scanLineNibbles
DO
pattern: Nibble = scanLineInNibbles[i];
j: CARDINAL ← i+1;
limit: CARDINAL ← MIN[scanLineNibbles, i+16];
WHILE j<limit
DO
IF scanLineInNibbles[j]#pattern THEN EXIT;
j ← j+1;
ENDLOOP;
csl.codeWords[size] ← [repeats: j-i, pattern: pattern];
size ← size+1;
i ← j;
ENDLOOP;
csl.codeWordCount ← size;
END;
Texture:
PROC [ index:
CARDINAL ]
RETURNS [
REF GraphicsOps.Texture ] =
BEGIN
t: REF GraphicsOps.Texture ← NEW[GraphicsOps.Texture];
FOR i: [0..16)
IN [0..16)
DO
Stipple: TYPE = ARRAY [0..4) OF [0..16);
row: [0..4) = i MOD 4;
t[i] ← (4096+256+16+1)*(
SELECT index
FROM
0 => Stipple[01H, 02H, 04H, 08H],
1 => Stipple[04H, 02H, 01H, 08H],
2 => Stipple[00H, 0AH, 00H, 0AH],
3 => Stipple[08H, 00H, 08H, 00H],
4 => Stipple[0AH, 00H, 00H, 00H],
5 => Stipple[08H, 00H, 02H, 00H],
6 => Stipple[00H, 01H, 00H, 04H],
7 => Stipple[04H, 04H, 00H, 00H],
8 => Stipple[00H, 00H, 00H, 03H],
ENDCASE => Stipple[0FH, 0FH, 0FH, 0FH])[row];
ENDLOOP;
RETURN[t];
END;
PaintVersatecStripe:
PROC [ self: ViewerClasses.Viewer, context: Graphics.Context,
whatChanged:
REF
ANY, clear:
BOOL ]
-- ViewerClasses.PaintProc -- =
BEGIN
ps: PlotStateRef = NARROW[self.data];
x: INT = MAX[INT[0], (ps.bitmap.width-self.cw)/2];
y: INT = MAX[INT[0], (ps.bitmap.height-self.ch)/2];
context.SetCP[self.cw/2, self.ch/2];
GraphicsOps.DrawBitmap[self: context, bitmap: ps.bitmap,
w: MIN[self.cw, ps.bitmap.width], h: MIN[self.ch, ps.bitmap.height],
x: x, y: y, xorigin: ps.bitmap.width/2, yorigin: ps.bitmap.height/2];
END;
AbortProc: Menus.MenuProc = {abortPlot ← TRUE};
AbortEvent: CDEvents.EventProc = {
IF designIfAbort#
NIL
AND (design=
NIL
OR design=designIfAbort)
THEN {
abortPlot ← TRUE; designIfAbort ← NIL
}
};
AbortFile:
PROC [s:
IO.
STREAM ]
RETURNS [
IO.
STREAM ] =
{IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]};
SpoolToPlotter:
ENTRY
PROC = {SpoolFileToPlotter[latestPlotFile]};
SpoolFileToPlotter:
PROC [name: Rope.
ROPE] =
BEGIN
IF name #
NIL
THEN {
TerminalIO.WriteRope["spool file """];
TerminalIO.WriteRope[name];
TerminalIO.WriteRope[""".."];
FS.Copy[from: name, to: plotFileToSpool !
FS.Error =>
IF error.group # bug
THEN {
TerminalIO.WriteRope[" not done: "];
TerminalIO.WriteRope[error.explanation];
TerminalIO.WriteLn[];
CONTINUE;
}
];
TerminalIO.WriteRope[" spool finished\n"];
};
END;
Module START code...
END. -- of VersatecImpl