<> <> <> <> <> <<>> <> <<>> 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] = { <> 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] = { <> <<>> 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] = { <> <<>> 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] = { <> 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] = { <> 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 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] = { <> 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] = { <> 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[ 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 { <> 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] ={ <> < font.>> < color.>> < 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] = { <> 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] = { <> 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] = { <> 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] = { <
> <<>> 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] = { <> 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] = { <> 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] = { <> <<>> 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] = { <> <<>> 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] = { <> <<>> 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] = { <> <<>> 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] = { <> <<>> 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]; <> 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] = { <> <<>> 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] = { <> 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]= { <> <<>> 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] = { <> <<>> 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] = { <> <> <<>> dData: SilDisplayData _ data.displayData; <> 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] = { <> <<>> 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] = { <> <<>> 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] = { <> <<>> 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] = { <> 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;}; <> { 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; <> Imager.Scale2T[context, [metersPerPoint, -metersPerPoint]]; Imager.TranslateT[context,[ -boxXMin, -boxYMin-pageYPoints-marginY]]; --translate origin to current page. Includes margins. Imager.SetPriorityImportant[context, TRUE]; <> 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] = { <> <<>> 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; <> 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] = { <> << 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] = { <> <<>> 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] = { <> <<>> 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] = { <> <<>> dData: SilDisplayData _ data.displayData; lViewer: ViewerClasses.Viewer _ SilUserInput.GetBiScroller[data.uiData].QuaViewer[]; <> 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]= { <> <<>> 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.