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...)
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
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] =
Resets default values of all graphics parameters (color, justification, font, scale factors).
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
Redefines origin at the given coordinates, rounded to the nearest pixel
{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;
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.
bufferChanged:
BOOLEAN ←
TRUE;
Set by operations that change buffer size or position, reset by PaintProc after dumping buf onto viewer.
PicChanged: ENTRY PROC = INLINE {picChanged ← TRUE};
- - - - BUFFER-RELATED PROCEDURES
CreateBitmap:
PROC [width, height:
INTEGER]
RETURNS [im:
REF ImMaps.PixelMap, gra: GraphicsOps.BitmapRef] =
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.
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] =
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.
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.