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; 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; 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; 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; DrawPoint: PUBLIC PROC[coords: Coords] = BEGIN DoDraw: PROC = {SetOrg[ctx, coords]; Imager.MaskRectangle[ctx, -1, -1, 2, 2]}; Imager.DoSave[ctx, DoDraw]; PicChanged[] END; 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; 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; 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}; 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; 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}; 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]]}; 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; SetPictureSize[width: 612, height: 792]; -- 8.5 by 11 inches Whiten[]; SetScreenContext[] END.  JunoGraphicsImpl.mesa Coded July 1982 by Donna M. Auguste & Greg Nelson Edited December 7, 1982 5:10 pm Last Edited by: Gnelson, June 27, 1983 3:51 pm Last Edited by: Stolfi, June 15, 1984 7:48:38 am PDT These are procedures which directly affect the Juno bitmap. Imported by JunoTop and its submodules (JunoAlgebraImpl, JunoBody, JunoOldSolver...) - - - - 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). - - - - GRAPHICS STATE OPS Resets default values of all graphics parameters (color, justification, font, scale factors). - - - - POINT HIGHLIGHTS (AFFECTS SCREEN IMAGE ONLY) Trajectories for point highlights (Shouldn't we use a special symbol font instead?): Redefines origin at the given coordinates, rounded to the nearest pixel - - - - POINTS - - - - LINES, STROKES, FILLED PATHS - - - - CHARS AND ROPES - - - - 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). Signals that something (bits, buffer size, buffer offset, caret position) changed since last painting on viewer. Set by operations that paint on buf. Reset by PaintBuffer after dumping buf onto viewer. Set by operations that change buffer size or position, reset by PaintProc after dumping buf onto viewer. - - - - BUFFER-RELATED PROCEDURES This abominable crock creates a new bitmap of the specified size, and two descriptors to it, one suitable to paint into with the Imager, the other suitable to paint from with GraphisOps. - - - - BLINKING CARET The following data is also protected by the monitor lock: - - - - VIEWER/JUNO COORDINATE MAPPING - - - - BUFFER PAINTING Paints the bitmap buffer on the viewer. Also recomputes the Juno-to-Viewer coordinate transformations, to account for the current size of bitmap and viewer. - - - - INITIALIZATION Ê ¿˜™™J™1J™J™.J™6—J™šœ˜šœŸœœ˜šœ˜Jšœ˜Jšœ˜šœœ˜šœ˜JšœU˜U—šœ˜Jšœ"˜"—šœ ˜ Jšœ#˜#—šœ ˜ JšœE˜E—šœ˜Jšœ+˜+—šœ ˜ Jšœ+˜+—Jšœœœ˜——Jšœœ˜—Jšœ)˜)—Jšœœ˜——šŸœ™šœŸ œœœ˜)šœ˜šœŸœœ˜JšœA˜A—Jšœ)˜)—Jšœœ˜——šŸœ$™%š œŸœœœœœ˜;šœ˜JšœRœœœ˜—Jšœœ˜—š œŸœœœœœ˜@šœ˜JšœXœœœ˜‡—Jšœœ˜—š œŸ œœœœ˜Ršœ˜Jšœœœœ)˜9—Jšœœ˜—š œŸ œœœ%œ˜Wšœ˜Jšœœœœ0˜@—Jšœœ˜—šœŸœœœ˜.šœ˜Jšœ&˜&—Jšœœ˜—šœŸœœœ˜0šœ˜Jšœ(˜(—Jšœœ˜—šœŸ œœœ˜,Jšœ˜Jšœœ˜——šŸœ™š œŸœœœœ˜5šœ˜JšœŸœœ^˜k—Jšœœ˜—š œŸœœœœ˜5šœ˜šœŸ œœœ˜2Jšœœœœ œ)œœœ(œœ+˜þ—JšœŸœœC˜PJšœ)˜)—Jšœœ˜—š œŸ œœœœœ˜>šœ˜JšœžœœU˜oJšœ/˜/—Jšœœ˜——šŸœ™Jšœõ™õJšœžœœœ +žœœœ˜~Jšœžœœ 4˜XJšœž œ ;˜[š œž œœœœ˜#JšœÉ™É—šœž œœœ˜Jšœh™h—Jš œÐbn œœœœœ˜5—šŸœ!™"š œŸ œœœœœ/˜nJ™¼šœ˜Jšœ.œœ<œ|˜þ—Jšœœ˜—š œŸœœœœœ˜=šœ˜Jšœœœœœœ‹œœœœb˜ßJšœ2˜6—Jšœœ˜——šœ™Jšœ<™œ˜dšœ'™'J™u—šœ˜Jšœœœ†˜œJšœ9˜9Jšœ Aœf˜¨JšœÌ˜ÌJšœœœœ œœœœ0œ˜”Jš œœ œœœ‹œ˜¸Jšœ,˜1—Jšœœ˜——šŸœ™Jšœ* œ˜Z—Jšœœ˜—…—0øEÅ