-- command interpreter module of silicon (pretty picture) program
-- modified by McCreight, December 30, 1982  4:51 PM,
--    split into ppmain and ppinit

DIRECTORY
  ChipUserInt,
  multiGraphicsDefs,
  InlineDefs,
  AltoFileDefs,
  ppdddefs,ppddefs,
  ppdefs,
  ppMainDefs;

ppmain: PROGRAM
  IMPORTS
    ppdddefs, multiGraphicsDefs, ppdefs, ppddefs, ppMainDefs,
    InlineDefs, ChipUserInt
  EXPORTS ppMainDefs, ppdefs = PUBLIC
  BEGIN
  OPEN ppdefs, ppdddefs,ppddefs, ppMainDefs, multiGraphicsDefs, InlineDefs;

  ii: CARDINAL; -- exported to ppMainDefs
  ss: STRING;
  ke: keyEvent;
  cp, cpp: LONG POINTER TO cList;
  lp, lpp, lqp: listPtr;
  
  cmdArray: POINTER TO ARRAY [0..77B] OF cmdEnt = LOOPHOLE[@snerdArray];

  snerdArray: ARRAY [0..77B] OF POINTER ← [
    @cmZer, @cmDig, @cmDig, @cmDig, @cmDig, @cmDig, NIL, NIL  -- 0-7
    , NIL, @cm9, @cmA, @cmB, @cmC, @cmD, @cmE, @cmF  -- 89A-F
    , @cmG, @cmH, @cmI, NIL, NIL, @cmL, @cmM, @cmN  -- G-N
    , @cmO, @cmP, @cmQ, @cmR, @cmS, @cmT, @cmU, NIL  --O-V
    , @cmW, @cmX, NIL, @cmZ, @cmSemi, @cmEQ, @cmFlp, NIL  -- WXYZ;=,-
    , @cmFlp, @cmQues, NIL, NIL, @cmBSL, NIL, @cmUN, @cmUPAR  -- ./'[\](DN)←
    , NIL, @cmLF, NIL, @cmDEL, @cmSPC, @cmESC, NIL, NIL
    -- CR LF BS DEL SPC ESC ??? ???
    , NIL, NIL, NIL, @cmYUB, NIL, NIL, NIL, @cmBUT];
  -- ??? ??? ??? release yellow ??? ??? ??? NONE

  red: CARDINAL = 1;
  yellow: CARDINAL = 2;
  blue: CARDINAL = 4;
  notMouse: CARDINAL = 3770B;
  basicKbd: CARDINAL = 10B;
  ctrl: CARDINAL = 20B;
  tab: CARDINAL = 40B;
  ctrlTab: CARDINAL = 100B;
  shift: CARDINAL = 200B;
  ctrlShift: CARDINAL = 400B;
  tabShift: CARDINAL = 1000B;
  ctrlTabShift: CARDINAL = 2000B;
  ctrlTabAny: CARDINAL = ctrlTab+ctrlTabShift;
  else: CARDINAL = 7777B;

  cmZer: ARRAY [0..2] OF cmdLent ← [
    [red, doDefaultPnt], [ctrl, doDefaultSel], [else, ignore]];
  cmDig: ARRAY [0..2] OF cmdLent ← [
    [yellow, makCont], [ctrl+blue, selLayer], [else, ignore]];
  cmA: ARRAY [0..5] OF cmdLent ← [[red, doAsel],[yellow,doAlter],[blue, doASel],[ctrl, doRepeatOb], [tab, doSelectAll], [else, ignore]];
  cmB: ARRAY [0..4] OF cmdLent ← [[red, doBurr], [yellow, doMakBus], [ctrl, convToBus],
	[100B, convToBusDamnit], [else, ignore]];
  cmC: ARRAY [0..5] OF cmdLent ← [
    [tab, setCols], [ctrl, defCell], [red, getCell], [ctrlTabAny, makeCif], [yellow, doCopy], [
    else, ignore]];
  cmD: ARRAY [0..3] OF cmdLent ← [
    [yellow, delPnt], [ctrl, delSel], [blue, doDeSel], [else, ignore]];
  cmE: ARRAY [0..4] OF cmdLent ← [
    [red, doExpP], [ctrl, doExpS], [tab, dispErf], [ctrlTabAny, getErfil], [
    else, ignore]];
  cmF: ARRAY [0..1] OF cmdLent ← [[ctrlTabShift, doFlush], [else, ignore]];
  cmG: ARRAY [0..1] OF cmdLent ← [[yellow, makWCont], [else, ignore]];
  cmH: ARRAY [0..1] OF cmdLent ← [[ctrlTabAny, doHard], [else, ignore]];
  cmI: ARRAY [0..4] OF cmdLent ← [[ctrlShift, doUnImplSel],[ctrl, doImplSel],[1B, doImplPnt],[ctrlTabAny, doInput], [else, ignore]];
  cmL: ARRAY [0..2] OF cmdLent ← [
    [red, doLenPnt],[ctrl, doLenSel], [else, ignore]];
  cmM: ARRAY [0..3] OF cmdLent ← [
    [yellow, doMove], [ctrl, mirrorSel], [red, mirrorPnt], [else, ignore]];
  cmN: ARRAY [0..4] OF cmdLent ← [
    [red, doNarwPnt], [ctrl, doNarwSel], [tab, doNormalize], [yellow, doTub], [else, ignore]];
  cmO: ARRAY [0..3] OF cmdLent ← [
    [ctrlTabAny, doOutput], [tab, doOvg], [yellow, doOvgR], [else, ignore]];
  cmP: ARRAY [0..4] OF cmdLent ← [
    [ctrl, pushSel], [red, pushPnt], [yellow,doPu], [shift,pushName],[else,ignore]];
  cmQ: ARRAY [0..2] OF cmdLent ← [[ctrlTabAny, doQuit], [yellow, oneWire], [else, ignore]];
  cmR: ARRAY [0..4] OF cmdLent ← [ [yellow, doRectangle],
    [2000B, doRestart], [ctrl, rotSel], [red, rotPnt], [else, ignore]];
  cmS: ARRAY [0..3] OF cmdLent ← [
    [red, doShrtPnt], [420B, doShrtSel], [yellow, doStretch], [else, ignore]];
  cmT: ARRAY [0..4] OF cmdLent ← [[ctrl, enterName],
    [red, enterText], [yellow, doTran], [tab, setFont], [else, ignore]];
  cmU: ARRAY [0..1] OF cmdLent ← [[ctrl, doUnDel], [else, ignore]];
  cmW: ARRAY [0..3] OF cmdLent ← [
    [red, doWidenPnt], [yellow,doWAlter],[ctrl, doWidenSel], [else, ignore]];
  cmX: ARRAY [0..1] OF cmdLent ← [[yellow, doTran], [else, ignore]];
  cmZ: ARRAY [0..2] OF cmdLent ← [[ctrl, doZee], [yellow, doATran],[else, ignore]];
  cmSemi: ARRAY [0..1] OF cmdLent ← [[ctrlTabAny, doRunConfig], [else, ignore]];
  cmUN: ARRAY [0..1) OF cmdLent ← [[else, unDo]];
  cmUPAR: ARRAY [0..1] OF cmdLent ← [[notMouse, doPop], [else, ignore]];
  cmSPC: ARRAY [0..4] OF cmdLent ← [
    [red, movColScrn], [blue, movBWScrn], [yellow, movMidScrn], [ctrl, flipWires], [
    else, ignore]];
  cmESC: ARRAY [0..1) OF cmdLent ← [[else, doESC]];
  cmYUB: ARRAY [0..1) OF cmdLent ← [[else, yellowUnButSeen]];
  cmBUT: ARRAY [0..3] OF cmdLent ← [
    [red, setMark], [blue, doSelect], [yellow, doDraw], [else, ignore]];
  cmQues: ARRAY [0..1) OF cmdLent ← [[else, ignore]];
  cmFlp: ARRAY [0..1] OF cmdLent ← [[ctrlTab+basicKbd, flipWires], [else, ignore]];
  cmEQ: ARRAY [0..1] OF cmdLent ← [[notMouse, movLft], [else, ignore]];
  cmBSL: ARRAY [0..1] OF cmdLent ← [[notMouse, movRgt], [else, ignore]];
  cmDEL: ARRAY [0..1] OF cmdLent ← [[notMouse, movDn], [else, ignore]];
  cmLF: ARRAY [0..1] OF cmdLent ← [[notMouse, movUp], [else, ignore]];
  cm9: ARRAY [0..1] OF cmdLent ← [[red+blue, modParam], [else, ignore]];

  CNcmdArray: POINTER TO ARRAY [0..77B] OF cmdEnt = LOOPHOLE[@CNsnerdArray];

  CNsnerdArray: ARRAY [0..77B] OF POINTER ← [
    NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL  -- 0-7
    , NIL, NIL, NIL, NIL, NIL, @cccD, NIL, NIL  -- 89A-F
    , NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL  -- G-N
    , NIL, NIL, @cccQ, NIL, NIL, @cccT, NIL, NIL  --O-V
    , NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL  -- WXYZ;=,-
    , NIL, NIL, NIL, NIL, NIL, NIL, @cccUN, NIL  -- ./'[\](DN)←
    , NIL, NIL, NIL, NIL, @cccSPC, NIL, NIL, NIL
    -- CR LF BS DEL SPC ESC ??? ???
    , NIL, NIL, NIL, @cccYUB, NIL, NIL, NIL, @cccBUT];
  -- ??? ??? ??? release yellow ??? ??? ??? NONE

  cccD: ARRAY [0..1] OF cmdLent ← [[ctrl, delCnSel], [else, ignore]];
  cccQ: ARRAY [0..1] OF cmdLent ← [[ctrlTabAny, doQuit], [else, ignore]];
  cccT: ARRAY [0..1] OF cmdLent ← [[tab, setFont], [else, ignore]];
  cccUN: ARRAY [0..1) OF cmdLent ← [[else, unZee]];
  cccSPC: ARRAY [0..3] OF cmdLent ← [
    [red, movColScrn], [blue, movBWScrn], [yellow, movMidScrn], [else, ignore]];
  cccYUB: ARRAY [0..1) OF cmdLent ← [[else, yellowUnButSeen]];
  cccBUT: ARRAY [0..1] OF cmdLent ← [[blue, doCnSelect], [else, ignore]];

  delCnSel: cmdProc =
    BEGIN
    cn: LONG POINTER TO list;
    cob: LONG POINTER TO cnText object;
    WHILE cnList # NIL DO
      cn ← cnList;
      cnList ← cnList.nxt;
      IF cn.selected THEN
        BEGIN cob ← LOOPHOLE[cn.ob]; delCellDef[cob.np, cob.op]; END;
      cn.ob.p.release[cn.ob];
      freeList[cn];
      ENDLOOP;
    dChange ← TRUE;
    doZee[k];
    END;

  unZee: cmdProc =
    BEGIN
    cn: LONG POINTER TO list;
    cellNameMode ← FALSE;
    dChange ← TRUE;
    WHILE cnList # NIL DO
      cn ← cnList.nxt;
      cnList.ob.p.release[cnList.ob];
      freeList[cnList];
      cnList ← cn;
      ENDLOOP;
    END;

  ignore, unDo: cmdProc = {noChange ← TRUE};

  doRestart: cmdProc =
    BEGIN
	IF sinceIOchanges THEN
	    BEGIN
		ke←typeInC["Unwritten-out Changes",
			"Should I restart anyway?","Type Y or N:"];
		IF ke.k # 42B THEN {refreshTypeInScreen[];RETURN};  -- Y?
	    END;
    refreshTypeInScreen[];
    masterList ← NIL;
    EraseHeap[];
    yelButFlg ← FALSE;
    dChange ← TRUE;
    anyChanges ← TRUE;
    sinceIOchanges ← FALSE;
    SIGNAL RestSig;
    END;


  doStretch: cmdProc =
    BEGIN
    r: Rect;
    dif, ln: INTEGER;
    yType, moveIt, found: BOOLEAN ← FALSE;
    IF NOT bb THEN RETURN;
    lp ← masterList;
    WHILE lp # NIL DO
      IF lp.selected AND (lp.ob.otyp = wire OR lp.ob.otyp = bus)
        AND lp.ob.p.inMe[lp.ob, markPnt.x-lp.lx, markPnt.y-lp.ly,lp.idx] THEN
        BEGIN
        ln ← lp.ob.size[1];
        IF BITAND[lp.idx, 4] = 0 THEN
          BEGIN
          dif ← yy - markPnt.y;
          yType ← TRUE;
          IF markPnt.y<lp.ly+ln/2 THEN BEGIN dif← -dif; moveIt←TRUE; END;
          END
        ELSE
          BEGIN
          dif ← xx - markPnt.x;
          yType ← FALSE;
          IF markPnt.x < lp.lx+ln/2 THEN BEGIN dif← -dif; moveIt←TRUE; END;
          END;
        found ← TRUE;
        EXIT;
        END;
      lp ← lp.nxt;
      ENDLOOP;
    IF NOT found THEN RETURN;
    lp ← masterList;
    WHILE lp # NIL DO
      IF lp.selected AND (lp.ob.otyp = wire OR lp.ob.otyp = bus) THEN
        BEGIN
        r ← getRect[lp];
        IF lp.ob.p.setParm[lp, length, dif, 1, FALSE] THEN
          BEGIN
          IF moveIt THEN
            BEGIN IF yType THEN lp.ly ← lp.ly-dif ELSE lp.lx ← lp.lx-dif;END;
          anyChanges ← sinceIOchanges ← TRUE;
          r ← mergeRects[getRect[lp], r];
          reDrawRect[r, 1, TRUE, TRUE, FALSE];
          END;
        END;
      lp ← lp.nxt;
      ENDLOOP;
    IF NOT wiring THEN setMark[k];
    END;

  doUnDel: cmdProc =
    BEGIN
    IF unDelPnt # NIL THEN
      BEGIN
      jj: CARDINAL ← 0;
      lpp ← lp ← unDelPnt;
      lpp.selected ← TRUE;
      WHILE lpp.nxt # NIL AND lpp.mark = lpp.nxt.mark DO
        lpp ← lpp.nxt; jj ← jj + 1; ENDLOOP;
      unDelPnt ← lpp.nxt;
      --		lpp.nxt←masterList;
      --		masterList←lp;
      WHILE lp # unDelPnt DO
        lqp ← lp.nxt;
        lp.deleted ← FALSE;
        masterList ← insertList[masterList, lp];
        reDrawRect[getRect[lp], 0, TRUE, TRUE, FALSE];
        selCount ← selCount + 1;
        lp ← lqp;
        ENDLOOP;
      anyChanges ← sinceIOchanges ← TRUE;
      unDelGrpCnt ← unDelGrpCnt - 1;
      unDelItemCnt ← unDelItemCnt - jj - 1;
      IF unDelPnt = NIL THEN unDelGrpCnt ← unDelItemCnt ← 0;
      END;
    END;
  doFlush: cmdProc =
    BEGIN
    flushDel[unDelPnt];
    unDelPnt ← NIL;
    unDelGrpCnt ← 0;
    unDelItemCnt ← 0;
    END;

  yelButFlg: BOOLEAN ← FALSE;

  yellowUnButSeen: cmdProc =
    BEGIN
    IF yelButFlg THEN
      BEGIN
      yelButFlg ← FALSE;
      IF k.mx > colWidth THEN
        BEGIN
        bwClipx2 ← bwClipx2 + bwxoff;
        bwClipy2 ← bwClipy2 + bwyoff;
        bwxoff ← ((k.mx - colWidth)*bwScaleD)/bwScaleN - markx;
        bwyoff ← (k.my*bwScaleD)/bwScaleN - marky;
        bwClipx2 ← bwClipx2 - bwxoff;
        bwClipy2 ← bwClipy2 - bwyoff;
        bwClipx1 ← -bwxoff;
        bwClipy1 ← -bwyoff;
        bChange ← TRUE;
        END
      ELSE
        BEGIN
        cClipx2 ← cClipx2 + cxoff;
        cClipy2 ← cClipy2 + cyoff;
        cxoff ← (k.mx*cScaleD)/cScaleN - markx;
        cyoff ← (k.my*cScaleD)/cScaleN - marky;
        cClipx2 ← cClipx2 - cxoff;
        cClipy2 ← cClipy2 - cyoff;
        cClipx1 ← -cxoff;
        cClipy1 ← -cyoff;
        cChange ← TRUE;
        END;
      RETURN;
      END;
    noChange ← TRUE;
    END;

  termWire: PROCEDURE [x, y: INTEGER, unSel: BOOLEAN] =
    BEGIN
    IF wclNx - x = 0 THEN wiringOrn ← 0
    ELSE IF wclNy - y = 0 THEN wiringOrn ← 2 ELSE makeaWire[x, y, 1, unSel];
    oldNx ← wclNx;
    oldNy ← wclNy;
    makeaWire[x, y, 0, unSel];
    END;

  doESC: cmdProc =
    BEGIN
    dChange ← TRUE;
    wiring←busMaking ← FALSE;
    boxing ← doingAreaSel ← FALSE;
    reCount[];
    END;

  doQuit: cmdProc =
    BEGIN OPEN ChipUserInt;
    IF NOT sinceIOchanges OR
        HeSaysYes["Unwritten-out Changes", "Should I quit anyway?"] THEN
        SIGNAL QuitSig;
    END;

  flipWires: cmdProc =
    BEGIN
    IF wiring THEN
      BEGIN wiringOrn ← (wiringOrn + 2) MOD 4; setWireParms[FALSE]; END;
    END;
  movColScrn: cmdProc = BEGIN cChange ← TRUE; setCoffset[xx, yy]; END;
  movMidScrn: cmdProc = {markx ← xx; marky ← yy; yelButFlg ← TRUE};
  movBWScrn: cmdProc = {bChange ← TRUE; setBWoffset[xx, yy]};

  noBBbuttons: cmdProc =
    BEGIN
    SELECT BITAND[k.ctl, 3] FROM
      1 => BEGIN [cChange, bChange] ← doRfeed[]; RETURN; END;
      2 => BEGIN [cChange, bChange] ← doYfeed[]; RETURN; END;
      3 => BEGIN [cChange, bChange] ← doBfeed[]; RETURN; END;
      ENDCASE;
    END;
  setMark: cmdProc =
    BEGIN
    IF wiring AND busMaking THEN
	BEGIN
		wiring ← FALSE;
		calcaBusAndDoIt[bmNews,TRUE,TRUE];
		calcaBusAndDoIt[0,FALSE,FALSE];
	END
     ELSE IF wiring THEN
      BEGIN termWire[xx, yy, BITAND[k.ctl, 34B] = 0]; wiring ← FALSE; END;
    putMark[xx, yy, k.mx>colWidth];
    END;
  doDraw: cmdProc =
    BEGIN
    IF wiring AND NOT busMaking THEN BEGIN makeaWire[xx, yy, 1, BITAND[k.ctl, 34B] = 0]; END
    ELSE IF NOT wiring THEN
      BEGIN
      IF NOT wireOK[favLev] THEN RETURN;
      anyChanges ← sinceIOchanges ← TRUE;
      wclNx ← markPnt.x;
      wclNy ← markPnt.y;
      wclLp ← lp;
      wirePrevPnt ← NIL;
      wiringOrnSet ← TRUE;
      wiringOrn ← IF ABS[wclNx - xx] < ABS[wclNy - yy] THEN 0 ELSE 2;
      wiringLev ← favLev;
      setWireParms[FALSE];
      busMaking ← FALSE;
      END
	ELSE
	    BEGIN
		calcaBusAndDoIt[bmNews,TRUE,TRUE];
		setBusParms[FALSE];
	    END;
    END;
calcaBusAndDoIt:PROCEDURE[newSpace:INTEGER,eraseSel,extnd:BOOLEAN] =
	    BEGIN
		ln1,ln2,lspc:INTEGER;
		wd:INTEGER←minWidthAr[wiringLev];
		spc,aa:INTEGER;
		vert:BOOLEAN←wiringOrn=0;
		IF vert THEN
		    BEGIN
			ln1←yy-wclNy;
			spc←bm2dx;
			lspc←bm2dy;
			aa←IF xx>wclNx THEN -newSpace ELSE newSpace;
			wiringOrn←2;
		    END
		 ELSE
		    BEGIN
			ln1←xx-wclNx;
			spc←bm2dy;
			lspc←bm2dx;
			aa←IF yy>wclNy THEN -newSpace ELSE newSpace;
			wiringOrn←0;
		    END;
		IF ln1<0 THEN aa←-aa;
		IF spc<0 THEN aa←-aa;
		ln2←ln1-lspc+aa;
		lp ← makeaBuss[ln1,ln2,spc,wclNx,wclNy,lspc,wd,
				bmCount,vert,extnd,wiringLev];
		IF vert THEN BEGIN bm2dy←aa;wclNy←yy;END
		 ELSE BEGIN bm2dx←aa;wclNx←xx;END ;
		masterList ← insertList[masterList, lp];
		IF createSel THEN
		    BEGIN selNewThing[masterList,lp,eraseSel];END;
		reDrawRect[getRect[lp], 0, TRUE, TRUE, FALSE];
	    END;

  CmdTwerpMess: PUBLIC PROCEDURE [os1, os2, os3: STRING,check:keCheckProc]
	RETURNS[kkk:keyEvent] =
    BEGIN
    invertColors[];

    typeOut[os1,os2,os3];

    kkk←CmdTwerp[check];
    restoreColors[];
    END;

  minSpaceAr:ARRAY level OF INTEGER = [2,6,4,6,2,2,2,2 , 2,6,4,8,2,2,2,2];

  doMakBus: cmdProc =
    BEGIN
	IF wiring AND busMaking THEN doDraw[k]
	ELSE
	    BEGIN
		checkMark:keCheckProc =
		    BEGIN
			return←FALSE;
			execute←(k.k=64B OR k.k=65B OR k.k=73B);
			IF (k.k=77B AND BITAND[15,k.ctl]=1) OR k.k=56B THEN
			    {return←TRUE;execute←FALSE};
		    END;
		ok: BOOLEAN;
		x,y:INTEGER;
		ke:keyEvent;
		IF NOT wireOK[favLev] THEN RETURN;
		x←xx;y←yy;
		ke←CmdTwerpMess["","Mark Origin of Second Wire","",checkMark];
		IF ke.k=56B THEN RETURN;
		xx←x;yy←y;
	        [ok, x, y] ← deScaledCursor[ke.mx, ke.my];
		IF NOT ok THEN RETURN;
		bm2dx←x-markPnt.x;
		bm2dy←y-markPnt.y;
		bmNews←minSpaceAr[favLev]+minWidthAr[favLev];
		[ok,bmCount,ke]←typeInNum["","Type Number of Wires","In BUS:"];
		IF NOT ok THEN RETURN;
		anyChanges ← sinceIOchanges ← TRUE;
		wiringLev ← favLev;
		wclNx ← markPnt.x;
		wclNy ← markPnt.y;
		wiringOrn←IF ABS[wclNx - xx] < ABS[wclNy - yy] THEN 0 ELSE 2;
		wiring←busMaking←TRUE;
		setBusParms[FALSE];
		refreshTypeInScreen[];
	    END;
    END;
makeaBuss:PROCEDURE[ln1,ln2,spc,x,y,lenSpc,wd,cnt:INTEGER,vert,extend:BOOLEAN,lev:level]
	RETURNS[lp:LONG POINTER TO list]=
    BEGIN
	tinc,binc:INTEGER;
	rots,refls:CARDINAL←0;
	wofn:INTEGER←((wd+lambdaGrid)/(2*lambdaGrid))*lambdaGrid;
	IF ln1<0 THEN
	    BEGIN
		IF vert THEN
		    BEGIN
			x←x-wofn;
			IF extend THEN y←y-wofn;
			IF spc<0 THEN
			    BEGIN
				tinc←lenSpc+ln2-ln1;
				binc←lenSpc;
				spc←-spc;
				x←x-(cnt-1)*spc;
				refls←1;
			    END
			 ELSE
			    BEGIN
				tinc←lenSpc+ln2-ln1;
				binc←lenSpc;
			    END;
			IF tinc<0 THEN y←y+tinc*(cnt-1);
			y←y+ln1;
		    END
		 ELSE
		    BEGIN
			rots←2;refls←1;
			y←y-wofn;
			IF extend THEN x←x-wofn;
			IF spc<0 THEN
			    BEGIN
				tinc←lenSpc+ln2-ln1;
				binc←lenSpc;
				spc←-spc;
				y←y-(cnt-1)*spc;
				refls←0;rots←6;
			    END
			 ELSE
			    BEGIN
				tinc←lenSpc+ln2-ln1;
				binc←lenSpc;
			    END;
			IF tinc<0 THEN x←x+tinc*(cnt-1);
			x←x+ln1;
		    END;
		ln1←-ln1;
		IF extend THEN ln1←ln1+wofn;
	    END
	 ELSE
	    BEGIN
		IF vert THEN
		    BEGIN
			x←x-wofn;
			IF spc<0 THEN
			    BEGIN
				tinc←lenSpc;
				binc←lenSpc+ln2-ln1;
				spc←-spc;
				x←x-(cnt-1)*spc;
				refls←1;
			    END
			 ELSE
			    BEGIN
				tinc←lenSpc;
				binc←lenSpc+ln2-ln1;
			    END;
			IF tinc<0 THEN y←y+tinc*(cnt-1);
		    END
		 ELSE
		    BEGIN
			rots←2;refls←1;
			y←y-wofn;
			IF spc<0 THEN
			    BEGIN
				tinc←lenSpc;
				binc←lenSpc+ln2-ln1;
				spc←-spc;
				y←y-(cnt-1)*spc;
				refls←0;rots←6;
			    END
			 ELSE
			    BEGIN
				tinc←lenSpc;
				binc←lenSpc+ln2-ln1;
			    END;
			IF tinc<0 THEN x←x+tinc*(cnt-1);
		    END;
		IF extend THEN ln1←ln1+wd-wofn;
	    END;
	lp ← makeList[
	  makeBus[ln1,wd,lev,cnt,spc,tinc,binc],x,y,
		  rots, refls];
    END;

  oneWire: cmdProc =
    BEGIN
    IF wiring THEN
      BEGIN
      oldNx ← wclNx;
      oldNy ← wclNy;
      makeaWire[xx, yy, 0, TRUE];
      wiring ← FALSE;
      END
    ELSE
      BEGIN
      IF NOT wireOK[favLev] THEN RETURN;
      anyChanges ← sinceIOchanges ← TRUE;
      wclNx ← markPnt.x;
      wclNy ← markPnt.y;
      wclLp ← lp;
      wirePrevPnt ← NIL;
      wiringOrnSet ← TRUE;
      wiringOrn ← IF ABS[wclNx - xx] < ABS[wclNy - yy] THEN 0 ELSE 2;
      wiringLev ← favLev;
      makeaWire[xx, yy, 0, TRUE];
      wiring ← FALSE;
      END;
    END;
  setWireParms: PROCEDURE [big: BOOLEAN] =
    BEGIN
    x, y, ww,wd,offs: INTEGER;
    wd ← minWidthAr[wiringLev];
    ww ← (wd*cScaleN)/cScaleD;
    offs←((wd+lambdaGrid)/(2*lambdaGrid))*lambdaGrid;
    offs ← (offs*cScaleN)/cScaleD;
    [, x, y, , ] ← cscaleRect[wclNx, wclNy, cClipx2 - 2, cClipy2 - 2];
    setupTempWires[ [x, y], wiringOrn,wiringLev,ww, offs, big];
    END;
  doDeSel: cmdProc =
    BEGIN
    IF doingAreaSel THEN
      BEGIN
      boxing ← doingAreaSel ← FALSE;
      unselAreaSingle[masterList, xx, yy];
      RETURN;
      END;
    unselSingle[masterList, xx, yy];
    RETURN;
    END;
  doASel: cmdProc =
    BEGIN
    boxing ← doingAreaSel ← FALSE;
    IF BITAND[k.ctl, 34B] = 0 THEN
      BEGIN selAreaSingle[masterList, xx, yy]; RETURN; END
    ELSE BEGIN selAreaExtend[masterList, xx, yy]; RETURN; END;
    END;
  doSelect: cmdProc =
    BEGIN
    IF doingAreaSel THEN
      BEGIN
      boxing ← doingAreaSel ← FALSE;
      IF BITAND[k.ctl, 34B] = 0 THEN
        BEGIN selAreaSingle[masterList, xx, yy]; RETURN; END
      ELSE BEGIN selAreaExtend[masterList, xx, yy]; RETURN; END;
      END;
    IF BITAND[k.ctl, 34B] = 0 THEN
      BEGIN selSingle[masterList, xx, yy]; RETURN; END
    ELSE BEGIN selExtend[masterList, xx, yy]; RETURN; END;
    END;

  doSelectAll: PUBLIC cmdProc =
    BEGIN
    boxing ← doingAreaSel ← FALSE;
    FOR lp: listPtr ← masterList, lp.nxt WHILE lp#NIL DO
      lp.selected ← TRUE;
      ENDLOOP;
    dChange ← TRUE;
    END;

  doNormalize: PUBLIC cmdProc =
    BEGIN
    IF cellStack#NIL THEN
      BEGIN
      p: Point = ChipUserInt.GridPoint[[x: (cellStack.origBB.x2+cellStack.origBB.x1)/2,
        y: (cellStack.origBB.y2+cellStack.origBB.y1)/2]];
      IF cursorOnBW THEN
        {setBWoffset[p.x, p.y]; bChange ← TRUE}
      ELSE {setCoffset[p.x, p.y]; cChange ← TRUE};
      END;
    END;

  doCnSelect: cmdProc =
    BEGIN
    IF doingAreaSel THEN
      BEGIN
      boxing ← doingAreaSel ← FALSE;
      IF BITAND[k.ctl, 34B] = 0 THEN
        BEGIN selAreaSingle[cnList, xx, yy]; RETURN; END
      ELSE BEGIN selAreaExtend[cnList, xx, yy]; RETURN; END;
      END;
    IF BITAND[k.ctl, 34B] = 0 THEN BEGIN selSingle[cnList, xx, yy]; RETURN; END
    ELSE BEGIN selExtend[cnList, xx, yy]; RETURN; END;
    END;
  strtAreaSel: PROCEDURE [xx, yy: INTEGER] =
    BEGIN
    x, y: INTEGER;
    doingAreaSel ← TRUE;
    selMarkPnt ← [xx, yy];
    [, x, y, , ] ← cscaleRect[
      selMarkPnt.x, selMarkPnt.y, cClipx2 - 2, cClipy2 - 2];
    setupBox[[x, y], FALSE];
    END;

  doAsel: cmdProc = BEGIN IF bb THEN strtAreaSel[xx, yy]; END;

  doX: cmdProc =
    BEGIN
    IF BITAND[k.ctl, 3] = 2 THEN  -- if yellow mouse button (draw)
      doTran[k];
    END;
  doTran: cmdProc =
    BEGIN
    IF bb THEN
      BEGIN
      anyChanges ← sinceIOchanges ← TRUE;
      lp ← makeList[
        makeXstr[cWidth*xRatiow, cLength*xRatiol, implant], xx, yy,
        basicOrientation, 0];
      masterList ← insertList[masterList, lp];
      IF createSel THEN
        BEGIN selNewThing[masterList, lp, TRUE]; putMark[xx, yy]; END;
      reDrawRect[getRect[lp], 0, TRUE, TRUE, FALSE];
      END;
    END;
  doATran: cmdProc =
    BEGIN
    IF bb THEN
      BEGIN
      anyChanges ← sinceIOchanges ← TRUE;
      lp ← makeList[
        makeAngleXstr[cWidth*xRatiow, cLength*xRatiol, implant], xx, yy,
        basicOrientation, 0];
      masterList ← insertList[masterList, lp];
      IF createSel THEN
        BEGIN selNewThing[masterList, lp, TRUE]; putMark[xx, yy]; END;
      reDrawRect[getRect[lp], 0, TRUE, TRUE, FALSE];
      END;
    END;
  doPu: PROCEDURE [k: keyEvent] =
    BEGIN
    xx, yy: INTEGER;
    bb: BOOLEAN;
    [bb, xx, yy] ← deScaledCursor[k.mx, k.my];
    IF NOT bb THEN RETURN;
    IF cMos THEN
      BEGIN
      anyChanges ← sinceIOchanges ← TRUE;
      lp ← makeList[
        makePXstr[cWidth*xRatiow, cLength*xRatiol, implant],
	    xx, yy,basicOrientation, 0];
      masterList ← insertList[masterList, lp];
      IF createSel THEN
        BEGIN selNewThing[masterList, lp, TRUE]; putMark[xx, yy]; END;
      reDrawRect[getRect[lp], 0, TRUE, TRUE, FALSE];
      END
     ELSE
      BEGIN
      anyChanges ← sinceIOchanges ← TRUE;
      lp ← makeList[
        makePullup[cWidth*pRatiow, cLength*pRatiol], xx, yy, basicOrientation, 0];
      masterList ← insertList[masterList, lp];
      IF createSel THEN
        BEGIN selNewThing[masterList, lp, TRUE]; putMark[xx, yy]; END;
      reDrawRect[getRect[lp], 0, TRUE, TRUE, FALSE];
      END;
    END;

  makeaWire: PROCEDURE [xx, yy, extend: INTEGER, unSel: BOOLEAN] =
    BEGIN
    tx, ty, ttx, tty: INTEGER;
    wdt, wdtt,wof,wofp, ln, llx, lly: CARDINAL;
    wdtt ← minWidthAr[wiringLev];
    wof←((wdtt+lambdaGrid)/(2*lambdaGrid))*lambdaGrid;
    wofp←wdtt-wof;
    wdt ← wdtt*extend;
    IF wiringOrn = 0 OR wiringOrn = 4 THEN
      BEGIN
      llx ← wdtt;
      IF extend=0 THEN tty←yy ELSE
        tty ← IF wclNy < yy THEN yy + wofp ELSE yy - wof;
      ty ← MIN[wclNy, tty];
      lly ← ln ← ABS[wclNy - tty];
      ttx ← wclNx - wof;
      IF wclNy = yy THEN
        lp ← makeList[makeWire[wdt, wdtt, wiringLev],
		 ttx, yy, wiringOrn, 0]
      ELSE lp ← makeList[makeWire[ln, wdtt, wiringLev],
		 ttx, ty, wiringOrn, 0];
      wclNy ← yy;
      END
    ELSE
      BEGIN
      lly ← wdtt;
      IF extend=0 THEN ttx←xx ELSE
        ttx ← IF wclNx < xx THEN xx + wofp ELSE xx - wof;
      tx ← MIN[wclNx, ttx];
      llx ← ln ← ABS[wclNx - ttx];
      tty ← wclNy - wof;
      IF wclNx = xx THEN
        lp ← makeList[makeWire[wdt, wdtt, wiringLev],
		 xx, tty, wiringOrn, 0]
      ELSE lp ← makeList[makeWire[ln, wdtt, wiringLev],
		 tx, tty, wiringOrn, 0];
      wclNx ← xx;
      END;
    wirePrevPnt ← lp;
    wclLp ← lp;
    wiringOrn ← (wiringOrn + 2) MOD 4;
    masterList ← insertList[masterList, lp];
    IF createSel THEN BEGIN selNewThing[masterList, lp, unSel]; END;
    setWireParms[FALSE];
    reDrawRect[getRect[lp], 1, TRUE, TRUE, FALSE];
    END;


CmdTwerp:PUBLIC PROCEDURE[lookAtChr:keCheckProc] RETURNS[keyEvent] =
    BEGIN
           retn,xeq:BOOLEAN;
	DO
	  tmpCP: cmdEnt;
	  IF dChange THEN cChange ← bChange ← TRUE;
	  IF cChange OR bChange THEN
		reDrawRect[[0, 0, 0, 0], 2, bChange, cChange, TRUE];
	  IF cChange THEN
	    BEGIN
		IF wiring THEN BEGIN IF busMaking THEN setBusParms[TRUE]
			ELSE setWireParms[TRUE];END;
		IF boxing THEN
		    BEGIN
			x, y: INTEGER;
			[, x, y, , ] ← cscaleRect[selMarkPnt.x,
				selMarkPnt.y, cClipx2 - 2, cClipy2 - 2];
			setupBox[[x, y], TRUE];
		    END;
		IF NOT bChange THEN redoCBBox[];
	    END;

	  IF NOT noChange THEN displayParameters[];
	  noChange ← dChange ← bChange ← cChange ← FALSE;

	  ke ← getKchr[];
	  [retn,xeq]←lookAtChr[ke];
	  ii ← IF BITAND[ke.ctl, 3]=0 THEN BITSHIFT[10B,BITSHIFT[ke.ctl,-2]]
		ELSE BITSHIFT[1, (BITAND[ke.ctl, 3] - 1)];
	  tmpCP ← IF cellNameMode THEN CNcmdArray[ke.k] ELSE cmdArray[ke.k];
	  IF tmpCP = NIL OR NOT xeq THEN ignore[ke]
	   ELSE
	    BEGIN
		[bb, xx, yy] ← deScaledCursor[ke.mx, ke.my];
		IF ke.k = 77B AND NOT bb THEN noBBbuttons[ke]
		ELSE
		FOR jj: CARDINAL IN [0..20) DO
			IF BITAND[ii, tmpCP[jj].mask] # 0 THEN
			BEGIN tmpCP[jj].proc[ke]; EXIT; END;
		ENDLOOP;
	    END;
	  IF retn THEN RETURN[ke];
	ENDLOOP;
    END;

  fontNumber: CARDINAL←0;
  fontNumberMax: CARDINAL = 3;
  fontTable: ARRAY [0..fontNumberMax) OF POINTER TO StrikeFont =
    [GetStrikeHandle["TimesRoman10"], GetStrikeHandle["Helvetica7"],
    GetStrikeHandle["TimesRoman8"]];

  setFont: cmdProc =
    BEGIN
    fontNumber ← fontNumber + 1;
    IF fontNumber >= fontNumberMax THEN fontNumber ← 0;
    fnt ← fontTable[fontNumber];
    END;

  fnt ← fontTable[0];

  END.