<> <> <> <> DIRECTORY ScreenDefs: FROM "ScreenDefs", Graphics USING[Context, PaintMode, Color, SetPaintMode, SetCP, white, black, Box, FontRef, MakeFont, FontBox, Translate, ClipBox, DrawRope, Save, Restore, RopeBox], Rope USING [ROPE], ScreenDefsExtras, GraphicsBasic USING [Vec], CGArea USING [InsertBox, New,Ref], CGSource USING [Ref, Rep], CGDevice USING [Ref], CGContext USING [Ref], CGMatrix USING [Ref,Map], GraphicsOps USING [MoveDeviceRectangle], PointDefs: FROM "PointDefs" USING [ IntegerSequence,IntegerSequenceRec,ScrPt,X,Y], Font USING [FontRec, FontGraphicsClassRec, FONT], ImagerTransform USING [Transformation, Create, Concat], GriffinMemoryDefs USING [CZone], Real USING [RoundI], GriffinDefs: FROM "GriffinDefs", GriffinViewer USING[GetViewer, PaintProc, DoPaint], ViewerOps USING [Top2Bottom], ViewerClasses USING[Viewer]; ScreenFns: PROGRAM IMPORTS GraphicsOps, GriffinDefs, Graphics, GriffinMemoryDefs, CGArea, CGMatrix, Real, GriffinViewer, ViewerOps, ImagerTransform EXPORTS ScreenDefs, ScreenDefsExtras = BEGIN OPEN ScreenDefs,PointDefs,GriffinMemoryDefs; TY,BY,LX,RX: INTEGER; initTY,initBY,initLX,initRX: INTEGER; CLIP: BOOLEAN _ TRUE; CULL: BOOLEAN _ FALSE; FNC: Graphics.PaintMode; white: Graphics.Color=Graphics.white; black: Graphics.Color=Graphics.black; opaque: Graphics.PaintMode = opaque; transparent: Graphics.PaintMode = transparent; <> ClearScreen: PUBLIC PROCEDURE [dc: Context] = BEGIN tl: ScrPt _ [LX,TY]; br: ScrPt _ [RX,BY]; EraseBox[tl,br, dc]; END; <> SetViewport: PUBLIC PROCEDURE [width,height: INTEGER] = BEGIN LX _ initLX _ 0; RX _ initRX _ width; TY _ initTY _ 0; BY _ initBY _ height; END; <> SetClipEdges: PUBLIC PROCEDURE [tl,br: PointDefs.ScrPt] = { <> [tl,br] _ ClipToScreen[tl,br]; IF br[X]RX OR br[X]BY OR br[Y]initRX THEN br[X] _ initRX; IF tl[Y] < initTY THEN tl[Y] _ initTY; IF br[Y] >initBY THEN br[Y] _ initBY; RETURN[tl,br]; END; ClipPointToScreen: PUBLIC PROC [pt: ScrPt] RETURNS [ScrPt] = BEGIN IF pt[X] < initLX THEN pt[X] _ initLX; IF pt[X] >initRX THEN pt[X] _ initRX; IF pt[Y] < initTY THEN pt[Y] _ initTY; IF pt[Y] >initBY THEN pt[Y] _ initBY; RETURN[pt]; END; ResetClipEdges: PUBLIC PROCEDURE = BEGIN OPEN PointDefs; tl: PointDefs.ScrPt _ [initLX,initTY]; br: PointDefs.ScrPt _ [initRX,initBY]; SetClipEdges[tl,br]; END; ClipOn: PUBLIC PROCEDURE = BEGIN CLIP _ TRUE; END; PrimeClipper: PUBLIC PROC [tl,br: PointDefs.ScrPt] RETURNS [ClipperState] = BEGIN IF tl[X] > RX OR tl[Y] > BY OR br[X] < LX OR br[Y] < TY THEN RETURN[cull]; IF tl[X] IN [LX..RX] AND tl[Y] IN [TY..BY] AND br[X] IN [LX..RX] AND br[Y] IN [TY..BY] THEN {CLIP _ FALSE; RETURN[inside]}; CLIP _ TRUE; RETURN[clip]; END; SetFunction: PUBLIC PROCEDURE [fnc: Graphics.PaintMode] = BEGIN FNC _ fnc; END; <> Width: INTEGER; Grey: GreyType; SetLineParms: PUBLIC PROCEDURE [ width: INTEGER, grey: GreyType]= BEGIN Width _ width; CurrentBrush _ CodedBrushes[Width]; Grey _ grey; END; left: INTEGER = 0; right: INTEGER = 1; CodedBrush: TYPE = ARRAY [left..right] OF BrushSide; BrushSide: TYPE = PointDefs.IntegerSequence; CodedBrushes: ARRAY [1..8] OF CodedBrush; CurrentBrush: CodedBrush; xleft, xright: ARRAY [0..7] OF INTEGER; leftBrush: BrushSide; rightBrush: BrushSide; brushSize: INTEGER; topIndex: INTEGER; topY: INTEGER; -- top of brush centerX: INTEGER; StartChain: PUBLIC PROCEDURE[pt: ScrPt, dc: Context] = { ref: CGContext.Ref _ NARROW[dc.data]; newPt: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[pt[X],YFlip[pt[Y]]]]; brushIndex: INTEGER; cgSource.color _ Grey; cgSource.mode _ FNC; cgDevice _ ref.device; DeviceClipper[ref.matrix]; leftBrush _ CurrentBrush[left]; rightBrush _ CurrentBrush[right]; brushSize _ leftBrush.length; topIndex _ 0; topY _ Real.RoundI[newPt.y] - brushSize/2; -- top of brush centerX _ Real.RoundI[newPt.x]; FOR brushIndex IN [0..brushSize) DO xleft[brushIndex] _ centerX + leftBrush[brushIndex]; xright[brushIndex] _ centerX + rightBrush[brushIndex]; ENDLOOP; }; NextChainPoint: PUBLIC PROCEDURE[dx,dy: INTEGER, dc: Context]= BEGIN OPEN PointDefs; brushIndex, rangeIndex, temp: INTEGER; <
> centerX _ centerX + dx; SELECT dy FROM -1 => BEGIN -- move brush up IF (topIndex _ topIndex -1) < 0 THEN topIndex _ topIndex + brushSize; <> <> NextScanLine[(topY + brushSize -1), xleft[topIndex], xright[topIndex], dc]; <> xleft[topIndex] _ 606; xright[topIndex] _ 0; topY _ topY - 1; END; 1 => BEGIN -- move brush down <> NextScanLine[topY, xleft[topIndex], xright[topIndex], dc]; <> xleft[topIndex] _ 606; xright[topIndex] _ 0; IF (topIndex _ topIndex +1) >= brushSize THEN topIndex _ 0; topY _ topY + 1; END; 0 => NULL; ENDCASE => BEGIN <> <> RETURN; END; rangeIndex _ topIndex; FOR brushIndex IN [0..brushSize) DO IF xleft[rangeIndex] > (temp _ centerX + leftBrush[brushIndex]) THEN xleft[rangeIndex] _ temp; IF xright[rangeIndex] < (temp _ centerX + rightBrush[brushIndex]) THEN xright[rangeIndex] _ temp; IF (rangeIndex _ rangeIndex + 1) >= brushSize THEN rangeIndex _ 0; ENDLOOP; END; EndChain: PUBLIC PROCEDURE [dc: Context] = BEGIN <> brushIndex: INTEGER; FOR brushIndex IN [0..brushSize) DO NextScanLine[topY, xleft[topIndex], xright[topIndex], dc]; topY _ topY + 1; IF (topIndex _ topIndex +1) >= brushSize THEN topIndex _ 0; ENDLOOP; END; SetFillParms: PUBLIC PROCEDURE [grey: GreyType] = {fillGrey _ grey}; fillGrey: GreyType _ black; StartArea: PUBLIC PROCEDURE[y: INTEGER, dc: Context] RETURNS[yScan,xOffset: INTEGER]= { ref: CGContext.Ref _ NARROW[dc.data]; newPt: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[0,YFlip[y]]]; yScan _ Real.RoundI[newPt.y]; xOffset _ Real.RoundI[newPt.x]; cgSource.color _ fillGrey; cgSource.mode _ FNC; cgDevice _ ref.device; DeviceClipper[ref.matrix]; RETURN[yScan,xOffset]; }; cgDevice: CGDevice.Ref _ NIL; cgBox: Graphics.Box; dLX,dRX,dTY,dBY: INTEGER; DeviceClipper: PROC [cgMatrix: CGMatrix.Ref] = { newPt: GraphicsBasic.Vec _ CGMatrix.Map[cgMatrix,[LX,YFlip[TY]]]; dLX _ Real.RoundI[newPt.x]; dTY _ Real.RoundI[newPt.y]; newPt _ CGMatrix.Map[cgMatrix,[RX,YFlip[BY]]]; dRX _ Real.RoundI[newPt.x]; dBY _ Real.RoundI[newPt.y]; }; <> NextScanLine: PUBLIC PROCEDURE[y,lx,rx: INTEGER, dc: Context] = { IF CLIP THEN BEGIN IF CULL THEN RETURN; IF lx>dRX OR rxdBY OR ydRX THEN rx _ dRX; END; cgBox _ [xmin: lx, ymin: y, xmax: rx, ymax: y]; CGArea.InsertBox[cgArea,cgBox]; cgDevice.Show[cgDevice,cgArea,cgSource,NIL]; }; HLine: PROCEDURE[y,lx,rx: INTEGER, grey: GreyType, dc: Context] = BEGIN IF CLIP THEN BEGIN IF CULL THEN RETURN; IF lx>RX OR rxBY OR yRX THEN rx _ RX; END; cgSource.color _ grey; cgSource.mode _ FNC; DrawBox[xmin: lx, ymin: y, xmax: rx, ymax: y, dc: dc]; END; InvertBox: PUBLIC PROCEDURE[tl,br: PointDefs.ScrPt, dc: Context] = BEGIN OPEN PointDefs; lx: INTEGER _ tl[X]; ty: INTEGER _ tl[Y]; --simpler this way on a number of counts rx: INTEGER _ br[X]; by: INTEGER _ br[Y]; IF CLIP THEN BEGIN IF CULL THEN RETURN; IF lx>RX OR rxBY OR byRX THEN rx _ RX; IF ty < TY THEN ty _ TY; IF by >BY THEN by _ BY; END; cgSource.mode _ invert; cgSource.color _ black; DrawBox[xmin: lx,ymin: ty,xmax: rx,ymax: by, dc: dc]; END; EraseBox: PUBLIC PROCEDURE[tl,br: PointDefs.ScrPt, dc: Context] = BEGIN OPEN PointDefs; lx: INTEGER _ tl[X]; ty: INTEGER _ tl[Y]; --simpler this way on a number of counts rx: INTEGER _ br[X]; by: INTEGER _ br[Y]; IF CLIP THEN BEGIN IF CULL THEN RETURN; IF lx>RX OR rxBY OR byRX THEN rx _ RX; IF ty < TY THEN ty _ TY; IF by >BY THEN by _ BY; END; cgSource.mode _ opaque; cgSource.color _ white; DrawBox[xmin: lx,ymin: ty,xmax: rx,ymax: by, dc: dc]; END; BoxFill: PUBLIC PROCEDURE[tl,br: PointDefs.ScrPt, dc: Context] = BEGIN OPEN PointDefs; lx: INTEGER _ tl[X]; ty: INTEGER _ tl[Y]; --simpler this way on a number of counts rx: INTEGER _ br[X]; by: INTEGER _ br[Y]; IF CLIP THEN BEGIN IF CULL THEN RETURN; IF lx>RX OR rxBY OR byRX THEN rx _ RX; IF ty < TY THEN ty _ TY; IF by >BY THEN by _ BY; END; cgSource.color _ fillGrey; cgSource.mode _ FNC; DrawBox[xmin: lx,ymin: ty,xmax: rx,ymax: by, dc: dc]; END; ngridpieces: INTEGER _ 0; gridT: INTEGER _ 3; GetGridParameters: PUBLIC PROCEDURE RETURNS[center: PointDefs.ScrPt,hgridlx,hgridrx,vgridty,vgridby,gridt: INTEGER]= BEGIN pt: PointDefs.ScrPt; ngridpieces _ 1+(initBY-initTY)/8; pt _ [(initRX-initLX)/2, (initBY-initTY)/2]; pt _ GriffinDefs.Grid[pt]; RETURN[pt,initLX,initRX,initTY,initBY,gridT]; END; BltVGrid: PUBLIC PROCEDURE[lx: INTEGER, dc: Context]= BEGIN ty: INTEGER _ GriffinDefs.Grid[[0,initTY]][Y]; THROUGH [0..ngridpieces] DO BLTBlockInScreen[vgridBlock,[lx,ty],transparent,dc]; ty _ ty+8; ENDLOOP; END; BltHGrid: PUBLIC PROCEDURE[ty: INTEGER, dc: Context]= BEGIN lx: INTEGER _ GriffinDefs.Grid[[0,initLX]][X]; THROUGH [0..ngridpieces] DO BLTBlockInScreen[hgridBlock,[lx,ty],transparent, dc]; lx _ lx+8; ENDLOOP; END; <> cgSource: CGSource.Ref _ CZone.NEW[CGSource.Rep _ [type: const, mode: opaque, fat: TRUE, color: black, bps: 0, xbase: NIL, xrast: 0]]; cgArea: CGArea.Ref _ CGArea.New[]; viewer: ViewerClasses.Viewer _ GriffinViewer.GetViewer[]; YFlip: PROC [y: INTEGER] RETURNS [INTEGER] = INLINE { RETURN[ViewerOps.Top2Bottom[viewer,y]]; }; menuFont: Graphics.FontRef _ Graphics.MakeFont["Cream10"]; ShowMenuString: PUBLIC PROCEDURE [origin: PointDefs.ScrPt, rope: Rope.ROPE, dc: Context] = { width,ascent: REAL; paintProc: GriffinViewer.PaintProc = { <> Graphics.ClipBox[self: dc, box: [xmin: LX, xmax: RX+1,ymin: YFlip[BY] , ymax: YFlip[TY]+1] ]; Graphics.Translate[dc,origin[X],YFlip[origin[Y]]]; Graphics.SetCP[dc,0,0]; [] _ Graphics.SetPaintMode[dc,opaque]; Graphics.DrawRope[self: dc,rope: rope,font: menuFont]; }; [,,,ascent] _ Graphics.FontBox[menuFont]; [,,width,] _ Graphics.RopeBox[font: menuFont, rope: rope]; origin[X] _ origin[X]-Real.RoundI[width/2]; origin[Y] _ origin[Y]+Real.RoundI[ascent]; IF dc=NIL THEN GriffinViewer.DoPaint[paintProc] ELSE {[] _ Graphics.Save[dc]; paintProc[dc]; Graphics.Restore[dc]}; }; flip: ImagerTransform.Transformation _ ImagerTransform.Create[0,-1,0,1,0,0]; DrawChar: PUBLIC PROCEDURE [font: Font.FONT, origin: PointDefs.ScrPt, char: CHAR, dc: Context] = { transformation: ImagerTransform.Transformation _ ImagerTransform.Concat[pre: font.actualTransformation, post: flip]; paintProc: GriffinViewer.PaintProc = { ref: CGContext.Ref _ NARROW[dc.data]; dorg: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[origin[X],YFlip[origin[Y]]]]; orgX: INTEGER _ Real.RoundI[dorg.x]; --origin in device coordinates orgY: INTEGER _ Real.RoundI[dorg.y]; lx,rx,y: INTEGER; fontProc: SAFE PROC [sMin, fMin: INTEGER, fSize: NAT] = TRUSTED { <> lx _ fMin+orgX; rx _ lx+fSize; y _ sMin+orgY; IF CLIP THEN BEGIN IF CULL THEN RETURN; IF lx>dRX OR rxdBY OR ydRX THEN rx _ dRX; END; cgBox _ [xmin: lx, ymin: y, xmax: rx, ymax: y]; CGArea.InsertBox[cgArea,cgBox]; }; DeviceClipper[ref.matrix]; --set up dRX, etc. cgSource.color _ black; cgSource.mode _ opaque; font.fontGraphicsClass.maskProc[font,transformation,char,fontProc]; ref.device.Show[ref.device,cgArea,cgSource,NIL]; }; IF dc=NIL THEN GriffinViewer.DoPaint[paintProc] ELSE paintProc[dc]; }; BLTBlockInScreen: PUBLIC PROCEDURE[src: BlockPtr, tl: PointDefs.ScrPt, fnc: Graphics.PaintMode, dc: Context]= BEGIN OPEN PointDefs; paintProc: GriffinViewer.PaintProc = { [] _ Graphics.SetPaintMode[dc,fnc]; Graphics.SetCP[dc, dlx,YFlip[dty]]; --flip y dc.procs.DrawBits[self: dc, base: src.base, raster: src.raster, bitsPerPixel: 0, w: drx-dlx+1, h: dby - dty +1, x: x, y: y, xorigin: x, yorigin: y]; }; dlx,dty,drx,dby,x,y: INTEGER; <> dlx _ tl[X]; dty _ tl[Y]; drx _ dlx + src.w -1; dby _ dty + src.h -1; IF CLIP THEN BEGIN IF CULL THEN RETURN; IF dlx>RX OR drxBY OR dbyRX THEN drx _ RX; IF dty < TY THEN dty _ TY; IF dby >BY THEN dby _ BY; END; x _ src.lx+(dlx-tl[X]); y _ src.ty+(dty-tl[Y]); IF dc=NIL THEN GriffinViewer.DoPaint[paintProc] ELSE paintProc[dc]; END; DrawBox: PROC[xmin,ymin,xmax,ymax: INTEGER, dc: Context] = { paintProc: PROC[dc: Graphics.Context] = { ref: CGContext.Ref _ NARROW[dc.data]; newMin: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[xmin,YFlip[ymin]]]; newMax: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[xmax,YFlip[ymax]]]; cgBox: Graphics.Box _ [xmin: newMin.x, ymin: newMin.y, xmax: newMax.x, ymax: newMax.y]; CGArea.InsertBox[cgArea,cgBox]; ref.device.Show[ref.device,cgArea,cgSource,NIL]; }; IF dc=NIL THEN GriffinViewer.DoPaint[paintProc] ELSE paintProc[dc]; }; MoveScreenBox: PUBLIC PROCEDURE[tl,br: PointDefs.ScrPt,dx,dy: INTEGER] = BEGIN paintProc: PROC[dc: Graphics.Context] = { ref: CGContext.Ref _ NARROW[dc.data]; from: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[tl[X],YFlip[tl[Y]]]]; to: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[tl[X]+dx,YFlip[tl[Y]+dy]]]; xbr: GraphicsBasic.Vec _ CGMatrix.Map[ref.matrix,[br[X],YFlip[br[Y]]]]; lx: INTEGER _ Real.RoundI[to.x]; ty: INTEGER _ Real.RoundI[to.y]; rx: INTEGER _ Real.RoundI[lx+xbr.x-from.x]; by: INTEGER _ Real.RoundI[ty+xbr.y-from.y]; IF lx>RX OR rxBY OR byRX THEN rx _ RX; IF ty < TY THEN ty _ TY; IF by >BY THEN by _ BY; GraphicsOps.MoveDeviceRectangle[self: dc, width: rx-lx+1, height: by-ty+1, --trust we're not scaled fromX: MAX[LX,Real.RoundI[from.x]], fromY: MAX[TY,Real.RoundI[from.y]], toX: lx, toY: ty]; }; GriffinViewer.DoPaint[paintProc]; END; vgridBlock,hgridBlock: ScreenDefs.BlockPtr; vgridbits: PACKED ARRAY [0..8) OF CARDINAL _ ALL[040000B]; hgridbits: PACKED ARRAY [0..4) OF CARDINAL _ ALL[100200B]; vgridBlock _ NEW[Block _ [@vgridbits,1,0,0,3,8]]; hgridBlock _ NEW[Block _ [@hgridbits,1,0,0,8,3]]; vgridbits[0] _ 120000B; --rest are "040000B" hgridbits[1] _ 77577B; --rest are "100200B" <> CodedBrushes[1] _[NEW[IntegerSequenceRec[1]],NEW[IntegerSequenceRec[1]]]; CodedBrushes[1][left][0]_ 0; CodedBrushes[1][right][0]_ 0; CodedBrushes[2] _[NEW[IntegerSequenceRec[2]],NEW[IntegerSequenceRec[2]]]; CodedBrushes[2][left][0]_ -1; CodedBrushes[2][left][1]_ -1; CodedBrushes[2][right][0]_ 0; CodedBrushes[2][right][1]_ 0; CodedBrushes[3] _[NEW[IntegerSequenceRec[3]],NEW[IntegerSequenceRec[3]]]; CodedBrushes[3][left][0]_ 0; CodedBrushes[3][left][1]_ -1; CodedBrushes[3][left][2]_ 0; CodedBrushes[3][right][0]_ 0; CodedBrushes[3][right][1]_ 1; CodedBrushes[3][right][2]_ 0; CodedBrushes[4] _[NEW[IntegerSequenceRec[4]],NEW[IntegerSequenceRec[4]]]; CodedBrushes[4][left][0]_ -1; CodedBrushes[4][left][1]_ -2; CodedBrushes[4][left][2]_ -2; CodedBrushes[4][left][3]_ -1; CodedBrushes[4][right][0]_ 0; CodedBrushes[4][right][1]_ 1; CodedBrushes[4][right][2]_ 1; CodedBrushes[4][right][3]_ 0; END.