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],
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:
BOOL ←
FALSE] = {
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:
BOOL ←
FALSE, 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:
BOOLEAN ←
TRUE]
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];
};
OutputNamedFile:
PUBLIC
PROC [data: SilData, name:
ROPE, viewer: ViewerClasses.Viewer] = {
Output a named Sil file.
wasClipped: BOOL ← FALSE;
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: BOOL ← FALSE;
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:
BOOL ←
FALSE, Aborted:
BOOL ←
FALSE, BackedUp:
BOOL ←
FALSE]= {
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.