<< JunoGraphicsImpl.mesa>> <<>> <> <> <> <> << These are procedures which directly affect the Juno bitmap.>> << Imported by JunoTop and its submodules (JunoAlgebraImpl, JunoBody, JunoOldSolver...)>> DIRECTORY JunoGraphics, Font USING [WidthVector], JunoUserEvents USING[], Real USING [RoundI], Rope USING [ROPE, Cat, Map, ActionType, Equal], Graphics USING [Context, Translate, Scale, SetCP, GetBounds, SetColor, black, SetStipple, DrawBox], GraphicsOps USING [BitmapRef, NewBitmap, DrawBitmap], Carets USING [StartCaret, StopCaret], Imager USING [MakeFont, FONT, Trajectory, Context, XOR, black, white, MoveTo, LineTo, LineToX, LineToY, Create, SpecialOp, Pair, SetXYRel, SetXY, Trans, ClipRectangle, ScaleT, SetPriorityImportant, SetColor, MaskRectangle, MakeGray, SetStrokeEnd, SetStrokeWidth, SetFont, DoSave, MaskFill, MaskStroke, MaskVector, CurveTo, ShowCharacters, ShowChar, Reset], ImagerPixelMaps USING [PixelMap, CreateFrameBuffer, Clear], ImagerBasic USING [ColorRep], ImagerPD USING [PDFileDescription, Raven, Puffin, PlateMaker]; JunoGraphicsImpl: CEDAR MONITOR IMPORTS Font, Real, Graphics, GraphicsOps, Carets, Imager, ImagerPD, ImagerPixelMaps, Rope EXPORTS JunoGraphics = BEGIN OPEN JunoGraphics, Evs: JunoUserEvents, ImMaps: ImagerPixelMaps, ImPD: ImagerPD, ImBas: ImagerBasic, Rope; << - - - - GRAPHICS STATE>> << The variables below need not be protected by the monitor lock, since they are set and used only by the main process (JunoTop). >> buf: REF ImMaps.PixelMap _ NIL; -- REF to Imager-style descriptor of buffer bitmap bufCtx: Imager.Context; -- A context that paints into buf. Origin at bottom left, 1 dot/unit ctx: Imager.Context _ NIL; -- Either bufCtx or a PD context (or NIL at first). invert: PUBLIC Color _ Imager.XOR; black: PUBLIC Color _ Imager.black; white: PUBLIC Color _ Imager.white; currentColor: PUBLIC Color _ Imager.black; currentEnds: PUBLIC ATOM _ $round; currentWidth: PUBLIC REAL _ 0; currentFontName: PUBLIC ROPE _ "Helvetica"; currentFontSize: PUBLIC REAL _ 12; currentFontFace: PUBLIC ATOM _ $regular; currentJustification: PUBLIC ATOM _ $left; currentFont: Imager.FONT; << - - - - GRAPHICS STATE OPS>> SetScreenContext: PUBLIC PROC = {IF ctx # NIL AND ctx # bufCtx THEN {[] _ Imager.SpecialOp[ctx, $Close, NIL]}; ctx _ bufCtx; ResetGraphicParameters[width: 0, color: invert]; PicChanged[] -- superfluous ? --}; SetPaperContext: PUBLIC PROC [device: ATOM, fileName: ROPE, mag: REAL _ 1.0] = BEGIN pageSize: Coords = SELECT device FROM $Raven => [8.5, 11], $Puffin => [8.5, 11], $PlateMaker => [8.5, 11], -- check these numbers ENDCASE => ERROR; paperCtx: Imager.Context = Imager.Create[$PD, SELECT device FROM $Raven => ImPD.Raven[fileName], $Puffin => ImPD.Puffin[fileName], $PlateMaker => ImPD.PlateMaker[fileName], ENDCASE => ERROR]; IF ctx # bufCtx AND ctx # NIL THEN {[] _ Imager.SpecialOp[ctx, $Close, NIL]}; ctx _paperCtx; ResetGraphicParameters[width: 0.4, color: black, mag: mag]; Imager.SetXY[ctx, [pageSize.x*72/2/mag, pageSize.y*72/2/mag]]; Imager.SetXYRel[ctx, [-currentPictureWidth/2, -currentPictureHeight/2]]; Imager.Trans[ctx]; Imager.ClipRectangle[ctx, 0, 0, currentPictureWidth, currentPictureHeight] END; Whiten: PUBLIC PROC = {ImMaps.Clear[buf^]; PicChanged[]}; ResetGraphicParameters: PROC [width: REAL, color: Color, mag: REAL _ 1.0] = <> BEGIN Imager.Reset[ctx]; Imager.ScaleT[ctx, 0.0254/72/mag]; Imager.SetPriorityImportant[ctx, TRUE]; DoSetFont[ctx: ctx, name: "Helvetica", face: $regular, size: 14]; [] _ SetEnds[$round]; [] _ SetColor[color]; [] _ SetWidth[width]; [] _ SetJustification[$left] END; SetColor: PUBLIC PROC [color: Color] RETURNS [old: Color] = BEGIN old _ currentColor; Imager.SetColor[ctx, color]; currentColor _ color END; IntensityToColor: PUBLIC PROC [intensity: REAL] RETURNS [color: Color] = BEGIN color _ Imager.MakeGray[intensity] END; RGBToColor: PUBLIC PROC [r, g, b: REAL] RETURNS [color: Color] = BEGIN color _ NEW [ImBas.ColorRep[constant] _ [constant [x: Real.RoundI[r*10000], y: Real.RoundI[g*10000], Y: Real.RoundI[b*10000]]]] END; SetEnds: PUBLIC PROC [ends: ATOM] RETURNS [old: ATOM] = BEGIN old _ currentEnds; Imager.SetStrokeEnd [ctx, SELECT ends FROM $round => round, $square => square, $butt => butt, ENDCASE => ERROR]; currentEnds _ ends END; SetWidth: PUBLIC PROC [width: REAL] RETURNS [old: REAL] = BEGIN old _ currentWidth; Imager.SetStrokeWidth [ctx, width]; currentWidth _ width END; SetFontName: PUBLIC PROC [name: ROPE] RETURNS [old: ROPE] = BEGIN old _ currentFontName; IF NOT Equal[currentFontName, name] THEN {DoSetFont [ctx, name, currentFontFace, currentFontSize]} END; SetFontSize: PUBLIC ENTRY PROC [size: REAL] RETURNS [old: REAL] = BEGIN old _ currentFontSize; IF currentFontSize # size THEN {DoSetFont [ctx, currentFontName, currentFontFace, size]} END; SetFontFace: PUBLIC ENTRY PROC [face: ATOM] RETURNS [old: ATOM] = BEGIN old _ currentFontFace; IF currentFontFace # face THEN {DoSetFont [ctx, currentFontName, face, currentFontSize]} END; DoSetFont: PROC [ctx: Imager.Context, name: ROPE, face: ATOM, size: REAL] = BEGIN currentFont _ Imager.MakeFont [name: Cat["Xerox/PressFonts/", name, SELECT face FROM $regular => "/MRR", $italic => "/MIR", $bold => "/BRR", $boldItalic => "/BIR", ENDCASE => ERROR], size: size]; currentFontName _ name; currentFontFace _ face; currentFontSize _ size; Imager.SetFont [ctx, currentFont] END; SetJustification: PUBLIC PROC [justification: ATOM] RETURNS [old: ATOM] = BEGIN old _ currentJustification; currentJustification _ justification END; << - - - - POINT HIGHLIGHTS (AFFECTS SCREEN IMAGE ONLY)>> << Trajectories for point highlights (Shouldn't we use a special symbol font instead?):>> plusTraj: Imager.Trajectory = Imager.MoveTo[[-1, -1]].LineTo[[-5, -1]].LineTo[[-5, +1]] .LineTo[[-1, +1]].LineTo[[-1, +5]].LineTo[[+1, +5]].LineTo[[+1, +1]] .LineTo[[+5, +1]].LineTo[[+5, -1]].LineTo[[+1, -1]].LineTo[[+1, -5]] .LineTo[[-1,-5]]; crossTraj: Imager.Trajectory = Imager.MoveTo[[-1, 0]].LineTo[[-5, +4]].LineTo[[-4, +5]] .LineTo[[0, +1]].LineTo[[+4, +5]].LineTo[[+5, +4]].LineTo[[+1, 0]] .LineTo[[+5, -4]].LineTo[[+4, -5]].LineTo[[0, -1]].LineTo[[-4, -5]] .LineTo[[-5,-4]]; diam6Traj: Imager.Trajectory = Imager.MoveTo[[-6,0]].LineTo[[0,-6]].LineTo[[6, 0]].LineTo[[0,6]]; diam5Traj: Imager.Trajectory = Imager.MoveTo[[-5,0]].LineTo[[0,-5]].LineTo[[5, 0]].LineTo[[0,5]]; box4Traj: Imager.Trajectory = Imager.MoveTo[[-4,-4]].LineToX[+4].LineToY[+4].LineToX[-4]; box3Traj: Imager.Trajectory = Imager.MoveTo[[-3,-3]].LineToX[+3].LineToY[+3].LineToX[-3]; SetOrg: PROC [ctx: Imager.Context, coords: Coords] = INLINE <> {Imager.SetXY[ctx, coords]; Imager.Trans[ctx]}; Highight: PUBLIC PROC [coords: Coords, symbol: PointSymbol] = BEGIN DoShow: PROC = BEGIN Imager.SetColor[ctx, invert]; SetOrg[ctx, coords]; SELECT symbol FROM box => {Imager.MaskRectangle[ctx, -4, -4, 8, 8]; Imager.MaskRectangle[ctx, -3, -3, 6, 6]}; plus => {Imager.MaskFill[ctx, plusTraj]}; cross => {Imager.MaskFill[ctx, crossTraj]}; diamond => {Imager.MaskFill[ctx, diam6Traj]; Imager.MaskFill[ctx, diam5Traj]}; dot => {Imager.MaskRectangle[ctx, -1, -1, 2, 2]}; bigDot => {Imager.MaskRectangle[ctx, -2, -2, 4, 4]}; ENDCASE => ERROR; END; Imager.DoSave[ctx, DoShow]; PicChanged[] END; << - - - - POINTS>> DrawPoint: PUBLIC PROC[coords: Coords] = BEGIN DoDraw: PROC = {SetOrg[ctx, coords]; Imager.MaskRectangle[ctx, -1, -1, 2, 2]}; Imager.DoSave[ctx, DoDraw]; PicChanged[] END; << - - - - LINES, STROKES, FILLED PATHS>> DrawEdge: PUBLIC PROC [p, q: Coords, thin: BOOL _ FALSE] = BEGIN Imager.MaskVector [context: ctx, p1: [p.x, p.y], p2: [q.x, q.y], strokeWidth: IF thin THEN 0 ELSE currentWidth]; PicChanged[] END; DrawArc: PUBLIC PROC [p, r, s, q: Coords, thin: BOOL _ FALSE] = BEGIN Imager.MaskStroke [context: ctx, t: Imager.MoveTo[p].CurveTo[r, s, q], strokeWidth: IF thin THEN 0 ELSE currentWidth]; PicChanged[] END; AppendEdge: PUBLIC PROC [t: Trajectory, p, q: Coords] RETURNS [new: Trajectory] = BEGIN IF t = NIL THEN t _ Imager.MoveTo[p]; new _ t.LineTo[q]; END; AppendArc: PUBLIC PROC [t: Trajectory, p, r, s, q: Coords] RETURNS [new: Trajectory] = BEGIN IF t = NIL THEN t _ Imager.MoveTo[p]; new _ t.CurveTo[r, s, q]; END; FillTrajectory: PUBLIC PROC [t: Trajectory] = BEGIN Imager.MaskFill[ctx, t]; PicChanged[] END; StrokeTrajectory: PUBLIC PROC [t: Trajectory] = BEGIN Imager.MaskStroke[ctx, t]; PicChanged[] END; GcTrajectory: PUBLIC PROC [t: Trajectory] = BEGIN END; << - - - - CHARS AND ROPES>> DrawChar: PUBLIC PROC [coords: Coords, char: CHAR] = BEGIN DoDraw: PROC = {SetOrg[ctx, coords]; Imager.ShowChar[ctx, char]}; Imager.DoSave[ctx, DoDraw]; PicChanged[] END; DrawRope: PUBLIC PROC [coords: Coords, rope: ROPE] = BEGIN LeftEndPoint: PROC RETURNS [lep: Coords] = INLINE {IF currentJustification = $left THEN {RETURN [coords]} ELSE {vec: Coords _ GetRopeDispl[rope]; IF currentJustification = $right THEN {RETURN [[coords.x-vec.x, coords.y-vec.y]]} ELSE {RETURN [[coords.x-vec.x/2, coords.y-vec.y/2]]}}}; DoDraw: PROC = {SetOrg[ctx, LeftEndPoint[]]; Imager.ShowCharacters[ctx, rope]}; Imager.DoSave[ctx, DoDraw]; PicChanged[] END; GetRopeDispl: PUBLIC PROC[rope: ROPE] RETURNS [vec: Coords] = BEGIN Act: ActionType = TRUSTED {w: Coords = Font.WidthVector[currentFont, c]; vec _ [vec.x+w.x, vec.y+w.y]}; vec _ [0,0]; [] _ Map[base: rope, action: Act] END; << - - - - BITMAP BUFFER>> << The following data (except picChanged and the bits in the bitmap buffer) must be protected by the monitor lock, since they are altered by the main client process (JunoTop) and consulted by the bitmap-to-viewer dumping process (RefreshViewer). >> currentPictureWidth: PUBLIC INTEGER _ 0; -- current picture dimensions (Juno units) currentPictureHeight: PUBLIC INTEGER _ 0; gbuf: GraphicsOps.BitmapRef _ NIL; -- REF to Graphics-style descriptor of buffer bitmap bufferPos: IntCoords _ [0, 0]; -- position of origin of bitmap buffer wrt origin of viewer picChanged: PUBLIC BOOLEAN _ TRUE; <> bufferChanged: BOOLEAN _ TRUE; <> PicChanged: ENTRY PROC = INLINE {picChanged _ TRUE}; << - - - - BUFFER-RELATED PROCEDURES>> CreateBitmap: PROC [width, height: INTEGER] RETURNS [im: REF ImMaps.PixelMap, gra: GraphicsOps.BitmapRef] = <> BEGIN gra _ GraphicsOps.NewBitmap [width, height]; TRUSTED{im _ NEW [ImMaps.PixelMap _ ImMaps.CreateFrameBuffer [pointer: LOOPHOLE [gra.base], words: gra.raster*gra.height, lgBitsPerPixel: 0, rast: gra.raster, lines: gra.height]]} END; SetPictureSize: PUBLIC ENTRY PROC [width, height: INTEGER] = BEGIN IF buf=NIL OR width # currentPictureWidth OR height # currentPictureHeight THEN {tmpCtx: Imager.Context; [buf, gbuf] _ CreateBitmap[width, height]; tmpCtx _ Imager.Create[deviceType: $LFDisplay, data: buf]; IF ctx # NIL AND ctx = bufCtx THEN ctx _ tmpCtx; bufCtx _ tmpCtx; currentPictureWidth _ width; currentPictureHeight _ height}; ImMaps.Clear[buf^]; bufferChanged _ picChanged _ TRUE END; << - - - - BLINKING CARET>> << The following data is also protected by the monitor lock: >> caretReallyOn: BOOL _ FALSE; -- if TRUE, caret is currently on (set by PaintBuffer) caretOn: PUBLIC BOOL _ FALSE; -- if TRUE, caret is being turned on (set by SetCaret) caretPos: PUBLIC Coords; -- current caret position, in Juno coordinates caretChanged: BOOL _ FALSE; -- set when caretPos changes, reset by PaintBuffer SetCaret: PUBLIC ENTRY PROC [on: BOOL _ TRUE, coords: Coords_[0,0]] = {caretOn _ on; caretPos _ coords; picChanged _ caretChanged _ TRUE}; << - - - - VIEWER/JUNO COORDINATE MAPPING>> ViewerToJuno: PUBLIC ENTRY PROC [viewer: Viewer, view: IntCoords] RETURNS [coords: IntCoords] = {coords.x _ view.x - bufferPos.x; coords.y _ (viewer.ch - view.y) - bufferPos.y}; InternalJunoToViewer: INTERNAL PROC [viewer: Viewer, coords: Coords] RETURNS [view: IntCoords] = INLINE {view.x _ Real.RoundI[coords.x]+bufferPos.x; view.y _ viewer.ch - (Real.RoundI[coords.y] + bufferPos.y)}; JunoToViewer: PUBLIC ENTRY PROC [viewer: Viewer, coords: Coords] RETURNS [view: IntCoords] = {RETURN [InternalJunoToViewer[viewer, coords]]}; << - - - - BUFFER PAINTING>> PaintBuffer: PUBLIC ENTRY PROC [viewer: Viewer, context: Graphics.Context, viewerChanged: BOOL] = <> <> BEGIN IF viewerChanged THEN {Graphics.SetStipple[self: context, pattern: 055132B]; Graphics.DrawBox[self: context, box: Graphics.GetBounds[self: context]]}; Graphics.SetColor[self: context, color: Graphics.black]; -- change coordinate system from top-to-bottom to bottom-to-top; Graphics.Translate[self: context, tx: 0, ty: viewer.ch]; Graphics.Scale[self: context, sx: 1, sy: -1]; Graphics.SetCP[self: context, x: bufferPos.x, y: bufferPos.y]; GraphicsOps.DrawBitmap [self: context, bitmap: gbuf, w: gbuf.width, h: gbuf.height, xorigin: 0, yorigin: currentPictureHeight]; IF caretReallyOn AND (NOT caretOn OR viewerChanged OR bufferChanged OR caretChanged) THEN {Carets.StopCaret[primary]; caretReallyOn _ FALSE}; IF caretOn AND NOT caretReallyOn THEN {view: IntCoords = InternalJunoToViewer[viewer, caretPos]; Carets.StartCaret[viewer, view.x, view.y, primary]; caretReallyOn _ TRUE}; picChanged _ bufferChanged _ caretChanged _ FALSE END; << - - - - INITIALIZATION>> SetPictureSize[width: 612, height: 792]; -- 8.5 by 11 inches Whiten[]; SetScreenContext[] END.