<> <> <> <> <> <> <> <> <> <> DIRECTORY Carets USING [ResumeCarets, SuspendCarets], AISFileFormat, Convert, Cursors, FS, Imager, ImagerArtwork, ImagerInterpress, ImagerTerminal, InterminalBackdoor, IO, MessageWindow, PressScreen, Real, Rope, SirPress, Terminal, ViewerClasses, ViewerLocks, ViewerSpecs, ViewerOps; PressScreenImpl: CEDAR MONITOR IMPORTS Carets, Convert, Cursors, FS, Imager, ImagerArtwork, ImagerInterpress, ImagerTerminal, InterminalBackdoor, IO, MessageWindow, Real, Rope, SirPress, Terminal, ViewerLocks, ViewerOps EXPORTS PressScreen = { OPEN PressScreen; ROPE: TYPE = Rope.ROPE; extraWords: NAT _ 6; -- Half-screen prints are widened by this much. PressScreen: PUBLIC PROC[pressFileName: Rope.ROPE, which: Side] = TRUSTED { <> screen: SirPress.PressHandle_ SirPress.Create[ fileNameForHeaderPage: pressFileName, outputStream: FS.StreamOpen[pressFileName, $create] ]; vt: Terminal.Virtual _ InterminalBackdoor.terminal; frameBuffer: Terminal.FrameBuffer _ Terminal.GetBWFrameBuffer[vt]; widthInWords: INT _ frameBuffer.wordsPerLine; halfWidthInWords: NAT _ widthInWords/2; screenPtr: LONG POINTER _ frameBuffer.base; <> IF which=bothSides THEN { screen.SetPageSize[height: 85, width: 110, unit: SirPress.in/10]; screen.BeginScannedRectangle[ x: 1, y: 1, numberOfLines: frameBuffer.height, dotsPerLine: widthInWords*16, height: 8*4, unit: SirPress.in/4] } ELSE screen.BeginScannedRectangle[ x: 1, y: 1, numberOfLines: frameBuffer.height, dotsPerLine: (halfWidthInWords+extraWords)*16, unit: SirPress.in/4]; <> FOR i: INT IN [0..frameBuffer.height) DO offset: LONG CARDINAL _ i*widthInWords; IF which=rightSide THEN offset _ offset + halfWidthInWords - extraWords; screen.UnsafeShowLine[screenPtr + offset]; ENDLOOP; <> screen.EndScannedRectangle[]; screen.ClosePress[]; }; fileNameTemplate: ROPE _ "Screen#.press"; <> count: INT _ 0; NewPressName: PUBLIC ENTRY PROCEDURE RETURNS [pressFileName: Rope.ROPE] = { <> ENABLE UNWIND => NULL; i: INT = Rope.Find[s1: fileNameTemplate, s2: "#"]; pressFileName _ IF i = -1 THEN fileNameTemplate ELSE fileNameTemplate.Replace[start: i, len: 1, with: Convert.RopeFromInt[count _ count + 1]]; }; MagnificationFactorTooLarge: PUBLIC SIGNAL = CODE; <> AISPageAlignmentHackFailed: PUBLIC SIGNAL = CODE; <> ScreenWorker: TYPE = PROC [screenParms: ScreenParameters, vt: Terminal.Virtual, context: Imager.Context, frameBuffer: Terminal.FrameBuffer, screenWidthInWords, clippedWidth: NAT, screenPtr: LONG POINTER]; DoScreenWork: PROC [screenParms: ScreenParameters, Prepare, WithLock, Finish: ScreenWorker] = { OPEN screenParms; vt: Terminal.Virtual _ InterminalBackdoor.terminal; context: Imager.Context _ ImagerTerminal.BWContext[vt: vt, pixelUnits: TRUE]; frameBuffer: Terminal.FrameBuffer _ Terminal.GetBWFrameBuffer[vt]; screenWidthInWords: NAT _ frameBuffer.wordsPerLine; clippedWidth: NAT _ MIN[frameBuffer.width-sourceLeft, sourceWidth]; screenPtr: LONG POINTER _ frameBuffer.base; sourceHeight _ MIN[sourceHeight, frameBuffer.height-sourceBottom]; Prepare[screenParms: screenParms, vt: vt, context: context, frameBuffer: frameBuffer, screenWidthInWords: screenWidthInWords, clippedWidth: clippedWidth, screenPtr: screenPtr]; IF displayCarets THEN { Carets.SuspendCarets[visible: TRUE]; }; { Locked: SAFE PROC ~ TRUSTED { context.MaskBox[[sourceLeft, sourceBottom, sourceLeft+borderWidth, sourceBottom+sourceHeight]]; context.MaskBox[[sourceLeft+clippedWidth-borderWidth, sourceBottom, sourceLeft+clippedWidth, sourceBottom+sourceHeight]]; context.MaskBox[[sourceLeft, sourceBottom, sourceLeft+clippedWidth, sourceBottom+borderWidth]]; context.MaskBox[[sourceLeft, sourceBottom+sourceHeight-borderWidth, sourceLeft+clippedWidth, sourceBottom+sourceHeight]]; context.SetColor[Imager.white]; context.MaskBox[[sourceLeft-16, sourceBottom, sourceLeft, sourceBottom+sourceHeight]]; context.MaskBox[[sourceLeft+clippedWidth, sourceBottom, sourceLeft+clippedWidth+16, sourceBottom+sourceHeight]]; IF displayCursor THEN { vt: Terminal.Virtual _ Terminal.Current[]; cursorArray: Terminal.BWCursorBitmap _ Terminal.GetBWCursorPattern[vt]; position: Terminal.Position _ Terminal.GetMousePosition[vt]; cursorInfo: Cursors.CursorInfo = Cursors.GetCursorInfo[]; context.SetColor[Imager.black]; context.MaskBits[base: @cursorArray, wordsPerLine: 1, sMin: 0, fMin: 0, sSize: 16, fSize: 16, tx: position.x+cursorInfo.hotX, ty: vt.bwHeight-(position.y+cursorInfo.hotY)]; }; WithLock[screenParms: screenParms, vt: vt, context: context, frameBuffer: frameBuffer, screenWidthInWords: screenWidthInWords, clippedWidth: clippedWidth, screenPtr: screenPtr]; <> }; IF lockViewers THEN ViewerLocks.CallUnderViewerTreeLock[Locked] ELSE Locked[]; }; IF displayCarets THEN { Carets.ResumeCarets[]; }; ViewerOps.PaintEverything[]; Finish[screenParms: screenParms, vt: vt, context: context, frameBuffer: frameBuffer, screenWidthInWords: screenWidthInWords, clippedWidth: clippedWidth, screenPtr: screenPtr]; }; pixelsPerWord: REAL = 16.0; micasPerPoint: REAL = 32.0; --not 2540/72.0, so we can print these press files with SPRUCE; at least, that's what Michael Plass alleged in the presence of Rick Beach and Mike Spreitzer on February 4, 1986, although experiments that day show it doesn't work. micasPerWord: REAL = micasPerPoint * pixelsPerWord; AISPressScreen: PUBLIC PROCEDURE [ pressFileName: ROPE, screenParms: ScreenParameters _ [], pageParms: PageParameters _ [] ] RETURNS [fileName: ROPE] = TRUSTED { OPEN screenParms, pageParms; <> <> <> trueName: Rope.ROPE _ IF pressFileName = NIL THEN NewAISPressName[] ELSE pressFileName; outputStream: IO.STREAM _ FS.StreamOpen[trueName, $create]; bytesSoFar: INT; screen: SirPress.PressHandle; sourceLeftInWords, sourceRightInWords: NAT; paperHeight, paperWidth, pageBorder, x, y: REAL; bytesPerPage: INT = 2048; wordsOfPressCommands: INT = 8; -- count of Press commands generated before dots so that the AIS image starts on a page boundary AISHeader: TYPE = RECORD [ header: AISFileFormat.AttributeHeader, partHeader: AISFileFormat.PartHeader, rasterPart: AISFileFormat.RasterPart, uca: AISFileFormat.UCACoding]; aisHeader: AISHeader _ [ header: [ password: AISFileFormat.passwordValue, length: 0], partHeader: [type: raster, length: SIZE[AISFileFormat.RasterPart]+SIZE[AISFileFormat.PartHeader]+SIZE[AISFileFormat.UCACoding]], rasterPart: [ scanCount: 0, scanLength: 0, scanDirection: 3, samplesPerPixel: 1, codingType: uca], uca: [ bitsPerSample: 0, wordsPerScanLine: 0, scanLinesPerBlock: 177777B, paddingPerBlock: 177777B ]]; aisHeaderPtr: LONG POINTER TO AISHeader _ @aisHeader; aisBlock: IO.UnsafeBlock _ [ base: LOOPHOLE[aisHeaderPtr], startIndex: 0, count: 2*SIZE[AISHeader]]; Prepare: ScreenWorker = CHECKED { OPEN screenParms; sourceLeftInWords _ MIN[sourceLeft/16, screenWidthInWords]; sourceRightInWords _ MIN[(sourceLeft+clippedWidth+15)/16, screenWidthInWords]; paperHeight _ IF landscape THEN 8.5*2540 ELSE 11*2540; paperWidth _ (11+8.5)*2540 - paperHeight; pageBorder _ (leftMarginInches + rightMarginInches)*2540; SELECT scaleToFit FROM fullPage => magnification _ MIN[ (paperWidth-pageBorder) / (micasPerWord*(sourceRightInWords-sourceLeftInWords)), (paperHeight-pageBorder)/(micasPerPoint*sourceHeight)]; halfPage => magnification _ MIN[ (paperWidth-pageBorder) / (micasPerWord*(sourceRightInWords-sourceLeftInWords)), (paperHeight-2*pageBorder) / (2.0*micasPerPoint*sourceHeight)]; useMagnification => NULL; ENDCASE; x _ (paperWidth-micasPerWord*(sourceRightInWords-sourceLeftInWords)*magnification)/2.0; y _ (paperHeight-micasPerPoint*sourceHeight*magnification)/2.0; IF x<0 OR y<0 OR x+micasPerWord*(sourceRightInWords-sourceLeftInWords)*magnification > paperWidth OR y+micasPerPoint*sourceHeight*magnification > paperHeight THEN SIGNAL MagnificationFactorTooLarge; <> aisHeader.uca.wordsPerScanLine _ sourceRightInWords-sourceLeftInWords; aisHeader.rasterPart.scanLength _ aisHeader.uca.wordsPerScanLine*16; aisHeader.rasterPart.scanCount _ sourceHeight; IO.UnsafePutBlock[outputStream, aisBlock]; IO.PutChar[outputStream, '\000]; IO.PutChar[outputStream, '\000]; THROUGH [0..bytesPerPage - IO.GetIndex[outputStream] - 2*wordsOfPressCommands) DO IO.PutChar[outputStream, '$]; ENDLOOP; <> screen _ SirPress.Create[ fileNameForHeaderPage: trueName, outputStream: outputStream ]; IF landscape THEN screen.SetPageSize[height: 85, width: 110, unit: SirPress.in/10]; screen.BeginScannedRectangle[ x: Real.RoundLI[x], y: Real.RoundLI[y], numberOfLines: sourceHeight, dotsPerLine: (sourceRightInWords-sourceLeftInWords)*16, height: Real.RoundLI[micasPerPoint*sourceHeight*magnification], unit: SirPress.mica]; <> bytesSoFar _ IO.GetIndex[outputStream]; IF bytesSoFar # bytesPerPage THEN SIGNAL AISPageAlignmentHackFailed; aisHeader.header.length _ bytesSoFar/2; IO.SetIndex[outputStream, 0]; IO.UnsafePutBlock[outputStream, aisBlock]; IO.SetIndex[outputStream, bytesSoFar]; }; WithLock: ScreenWorker = TRUSTED { OPEN screenParms; <> FOR i: INT IN [0..sourceHeight) DO offset: LONG CARDINAL _ (i+frameBuffer.height-sourceHeight-sourceBottom)*screenWidthInWords+sourceLeftInWords; screen.UnsafeShowLine[screenPtr + offset]; ENDLOOP; }; <<>> Finish: ScreenWorker = CHECKED { OPEN screenParms; <> screen.EndScannedRectangle[]; screen.ClosePress[]; }; DoScreenWork[screenParms, Prepare, WithLock, Finish]; RETURN [trueName]; }; pointsPerInch: REAL = 72.0; --not 72.27, because these are "screen points" metersPerPoint: REAL = Imager.metersPerInch/pointsPerInch; IPScreen: PUBLIC PROCEDURE [ipFileName: ROPE, screenParms: ScreenParameters _ [], pageParms: PageParameters _ []] RETURNS [fileName: ROPE] = { OPEN screenParms, pageParms; r: ImagerInterpress.Ref; paperWidth: REAL = (IF landscape THEN 11.0 ELSE 8.5)*pointsPerInch; paperHeight: REAL = (IF landscape THEN 8.5 ELSE 11.0)*pointsPerInch; pageBorder: REAL = (leftMarginInches + rightMarginInches)*pointsPerInch; x0, y0: REAL; Prepare: ScreenWorker = { SELECT scaleToFit FROM fullPage => magnification _ MIN[ (paperWidth-pageBorder) / sourceWidth, (paperHeight-pageBorder) / sourceHeight]; halfPage => magnification _ MIN[ (paperWidth-pageBorder) / sourceWidth, (paperHeight-2*pageBorder) / 2.0*sourceHeight]; useMagnification => NULL; ENDCASE; x0 _ (paperWidth-sourceWidth*magnification)/2.0; y0 _ (paperHeight-sourceHeight*magnification)/2.0; IF x0<0 OR y0<0 OR x0+sourceWidth*magnification > paperWidth OR y0+sourceHeight*magnification > paperHeight THEN SIGNAL MagnificationFactorTooLarge; }; WithLock: ScreenWorker = { OPEN screenParms; DoIPMaster: PROC [context: Imager.Context] = { context.ScaleT[metersPerPoint]; IF landscape THEN {context.TranslateT[t: [paperHeight, 0]]; context.RotateT[90]}; context.TranslateT[t: [x0, y0]]; context.ScaleT[magnification]; context.TranslateT[t: [-sourceLeft, -sourceBottom]]; context.ClipRectangle[[sourceLeft, sourceBottom, sourceWidth, sourceHeight]]; context.MaskBits[ base: screenPtr, wordsPerLine: frameBuffer.wordsPerLine, sMin: frameBuffer.height-sourceHeight-sourceBottom, fMin: sourceLeft, sSize: sourceHeight, fSize: sourceWidth, tx: sourceLeft, ty: sourceBottom+sourceHeight ]; }; ImagerInterpress.DoPage[self: r, action: DoIPMaster ! Imager.Error => { MessageWindow.Append[ message: Rope.Concat[error.explanation, " creating IPMaster"], clearFirst: TRUE]; CONTINUE} ]; }; <<>> Finish: ScreenWorker = { }; fileName _ IF ipFileName = NIL THEN NewIPName[] ELSE ipFileName; r _ ImagerInterpress.Create[fileName: fileName ! FS.Error => { MessageWindow.Append[message: error.explanation, clearFirst: TRUE]; GOTO Quit; }]; DoScreenWork[screenParms, Prepare, WithLock, Finish]; ImagerInterpress.Close[r]; EXITS Quit => NULL; }; StuffScreen: PUBLIC PROCEDURE [screenParms: ScreenParameters _ []] = { OPEN screenParms; Prepare: ScreenWorker = { }; WithLock: ScreenWorker = { OPEN screenParms; DoStuff: PROC [context: Imager.Context] = { context.TranslateT[t: [-sourceLeft, -sourceBottom]]; context.MaskBits[ base: screenPtr, wordsPerLine: frameBuffer.wordsPerLine, sMin: frameBuffer.height-sourceHeight-sourceBottom, fMin: sourceLeft, sSize: sourceHeight, fSize: sourceWidth, tx: sourceLeft, ty: sourceBottom+sourceHeight ]; }; ImagerArtwork.PasteArtwork[action: DoStuff, bounds: [0, 0, sourceWidth, sourceHeight], m: ImagerArtwork.Points[], clip: TRUE]; }; <<>> Finish: ScreenWorker = { }; DoScreenWork[screenParms, Prepare, WithLock, Finish]; }; aisFileNameTemplate: ROPE = "Screen#.AIS"; NewAISPressName: PUBLIC ENTRY PROCEDURE RETURNS [pressFileName: ROPE] = { <> ENABLE UNWIND => NULL; NextName: PROCEDURE RETURNS [ROPE] = { RETURN [aisFileNameTemplate.Replace[start: i, len: 1, with: Convert.RopeFromInt[count _ count + 1]]]; }; i: INT = Rope.Find[s1: aisFileNameTemplate, s2: "#"]; pressFileName _ IF i = -1 THEN aisFileNameTemplate ELSE NextName[]; DO s: FS.OpenFile; s _ FS.Open[pressFileName ! FS.Error => GO TO ThisNameIsOkay]; FS.Close[s]; pressFileName _ NextName[]; ENDLOOP; EXITS ThisNameIsOkay => NULL; }; ipFileNameTemplate: ROPE = "Screen#.IP"; NewIPName: PUBLIC ENTRY PROCEDURE RETURNS [ipFileName: ROPE] = { <> ENABLE UNWIND => NULL; NextName: PROCEDURE RETURNS [ROPE] = { RETURN [ipFileNameTemplate.Replace[start: i, len: 1, with: Convert.RopeFromInt[count _ count + 1]]]; }; i: INT = Rope.Find[s1: ipFileNameTemplate, s2: "#"]; ipFileName _ IF i = -1 THEN ipFileNameTemplate ELSE NextName[]; DO s: FS.OpenFile; s _ FS.Open[ipFileName ! FS.Error => GO TO ThisNameIsOkay]; FS.Close[s]; ipFileName _ NextName[]; ENDLOOP; EXITS ThisNameIsOkay => NULL; }; }. 6-Apr-82 12:01:31 Teitelman fixed PressScreenButton to clear message window first. May 4, 1982 4:39 pm Cattell: print msg saying whether half or full screen. Also, no longer need config 'cause SirPressPackage is external. June 18, 1982 1:58 pm Cattell: convert to 3.2; leave a little left margin to avoid printer truncation. November 15, 1982 12:30 pm Plass: Made client-callable interface. November 15, 1982 2:30 pm Plass: Made rightSide work, removed button interface, made half-screen resolution match what Spruce can sometimes handle. November 16, 1982 10:57 am Plass: Tracked SirPress changes. February 21, 1984 10:12:39 am PST Plass: Fixed AIS header to make a proper AIS file. April 25, 1985 11:05:01 am PST: Imager conversion.