SilDisplayUtilsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
See also SilDisplayUtilsImplA.mesa
Tracy Larrabee: March 29, 1984 1:37:04 pm PST
Last Edited by Ken Pier, May 7, 1986 10:34:48 am PDT
A module implementing some display service routines.
DIRECTORY
Ascii USING
[BS, ControlA, ControlQ, ControlW, CR, DEL, Digit, ESC, SP],
BiScrollers USING
[BiScroller, QuaViewer, ViewportBox],
ImagerFont USING
[Extents, Font, RopeBoundingBox],
FileNames USING
[GetShortName, Directory],
FS USING
[Error, FileInfo],
Geom2D USING
[id, Rect],
Imager USING
[black, Box, Color, MakeGray, Context, MaskRectangleI, Rectangle, Scale2T, ScaleT, SetColor, SetPriorityImportant, TranslateT, white ],
ImagerBackdoor USING
[GetT, SetT, GetBounds],
ImagerInterpress USING
[Ref, Create, DoPage, Close],
ImagerPress USING
[SimpleCreate, NewPage, DoWithWarnings, Close, Warning, PrinterType],
ImagerTransformation USING
[PostScale2, PostTranslate, TransformRectangle],
MessageWindow USING
[Append, Blink],
Real USING
[Fix, RoundI, RealException],
RefText USING
[AppendChar, SkipTo],
Rope USING
[Cat, Concat, Equal, Fetch, Find, FromChar, Length, ROPE, Substr, SkipTo, ToRefText],
UserProfile USING
[ListOfTokens],
ViewerClasses USING
[Viewer],
ViewerOps USING
[PaintViewer, SetNewVersion],
SilColor,
SilDisplayInternal,
SilDisplay,
SilDisplayUtils,
SilFile,
SilKernel,
SilUserInput
;
SilDisplayUtilsImpl: CEDAR MONITOR
IMPORTS Ascii, BiScrollers, FileNames, FS, Geom2D, Imager, ImagerBackdoor, ImagerFont, ImagerInterpress, ImagerPress, ImagerTransformation, MessageWindow, Real, Rope, RefText, UserProfile, SilFile, SilDisplay, SilUserInput, ViewerOps, SilColor, SilKernel, SilDisplayUtils
EXPORTS SilDisplayUtils, SilKernel
= BEGIN OPEN SilFile;
ROPE: TYPE = Rope.ROPE;
SilData: TYPE = SilKernel.SilData;
SilDisplayData: TYPE = REF SilDisplayDataRec;
SilDisplayDataRec: PUBLIC TYPE = SilDisplayInternal.SilDisplayDataRec;
SilModel: TYPE = SilFile.SilModel;
SilUIData: TYPE = SilKernel.SilUIData;
ContextChoice: TYPE = SilDisplayUtils.ContextChoice;
AttributeRec: TYPE = SilDisplayUtils.AttributeRec;
Orientation: TYPE = SilDisplayUtils.Orientation;
BoxEnd: TYPE = SilDisplayUtils.BoxEnd;
FileType: TYPE = SilDisplayUtils.FileType;
metersPerPoint: REAL = .0254/72.0; -- DO NOT USE Imager.metersPerPoint where point=72.27
pointsPerInch: REAL = 72.0; -- DO NOT USE Imager.pointsPerInch where point=72.27
margin: INTEGER ← 9; -- 1/4 inch (i.e.2*9=18) points
ModifyContext: PUBLIC PROC [makeContext: ContextChoice ← normal, dData: SilDisplayData, ctx: Imager.Context] = {
Modify the context to reflect the current state of the window as supplied in the display data.
IF ctx = NIL THEN RETURN;
IF makeContext = magnified THEN {
dData.trans ← ImagerBackdoor.GetT[ctx]; -- save transformation for later
Imager.ScaleT[ctx, dData.currentMagnification];
Imager.TranslateT[ctx, [dData.xOffset, dData.yOffset]];
}
ELSE ImagerBackdoor.SetT[ctx, dData.trans]; -- restore transformation
};
MagnifyDrawing: PUBLIC PROC [data: SilData, ctx: Imager.Context, xMin, yMin, xMax, yMax: INTEGER] = {
Enter Magnify mode. Modify the display of the drawing and the state of the display data to reflect the change. Send the boundin box of the region intended to be magnified.
largeMagnification: INTEGER = 10;
maxMagnification: INTEGER = SilDisplayInternal.maxMagnification;
dData: SilDisplayData ← data.displayData;
bxMin, byMin, bxMax, byMax: INTEGER;
[bxMin, byMin, bxMax, byMax] ← BoundingBoxOfContext [ctx];
Imager.SetColor[ctx, Imager.white];
Imager.MaskRectangleI[ctx, bxMin, byMin, bxMax - bxMin, byMax - byMin];
dData.magnificationOn ← NOT dData.magnificationOn;
IF dData.magnificationOn THEN {
bs: BiScrollers.BiScroller ← SilUserInput.GetBiScroller[data.uiData];
bb: Geom2D.Rect ← BiScrollers.ViewportBox[bs]; -- rect: x,y,w,h
dData.currentMagnification ← Real.RoundI[MIN[
IF xMax - xMin # 0 THEN bb.w / (xMax - xMin) ELSE largeMagnification,
IF yMax - yMin # 0 THEN bb.h / (yMax - yMin) ELSE largeMagnification,
maxMagnification]];
dData.xOffset ← bb.x/dData.currentMagnification - xMin;
dData.yOffset ← bb.y/(-dData.currentMagnification) - yMax;
ModifyContext[magnified, dData, ctx];
}
ELSE {
dData.currentMagnification ← 1;
dData.xOffset ← 0;
dData.yOffset ← 0;
ModifyContext[normal, dData, ctx];
};
SilUserInput.MagnifyGrid[data.uiData, dData.xOffset, dData.yOffset, dData.currentMagnification];
[xMin, yMin, xMax, yMax] ← BoundingBoxOfContext [ctx];
MergeRebuild[dData, data.model, xMin, yMin, xMax, yMax];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Mag, intArg1: dData.currentMagnification]
};
SilRebuild: PUBLIC PROC [data: SilData, ctx: Imager.Context] = {
Rebuild the display inside the box given in dData.
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
sSel: SilSelection ← SilFile.GetSelection[];
cxMin, cyMin, cxMax, cyMax: INTEGER;
[xMin: cxMin, yMin: cyMin, xMax: cxMax, yMax: cyMax] ← BoundingBoxOfContext[ctx];
SELECT dData.rebuildStage FROM
Background => { --Do background main picture objects
WHILE dData.currentBkgndObj # NIL AND NOT SilUserInput.InputAvailable[uiData] DO
IF IBBoxFilter[cxMin, cyMin, cxMax, cyMax, dData.currentBkgndObj.first] AND IBBoxFilter[dData.rebuildMinX, dData.rebuildMinY, dData.rebuildMaxX, dData.rebuildMaxY, dData.currentBkgndObj.first] AND NOT (model=sSel.model AND dData.currentBkgndObj.first.selectObj#NIL) THEN
SilDisplayUtils.PaintObject[model, dData.currentBkgndObj.first, show, ctx];
dData.currentBkgndObj ← dData.currentBkgndObj.rest;
ENDLOOP;
IF dData.currentBkgndObj = NIL THEN { --Reached end, now do next
IF sSel.model = model THEN {
dData.rebuildStage ← SelectedBackground;
dData.currentBkgndObj ← sSel.objects;
}
ELSE {
dData.currentFgndObj ← GetObjectList[model, fgnd];
dData.rebuildStage ← Foreground;
};
SilRebuild[data, ctx];
};
};
SelectedBackground => { --Do selected background objects
WHILE dData.currentBkgndObj # NIL AND NOT SilUserInput.InputAvailable[uiData] DO
IF dData.currentBkgndObj.first.font IN InternalBackgroundBoxFonts AND IBBoxFilter[cxMin, cyMin, cxMax, cyMax, dData.currentBkgndObj.first] AND IBBoxFilter[dData.rebuildMinX, dData.rebuildMinY, dData.rebuildMaxX, dData.rebuildMaxY, dData.currentBkgndObj.first] THEN
SilDisplayUtils.PaintObject[model, dData.currentBkgndObj.first, select, ctx]; --selected object
dData.currentBkgndObj ← dData.currentBkgndObj.first.selectObj;
ENDLOOP;
IF dData.currentBkgndObj = NIL THEN { --Reached the end of selected objects
IF dData.selectedOnly THEN {
IF sSel.model = model THEN dData.currentFgndObj ← sSel.objects
ELSE dData.currentFgndObj ← NIL;
dData.rebuildStage ← SelectedForeground;
}
ELSE {
dData.currentFgndObj ← GetObjectList[model, fgnd];
dData.rebuildStage ← Foreground;
};
SilRebuild[data, ctx];
};
};
SelectedForeground => { --Do selected objects
WHILE dData.currentFgndObj # NIL AND NOT SilUserInput.InputAvailable[uiData] DO
IF NOT dData.currentFgndObj.first.font IN InternalBackgroundBoxFonts AND IBBoxFilter[cxMin, cyMin, cxMax, cyMax, dData.currentFgndObj.first] AND IBBoxFilter[dData.rebuildMinX, dData.rebuildMinY, dData.rebuildMaxX, dData.rebuildMaxY, dData.currentFgndObj.first] THEN
SilDisplayUtils.PaintObject[model, dData.currentFgndObj.first, select, ctx]; --selected object
dData.currentFgndObj ← dData.currentFgndObj.first.selectObj;
ENDLOOP;
IF dData.currentFgndObj = NIL THEN { --Reached the end of selected objects, now done
IF dData.ticsOn THEN
DisplayTicBox[show, dData, model, ctx, dData.rebuildMinX, dData.rebuildMinY, dData.rebuildMaxX, dData.rebuildMaxY];
IF dData.framesOn THEN {
xMin, yMin, xMax, yMax: INTEGER;
[xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax] ← BoundingBoxOfContext[ctx];
DisplayFrameBoxes[show, dData, model, ctx, xMin, yMin, xMax, yMax];
};
dData.inRebuild ← FALSE;
dData.needRebuild ← FALSE;
};
};
Foreground => { --Do main picture objects
WHILE dData.currentFgndObj # NIL AND NOT SilUserInput.InputAvailable[uiData] DO
IF IBBoxFilter[cxMin, cyMin, cxMax, cyMax, dData.currentFgndObj.first] AND IBBoxFilter[dData.rebuildMinX, dData.rebuildMinY, dData.rebuildMaxX, dData.rebuildMaxY, dData.currentFgndObj.first] AND NOT (model=sSel.model AND dData.currentFgndObj.first.selectObj#NIL) THEN
SilDisplayUtils.PaintObject[model, dData.currentFgndObj.first, show, ctx];
dData.currentFgndObj ← dData.currentFgndObj.rest;
ENDLOOP;
IF dData.currentFgndObj = NIL THEN { --Reached the end of the objects, now do next
dData.rebuildStage ← SelectedForeground;
IF sSel.model = model THEN dData.currentFgndObj ← sSel.objects
ELSE dData.currentFgndObj ← NIL;
SilRebuild[data, ctx];
};
};
ENDCASE => NULL;
};
MergeRebuild: PUBLIC PROC [dData: SilDisplayData, model: SilModel, xMin, yMin, xMax, yMax: INTEGER, selectedOnly: BOOLFALSE] = {
Set the fields in dData to reflect the fact that any current rebuilds should include the box defined by xMin, yMin, xMax, yMax. If SelectedOnly then only rebuild the selected objects.
IF dData.inRebuild THEN {
xMin ← MIN[xMin, dData.rebuildMinX];
yMin ← MIN[yMin, dData.rebuildMinY];
xMax ← MAX[xMax, dData.rebuildMaxX];
yMax ← MAX[yMax, dData.rebuildMaxY];
selectedOnly ← (dData.rebuildStage = SelectedBackground OR
dData.rebuildStage = SelectedForeground) AND selectedOnly;
};
dData.needRebuild ← TRUE;
dData.rebuildMinX ← xMin;
dData.rebuildMinY ← yMin;
dData.rebuildMaxX ← xMax;
dData.rebuildMaxY ← yMax;
dData.inRebuild ← TRUE;
dData.selectedOnly ← selectedOnly;
dData.rebuildStage ← IF selectedOnly THEN SelectedBackground ELSE Background;
IF NOT selectedOnly THEN {
dData.currentFgndObj ← GetObjectList[model, fgnd];
dData.currentBkgndObj ← GetObjectList[model, bkgnd];
}
ELSE {
dData.currentFgndObj ← GetSelection[].objects;
dData.currentBkgndObj ← GetSelection[].objects;
};
};
ExpandMacro: PUBLIC PROC [model: SilModel, char: CHAR, x, y: INTEGER, oneLevel: BOOL, ctx: Imager.Context] = {
Expand the Macro Given. If oneLevel then don't expand any contained macros.
FOR s: SilObject ← GetObjectList[model, macro, InternalFileMacroFont, char], s.rest WHILE s # NIL DO
macElem: SilObjectRec ← s.first;
macElem.xMin ← macElem.xMin + x;
macElem.yMin ← macElem.yMin + y;
macElem.xMax ← macElem.xMax + x;
macElem.yMax ← macElem.yMax + y;
If a library uses a macro, it must be a macro in its own font
IF macElem.font IN SilFile.InternalFileMacroFonts AND NOT oneLevel THEN
ExpandMacro[model, Rope.Fetch[macElem.value], macElem.xMin, macElem.yMin, oneLevel, ctx]
ELSE {
SilFile.DefineSelectWithObject[model, SilFile.AddObjectToMainPicture[model, macElem]];
SilDisplayUtils.PaintObject[model, macElem, select, ctx];
};
ENDLOOP;
};
EraseArea: PUBLIC PROC [xMin, yMin, xMax, yMax: INTEGER, ctx: Imager.Context] = {
Erase an area of the screen. Used for making sure the screen starts from scratch.
Imager.SetColor[ctx, Imager.white];
Imager.MaskRectangleI[ctx, xMin, yMin, xMax - xMin, yMax - yMin];
};
MergeArea: PUBLIC PROC [dData: SilDisplayData, model: SilModel, xMin, yMin, xMax, yMax: INTEGER, ctx: Imager.Context] = {
merge an area into the area needing rebuilding
MergeRebuild[dData: dData, model: model, xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax, selectedOnly: FALSE];
};
BBoxFilter: PUBLIC PROC [xMin, yMin, xMax, yMax: INTEGER, sobr: SilObjectRec] RETURNS [BOOL] = {
RETURN TRUE if some part of sobr appears inside the box.
RETURN[ NOT (yMin > sobr.yMax OR xMin > sobr.xMax OR yMax < sobr.yMin OR xMax < sobr.xMin)];
};
IBBoxFilter: PROC [xMin, yMin, xMax, yMax: INTEGER, sobr: SilObjectRec] RETURNS [BOOL] = INLINE {
INLINE COPY OF BBoxFilter
RETURN[ NOT (yMin > sobr.yMax OR xMin > sobr.xMax OR yMax < sobr.yMin OR xMax < sobr.xMin)];
};
AttributeFromChar: PUBLIC PROC [char: CHAR] RETURNS [AR: AttributeRec] ={
Return information about which attribute is referenced by the given char.
char = 0-9 => font.
char = D,R,O,Y,L,G,T,C,A,V,U,M,P,S,N,or W => color.
char = b,B,i,or I => face.
hue: INTEGER ← Rope.Find[SilColor.colorOrder, Rope.FromChar[char], 0, FALSE];
SELECT TRUE FROM
Ascii.Digit[char] => RETURN[ [referenced: font, font: char - '0] ];
hue # -1  => RETURN[ [referenced: color, color: hue] ];
char = 'b  => RETURN[ [referenced: face, face: bold] ];
char = 'B  => RETURN[ [referenced: face, face: nonBold] ];
char = 'i  => RETURN[ [referenced: face, face: italic] ];
char = 'I  => RETURN[ [referenced: face, face: nonItalic] ];
ENDCASE  => RETURN[ [referenced: invalid] ];
};
AttributeFilter: PUBLIC PROC [AR: AttributeRec, sobr: SilObjectRec] RETURNS [passed: BOOL] = {
The AttributeRec contains a discription of certain attributes which sobr may or may not have Return TRUE if sobr has the attribute described in AR.
SELECT AR.referenced FROM
color => RETURN [sobr.color = AR.color];
font => RETURN [SilFile.InternalFontFromUserFont[AR.font, TRUE] = sobr.font OR SilFile.InternalFontFromUserFont[AR.font, FALSE] = sobr.font];
face => SELECT AR.face FROM
italic => RETURN [sobr.italic];
nonItalic => RETURN [NOT sobr.italic];
bold => RETURN [SilFile.FontIsBold[sobr.font] ];
nonBold => RETURN [NOT SilFile.FontIsBold[sobr.font] ];
ENDCASE;
ENDCASE;
};
OffsetFilter: PUBLIC PROC [sobr: SilObjectRec, offsetDirection: Orientation, offset, xMin, yMin, xMax, yMax: INTEGER] RETURNS [passed: BOOLFALSE, bEnd: BoxEnd ← long] = {
Return TRUE if sobr represents a box with just one end inside the box defined by xMin, yMin, xMax, yMax and could be appropriately shortened or lengthened in the direction and by the amount given.
IF sobr.font NOT IN InternalBoxFonts THEN RETURN [passed: FALSE];
SELECT offsetDirection FROM
vertical => {
IF sobr.yMax - sobr.yMin <= sobr.xMax - sobr.xMin THEN RETURN [passed: FALSE];
IF sobr.xMin < xMin OR sobr.xMin > xMax THEN RETURN [passed: FALSE];
IF sobr.yMin >= yMin AND sobr.yMin <= yMax AND sobr.yMax > yMax THEN
IF sobr.yMin + offset < sobr.yMax THEN RETURN [passed: TRUE, bEnd: short];
IF sobr.yMax >= yMin AND sobr.yMax <= yMax AND sobr.yMin < yMin THEN
IF sobr.yMax + offset > sobr.yMin THEN RETURN [passed: TRUE, bEnd: long];
IF (sobr.yMax + sobr.yMin) / 2 >= yMin
AND (sobr.yMax + sobr.yMin) / 2 <= yMax THEN RETURN [passed: FALSE];
RETURN [passed: FALSE];
};
horizontal => {
IF sobr.xMax - sobr.xMin <= sobr.yMax - sobr.yMin THEN RETURN[passed: FALSE];
IF sobr.yMin < yMin OR sobr.yMin > yMax THEN RETURN [passed: FALSE];
IF sobr.xMin >= xMin AND sobr.xMin <= xMax AND sobr.xMax > xMax THEN
IF sobr.xMin + offset < sobr.xMax THEN RETURN [passed: TRUE, bEnd: short];
IF sobr.xMax >= xMin AND sobr.xMax <= xMax AND sobr.xMin < xMin THEN
IF sobr.xMax + offset > sobr.xMin THEN RETURN [passed: TRUE, bEnd: long];
IF (sobr.xMax + sobr.xMin) / 2 >= xMin
AND (sobr.xMax + sobr.xMin) / 2 <= xMax THEN RETURN [passed: FALSE];
RETURN [passed: FALSE];
};
ENDCASE;
};
StretchBox: PUBLIC PROC [sob: SilObject, offsetDirection: Orientation, bEnd: BoxEnd, offset: INTEGER] = {
Stretch the box given by sob by the amount given by offset in the direction given by offsetDirection at the box end given by bEnd.
SELECT offsetDirection FROM
vertical => SELECT bEnd FROM
long => sob.first.yMax ← sob.first.yMax + offset;
short => sob.first.yMin ← sob.first.yMin + offset;
ENDCASE;
horizontal => SELECT bEnd FROM
long => sob.first.xMax ← sob.first.xMax + offset;
short => sob.first.xMin ← sob.first.xMin + offset;
ENDCASE;
ENDCASE;
};
FixBoxConnectivity: PUBLIC PROC [dData: SilDisplayData, sobrIn: SilObjectRec, boxDir: Orientation] RETURNS [sobr: SilObjectRec] = {
Figure out from the dData given if the current box is going to have to be extended by a box length in order to provide a nice connection in the lower right hand corner (you may have to draw a few boxes in Sil to feel comfortable with this statement).
sobr ← sobrIn;
SELECT boxDir FROM
vertical => {
IF dData.lastBoxLeftToRight AND sobr.xMin = dData.lastBoxPointX AND sobr.yMax = dData.lastBoxPointY THEN sobr.yMax ← sobr.yMax + dData.currentBoxWidth;
dData.lastBoxTopToBottom ← TRUE;
dData.lastBoxPointX ← sobr.xMin;
dData.lastBoxPointY ← sobr.yMax;
};
horizontal => {
IF dData.lastBoxTopToBottom AND sobr.xMax = dData.lastBoxPointX AND sobr.yMin = dData.lastBoxPointY THEN sobr.xMax ← sobr.xMax + dData.currentBoxWidth;
dData.lastBoxLeftToRight ← TRUE;
dData.lastBoxPointX ← sobr.xMax;
dData.lastBoxPointY ← sobr.yMin;
};
ENDCASE;
};
BoundingBoxOfContext: PUBLIC PROC [ctx: Imager.Context] RETURNS [xMin, yMin, xMax, yMax: INTEGER] = {
Return the bounding box of the context given, in client coordinates.
rect: Imager.Rectangle ← ImagerBackdoor.GetBounds[context: ctx]; --returns client coordinates
xMin ← Real.RoundI[rect.x];
yMin ← Real.RoundI[rect.y];
xMax ← Real.RoundI[rect.x + rect.w];
yMax ← Real.RoundI[rect.y + rect.h];
};
DeselectAndPaintAll: PUBLIC ENTRY PROC [model: SilModel, ctx: Imager.Context] = {
Deselect all of the objects which are currently selected.
LocalPASAD[model, ctx];
SilFile.DeselectAll[];
};
PaintAllSelectedAsDeselected: PUBLIC ENTRY PROC [model: SilModel, ctx: Imager.Context] = {
LocalPASAD[model: model, ctx: ctx];
};
LocalPASAD: PROC [model: SilModel, ctx: Imager.Context] = {
If there are objects selected from this model, paint all of them as deselected, but dont change the data structure.
bXmin, bYmin, bXmax, bYmax: INTEGER;
sSel: SilSelection ← GetSelection[];
IF model # sSel.model THEN RETURN;
[bXmin, bYmin, bXmax, bYmax] ← BoundingBoxOfContext [ctx];
FOR s: SilObject ← sSel.objects, s.first.selectObj WHILE s # sSel.lastObject DO
IF IBBoxFilter[bXmin, bYmin, bXmax, bYmax, s.first] THEN
SilDisplayUtils.PaintObject[model, s.first, show, ctx]; --UNselect all objects
ENDLOOP;
};
DisplayGrid: PUBLIC PROC [eraseOrShow: SilDisplayUtils.DisplayChoice, dData: SilDisplayData, model: SilModel, ctx: Imager.Context] = {
Erase or display the grids as specified in dData.
bXmin, bYmin, bXmax, bYmax: INTEGER;
[bXmin, bYmin, bXmax, bYmax] ← BoundingBoxOfContext [ctx];
DisplayTicBox[eraseOrShow, dData, model, ctx, bXmin, bYmin, bXmax, bYmax];
};
DisplayTicBox: PROC [eraseOrShow: SilDisplayUtils.DisplayChoice, dData: SilDisplayData, model: SilModel, ctx: Imager.Context, xMin, yMin, xMax, yMax: INTEGER] = {
Erase or display the tics in the box given as specified in dData.
ticSpacing: INTEGER ← dData.ticSpacing;
startX: INTEGER ← (xMin / ticSpacing) * ticSpacing;
startY: INTEGER ← (yMin / ticSpacing) * ticSpacing;
IF startX < xMin THEN startX ← startX + ticSpacing;
IF startY < yMin THEN startY ← startY + ticSpacing;
IF eraseOrShow = erase THEN Imager.SetColor[ctx, Imager.white]
ELSE Imager.SetColor[ctx, Imager.black];
FOR j: INTEGER ← startY, j + ticSpacing WHILE j <= yMax DO
FOR i: INTEGER ← startX, i + ticSpacing WHILE i <= xMax DO
Imager.MaskRectangleI[ctx, i, j, 1, 1];
ENDLOOP;
ENDLOOP;
IF eraseOrShow = erase THEN
MergeRebuild[dData, model, xMin, yMin, xMax, yMax];
};
DisplayFrames: PUBLIC PROC [eraseOrShow: SilDisplayUtils.DisplayChoice, dData: SilDisplayData, model: SilModel, ctx: Imager.Context] = {
Erase or display the page frames as specified in dData.
xMin, yMin, xMax, yMax: INTEGER;
[xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax] ← BoundingBoxOfContext[ctx: ctx];
DisplayFrameBoxes[eraseOrShow, dData, model, ctx, xMin, yMin, xMax, yMax];
};
DisplayFrameBoxes: PROC [eraseOrShow: SilDisplayUtils.DisplayChoice, dData: SilDisplayData, model: SilModel, ctx: Imager.Context, xMin, yMin, xMax, yMax: REAL] = {
Erase or display the page frames in the box given. Frames are constrained to lie on a four pixel boundary.
Fix: PRIVATE PROC [r: REAL] RETURNS[INT] = { RETURN[Real.Fix[r]] };
Floor: PRIVATE PROC [a: REAL] RETURNS[c: REAL] = {
c ← Fix[a ! Real.RealException => { c ← a; CONTINUE }];
IF c>a THEN RETURN[c-1] ELSE RETURN[c];
};
DrawFrame: PROC [xMin, yMin, xMax, yMax: INTEGER, mode: SilDisplayUtils.DisplayChoice, lineW: NAT] = {
IF mode = erase THEN Imager.SetColor[ctx, Imager.white]
ELSE Imager.SetColor[ctx, frameColor];
Imager.MaskRectangleI[ctx, xMin, yMin, xMax-xMin, lineW];
Imager.MaskRectangleI[ctx, xMin, yMin, lineW, yMax-yMin];
Imager.MaskRectangleI[ctx, xMax, yMin, lineW, yMax-yMin];
Imager.MaskRectangleI[ctx, xMin, yMax, xMax-xMin, lineW];
};
marginX, marginY: INTEGER ← margin;
pageXSize: REAL ← 8.5;
pageYSize: REAL ← 11.0;
mXMinI, mYMinI, mXMaxI, mYMaxI: INTEGER ← 0;
xMin4, yMin4, xMax4, yMax4: INTEGER ← 0;
pageXPoints, pageYPoints: INTEGER;
frameColor: Imager.Color ← Imager.MakeGray[f: 0.5];
THE FOLLOWING CODE STOLEN FROM HardcopyFile
pageXPoints ← Real.RoundI[pageXSize*pointsPerInch] - 2*marginX; --framed part
pageYPoints ← Real.RoundI[pageYSize*pointsPerInch]- 2*marginY; --framed part
mXMinI ← Real.RoundI[Floor[xMin/pageXPoints] * pageXPoints]; --round to nearest page boundary
mYMinI ← Real.RoundI[Floor[yMin/pageYPoints] * pageYPoints];
mXMaxI ← Real.RoundI[xMax];
mYMaxI ← Real.RoundI[yMax];
FOR x: INTEGER ← mXMinI, x + pageXPoints UNTIL x > mXMaxI DO
FOR y: INTEGER ← mYMinI, y+pageYPoints UNTIL y > mYMaxI DO
xMin4 ← (x+marginX)+(4-((x+marginX) MOD 4)); -- round up to nearest four pixels
yMin4 ← (y+marginY)+(4-((y+marginY) MOD 4));
xMax4 ← (x+pageXPoints-marginX)-((x+pageXPoints-marginX) MOD 4); --round down
yMax4 ← (y+pageYPoints-marginY)-((y+pageYPoints-marginY) MOD 4);
DrawFrame[xMin: xMin4, yMin: yMin4, xMax: xMax4, yMax: yMax4, mode: eraseOrShow, lineW: 2];
ENDLOOP;
ENDLOOP;
IF eraseOrShow = erase THEN
MergeRebuild[dData, model, mXMinI, mYMinI, mXMaxI, mYMaxI];
};
AbortRopeInput: PUBLIC PROC [data: SilData, markX, markY: INTEGER, ctx: Imager.Context] = {
Call this if the user was inputting a rope, but changed his mind for some reason.
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
uiData: SilUIData ← data.uiData;
SELECT dData.mode FROM
InputingRope => IF dData.collectingObject.value # NIL THEN {
xMin, yMin, xMax, yMax: INTEGER;
IF Rope.Length[dData.collectingObject.value] > 0 THEN {
SilDisplayUtils.PaintObject[model, dData.collectingObject, erase, ctx];
[xMin, yMin, xMax, yMax] ← BoundingBoxOfObject[data.model, dData.collectingObject];
MergeRebuild[dData, model,
dData.collectingObject.xMin + xMin, dData.collectingObject.yMin + yMin, dData.collectingObject.xMin + xMax, dData.collectingObject.yMin + yMax];
};
dData.collectingText.length ← 0;
};
InputingInputFileName, EditingExistingInputFileName,
InputingOutputFileName, EditingExistingOutputFileName,
WaitingForKillConfirmation, WaitingForMacroDefConfirmation,
WaitingForMacroDeleteConfirmation => {
MessageWindow.Append["", TRUE];
dData.collectingFileName.length ← 0;
};
WaitingForKillConfirmation => {
MessageWindow.Append["", TRUE];
};
ENDCASE;
dData.mode ← WaitingToInputRope;
SilUserInput.NotInputingRope[uiData];
};
BoundingBoxOfModel: PUBLIC PROC [dData: SilDisplayData, model: SilModel, mapArea: BOOLEANTRUE] RETURNS [rect: Geom2D.Rect] = {
This module originally made many calls to BoundingBoxOfObject which is an expensive routine. We will assume instead that all the objects in the model know their bounds. BoundingBoxOfObject is normally called for the boundaries of new character objects.
box: Imager.Box;
fobList: SilFile.SilObject ← SilFile.GetObjectList[model, fgnd];
bobList: SilFile.SilObject ← SilFile.GetObjectList[model, bkgnd];
IF fobList=NIL AND bobList=NIL THEN RETURN [[0.0, 0.0, 1.0, 1.0]]; --no objects in mode, return small BBox
box.xmin ← box.ymin ← LAST[INTEGER];
box.xmax ← box.ymax ← FIRST[INTEGER];
FOR s: SilObject ← fobList, s.rest WHILE s#NIL DO
box.xmin ← MIN[box.xmin, s.first.xMin];
box.ymin ← MIN[box.ymin, s.first.yMin];
box.xmax ← MAX[box.xmax, s.first.xMax];
box.ymax ← MAX[box.ymax, s.first.yMax];
ENDLOOP;
FOR s: SilObject ← bobList, s.rest WHILE s#NIL DO
box.xmin ← MIN[box.xmin, s.first.xMin];
box.ymin ← MIN[box.ymin, s.first.yMin];
box.xmax ← MAX[box.xmax, s.first.xMax];
box.ymax ← MAX[box.ymax, s.first.yMax];
ENDLOOP;
rect.x ← box.xmin; rect.y ← box.ymin;
rect.w ← (box.xmax-box.xmin); rect.h ← (box.ymax-box.ymin);
IF mapArea THEN rect ← ImagerTransformation.TransformRectangle[
Geom2D.id.PostTranslate[[dData.xOffset, dData.yOffset]].PostScale2[[dData.currentMagnification, -dData.currentMagnification]], rect];
};
BoundingBoxOfObject: PUBLIC PROC [model: SilModel, sobr: SilObjectRec] RETURNS [xMin, yMin, xMax, yMax: INTEGER]= {
Return the bounding box of the Object given. Do not assume that the bounding box given in sobr is correct.
SELECT sobr.font FROM
IN InternalPresetFonts => {
extents: ImagerFont.Extents ← ImagerFont.RopeBoundingBox[font: SilDisplayUtils.GetFont[sobr.font, sobr.italic], rope: sobr.value];
RETURN[0, 0, Real.RoundI[extents.leftExtent+extents.rightExtent], Real.RoundI[extents.ascent+extents.descent]]
};
IN InternalMacroFonts => {
mxMin, myMin, mxMax, myMax: INTEGER;
[xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax] ← SilFile.GetMacroBoundingBox[model, sobr.font, Rope.Fetch[sobr.value, 0]];
FOR i: INT IN [1..Rope.Length[sobr.value]) DO
[mxMin, myMin, mxMax, myMax] ← SilFile.GetMacroBoundingBox[model, sobr.font, Rope.Fetch[sobr.value, i]];
yMin ← MIN[yMin, myMin];
yMax ← MAX[yMax, myMax];
xMax ← xMax + mxMax - mxMin;
ENDLOOP;
};
IN InternalBoxFonts => {
RETURN[sobr.xMin, sobr.yMin, sobr.xMax, sobr.yMax];
};
ENDCASE;
};
GuessFileName: PUBLIC PROC [data: SilData, file: FileType] = {
Guess as to the appropriate file name for input or output. Set appropriate data values and place file name in message window for user to edit.
dData: SilDisplayData ← data.displayData;
name: ROPE ← SilFile.GetActiveFileName[data.model];
IF Rope.Equal[name, ""] THEN name ← SilFile.GetLastActiveFileName[data.model];
SELECT file FROM
input => {
MessageWindow.Append["Input file: ", TRUE];
IF Rope.Equal[name, ""] THEN
dData.mode ← InputingInputFileName
ELSE
dData.mode ← EditingExistingInputFileName;
};
output => {
IF dData.largeFormat THEN MessageWindow.Append["Output Large Format file: ", TRUE] ELSE MessageWindow.Append["Output file: ", TRUE];
IF Rope.Equal[name, ""] THEN
dData.mode ← InputingOutputFileName
ELSE
dData.mode ← EditingExistingOutputFileName;
};
ENDCASE;
MessageWindow.Append[name, FALSE];
dData.collectingFileName ← Rope.ToRefText[name];
SilUserInput.InputingRope[data.uiData];
};
GuessHardFileName: PUBLIC PROC [data: SilData, c: CHAR] = {
Guess as to the appropriate file name to produce for hardcopy output. Set appropriate data values and place file name in message window for user to edit. C will indicate what type of device to produce the Interpress file for: PD files are no longer produced directly
R for Raven/300, H for Hornet/384, M for PlateMaker, U for Puffin, C for ColorVersatec, and D for Dover printer format.
dData: SilDisplayData ← data.displayData;
now strip the current file name back so a proper hardcopy extension will be added
name: ROPE ← SilFile.GetActiveFileName[data.model];
dir: ROPE ← FileNames.Directory[name];
name ← FileNames.GetShortName[name];
name ← Rope.Substr[base: name, len: Rope.SkipTo[s: name, skip: "."]];
SELECT c FROM
'R, 'r => dData.pdDev ← raven300;
'H, 'h => dData.pdDev ← raven384;
'M, 'm => dData.pdDev ← plateMaker;
'U, 'u => dData.pdDev ← puffin;
'C, 'c => dData.pdDev ← colorVersatec;
'D, 'd => dData.pdDev ← nil; -- Dover
'P, 'p => dData.pdDev ← nil; -- Press
ENDCASE => {
MessageWindow.Append["Illegal Hardcopy Device", TRUE]; MessageWindow.Blink;
RETURN;
};
MessageWindow.Append["Hardcopy file: ", TRUE];
IF Rope.Equal[name, ""] THEN dData.mode ← InputingHardFileName
ELSE {
dData.mode ← EditingExistingHardFileName;
name ← CheckHardFileExtension[data, Rope.Concat[dir, name]]; --restore directory part
MessageWindow.Append[name, FALSE];
dData.collectingFileName ← Rope.ToRefText[name];
};
SilUserInput.InputingRope[data.uiData];
};
InputNamedFile: PUBLIC PROC [data: SilData, name: ROPE, ctx: Imager.Context] = {
Input a named Sil file. It should be noted that a Sil file maybe read in more than once, and will result in two copies of each file object existing in the Sil environment (any number of different files can also be read in and co-exist).
bXmin, bYmin, bXmax, bYmax: INTEGER;
dData: SilDisplayData ← data.displayData;
model: SilModel ← data.model;
name ← CheckFileExtension[name, input];
SilFile.MainFileToModel[model, name, dData.relativeInput ! SilKernel.SilError => {
MessageWindow.Append[name, TRUE];
MessageWindow.Append[" not found.", FALSE];
GOTO Done;}];
[bXmin, bYmin, bXmax, bYmax] ← BoundingBoxOfContext [ctx];
MergeRebuild[data.displayData, model, bXmin, bYmin, bXmax, bYmax, FALSE];
EXITS
Done => NULL;
};
OutputNamedFile: PUBLIC PROC [data: SilData, name: ROPE, viewer: ViewerClasses.Viewer] = {
Output a named Sil file.
wasClipped: BOOLFALSE;
dData: SilDisplayData ← data.displayData;
AltoScreenWidth: INTEGER = SilDisplayInternal.AltoScreenWidth;
AltoScreenLength: INTEGER = SilDisplayInternal.AltoScreenLength;
name ← CheckFileExtension[name, IF dData.largeFormat THEN largeOutput ELSE output];
[wasClipped] ← SilFile.ModelToFile[model: data.model, name: name, clipIt: dData.clipOutputFile, large: dData.largeFormat, xMin: 0, yMin: 0, xMax: AltoScreenWidth, yMax: AltoScreenLength
! SilKernel.SilError => {
MessageWindow.Append["Not possible to store ", TRUE];
MessageWindow.Append[name, FALSE];
REJECT}]; --propogate signal to caller. Retain status as "edited".
IF wasClipped THEN
MessageWindow.Append["Objects outside of Alto screen boundaries not saved. ", TRUE];
dData.edited ← FALSE;
};
KillConfirmedFile: PUBLIC PROC [data: SilData, ctx: Imager.Context, viewer: ViewerClasses.Viewer] = {
Kill a Sil file. User has already confirmed this kill. viewer is the Abutter
bXmin, bYmin, bXmax, bYmax: INTEGER;
dData: SilDisplayData ← data.displayData;
SilFile.ClearModel[data.model];
viewer.name ← "SilNoName";
[bXmin, bYmin, bXmax, bYmax] ← BoundingBoxOfContext [ctx];
EraseArea[bXmin, bYmin, bXmax, bYmax, ctx];
MergeRebuild[dData, data.model, bXmin, bYmin, bXmax, bYmax];
SilDisplayUtils.ChangeCommandLineData[data: data, ctx: ctx, change: Selections, intArg1: SilFile.GetSelection[].numObjects];
dData.edited ← FALSE;
viewer.newVersion ← viewer.newFile ← FALSE; --Abutter
viewer.child.newVersion ← viewer.child.newFile ← FALSE; --ViewRec
viewer.child.sibling.newVersion ← viewer.child.sibling.newFile ← FALSE; --BiScroller
viewer.icon ← SilDisplay.GetIcon[dirtyIcon: FALSE];
ViewerOps.PaintViewer[viewer, caption];
};
HardcopyFile: PUBLIC PROC [data: SilData, name: ROPE] = {
Produce a hardcopy file with the name given for the sil data given.
ENABLE FS.Error => {
MessageWindow.Append["Error Attempting File: ", TRUE];
MessageWindow.Append[name, FALSE];
MessageWindow.Append[" ", FALSE];
MessageWindow.Append[error.explanation, FALSE];
GOTO ErrorOut;
};
Fix: PRIVATE PROC [r: REAL] RETURNS[INT] = { RETURN[Real.Fix[r]] };
Floor: PRIVATE PROC [a: REAL] RETURNS[c: REAL] = {
c ← Fix[a ! Real.RealException => { c ← a; CONTINUE }];
IF c>a THEN RETURN[c-1] ELSE RETURN[c]
};
ipRef: ImagerInterpress.Ref ← NIL;
spruceCtx: Imager.Context ← NIL;
pageXSize, pageYSize: REAL ← 0.0;
marginX, marginY: INTEGER ← margin;
dData: SilDisplayData ← data.displayData;
name ← CheckHardFileExtension[data, name];
MessageWindow.Append["Creating Hardcopy file: ", TRUE];
MessageWindow.Append[name, FALSE];
SELECT dData.pdDev FROM
nil => { -- nil means make a Spruce style Press file
spruceCtx ← ImagerPress.SimpleCreate[fileName: name, printerType: spruce]; pageXSize ← 8.5; pageYSize ← 11.0;};
IN [raven300..colorVersatec] => {
ipRef ← ImagerInterpress.Create[fileName: name];
SELECT dData.pdDev FROM
raven300 => {pageXSize ← 8.5; pageYSize ← 11.0;};
raven384 => {pageXSize ← 8.5; pageYSize ← 11.0;};
plateMaker => {pageXSize ← 11.0; pageYSize ← 8.5;};
puffin => {pageXSize ← 11.0; pageYSize ← 8.5;};
colorVersatec => {pageXSize ← 40.0; pageYSize ← 100.0;};
ENDCASE => {MessageWindow.Append["UnImplemented PD Device", TRUE]; RETURN;};
};
ENDCASE => {MessageWindow.Append["UnImplemented Output Device", TRUE]; RETURN;};
With the advent of BiScrollers, Sil files can now be multipage. This code breaks drawings into separate pages for printing.
{
DoSpruceProc: PROC [] = { --this PROC will be called by the ImagerPress package to make a Spruce style Press file page
ImagerPress.NewPage[context: spruceCtx]; --resets context to initial state (meters)
DoPageProc[context: spruceCtx];
};
DoPageProc: PROC [context: Imager.Context] = { --this PROC will be called to image a page
obCount: INT ← 0;
maxObCount: INT ← 100;
adjust the imager context to view this page properly
Imager.Scale2T[context, [metersPerPoint, -metersPerPoint]];
Imager.TranslateT[context,[ -boxXMin, -boxYMin-pageYPoints-marginY]]; --translate origin to current page. Includes margins.
Imager.SetPriorityImportant[context, TRUE];
now, scan the model for all objects in this page
FOR o: SilObject ← GetObjectList[model: data.model, mode: bkgnd], o.rest WHILE o # NIL DO
IF IBBoxFilter[xMin: boxXMin, yMin: boxYMin, xMax: boxXMax, yMax: boxYMax, sobr: o.first] THEN
SilDisplayUtils.PaintObject[model: data.model, sobr: o.first, dMode: show, ctx: context, oneLevel: FALSE, foregroundOnly: FALSE, print: TRUE];
ENDLOOP;
FOR o: SilObject ← GetObjectList[model: data.model, mode: fgnd], o.rest WHILE o # NIL DO
IF IBBoxFilter[xMin: boxXMin, yMin: boxYMin, xMax: boxXMax, yMax: boxYMax, sobr: o.first] THEN {
SilDisplayUtils.PaintObject[model: data.model, sobr: o.first, dMode: show, ctx: context, oneLevel: FALSE, foregroundOnly: FALSE, print: TRUE];
IF (obCount ← obCount+1) = maxObCount THEN {
MessageWindow.Append[".", FALSE];
obCount ← 0;
};
};
ENDLOOP;
};
modelXMin, modelYMin, modelXMax, modelYMax: REAL ← 0.0;
modelXMinI, modelYMinI, modelXMaxI, modelYMaxI: INTEGER ← 0;
boxXMin, boxYMin, boxXMax, boxYMax: INTEGER ← 0;
pageXPoints, pageYPoints: INTEGER ← 0;
pageXPoints ← Real.RoundI[pageXSize*pointsPerInch] - 2*marginX;
pageYPoints ← Real.RoundI[pageYSize*pointsPerInch] - 2*marginY;
[[x: modelXMin, y: modelYMin, w: modelXMax, h: modelYMax]] ← BoundingBoxOfModel[dData: dData, model: data.model, mapArea: FALSE];
modelXMax ← modelXMax+modelXMin; --change w to xmax
modelYMax ← modelYMax+modelYMin; --change h to ymax
modelXMinI ← Real.RoundI[Floor[modelXMin/pageXPoints] * pageXPoints]; --round to nearest page boundary
modelYMinI ← Real.RoundI[Floor[modelYMin/pageYPoints] * pageYPoints];
modelXMaxI ← Real.RoundI[modelXMax];
modelYMaxI ← Real.RoundI[modelYMax];
FOR x: INTEGER ← modelXMinI, x + pageXPoints UNTIL x > modelXMaxI DO
boxXMin ← x-marginX; boxXMax ← x + pageXPoints + marginX - 1;
FOR y: INTEGER ← modelYMinI, y+pageYPoints UNTIL y > modelYMaxI DO
boxYMin ← y-marginY; boxYMax ← y + pageYPoints + marginY - 1;
IF ipRef=NIL THEN ImagerPress.DoWithWarnings[context: spruceCtx, action: DoSpruceProc ! ImagerPress.Warning => {
MessageWindow.Append["ImagerPress Warning: ", TRUE];
MessageWindow.Append[explanation, FALSE];
RESUME;};]
ELSE ImagerInterpress.DoPage[self: ipRef, action: DoPageProc];
MessageWindow.Append["!", FALSE];
ENDLOOP
ENDLOOP;
};
IF ipRef=NIL THEN ImagerPress.Close[spruceCtx] ELSE ImagerInterpress.Close[ipRef];
MessageWindow.Append["Hardcopy file: ", TRUE];
MessageWindow.Append[name, FALSE];
MessageWindow.Append[" created.", FALSE];
EXITS
ErrorOut => NULL; --FS.Error detected
};
DefineConfirmedMacro: PUBLIC PROC [data: SilData, name: CHAR, ctx: Imager.Context] = {
Define a macro from the selected objects. User has already confirmed this definition.
MacroDefGrid: INTEGER = 4;
macroAlreadyInUse: BOOLFALSE;
dData: SilDisplayData ← data.displayData;
sSel: SilSelection ← GetSelection[];
xRef: INTEGER ← sSel.xMin;
yRef: INTEGER ← sSel.yMin;
xRef ← (xRef / MacroDefGrid) * MacroDefGrid;
yRef ← (yRef / MacroDefGrid) * MacroDefGrid;
now find any old uses and get rid of them
FOR s: SilObject ← GetObjectList[data.model, fgnd], s.rest WHILE s # NIL DO
IF s.first.font = InternalFileMacroFont THEN {
FOR i: INT IN [0..Rope.Length[s.first.value]) DO
IF Rope.Fetch[s.first.value, i] = dData.macroDefName THEN {
SilDisplayUtils.PaintObject[data.model, s.first, erase, ctx];
macroAlreadyInUse ← TRUE;
EXIT; --need not look further
};
ENDLOOP;
};
ENDLOOP;
SilFile.DefineMacroFromSelection[data.model, name, xRef, yRef];
IF macroAlreadyInUse THEN {
bXmin, bYmin, bXmax, bYmax: INTEGER;
[bXmin, bYmin, bXmax, bYmax] ← BoundingBoxOfContext [ctx];
MergeRebuild[dData, data.model, bXmin, bYmin, bXmax, bYmax];
};
};
ClearConfirmedMacroDefs: PUBLIC PROC [data: SilData, ctx: Imager.Context] = {
Clear all Macro Definitions. User has already confirmed this drastic act.
This is going to look drastic (erasing the screen and then redrawing it), but it is
a drastic step. Also, I think that erasing only the objects defined by macros
would be not much better and a lot more work to program.
dData: SilDisplayData ← data.displayData;
bXmin, bYmin, bXmax, bYmax: INTEGER;
[bXmin, bYmin, bXmax, bYmax] ← BoundingBoxOfContext [ctx];
SilFile.ClearMacros[data.model]; -- also deletes macro containing objects
EraseArea[bXmin, bYmin, bXmax, bYmax, ctx];
MergeRebuild[dData, data.model, bXmin, bYmin, bXmax, bYmax];
};
CheckFileExtension: PUBLIC PROC [name: ROPE, type: FileType] RETURNS[nameAndExt: ROPE] = {
If the fileName given has no extension and no dot on the end add an appropriate extension
dir: ROPE ← FileNames.Directory[name];
sName: ROPE ← FileNames.GetShortName[name];
IF Rope.Find[s1: sName, s2: ".", case: FALSE] #-1 THEN RETURN[name]; --already has an extension
SELECT type FROM -- no dot, so add extension
output => RETURN[Rope.Concat[name, ".Sil"]];
largeOutput => RETURN[Rope.Concat[name, ".LSil"]];
input => { -- test a series of possible file name extensions until find one that exists
list: LIST OF Rope.ROPE ← UserProfile.ListOfTokens[key: "Sil.FileExtensions", default: LIST[".LSil", ".Sil"]];
FOR l: LIST OF Rope.ROPE ← list, l.rest UNTIL l=NIL DO
fname: ROPE ← Rope.Cat[name, ".", l.first];
[] ← FS.FileInfo[name: fname, wDir: dir ! FS.Error => LOOP];
RETURN[fname]; -- file with extension exists
ENDLOOP;
};
ENDCASE => NULL;
RETURN[name]; -- file does not exist
};
CheckHardFileExtension: PROC [data: SilData, name: ROPE] RETURNS[nameAndExt: ROPE] = {
If the fileName given has no extension and no dot on the end add an appropriate extension.
dData: SilDisplayData ← data.displayData;
sName: ROPE ← FileNames.GetShortName[name];
IF Rope.Find[s1: sName, s2: ".", case: FALSE] #-1 THEN RETURN[name]; --already has an extension
SELECT dData.pdDev FROM
raven300 => RETURN[Rope.Concat[name, ".ip.raven"] ];
raven384 => RETURN[Rope.Concat[name, ".ip.hornet"] ];
plateMaker => RETURN[Rope.Concat[name, ".ip.plateMaker"] ];
puffin => RETURN[Rope.Concat[name, ".ip.puffin"] ];
colorVersatec => RETURN[Rope.Concat[name, ".ip.colorVersatec"] ];
nil => RETURN[Rope.Concat[name, ".press"] ];
ENDCASE;
};
MarkFileAsEdited: PUBLIC PROC [data: SilData, ctx: Imager.Context, viewer: ViewerClasses.Viewer] = {
Mark the file as edited. This may involve the removal of "build marks." (Visual cues put in Sil files by post processing DA programs.
dData: SilDisplayData ← data.displayData;
lViewer: ViewerClasses.Viewer ← SilUserInput.GetBiScroller[data.uiData].QuaViewer[];
This viewer is of a BiScroller; its parent is an Abutter
IF NOT dData.edited THEN {
dData.edited ← TRUE;
ViewerOps.SetNewVersion[lViewer]; -- needed for emergency SAVE to work
ViewerOps.SetNewVersion[lViewer.parent]; -- needed for emergency SAVE to work
lViewer.parent.icon ← SilDisplay.GetIcon[dirtyIcon: TRUE];
IF SilFile.MarkFileAsEdited[data.model] THEN {
FOR i: BuildMarkIndex IN BuildMarkIndex DO
EraseArea[buildMarks[i].xMin, buildMarks[i].yMin, buildMarks[i].xMax, buildMarks[i].yMax, ctx];
MergeRebuild[dData, data.model, buildMarks[i].xMin, buildMarks[i].yMin, buildMarks[i].xMax, buildMarks[i].yMax];
ENDLOOP;
};
};
};
EditText: PUBLIC PROC [EditThis: REF TEXT, c: CHAR] RETURNS [Edited: REF TEXT, Finished: BOOLFALSE, Aborted: BOOLFALSE, BackedUp: BOOLFALSE]= {
Reflect the effect of this input char on the text given. If the input character implies that this rope has been aborted or finished, return the apropriate values. Return BackedUp TRUE if the some characters in the rope had to be removed.
SELECT c FROM
IN SilFile.PrintingChars, Ascii.SP =>
EditThis ← RefText.AppendChar[EditThis, c];
Ascii.BS, Ascii.ControlA => IF EditThis.length > 0 THEN {
EditThis.length ← EditThis.length - 1;
BackedUp ← TRUE;
};
Ascii.ControlQ => {
EditThis.length ← 0;
BackedUp ← TRUE;
};
Ascii.ControlW => {
stop: INTEGER ← 0;
lastStop: INTEGER ← 0;
WHILE stop # EditThis.length AND stop # EditThis.length - 1 DO
lastStop ← stop;
stop ← RefText.SkipTo[EditThis, lastStop + 1, " ./!<["];
ENDLOOP;
IF lastStop # EditThis.length AND lastStop # 0 THEN
EditThis.length ← lastStop + 1
ELSE
EditThis.length ← 0;
BackedUp ← TRUE;
};
Ascii.DEL => {
Aborted ← TRUE;
BackedUp ← TRUE;
};
Ascii.ESC, Ascii.CR =>
Finished ← TRUE;
Don't do anything - spurious input probably the result of a confused user
ENDCASE => NULL;
Edited ← EditThis;
};
END.