{Probable bug in loop at label wireydrawn:}
{loop variable screwed up by complex condition}
{I'm afraid it takes level 1.5 graphics interaction to reproduce the exact}
{conditions of failure}

 %include "level1:graphinc.imp"

%begin

{framestore sizes}
%constant %integer framestorexl = 0, framestorexr = 687,
                   framestoreyb = 0, framestoreyt = 511

{display & editing area}
%constant %integer windowframe = 12,
  windowxl = framestorexl+windowframe,
  windowxr = framestorexr-windowframe,
  windowyb = framestoreyb+windowframe,
  windowyt = framestoreyt-windowframe

{virtual grid size}
%constant %integer vgridxl = 0, vgridxr = 255,
                   vgridyb = 0, vgridyt = 255

{virtual grid data structures}
%byte %integer %array vgrid(vgridxl:vgridxr, vgridyb:vgridyt)
%byte %integer %array hvgrid(vgridxl:vgridxr+1, vgridyb:vgridyt)
%byte %integer %array vvgrid(vgridxl:vgridxr, vgridyb:vgridyt+1)

{menu item codings}
%constant %integer mpoly = 1, mdiff = 2, mmetal1 = 3, mmetal2 = 4
%constant %integer mcontact = 5, msubcon = 6, mtranx = 7, mtrany = 8
%constant %integer mptranx = 9, mptrany = 10, mpwell = 11
%constant %integer mzoom = 12, minput = 13, moutput = 14
%constant %integer mitems = 14

{menu scales}
%constant %integer mwscale = 8, mtscale = 4, mtscale3 = 12

{positions of items in menu}
%constant %integer %array mitemx(1:mitems) = %c
  20, 48, 76, 104, 132, 160, 22, 56, 90, 124, 158,
  20, 20, 68
%constant %integer %array mitemxl(1:mitems) = %c
  0, 34, 62, 90, 118, 146, 0, 39, 73, 107, 141,
  0, 0, 53
%constant %integer %array mitemxr(1:mitems) = %c
  33, 61, 89, 117, 145, 180, 38, 72, 106, 140, 180,
  41, 52, 110
%constant %integer %array mitemy(1:mitems) = %c
  96(6), 66(5), 36, 10(2)
%constant %integer %array mitemyb(1:mitems) = %c
  84(6), 49(5), 23, 0(2)
%constant %integer %array mitemyt(1:mitems) = %c
  114(6), 83(5), 48, 22(2)

{menu size}
%constant %integer menuxs = 180, menuys = 114

{cursor outline box in scale units}
%constant %integer %array curxl(1:mitems) = %c
  -1(6), -3(5), -1(3)
%constant %integer %array curxr(1:mitems) = %c
  1(6), 3(5), 1(3)
%constant %integer %array curyb(1:mitems) = %c
  -1(6), -3(5), -1(3)
%constant %integer %array curyt(1:mitems) = %c
  1(6), 3(5), 1(3)

{layer codings}
%constant %integer poly = 1, diff = 2, metal1 = 4, metal2 = 8,
                   pwell = 16, contact = 32, alllayers = 63,
                   grid = 64, menuback = 128

{codings for wire erasing in progress}
%constant %integer polywireerased = 16, diffwireerased = 32,
                   metal1wireerased = 64, metal2wireerased = 128

{primitive codings}
%constant %integer tranx = 1, trany = 2, subcon = 4
                   {pwell = 16, contact = 32}

{window frame colours}
%constant %integer %array windowframelr(1:mitems) = %c
 poly, diff, metal1, metal2, menuback, menuback,
 poly, diff, poly, diff, pwell,
 menuback(3)
%constant %integer %array windowframebt(1:mitems) = %c
 poly, diff, metal1, metal2, menuback, menuback,
 diff, poly, diff, poly, pwell,
 menuback(3)

{wire drawing directions}
%constant %integer nodir = 0, south = 1, east = 2, north = 3, west = 4

{state values}
%constant %integer nostate = 0, drawing = 1, erasing = 2

{button states}
%constant %integer notpressed = 0, pressed = 1, released = 2, stillpressed = 3

%half %integer %array cmap (0:255)
%integer backgroundcolour, flashcolour

%routine %spec setupcolourmap
%routine %spec drawwindowframe(%integer b, r, t, l)
%routine %spec setupnewscale(%integer newscale)
%routine %spec clipfill(%integer xl, yb, xr, yt)
%routine %spec clipvline(%integer x, yb, yt)
%routine %spec cliphline(%integer xl, xr, y)
%routine %spec clipdbtline(%integer xl, yb, xr, yt)
%routine %spec clipdtbline(%integer xl, yt, xr, yb)
%routine %spec outline(%integer xl, yb, xr, yt)
%routine %spec clipoutline(%integer xl, yb, xr, yt)
%routine %spec drawwirex(%integer layer, gx, gy)
%routine %spec erasewirex(%integer layer, gx, gy)
%routine %spec drawwirey(%integer layer, gx, gy)
%routine %spec erasewirey(%integer layer, gx, gy)
%routine %spec drawtranx(%integer gx, gy)
%routine %spec drawtrany(%integer gx, gy)
%routine %spec drawcontact(%integer gx, gy)
%routine %spec drawsubcon(%integer gx, gy)
%routine %spec drawpwell(%integer gx, gy)
%routine %spec redrawdesign
%routine %spec redrawgridpoint(%integer gx, gy)
%routine %spec redrawprim(%integer gx, gy)
%routine %spec redrawwirex(%integer gx, gy)
%routine %spec redrawwirey(%integer gx, gy)
%routine %spec drawcursor
%routine %spec erasecursor
%routine %spec pan(%integer xi, yi)
%routine %spec zoomin
%routine %spec zoomout
%routine %spec drawmenu
%routine %spec erasemenu
%routine %spec flash

{display grid coordinate arrays}
{bounds -1 & +1 to avoid problems with off-display grid points}
%short %integer %array gridx(vgridxl-1:vgridxr+1),
                       gridy(vgridyb-1:vgridyt+1)

{grid window position within virtual grid}
%integer wgridxl, wgridxr, wgridyb, wgridyt

{display grid limits}
%constant %integer gridxl = 0, gridyb = 0
%integer gridxr, gridyt

{menu variables}
%integer menuxl, menuxr, menuyb, menuyt

%integer curbuts, curgx, curgy, newbuts, newgx, newgy, vgx, vgy, vg, vgw
%integer scale, scale2, scale3, scale4, scale6, x, y, xi, yi, curx, cury, s
%integer state, butl, butm, butr, curtype, newtype, vgwh, vgwv
%integer wirestartgx, wirestartgy, wirecurgx, wirecurgy
%integer curwiredir, newwiredir, layer
%integer xl, xr, yb, yt

%switch action(1:mitems), wireaction(0:2)
%switch wiredrawn(nodir:west), undrawwire(nodir:west), drawwire(nodir:west)
%switch wireerased(nodir:west), unerasewire(nodir:west), erasewire(nodir:west)

  {clear virtual grid}
  %for x = vgridxl, 1, vgridxr %cycle
    %for y = vgridyb, 1, vgridyt %cycle
      vgrid(x, y) = 0
      hvgrid(x, y) = 0
      vvgrid(x, y) = 0
    %repeat
  %repeat
  hvgrid(vgridxr+1, y) = 0 %for y = vgridyb, 1, vgridyt
  vvgrid(x, vgridyt+1) = 0 %for x = vgridxl, 1, vgridxr

  {initialise display}
  clear
  setupcolourmap
  drawwindowframe(poly, poly, poly, poly)

  {put display window in middle of virtual grid}
  wgridxl = (vgridxl+vgridxr)//2
  wgridyb = (vgridyb+vgridyt)//2

  {put cursor in middle of window}
  curgx = 0
  curgy = 0
  gridx(curgx) = (windowxl+windowxr)//2
  gridy(curgy) = (windowyb+windowyt)//2

  {create initial display}
  setupnewscale(6)

  mousex = (windowxr+windowxl)//2
  mousey = (windowyt+windowyb)//2

  curbuts = mousebuttons
  curtype = mpoly
  drawcursor

menu:{enter menu sequence}
  drawmenu

menuloop:{select next cursor type}
  x = mousex
  y = mousey
  %if x < menuxl %then x = menuxl %and mousex = x %else %c
  %if x > menuxr %then x = menuxr %and mousex = x
  %if y < menuyb %then y = menuyb %and mousey = y %else %c
  %if y > menuyt %then y = menuyt %and mousey = y

  {find new menu cursor type}
  x = x-menuxl
  y = y-menuyb
  %for newtype = 1, 1, mitems %cycle
    %if mitemxl(newtype) <= x <= mitemxr(newtype) %and %c
        mitemyb(newtype) <= y <= mitemyt(newtype) %then %exit
  %repeat

  {change cursor outline if necessary}
  %if newtype # curtype %then %start
    {erase old cursor}
    colour(0); enable(contact)
    outline(mitemxl(curtype)+menuxl, mitemyb(curtype)+menuyb,
            mitemxr(curtype)+menuxl, mitemyt(curtype)+menuyb)
    {draw new cursor}
    curtype = newtype
    colour(contact); enable(contact)
    outline(mitemxl(curtype)+menuxl, mitemyb(curtype)+menuyb,
            mitemxr(curtype)+menuxl, mitemyt(curtype)+menuyb)

  %finish

  {look at buttons}
  newbuts = mousebuttons
  butl = (curbuts&1)<<1!(newbuts&1)
  butm = (curbuts&2)!(newbuts&2)>>1
  butr = (curbuts&4)>>1!(newbuts&4)>>2
  ! 0 : not pressed
  ! 1 : pressed
  ! 2 : released
  ! 3 : still pressed
  curbuts = newbuts
  %unless butl = pressed %or butm = pressed %then ->menuloop

  {change window frame colour for selected menu item}
  drawwindowframe(windowframebt(curtype), windowframelr(curtype),
                  windowframebt(curtype), windowframelr(curtype))

display:{enter main edit loop}
  erasemenu
  drawcursor
  state = nostate

displayloop:{edit}

  {check for cursor at edge of display for panning}
  x = mousex
  y = mousey
  xi = 0
  yi = 0
  %if x < windowxl %then xi = -1 %else %c
  %if x > windowxr %then xi = 1
  %if y < windowyb %then yi = -1 %else %c
  %if y > windowyt %then yi = 1
  %if xi # 0 %or yi # 0 %then %start
    %if x < framestorexl %then x = framestorexl %and mousex = x
    %if x > framestorexr %then x = framestorexr %and mousex = x
    %if y < framestoreyb %then y = framestoreyb %and mousey = y
    %if y > framestoreyt %then y = framestoreyt %and mousey = y
    erasecursor
    colour(contact); enable(contact)
    plot(x,y)
    pan(xi, yi)
    ->displayloop
  %finish

  newgx = x//scale6
  newgy = y//scale6
  %if newgx < gridxl %then newgx = gridxl %else %c
  %if newgx > gridxr %then newgx = gridxr
  %if newgy < gridyb %then newgy = gridyb %else %c
  %if newgy > gridyt %then newgy = gridyt
  %if newgx # curgx %or newgy # curgy %then %start
    erasecursor
    curgx = newgx
    curgy = newgy
    drawcursor
  %finish

  {look at buttons}
  newbuts = mousebuttons
  butl = (curbuts&1)<<1!(newbuts&1)
  butm = (curbuts&2)!(newbuts&2)>>1
  butr = (curbuts&4)>>1!(newbuts&4)>>2
  ! 0 : not unpressed
  ! 1 : pressed
  ! 2 : released
  ! 3 : still pressed
  curbuts = newbuts
  %if butr = pressed %then ->menu

  vgx = curgx+wgridxl
  vgy = curgy+wgridyb
  vg = vgrid(vgx, vgy)
  {what wires come to this grid point?}
  vgwh = hvgrid(vgx,vgy)!hvgrid(vgx+1,vgy)
  vgwv = vvgrid(vgx,vgy)!vvgrid(vgx,vgy+1)
  vgw = vgwh!vgwv

  ->action(curtype)
      
{------------------------------------------------------------------------------}

action(mpoly):{poly selected}
  layer = poly
  ->wireaction(state)

{------------------------------------------------------------------------------}

action(mdiff):{diff selected}
  layer = diff
  ->wireaction(state)

{------------------------------------------------------------------------------}

action(mmetal1):{metal1 selected}
  layer = metal1
  ->wireaction(state)

{------------------------------------------------------------------------------}

action(mmetal2):{metal2 selected}
  layer = metal2
  ->wireaction(state)

{------------------------------------------------------------------------------}

wireaction(0):{no drawing or erasing in progress}
  %if butm = pressed %or butl = pressed %then %start  {start drawing or erasing}
    wirestartgx = curgx
    wirestartgy = curgy
    wirecurgx = curgx
    wirecurgy = curgy
    curwiredir = nodir
    %if butm = pressed %then state = drawing %else state = erasing
  %finish
  ->displayloop

{------------------------------------------------------------------------------}

wireaction(drawing):{drawing wire}
  %if butm = stillpressed %then ->wiredrawing
  {butm = released assumed}
  state = nostate
  {check and confirm wire drawn}
  ->wiredrawn(curwiredir)

wiredrawn(nodir):
    ->displayloop

wiredrawn(south):
    x = wirestartgx+wgridxl
    yb = wirecurgy+wgridyb+1
    yt = wirestartgy+wgridyb
%option "-code-tt"
wireydrawn:
    %for y = yb, 1, yt %cycle
      %if vvgrid(x, y)&layer # 0 %then %continue
      {check wire segment for incompatibility}
      %if layer = poly %then %start
        %if (vvgrid(x, y-1)!vvgrid(x, y)!vvgrid(x, y+1))&diff#0 %c
          %or (vgrid(x, y-1)!vgrid(x, y))&(tranx!contact!subcon)#0 %c
          %or ((hvgrid(x, y-1)!hvgrid(x+1, y-1))&diff # 0 %c
            %and vgrid(x-1, y)&trany = 0) %c
          %or ((hvgrid(x, y)!hvgrid(x+1, y))&diff # 0 %c
            %and vgrid(x, y)&trany = 0) %then ->wireyko
      %finish %else %c
      %if layer = diff %then %start
        %if (vvgrid(x, y-1)!vvgrid(x, y)!vvgrid(x, y+1))&poly#0 %c
          %or (vgrid(x, y-1)!vgrid(x, y))&(trany!contact!subcon)#0 %c
          %or ((hvgrid(x, y-1)!hvgrid(x+1, y-1))&poly # 0 %c
            %and vgrid(x, y-1)&tranx = 0) %c
          %or ((hvgrid(x, y)!hvgrid(x+1, y))&poly # 0 %c
            %and vgrid(x, y)&tranx = 0) %then ->wireyko
      %finish %else %start    {metal1 or metal2}
        %if (vgrid(x, y-1)!vgrid(x, y))&(contact!subcon) # 0 %then ->wireyko
      %finish
      vvgrid(x, y) = vvgrid(x, y)!layer
      %continue

wireyko:erasewirey(layer, x-wgridxl, y-wgridyb)
      %if y # yt %then drawwirey(layer, x-wgridxl, y+1-wgridyb)
      flash
    %repeat
    ->displayloop

wiredrawn(east):
    xl = wirestartgx+wgridxl+1
    xr = wirecurgx+wgridxl
    y = wirestartgy+wgridyb
wirexdrawn:
    %for x = xl, 1, xr %cycle
      %if hvgrid(x, y)&layer # 0 %then %continue
      {check wire segment for incompatibility}
      %if layer = poly %then %start
        %if (hvgrid(x-1, y)!hvgrid(x, y)!hvgrid(x+1, y))&diff#0 %c
          %or (vgrid(x-1, y)!vgrid(x, y))&(trany!contact!subcon)#0 %c
          %or vgrid(x-1, y)&pwell # vgrid(x, y)&pwell %c
          %or ((vvgrid(x-1, y)!vvgrid(x-1, y+1))&diff # 0 %c
            %and vgrid(x-1, y)&tranx = 0) %c
          %or ((vvgrid(x, y)!vvgrid(x, y+1))&diff # 0 %c
            %and vgrid(x, y)&tranx = 0) %then ->wirexko
      %finish %else %c
      %if layer = diff %then %start
        %if (hvgrid(x-1, y)!hvgrid(x, y)!hvgrid(x+1, y))&poly#0 %c
          %or (vgrid(x-1, y)!vgrid(x, y))&(tranx!contact!subcon)#0 %c
          %or ((vvgrid(x-1, y)!vvgrid(x-1, y+1))&poly # 0 %c
            %and vgrid(x-1, y)&trany = 0) %c
          %or ((vvgrid(x, y)!vvgrid(x, y+1))&poly # 0 %c
            %and vgrid(x, y)&trany = 0) %then ->wirexko
      %finish %else %start    {metal1 or metal2}
        %if (vgrid(x-1, y)!vgrid(x, y))&(contact!subcon) # 0 %then ->wirexko
      %finish
      hvgrid(x, y) = hvgrid(x, y)!layer
      drawwirex(layer, x-wgridxl, y-wgridyb)
      %continue

wirexko:erasewirex(layer, x-wgridxl, y-wgridyb)
      %if x # xr %then drawwirex(layer, x+1-wgridxl, y-wgridyb)
      flash
    %repeat
    ->displayloop

wiredrawn(north):
    x = wirestartgx+wgridxl
    yb = wirestartgy+wgridyb+1
    yt = wirecurgy+wgridyb
    ->wireydrawn

wiredrawn(west):
    xl = wirecurgx+wgridxl+1
    xr = wirestartgx+wgridxl
    y = wirestartgy+wgridyb
    ->wirexdrawn

wiredrawing:{button remaining pressed}

  {find new direction}
  x = curgx-wirestartgx
  y = curgy-wirestartgy
  %if x = 0 %and y = 0 %then newwiredir = nodir %else %start
    %if x >= y %then %start
      %if x > -y %then newwiredir = east %else newwiredir = south
    %finish %else %start
      %if x > -y %then newwiredir = north %else newwiredir = west
    %finish
  %finish

  %if newwiredir # curwiredir %then %start
    {erase wire so far drawn in wrong direction}
    ->undrawwire(curwiredir)

undrawwire(nodir):
    ->endundrawwire

undrawwire(south):
    erasewirey(layer, wirestartgx, y) %for y = wirecurgy+1, 1, wirestartgy
    ->endundrawwire

undrawwire(east):
    erasewirex(layer, x, wirestartgy) %for x = wirecurgx, -1, wirestartgx+1
    ->endundrawwire

undrawwire(north):
    erasewirey(layer, wirestartgx, y) %for y = wirecurgy, -1, wirestartgy+1
    ->endundrawwire

undrawwire(west):
    erasewirex(layer, x, wirestartgy) %for x = wirecurgx+1, 1, wirestartgx
    ->endundrawwire

endundrawwire:
    wirecurgx = wirestartgx
    wirecurgy = wirestartgy
    curwiredir = newwiredir
  %finish    {wire in wrong direction gotten rid of}
  ->drawwire(curwiredir)

{------------------------------------------------------------------------------}

drawwire(nodir):
  drawcursor    
  ->displayloop

{------------------------------------------------------------------------------}

drawwire(south):
  %if curgy <= wirecurgy %then %start    {extend southwards}
    yt = wirecurgy+1    {draw previous segment to allow for cursor erase}
    %if wirecurgy = wirestartgy %then yt = yt-1
    drawwirey(layer, wirestartgx, y) %for y = yt, -1, curgy+1
  %finish %else %start    {gone too far southwards}
    erasewirey(layer, wirestartgx, y) %for y = wirecurgy+1, 1, curgy
  %finish
  wirecurgy = curgy
  ->displayloop

{------------------------------------------------------------------------------}

drawwire(east):
  %if curgx >= wirecurgx %then %start    {extend eastwards}
    xl = wirecurgx    {draw previous segment to deal with cursor erase}
    %if wirecurgx = wirestartgx %then xl = xl+1    {not if at start}
    drawwirex(layer, x, wirestartgy) %for x = xl, 1, curgx
  %finish %else %start    {gone too far eastwards so erase back}
    erasewirex(layer, x, wirestartgy) %for x = wirecurgx, -1, curgx+1
  %finish
  wirecurgx = curgx
  ->displayloop

{------------------------------------------------------------------------------}

drawwire(north):
  %if curgy >= wirecurgy %then %start    {extend northwards}
    yb = wirecurgy    {draw previous wire segment also}
    %if wirecurgy = wirestartgy %then yb = yb+1
    drawwirey(layer, wirestartgx, y) %for y = yb, 1, curgy
  %finish %else %start    {gone too far northwards}
    erasewirey(layer, wirestartgx, y) %for y = wirecurgy, -1, curgy+1
  %finish
  wirecurgy = curgy
  ->displayloop

{------------------------------------------------------------------------------}

drawwire(west):
  %if curgx <= wirecurgx %then %start    {extend westwards}
    xr = wirecurgx+1
    %if wirecurgx = wirestartgx %then xr = xr-1
    drawwirex(layer, x, wirestartgy) %for x = xr, -1, curgx+1
  %finish %else %start    {gone too far westwards}
    erasewirex(layer, x, wirestartgy) %for x = wirecurgx+1, 1, curgx
  %finish
  wirecurgx = curgx
  ->displayloop

{------------------------------------------------------------------------------}

action(mcontact):{contact selected}
  %if butm = pressed %then %start    {draw contact}
    %if vg&(tranx!trany!subcon) # 0 %or (vgw # poly!metal1 %and %c
      vgw # diff!metal1 %and vgw # metal1!metal2) %then flash %c
      %else vgrid(vgx, vgy) = vg!contact
  %finish %else %c
  %if butl = pressed %then vgrid(vgx, vgy) = vg&(\contact)    {erase contact}
  ->displayloop

{------------------------------------------------------------------------------}

action(msubcon):{subcon selected}
  %if butm = pressed %then %start    {draw subcon}
    %if vg&(tranx!trany!contact) # 0 %or vgw&(\metal2) # metal1 %then flash %c
      %else vgrid(vgx, vgy) = vg!subcon
  %finish %else %c
  %if butl = pressed %then vgrid(vgx, vgy) = vg&(\subcon)    {erase subcon}
  ->displayloop

{------------------------------------------------------------------------------}

action(mtranx):{tranx selected}
  %if butm = pressed %then %start    {draw tranx}
    %if vg&(trany!contact!subcon) # 0 %c
      %or vgwh&diff # 0 %or vgwv&poly # 0 %c
      %then flash %else vgrid(vgx, vgy) = vg!tranx
  %finish %else %c
  %if butl = pressed %then vgrid(vgx, vgy) = vg&(\tranx)    {erase tranx}
  ->displayloop

{------------------------------------------------------------------------------}

action(mtrany):{trany selected}
  %if butm = pressed %then %start    {draw trany}
    %if vg&(tranx!contact!subcon) # 0 %c
      %or vgwh&poly # 0 %or vgwv&diff # 0 %c
      %then flash %else vgrid(vgx, vgy) = vg!trany
  %finish %else %c
  %if butl = pressed %then vgrid(vgx, vgy) = vg&(\trany)    {erase trany}
  ->displayloop

{------------------------------------------------------------------------------}

action(mptranx):{ptranx selected}
  %if butm = pressed %then %start    {draw ptranx}
    %if vg&(trany!contact!subcon) # 0 %c
      %or vgwh&diff # 0 %or vgwv&poly # 0 %c
      %then flash %else vgrid(vgx, vgy) = vg!tranx!pwell
  %finish %else %c
  %if butl = pressed %then vgrid(vgx, vgy) = vg&(\tranx)&(\pwell) {erase ptranx}
  ->displayloop

{------------------------------------------------------------------------------}

action(mptrany):{ptrany selected}
  %if butm = pressed %then %start    {draw ptrany}
    %if vg&(tranx!contact!subcon) # 0 %c
      %or vgwh&poly # 0 %or vgwv&diff # 0 %c
      %then flash %else vgrid(vgx, vgy) = vg!trany!pwell
  %finish %else %c
  %if butl = pressed %then vgrid(vgx, vgy) = vg&(\trany)&(\pwell) {erase ptrany}
  ->displayloop

{------------------------------------------------------------------------------}

action(mpwell):{pwell selected}
  %if butm = pressed %then %start    {draw pwell}
  %finish %else %c
  %if butl = pressed %then %start    {erase pwell}
  %finish
  ->displayloop

{------------------------------------------------------------------------------}

action(mzoom):{zoom selected}
  %if butm = pressed %then zoomin %else %c
  %if butl = pressed %then zoomout
  ->displayloop

{------------------------------------------------------------------------------}

%routine setupcolourmap
%integer %function cmapc (%integer red, green, blue)
  %result = (blue<<5!green)<<5+red
%end
%integer i

  cmap(i) = 0 %for i=0,1,255
  backgroundcolour = cmapc(14,16,14)
  flashcolour = cmapc(31,0,0)
  cmap(0) = backgroundcolour
  cmap(poly) = cmapc(28,0,0)
  cmap(diff) = cmapc(0,26,0)
  cmap(diff+poly) = cmapc(18,18,0)
  cmap(metal1) = cmapc(15,15,31)
  cmap(metal1+poly) = cmapc(22,8,22)
  cmap(metal1+diff) = cmapc(8,24,24)
  cmap(metal1+diff+poly) = cmapc(18,18,31)
  cmap(metal2) = cmapc(0,0,31)
  cmap(metal2+poly) = cmapc(24,0,31)
  cmap(metal2+diff) = cmapc(0,24,31)
  cmap(metal2+diff+poly) = cmapc(24,24,31)
  cmap(metal2+metal1) = cmapc(8,8,31)
  cmap(metal2+metal1+poly) = cmapc(31,8,31)
  cmap(metal2+metal1+diff) = cmapc(8,31,31)
  cmap(metal2+metal1+diff+poly) = cmapc(24,24,24)

  {pwell colour lowest priority}
  cmap(pwell) = cmapc(20,20,0)
  cmap(pwell+i) = cmap(i) %for i=1, 1, pwell-1

  {contact colour high priority}
  cmap(i) = cmapc(24,24,24) %for i=contact,1,2*contact-1

  {grid colour higher priority}
  cmap(i) = cmapc(28,28,28) %for i=grid,1,2*grid-1

  {menu background highest priority}
  cmap(i) = cmapc(16,18,16) %for i=menuback,1,2*menuback-1
  cmap(menuback+i) = cmap(i) %for i=1, 1, grid-1

  updatecolourmap(cmap(0))

%end

{------------------------------------------------------------------------------}

%routine drawwindowframe(%integer b, r, t, l)
%own %integer frame = 0

  %if frame = 0 %then %start
    colour(grid); enable(grid)
    outline(framestorexl, framestoreyb, framestorexr, windowyb-1)
    outline(windowxr+1, framestoreyb, framestorexr, framestoreyt)
    outline(framestorexl, windowyt+1, framestorexr, framestoreyt)
    outline(framestorexl, framestoreyb, windowxl-1, framestoreyt)
    frame = 1
  %finish

  {clear frame first}
  colour(0); enable(alllayers+menuback)
  fill(framestorexl+1, framestoreyb+1, windowxl-2, framestoreyt-1)
  fill(windowxr+2, framestoreyb+1, framestorexr-1, framestoreyt-1)
  fill(framestorexl+1, framestoreyb+1, framestorexr-1, windowyb-2)
  fill(framestorexl+1, windowyt+2, framestorexr-1, framestoreyt-1)

  {fill in new colours}
  colour(b); enable(b)
  fill(framestorexl+1, framestoreyb+1, framestorexr-1, windowyb-2)
  colour(r); enable(r)
  fill(windowxr+2, framestoreyb+1, framestorexr-1, framestoreyt-1)
  colour(t); enable(t)
  fill(framestorexl+1, windowyt+2, framestorexr-1, framestoreyt-1)
  colour(l); enable(l)
  fill(framestorexl+1, framestoreyb+1, windowxl-2, framestoreyt-1)

%end

{------------------------------------------------------------------------------}

%routine setupnewscale(%integer newscale)
%integer x, y, curx, cury, curvgx, curvgy

  scale = newscale
  scale2 = 2*scale
  scale3 = 3*scale
  scale4 = 4*scale
  scale6 = 6*scale

  {current pixel position in old scale; this is the zoom fixed point}
  curx = gridx(curgx)
  cury = gridy(curgy)

  {current virtual grid cursor position}
  curvgx = curgx+wgridxl
  curvgy = curgy+wgridyb

  {virtual grid position of new window}
  wgridxl = curvgx-(curx-windowxl)//scale6
  wgridxr = curvgx+(windowxr-curx)//scale6
  wgridyb = curvgy-(cury-windowyb)//scale6
  wgridyt = curvgy+(windowyt-cury)//scale6

  {new display window limits}
  gridxr = wgridxr-wgridxl
  gridyt = wgridyt-wgridyb

  {new current display grid position}
  curgx = curvgx-wgridxl
  curgy = curvgy-wgridyb

  {work out coordinate positions for display grid}
  {bounds -1 & +1 for first off-display grid points}
  curx = curx-scale6*(curgx+1)
  %for x = -1, 1, gridxr+1 %cycle
    gridx(x) = curx
    curx = curx+scale6
  %repeat

  cury = cury-scale6*(curgy+1)
  %for y = -1, 1, gridyt+1 %cycle
    gridy(y) = cury
    cury = cury+scale6
  %repeat

  {clear display window}
  colour(0); enable(alllayers+grid)
  fill(windowxl, windowyb, windowxr, windowyt)

  {redraw grid}
  colour(grid); enable(grid)
  %for x=gridxl, 1, gridxr %cycle
    %for y=gridyb, 1, gridyt %cycle
      plot(gridx(x), gridy(y))
    %repeat
  %repeat

  redrawdesign

%end

{------------------------------------------------------------------------------}

%routine clipfill(%integer xl, yb, xr, yt)

  %if xl < windowxl %then xl = windowxl
  %if yb < windowyb %then yb = windowyb
  %if xr > windowxr %then xr = windowxr
  %if yt > windowyt %then yt = windowyt
  fill(xl, yb, xr, yt)

%end

{------------------------------------------------------------------------------}

%routine clipvline(%integer x, yb, yt)
{clip & draw vertical line}

  %if x < windowxl %or x > windowxr %then %return
  %if yb < windowyb %then yb = windowyb
  %if yt > windowyt %then yt = windowyt
  vline(x, yb, yt)

%end

{------------------------------------------------------------------------------}

%routine cliphline(%integer xl, xr, y)
{clip & draw horizontal line}

  %if y < windowyb %or y > windowyt %then %return
  %if xl < windowxl %then xl = windowxl
  %if xr > windowxr %then xr = windowxr
  hline(xl, xr, y)

%end

{------------------------------------------------------------------------------}

%routine clipdbtline(%integer xl, yb, xr, yt)
{clip & draw (bottom left to top right) diagonal line}
%integer xll, xrr

  {clip bottom left end}
  %if xl < windowxl %or yb < windowyb %then %start
    xll = xl+windowyb-yb
    %if xll >= windowxl %then xl = xll %and yb = windowyb %c
                        %else xl = windowxl %and yb = yb+windowxl-xl
  %finish

  {clip top right end}
  %if xr > windowxr %or yt > windowyt %then %start
    xrr = xr+windowyt-yt
    %if xrr <= windowxr %then xr = xrr %and yt = windowyt %c
                        %else xr = windowxr %and yt = yt+windowxr-xr
  %finish

  line(xl, yb, xr, yt)

%end

{------------------------------------------------------------------------------}

%routine clipdtbline(%integer xl, yt, xr, yb)
{clip & draw (top left to bottom right) diagonal line}
%integer xll, xrr

  {clip top left end}
  %if xl < windowxl %or yt > windowyt %then %start
    xll = xl+yt-windowyt
    %if xll >= windowxl %then xl = xll %and yt = windowyt %c
                        %else xl = windowxl %and yt = yt+xl-windowxl
  %finish

  {clip bottom right end}
  %if xr > windowxr %or yb < windowyb %then %start
    xrr = xr+yb-windowyb
    %if xrr <= windowxr %then xr = xrr %and yb = windowyb %c
                        %else xr = windowxr %and yb = yb+xr-windowxr
  %finish

  line(xl, yt, xr, yb)

%end

{------------------------------------------------------------------------------}

%routine outline(%integer xl, yb, xr, yt)

  hline(xl, xr, yb)
  vline(xr, yb, yt)
  hline(xl, xr, yt)
  vline(xl, yb, yt)

%end

{------------------------------------------------------------------------------}

%routine clipoutline(%integer xl, yb, xr, yt)

  %if yb >= windowyb %then cliphline(xl, xr, yb)
  %if xr <= windowxr %then clipvline(xr, yb, yt)
  %if yt <= windowyt %then cliphline(xl, xr, yt)
  %if xl >= windowxl %then clipvline(xl, yb, yt)

%end

{------------------------------------------------------------------------------}

%routine drawwirex(%integer layer, gx, gy)

  colour(layer); enable(layer)

  clipfill(gridx(gx-1)-scale, gridy(gy)-scale,
           gridx(gx)+scale, gridy(gy)+scale)

%end

{------------------------------------------------------------------------------}

%routine erasewirex(%integer layer, gx, gy)

  colour(0); enable(layer)

  clipfill(gridx(gx-1)-scale, gridy(gy)-scale,
           gridx(gx)+scale, gridy(gy)+scale)

  {redraw end points}
  redrawgridpoint(gx-1, gy)
  redrawgridpoint(gx, gy)

%end

{------------------------------------------------------------------------------}

%routine drawwirey(%integer layer, gx, gy)

  colour(layer); enable(layer)

  clipfill(gridx(gx)-scale, gridy(gy-1)-scale,
           gridx(gx)+scale, gridy(gy)+scale)

%end

{------------------------------------------------------------------------------}

%routine erasewirey(%integer layer, gx, gy)

  colour(0); enable(layer)

  clipfill(gridx(gx)-scale, gridy(gy-1)-scale,
           gridx(gx)+scale, gridy(gy)+scale)

  {redraw end points}
  redrawgridpoint(gx, gy-1)
  redrawgridpoint(gx, gy)

%end

{------------------------------------------------------------------------------}

%routine drawtranx(%integer gx, gy)

  {poly in x-direction}
  colour(poly); enable(poly)

  clipfill(gridx(gx)-scale3, gridy(gy)-scale,
           gridx(gx)+scale3, gridy(gy)+scale)

  {diff in y-direction}
  colour(diff); enable(diff)

  clipfill(gridx(gx)-scale, gridy(gy)-scale3,
           gridx(gx)+scale, gridy(gy)+scale3)

%end

{------------------------------------------------------------------------------}

%routine drawtrany(%integer gx, gy)

  {poly in y-direction}
  colour(poly); enable(poly)

  clipfill(gridx(gx)-scale, gridy(gy)-3*scale,
           gridx(gx)+scale, gridy(gy)+3*scale)

  {diff in x-direction}
  colour(diff); enable(diff)

  clipfill(gridx(gx)-3*scale, gridy(gy)-scale,
           gridx(gx)+3*scale, gridy(gy)+scale)

%end

{------------------------------------------------------------------------------}

%routine drawcontact(%integer gx, gy)
%integer xm, xp, ym, yp 

  colour(contact); enable(contact)

  {draw outline}
  xm = gridx(gx)-scale2
  xp = xm+scale4
  ym = gridy(gy)-scale2
  yp = ym+scale4

  cliphline(xm, xp, ym)
  clipvline(xp, ym, yp)
  cliphline(xm, xp, yp)
  clipvline(xm, ym, yp)

  {draw diagonal lines}
  clipdbtline(xm, ym, xp, yp)
  clipdtbline(xm, yp, xp, ym)

%end

{------------------------------------------------------------------------------}

%routine drawsubcon(%integer gx, gy)
%integer x, y, xm, xp, ym, yp 

  colour(contact); enable(contact)

  {draw outline}
  x = gridx(gx)
  xm = x-scale2
  xp = xm+scale4
  y = gridy(gy)
  ym = y-scale2
  yp = ym+scale4

  cliphline(xm, xp, ym)
  clipvline(xp, ym, yp)
  cliphline(xm, xp, yp)
  clipvline(xm, ym, yp)

  {draw cross}
  clipvline(x, ym, yp)
  cliphline(xm, xp, y)

%end

{------------------------------------------------------------------------------}

%routine drawpwell(%integer gx, gy)
%integer x, y

  colour(pwell); enable(pwell)

  x = gridx(gx)
  y = gridy(gy)
  clipfill(x-scale3, y-scale3, x+scale3, y+scale3)

%end

{------------------------------------------------------------------------------}

%routine redrawdesign
%integer x, y

  %for x = gridxl, 1, gridxr %cycle
    %for y = gridyb, 1, gridyt %cycle
      redrawprim(x, y)
      redrawwirex(x, y)
      redrawwirey(x, y)
    %repeat
  %repeat

  {draw rightmost column of horizontal wires}
  redrawwirex(gridxr+1, y) %for y = gridyb, 1, gridyt

  {draw topmost row of vertical wires}
  redrawwirey(x, gridyt+1) %for x = gridxl, 1, gridxr

%end

{------------------------------------------------------------------------------}

%routine redrawgridpoint(%integer gx, gy)

  redrawprim(gx, gy)
  redrawwirex(gx, gy)
  redrawwirex(gx+1, gy)
  redrawwirey(gx, gy)
  redrawwirey(gx, gy+1)

%end

{------------------------------------------------------------------------------}

%routine redrawprim(%integer gx, gy)
%integer p

  p = vgrid(gx+wgridxl, gy+wgridyb)
  %if p # 0 %then %start
    %if p&pwell # 0 %then drawpwell(gx, gy)
    %if p&tranx # 0 %then drawtranx(gx, gy) %else %c
    %if p&trany # 0 %then drawtrany(gx, gy) %else %c
    %if p&contact # 0 %then drawcontact(gx, gy) %else %c
    %if p&subcon # 0 %then drawsubcon(gx, gy)
  %finish

%end

{------------------------------------------------------------------------------}

%routine redrawwirex(%integer gx, gy)
%integer wires, drawn, erased, layers

  wires = hvgrid(gx+wgridxl, gy+wgridyb)
  drawn = wires&16_f
  erased = wires>>4
  layers = drawn&(\erased)
  %if layers # 0 %then drawwirex(layers, gx, gy)

%end

{------------------------------------------------------------------------------}

%routine redrawwirey(%integer gx, gy)
%integer layers

  layers = vvgrid(gx+wgridxl, gy+wgridyb)
  %if layers # 0 %then drawwirey(layers, gx, gy)

%end

{------------------------------------------------------------------------------}

%routine pan(%integer xi, yi)

  {clear display window}
  colour(0)
  enable(alllayers)
  fill(windowxl, windowyb, windowxr, windowyt)

  wgridxl = wgridxl+xi
  wgridxr = wgridxr+xi
  wgridyb = wgridyb+yi
  wgridyt = wgridyt+yi
  redrawdesign

%end

{------------------------------------------------------------------------------}

%routine zoomin

  setupnewscale(scale+1)

%end

{------------------------------------------------------------------------------}

%routine zoomout

  setupnewscale(scale-1) %unless scale = 1

%end

{------------------------------------------------------------------------------}

%routine drawmenu
%integer x, y, xl, xr, yb, yt

  erasecursor

  {fit menu into display window}
  menuxl = mousex-mitemx(curtype)
  menuxr = menuxl+menuxs
  %if menuxl < windowxl %then menuxl = windowxl %and menuxr = menuxl+menuxs
  %if menuxr > windowxr %then menuxr = windowxr %and menuxl = menuxr-menuxs

  menuyb = mousey-mitemy(curtype)
  menuyt = menuyb+menuys
  %if menuyb < windowyb %then menuyb = windowyb %and menuyt = menuyb+menuys
  %if menuyt > windowyt %then menuyt = windowyt %and menuyb = menuyt-menuys

  {clear menu area and draw menu grid}
  colour(menuback)
  enable(alllayers+menuback)
  fill(menuxl, menuyb, menuxr, menuyt)

  {draw menu outline}
  colour(contact)
  enable(contact)
  outline(menuxl, menuyb, menuxr, menuyt)

  {draw menu poly}
  x = mitemx(mpoly)+menuxl
  y = mitemy(mpoly)+menuyb
  colour(poly); enable(poly)
  fill(x-mwscale, y-mwscale, x+mwscale, y+mwscale)

  {draw menu diff}
  x = mitemx(mdiff)+menuxl
  y = mitemy(mdiff)+menuyb
  colour(diff); enable(diff)
  fill(x-mwscale, y-mwscale, x+mwscale, y+mwscale)

  {draw menu metal1}
  x = mitemx(mmetal1)+menuxl
  y = mitemy(mmetal1)+menuyb
  colour(metal1); enable(metal1)
  fill(x-mwscale, y-mwscale, x+mwscale, y+mwscale)

  {draw menu metal2}
  x = mitemx(mmetal2)+menuxl
  y = mitemy(mmetal2)+menuyb
  colour(metal2); enable(metal2)
  fill(x-mwscale, y-mwscale, x+mwscale, y+mwscale)

  {draw menu contact}
  x = mitemx(mcontact)+menuxl
  xl = x-mwscale
  xr = x+mwscale
  y = mitemy(mcontact)+menuyb
  yb = y-mwscale
  yt = y+mwscale
  colour(contact); enable(contact)
  outline(xl, yb, xr, yt)
  line(xl, yb, xr, yt)
  line(xl, yt, xr, yb)

  {draw menu substrate contact}
  x = mitemx(msubcon)+menuxl
  xl = x-mwscale
  xr = x+mwscale
  y = mitemy(msubcon)+menuyb
  yb = y-mwscale
  yt = y+mwscale
  colour(contact); enable(contact)
  outline(xl, yb, xr, yt)
  vline(x, yb, yt)
  hline(xl, xr, y)

  {draw menu tranx}
  x = mitemx(mtranx)+menuxl
  y = mitemy(mtranx)+menuyb
  colour(poly); enable(poly)
  fill(x-mtscale3, y-mtscale, x+mtscale3, y+mtscale)
  colour(diff); enable(diff)
  fill(x-mtscale, y-mtscale3, x+mtscale, y+mtscale3)

  {draw menu trany}
  x = mitemx(mtrany)+menuxl
  y = mitemy(mtrany)+menuyb
  colour(poly); enable(poly)
  fill(x-mtscale, y-mtscale3, x+mtscale, y+mtscale3)
  colour(diff); enable(diff)
  fill(x-mtscale3, y-mtscale, x+mtscale3, y+mtscale)

  {draw menu ptranx}
  x = mitemx(mptranx)+menuxl
  y = mitemy(mptranx)+menuyb
  colour(pwell); enable(pwell)
  fill(x-mtscale3, y-mtscale3, x+mtscale3, y+mtscale3)
  colour(poly); enable(poly)
  fill(x-mtscale3, y-mtscale, x+mtscale3, y+mtscale)
  colour(diff); enable(diff)
  fill(x-mtscale, y-mtscale3, x+mtscale, y+mtscale3)

  {draw menu ptrany}
  x = mitemx(mptrany)+menuxl
  y = mitemy(mptrany)+menuyb
  colour(pwell); enable(pwell)
  fill(x-mtscale3, y-mtscale3, x+mtscale3, y+mtscale3)
  colour(poly); enable(poly)
  fill(x-mtscale, y-mtscale3, x+mtscale, y+mtscale3)
  colour(diff); enable(diff)
  fill(x-mtscale3, y-mtscale, x+mtscale3, y+mtscale)

  {draw menu pwell}
  x = mitemx(mpwell)+menuxl
  y = mitemy(mpwell)+menuyb
  colour(pwell); enable(pwell)
  fill(x-mtscale3, y-mtscale3, x+mtscale3, y+mtscale3)

  {draw zoom icon}
  colour(contact); enable(contact)
  x = mitemx(mzoom)+menuxl
  y = mitemy(mzoom)+menuyb
  outline(x-mwscale, y-mwscale, x+mwscale, y+mwscale)
  outline(x-mtscale, y-mtscale, x+mtscale, y+mtscale)

  {draw 'input' text}
  x = mitemx(minput)+menuxl
  y = mitemy(minput)+menuyb
  textat(x, y)
  showstring("in")

  {draw 'output' text}
  x = mitemx(moutput)+menuxl
  y = mitemy(moutput)+menuyb
  textat(x, y)
  showstring("out")

  {outline current cursor type}
  colour(contact); enable(contact)
  outline(mitemxl(curtype)+menuxl, mitemyb(curtype)+menuyb,
          mitemxr(curtype)+menuxl, mitemyt(curtype)+menuyb)

%end

{------------------------------------------------------------------------------}

%routine erasemenu

  {erase menu area}
  colour(0)
  enable(alllayers+menuback)
  fill(menuxl, menuyb, menuxr, menuyt)

  redrawdesign
  curgx = mousex//scale6
  curgy = mousey//scale6
  drawcursor

%end

{------------------------------------------------------------------------------}

%routine drawcursor
%integer x, y, xl, yb, xr, yt, layer
%switch cur(1:mitems)

  ->cur(curtype)

cur(mpoly):layer = poly
  ->wirecursor

cur(mdiff):layer = diff
  ->wirecursor

cur(mmetal1):layer = metal1
  ->wirecursor

cur(mmetal2):layer = metal2
  ->wirecursor

wirecursor:{draw cursor box for wires}
  x = gridx(curgx)
  xl = x-scale
  xr = x+scale
  y = gridy(curgy)
  yb = y-scale
  yt = y+scale

  colour(layer); enable(layer)
  clipfill(xl, yb, xr, yt)
  ->drawout
    
cur(mcontact):drawcontact(curgx, curgy)
  ->drawout

cur(msubcon):drawsubcon(curgx, curgy)
  ->drawout

cur(mtranx):drawtranx(curgx, curgy)
  ->drawout

cur(mtrany):drawtrany(curgx, curgy)
  ->drawout

cur(mptranx):drawpwell(curgx, curgy)
  drawtranx(curgx, curgy)
  ->drawout

cur(mptrany):drawpwell(curgx, curgy)
  drawtrany(curgx, curgy)
  ->drawout

cur(mpwell):drawpwell(curgx, curgy)
  ->drawout

cur(mzoom):
  x = gridx(curgx)
  xl = x-scale2
  xr = x+scale2
  y = gridy(curgy)
  yb = y-scale2
  yt = y+scale2

  colour(contact); enable(contact)
  clipoutline(xl, yb, xr, yt)
  ->drawout
    
drawout:{draw cursor outline)
  colour(contact); enable(contact)
  x = gridx(curgx)
  y = gridy(curgy)
  clipoutline(x+curxl(curtype)*scale, y+curyb(curtype)*scale,
              x+curxr(curtype)*scale, y+curyt(curtype)*scale)

%end

{------------------------------------------------------------------------------}

%routine erasecursor
%integer x, y

  x = gridx(curgx)
  y = gridy(curgy)
  colour(0); enable(alllayers)
  clipfill(x-scale3, y-scale3, x+scale3, y+scale3)

  redrawgridpoint(curgx, curgy)

%end

{------------------------------------------------------------------------------}

%routine flash
%integer i
  cmap(0) = flashcolour
  updatecolourmap(cmap(0))
  %for i = 1,1,20000 %cycle
  %repeat
  cmap(0) = backgroundcolour
  updatecolourmap(cmap(0))
%end
{------------------------------------------------------------------------------}

%endofprogram

