4.3BSD/usr/contrib/icon/src/lib/gpack.icn

#	GPACK(2)
#
#	Graphics Package
#
#	Stephen B. Wampler
#
#	Last modified 7/10/83
#
### note - currently no clipping is performed.  needs work.

global _wno			# current window runner
global Window
global Wscale			# list of window attributes
global MODE, ESC                # chromatic commands
global OFF, ON
global DOT, VECTOR, RECTANGLE, CIRCLE, ARC, CONCVECT, INCDOT
global XMAX, YMAX
global BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE, BLINK

#  set the mode
#
procedure clip(mode)
    suspend Window[_wno].cmode <- mode      # mode is ON/OFF
end

#  clip the object
#
procedure clipped(object)
   case type(object) of {
      default: return object
      }
end

#  set the color
#
procedure color(colr)
   if colr % 8 ~= Window[_wno].fc then {
      writes(MODE,"C",colr % 8)
      Window[_wno].fc := colr % 8
      }
   return
end

#  set the background color
#
procedure bckgrnd(colr)
   if colr % 8 ~= Window[_wno].bc then {
      writes(MODE,"M")
      writes(MODE,"C",colr % 8)
      Window[_wno].bc := colr % 8
      writes(MODE,"N")
      }
   return
end

#  set the cursor color
#
procedure curcol(colr)
   writes(MODE,"Q",colr % 8)
   return
end

#  enable particular color guns
#
procedure enable(colr)
   writes(MODE,":","0123456789ABCDEF"[colr+1])
   return
end




#  draw an object
#
procedure draw(object)
   local pts, p0
   if /object then fail
   object := clipped(object) | fail
   every _plot() do {                    #      switch to plot mode
      case type(object) of {
         "co-expression": while draw(@object)
         "motion":   {
                     _xydel(object.xdel,object.ydel)
                     }
         "point":    {
                     _point(object.x,object.y)
                     }
         "dot":      {
                     mode(DOT)
                     _point(object.x,object.y)
                     }
         "line":     {
                     mode(VECTOR)
                     _point(object.a.x,object.a.y)
                     _point(object.b.x,object.b.y)
                     }
         "box":      {
                     mode(RECTANGLE)
                     _point(object.a.x,object.a.y)
                     _point(object.b.x,object.b.y)
                     }
         "circle":   {
                     mode(CIRCLE)
                     _point(object.center.x,object.center.y)
                     _number(object.radius)
                     }
         "arc":      {
                     mode(ARC)
                     _point(object.center.x,object.center.y)
                     _number(object.radius)
                     _number(object.start)
                     _number(object.stop)
                     }
         "points":   {
                     mode(DOT)
                     every draw(!(object.pts))
                     }
         "lines":    {
                     pts := create !object.pts
                     p0 := @pts
                     mode(VECTOR)
                     while draw(line(.p0,p0 := @pts))
                     }
         "polygon":  {
                     mode(VECTOR)
                     draw(lines(object.pts))
                     draw(line(object.pts[0],object.pts[1]))
                     }
         "incdots":  {
                     mode(INCDOT)
                     draw(object.start)
                     every draw(!object.motions)
                     }
         default  :
              write(&errout,"don't know how to draw ",type(object))
         }
   }

   return
end


# clear the screen

procedure erase()
   writes("\014")
   return
end

#  switch to fill mode
#
procedure _fill()
   if Window[_wno].fmode == OFF then {
      writes(MODE,"F")
      suspend Window[_wno].fmode <- ON
      writes(MODE,"L")
      fail
      }
   return
end

#  leave fill mode
#
procedure _nofill()
   if Window[_wno].fmode == ON then {
      writes(MODE,"L")
      suspend Window[_wno].fmode <- OFF
      writes(MODE,"F")
      fail
      }
   return
end

#  initialize
#
procedure ginit()
   MODE         := "\01"
   ESC          := "\033"
   ON           := "on"
   OFF          := "off"
   XMAX         := 511
   YMAX         := 511
   Window := list(4)
   every Window[1 to 4] := wind(OFF,OFF,OFF,OFF,ON,"",-1,-1,point(0,0),point(511,511))
   every window(1 to 4) do {
      writes(MODE,"\25")                # plot off
      writes(MODE,"L")                  # fill off
      writes(MODE,"R")                  # roll on
      }
   Wscale := list(4)
   every Wscale[1 to 4] := scaling(1,0,1,0)
   _wno := 1
   DOT          := "%"
   VECTOR       := "'"
   RECTANGLE    := "+"
   CIRCLE       := "*"
   ARC          := ")"
   CONCVECT     := ")"
   INCDOT       := "&"
   BLACK        := 0
   BLUE         := 1
   GREEN        := 2
   CYAN         := 3
   RED          := 4
   MAGENTA      := 5
   YELLOW       := 6
   WHITE        := 7
   BLINK        := 8
end

# set plot submode (internal routine)
#
procedure mode(newmode)
   if newmode ~== Window[_wno].psubmode then {
      writes(newmode)
      suspend Window[_wno].psubmode <- newmode
      writes(Window[_wno].psubmode)
      fail
      }
   return
end

# move cursor to (x,y)  (internal routine)
#
procedure movcur(x,y)
   writes(MODE,"U")
   _point(x,y)
   return
end

#  switch to plot mode
#
procedure _plot()
   if Window[_wno].pmode == OFF then {
      Window[_wno].psubmode := " "
      writes(MODE,"G")
      suspend Window[_wno].pmode <- ON
      writes("\25")
      fail
      }
   return
end

#  switch to character mode
#
procedure _char()
   if Window[_wno].pmode == ON then {
      writes("\25")
      suspend Window[_wno].pmode <- OFF
      writes(MODE,"G")
      fail
      }
   return
end





# put out a point (x,y)  (internal routines)

#  write a point
#
procedure _point(x,y)
  _number(xfit(x))
  _number(yfit(y))
   return
end

#  write a number
#
procedure _number(n)
   if n <= 99 then
      writes(n,",")
   else
      writes(n)
   return
end


# graphic record types

record point(x,y)
record dot(x,y)
record line(a,b)
record box(a,b)
record circle(center,radius)
record arc(center,radius,start,stop)
record points(pts)
record lines(pts)
record polygon(pts)
record incdots(start,motions)
record motion(xdel,ydel)

# window records

record wind(pmode,smode,cmode,fmode,rmode,psubmode,fc,bc,lowerleft,upperright)
record scaling(xslope,xinter,yslope,yinter)


#  reset windows
#
procedure restore()

   every window(3 to 0 by -1) do {
      setscale(0,0,511,511,0,0,511,511)
      wsize(0,0,511,511)
      _char()
      _roll()
      enable(WHITE+BLINK)
      }

end


#  turn on roll
#
procedure _roll()
   if Window[_wno].rmode ~== ON then {
      writes(MODE,"R")
      suspend Window[_wno].rmode <- ON
      writes(MODE,"P")
      fail
      }
   return
end

#  turn off roll
#
procedure _noroll()
   if Window[_wno].rmode ~== OFF then {
      writes(MODE,"P")
      suspend Window[_wno].rmode <- OFF
      writes(MODE,"R")
      fail
      }
   return
end







procedure setscale(xmin,ymin,xmax,ymax,colmin,rowmin,colmax,rowmax)

   Wscale[_wno].xslope := real(colmax-colmin) / (xmax-xmin)
   Wscale[_wno].xinter := colmin - xmin * Wscale[_wno].xslope

   Wscale[_wno].yslope := real(rowmax-rowmin) / (ymax-ymin)
   Wscale[_wno].yinter := rowmin - (ymin * Wscale[_wno].yslope)
   return
end

procedure xfit(x)
   if Window[_wno].smode === ON then
      return integer(Wscale[_wno].xslope * x + Wscale[_wno].xinter + 0.5)
   else return integer(x + 0.5)
end

procedure yfit(y)
   if Window[_wno].smode === ON then
      return integer(Wscale[_wno].yslope * y + Wscale[_wno].yinter + 0.5)
   else return integer(y + 0.5)
end

procedure scale(pt)
   if Window[_wno].smode === ON then
      return point(
         integer(Wscale[_wno].xslope * pt.x + Wscale[_wno].xinter + 0.5),
         integer(Wscale[_wno].yslope * pt.y + Wscale[_wno].yinter + 0.5)
         )
   else return pt
end

procedure _scale(mode)
   suspend Window[_wno].smode <- mode
end

# place text on screen at (x,y)
#
procedure text(x,y,s)
   every _char() do {
      movcur(x,y)
      writes(s)
      }
   return
end

#  switch to window w (0-3)
#
procedure window(w)
   writes(ESC,"OA",w % 4)
   _wno := w % 4 + 1
   return
end

#  set new window size
#
procedure wsize(x0,y0,x1,y1)
   writes(MODE,"W")
   _point(x0,y0)
   _point(x1,y1)
   Window[_wno].lowerleft := point(x0,y0)
   Window[_wno].upperright := point(x1,y1)
   return
end

# output deltax, deltay to terminal
#
procedure _xydel(xdel,ydel)
   local signx, signy, byte
   static chars
   initial chars := string(&cset)
   signx := signy := 0
   if xdel < 0 then {
      signx := 32
      xdel := -xdel
      }
   if ydel < 0 then {
      signy := 4
      ydel := -ydel
      }
   byte := 64 + signx + xdel*8 + signy + ydel
   writes(chars[65 + signx + (xdel % 4)*8 + signy + (ydel % 4)])
   return
end