-- December 7, 1982 5:10 pm
--  JunoGraphicsImpl.mesa coded July 1982 by Donna M. Auguste & Greg Nelson

--  These are procedures which directly affect the Juno bitmap.
--  Imported by JunoTop & JunoAlgebra
-- Last Edited by: Gnelson, June 27, 1983 3:51 pm

DIRECTORY JunoGraphics, Graphics, GraphicsOps, ViewerClasses, GraphicsToPress,
               Rope, Terminal, JunoStorage, VFonts, IO, Atom, Real, 
               MessageWindow, GraphicsToPressPrivate, SirPress;

JunoGraphicsImpl: PROGRAM
  IMPORTS Graphics, GraphicsOps,  JunoStorage, GraphicsToPress,
              VFonts, Rope, MessageWindow, GraphicsToPressPrivate, SirPress, Real 
  EXPORTS JunoGraphics =
  BEGIN  OPEN JS: JunoStorage;

PointPtr: TYPE = JS.PointPtr;
  
bm: GraphicsOps.BitmapRef ← GraphicsOps.NewBitmap [width: 1024, height: 808];
screenContext: Graphics.Context ← GraphicsOps.NewContextFromBitmap [bm];
pressContext: Graphics.Context;
dc: Graphics.Context ← screenContext; 
 -- dc = screenContext except when making a press file, when dc = pressContext.
screenwidth: CARDINAL ← 1024; 
screenheight: CARDINAL  ← 808;
viewerChanged: PUBLIC BOOLEAN ← TRUE;
halfX, halfY: REAL ← 404.0;   -- 404 = 808 (default screenheight) / 2
cursorOffsetY: PUBLIC REAL ← 0;

currentFont: PUBLIC Rope.ROPE ← "Helvetica";
currentPointSize: PUBLIC INT ← 16;
currentBold: PUBLIC BOOL ← FALSE;
currentItalic: PUBLIC BOOL ← FALSE;
    
myfont: PUBLIC Graphics.FontRef ←
    VFonts.GraphicsFont[VFonts.EstablishFont[currentFont, currentPointSize]];
fontHeight : PUBLIC INTEGER ←
                VFonts.FontHeight[VFonts.EstablishFont[currentFont,currentPointSize]];

bitmap: GraphicsOps.BitmapRef = GraphicsOps.NewBitmap[16, 16];

sirPressHandle: SirPress.PressHandle;

DcGetsPressContext: PUBLIC PROC[filename: Rope.ROPE] =
{ pressContext  ← GraphicsToPress.NewContext[filename];
  sirPressHandle ← GraphicsToPressPrivate.SirPressHandle[pressContext];
  [] ← Graphics.SetPaintMode[pressContext, opaque];
  dc ← pressContext};

DcGetsScreenContext: PUBLIC PROC =
{GraphicsToPress.Close[pressContext];
 dc ← screenContext};

SetPaintMode: PUBLIC PROC [mode: Graphics.PaintMode] =  {
  [] ← Graphics.SetPaintMode[screenContext, mode] };

GetNewFont: PUBLIC PROC =
{ myfont ←
    VFonts.GraphicsFont[VFonts.EstablishFont[currentFont, currentPointSize, currentBold, currentItalic]];
   fontHeight ← 
     VFonts.FontHeight[VFonts.EstablishFont[currentFont,currentPointSize]]};

DrawPattern: PUBLIC PROC[p:Terminal.BWCursorBitmap, x, y: REAL] =
 {LOOPHOLE[bitmap.base, LONG POINTER TO Terminal.BWCursorBitmap]↑ ← p;
  Graphics.SetCP[dc, x, y];
  GraphicsOps.DrawBitmap[dc, bitmap, 16, 16];
  viewerChanged ← TRUE};
  
Hylite: PUBLIC PROC[x,y: INTEGER, d:INTEGER] =
  {SELECT d FROM
    0 => {Graphics.DrawBox[dc, [x - 5, y+4, x+4, y+5]];
          Graphics.DrawBox[dc, [x+4, y-4, x+5, y+5]];
	  Graphics.DrawBox[dc, [x-4, y-5, x+5, y-4]];
	  Graphics.DrawBox[dc, [x-5, y-5, x-4, y+4]]};
    1 => {Graphics.DrawBox[dc, [x - 1, y - 5, x + 1, y + 5]];
          Graphics.DrawBox[dc, [x - 5, y - 1, x + 5, y + 1]]};
  > 1 => {p: Graphics.Path ← Graphics.NewPath[];
          Graphics.MoveTo[p, x - 1, y];
          Graphics.LineTo[p, x-5, y+4];
	  	   Graphics.LineTo[p, x-4, y+5]; 
          Graphics.LineTo[p, x, y+1];
          Graphics.LineTo[p, x+4, y+5];
          Graphics.LineTo[p, x+5, y+4];
          Graphics.LineTo[p, x+1,y];
          Graphics.LineTo[p, x+5,y-4];
          Graphics.LineTo[p, x+4,y-5];
          Graphics.LineTo[p, x,y-1];
          Graphics.LineTo[p, x-4,y-5];
          Graphics.LineTo[p, x-5,y-4];
          Graphics.DrawArea[dc, p]};
    ENDCASE => ERROR;
   viewerChanged ← TRUE}; 
   
RopeBox: PUBLIC PROC[myRope: Rope.ROPE]
                            RETURNS [REAL, REAL, REAL, REAL] =
 { xmin, ymin, xmax, ymax: REAL;
   [xmin, ymin, xmax, ymax] ← Graphics.RopeBox [myfont, myRope];
   RETURN[xmin, ymin, xmax, ymax]  };
 
CharWidth: PUBLIC PROC[char: CHAR] RETURNS [REAL, REAL] =
{ xw, yw: REAL;
   [xw, yw] ← Graphics.CharWidth [myfont, char];
   RETURN[xw, yw] };

DrawChar: PUBLIC PROC [char: CHAR, x, y: REAL] =
{   Graphics.SetCP[dc, x, y];
    Graphics.DrawChar [dc, char, myfont];
    viewerChanged ← TRUE};
   
DrawRope: PUBLIC PROC [myRope: Rope.ROPE, x, y: REAL] =
{   Graphics.SetCP[dc, x, y];
    Graphics.DrawRope [self: dc, rope: myRope, font: myfont];
    viewerChanged ← TRUE};

PaintMe: PUBLIC ViewerClasses.PaintProc  
-- self: Viewer,
-- context: Graphics.Context,
-- whatChanged: REF ANY,
-- clear: BOOL
= TRUSTED
  {box: Graphics.Box = Graphics.GetBounds[context];
    halfX ← (box.xmax - box.xmin) / 2.0;
    halfY ← (box.ymax - box.ymin) / 2.0;
    cursorOffsetY ← halfY - (screenheight/2);
   IF self.iconic THEN RETURN;
   [ ] ← Graphics.SetPaintMode[self: context, mode: opaque];
   Graphics.SetCP[self: context, x: 0, y: halfY ];
   GraphicsOps.DrawBitmap
     [self: context, bitmap: bm, w: screenwidth, h: screenheight,
      x: 0, y: 0, xorigin: 0,
      yorigin: screenheight/2] };
      
         
 Whiten: PUBLIC PROC =
  { IF dc = screenContext THEN
         {[] ← Graphics.SetPaintMode[dc, opaque];
          Graphics.SetColor[dc, Graphics.white];
          Graphics.DrawBox[dc, [0, 0, 1200, 808]];
          Graphics.SetColor[dc, Graphics.black];
          [] ← Graphics.SetPaintMode[dc, invert]; }
          };
     
 	
DrawPoint: PUBLIC PROC[x, y: INTEGER] =
  {IF dc = screenContext THEN 
     {p: Graphics.Path ← Graphics.NewPath[];
      Graphics.MoveTo[p, x - 1, y - 1];
      Graphics.LineTo[p, x - 1, y + 1];
      Graphics.LineTo[p, x + 1, y + 1];
      Graphics.LineTo[p, x + 1, y - 1];
      Graphics.DrawArea[dc, p];
      viewerChanged ← TRUE}
	};

DrawEdge: PUBLIC PROC[x1, y1, x2, y2: REAL] =
  {p: Graphics.Path ← Graphics.NewPath[];
   Graphics.MoveTo[p, x1, y1];
   Graphics.LineTo[p, x2, y2];
   Graphics.DrawStroke[dc, p, 1, FALSE, round];
   viewerChanged ← TRUE};
  
DrawArc: PUBLIC PROC[x1, y1, x2, y2, x3, y3, x4, y4: REAL] =
  {p: Graphics.Path ← Graphics.NewPath[];
	Graphics.MoveTo[p, x1, y1];
   Graphics.CurveTo[p, x2, y2, x3, y3, x4, y4];
   Graphics.DrawStroke[dc, p, 1, FALSE, round];
   viewerChanged ← TRUE};

DrawString: PUBLIC PROC[x3, y3: REAL, 
                                myRope: Rope.ROPE, 
                                stringFont: Graphics.FontRef ← myfont,
                                fontName: Rope.ROPE,
                                fontSize: INT,
                                bold, italic: BOOL] = 
     {Ord: PROC[b: BOOL] RETURNS [INT] =
       {IF b THEN RETURN[1] ELSE RETURN[0]};
       IF dc = screenContext THEN
        {Graphics.SetCP[dc, x3, y3];
         IF stringFont = NIL THEN
           stringFont ← 
             VFonts.GraphicsFont[VFonts.EstablishFont[fontName, fontSize, bold, italic]];
         Graphics.DrawRope[self: dc, rope: myRope, font: stringFont];
         RETURN};
       -- dc = pressContext
       SirPress.SetFont[sirPressHandle, fontName, fontSize, Ord[italic] + 2 * Ord[bold]];
       SirPress.PutText[sirPressHandle, myRope, Real.RoundLI[x3 * SirPress.pt],
                          Real.RoundLI[y3 * SirPress.pt], 1]};
     	  
NewGraphicsPoint: PROC [x,y: INTEGER,  visible: BOOL ← TRUE] 
     RETURNS [PointPtr] =
      {p: JS.PointPtr ← JS.AddPoint[x,y];
        p.visible ← visible;
        IF visible THEN DrawPoint[x,y];
        RETURN [p]};
        
Blink: PUBLIC PROC[item1, item2, item3, item4, item5:  Rope.ROPE ← NIL] =
   {errMsg: Rope.ROPE ← Rope.Cat[item1, item2, item3, item4, item5, "\n"];  
      --  the last rope concatenated is a carriage return
    MessageWindow.Clear[];
    MessageWindow.Append[errMsg];
    MessageWindow.Blink[]};
 
 p:Graphics.Path ← Graphics.NewPath[];
 
 pathEmpty: BOOL;
 
 colorStack: LIST OF Graphics.Color ← NIL;
 color: Graphics.Color ← Graphics.black;
 endsStack: LIST OF Graphics.StrokeEnds ← NIL;
 ends: Graphics.StrokeEnds ← round;
 widthStack: LIST OF REAL ← NIL;
 width: REAL ← 0;
 
 BeginStroke: PUBLIC PROC =
   {Graphics.FlushPath[p];
    pathEmpty ← TRUE};

EdgeStroke: PUBLIC PROC[x1, y1, x2, y2: REAL] =
  {IF pathEmpty THEN {Graphics.MoveTo[p, x1, y1]; pathEmpty ← FALSE};
   Graphics.LineTo[p, x2, y2]};

ArcStroke: PUBLIC PROC[x1, y1, x2, y2, x3, y3, x4, y4: REAL] =
  {IF pathEmpty THEN {Graphics.MoveTo[p, x1, y1]; pathEmpty ← FALSE};
   Graphics.CurveTo[p, x2, y2, x3, y3, x4, y4]};

DrawStroke: PUBLIC PROC =
  {Graphics.DrawStroke[dc, p, width, FALSE, ends]};

DrawArea: PUBLIC PROC =
  {Graphics.DrawArea[dc, p, FALSE]};
  
PushColor: PUBLIC PROC[a: REF] =
  {colorStack ← CONS[color, colorStack];
   color ← LookUpColor[a];
   Graphics.SetColor[dc, color]};  
   
PopColor: PUBLIC PROC =
  {color ← colorStack.first;
   Graphics.SetColor[dc, color];
   colorStack ← colorStack.rest};
   
PushEnds: PUBLIC PROC[a: REF] =
  {endsStack ← CONS[ends, endsStack];
   ends ← LookUpEnds[a]};

PopEnds: PUBLIC PROC =
  {ends ← endsStack.first;
   endsStack ← endsStack.rest};
   
PushWidth: PUBLIC PROC[r: REAL] =
 {widthStack ← CONS[width, widthStack];
  width ← r};

PopWidth: PUBLIC PROC =
  {width ← widthStack.first;
   widthStack ← widthStack.rest};

LookUpColor: PROC[r: REF] RETURNS [Graphics.Color] =
  {SELECT TRUE FROM
    r = $black => RETURN[Graphics.black];
    r = $white => RETURN[Graphics.white];
    r = $grey => RETURN[[r: 64, g: 64, b: 64]];
    
    r = $red => RETURN[[r: 255, g: 0, b: 0]];
    r = $blue => RETURN[[r:0, g: 0, b: 255]];
    r = $green => RETURN[[r:0, g:255, b: 0]];
    
    r = $darkred => RETURN[[r: 128, g: 0, b: 0]];
    r = $darkblue => RETURN[[r:0, g: 0, b: 128]];
    r = $darkgreen => RETURN[[r:0, g:128, b: 0]];
    
    r = $lightred => RETURN[[r: 255, g: 64, b: 64]];
    r = $lightblue => RETURN[[r:64, g: 64, b: 255]];
    r = $lightgreen => RETURN[[r:64, g:255, b: 64]];

    r = $yellow => RETURN[[r: 255, g: 255, b: 0]];
    r = $cyan => RETURN[[r: 0, g: 255, b: 255]];
    r = $magenta => RETURN[[r: 255, g: 0, b: 255]];
    
    r = $darkyellow => RETURN[[r: 128, g: 128, b: 0]];
    r = $darkcyan => RETURN[[r: 0, g: 128, b: 128]];
    r = $darkmagenta => RETURN[[r: 128, g: 0, b: 128]];
    
    r = $lightyellow => RETURN[[r: 255, g: 255, b:64 ]];
    r = $lightcyan => RETURN[[r: 64, g: 255, b: 255]];
    r = $lightmagenta => RETURN[[r: 255, g: 64, b: 255]];
    
  ENDCASE => ERROR};

LookUpEnds: PROC[r: REF] RETURNS [Graphics.StrokeEnds] =
  {SELECT TRUE FROM
    r = $butt => RETURN[butt];
    r = $square => RETURN[square];
    r = $round => RETURN[round]
  ENDCASE => ERROR};            
                   
END.