-- monochrome screen drawing module of silicon (pretty picture) program
-- last modified by E. McCreight, March 29, 1983  12:13 PM
DIRECTORY
  ChipOrient,
  InlineDefs,
  IODefs,
  AltoDefs,
  AltoFileDefs,
  MiscDefs,
  multiGraphicsDefs,
  SegmentDefs,
  ProcessDefs,
  ppdddefs,ppddefs,
  ppdefs,
  ppoutdefs;

ppdrawBW: PROGRAM
  IMPORTS
    ChipOrient, ppdefs, ppddefs, InlineDefs, MiscDefs,
    multiGraphicsDefs, ProcessDefs,
    SegmentDefs, ppdddefs, ppoutdefs
  EXPORTS ppdefs, ppddefs =
  BEGIN
  OPEN ppdefs, ppddefs, ppdddefs,InlineDefs, multiGraphicsDefs,
    SegmentDefs, IODefs;

  bwScale: PUBLIC INTEGER ← 8;
  bwScaleN: PUBLIC INTEGER ← 1;
  bwScaleD: PUBLIC INTEGER ← 2;
  bwxoff, bwyoff: PUBLIC INTEGER ← 0;

  bwClipx1: PUBLIC INTEGER ← 0;
  bwClipx2: PUBLIC INTEGER ← 1212;
  bwClipy1: PUBLIC INTEGER ← 0;
  bwClipy2: PUBLIC INTEGER ← 1278;


  fnt: PUBLIC POINTER TO StrikeFont;

  bwCurs: PUBLIC ARRAY [0..15] OF CARDINAL ← [
    177400B, 177000B, 176000B, 176000B, 177000B, 177400B, 147600B, 103700B, 1740B,
    760B, 370B, 174B, 76B, 37B, 16B, 4B];

  bwCursI: PUBLIC ARRAY [0..15] OF CARDINAL ← [
    0B, 76000B, 74000B, 74000B, 76000B, 47000B, 03400B, 01600B, 700B, 340B, 160B,
    70B, 34B, 16B, 4B, 0B];

  bwCurs4: ARRAY [0..15] OF CARDINAL ← [
    140160B, 20774B, 21774B, 23776B, 23776B, 20776B, 20376B, 20174B, 20030B,
    20034B, 20036B, 70077B, 77777B, 37777B, 20177B, 20177B];

  bwCurs2: ARRAY [0..15] OF CARDINAL ← [
    170000B, 103740B, 117770B, 137774B, 37774B, 60006B, 63146B, 60006B, 60006B,
    60006B, 160607B, 150013B, 146063B, 141703B, 140603B, 140603B];

  bwCurs1: ARRAY [0..15] OF CARDINAL ← [
    100160B, 60370B, 70160B, 24040B, 22370B, 11406B, 4405B, 3405B, 776B, 404B,
    404B, 404B, 774B, 120B, 120B, 734B];

  grayLtab: ARRAY level OF Color ← [10, 1, 4, 2, 14, 8, 8, 10,
	10,1,10,11,10,13,10,10];

  bwscale: PROCEDURE [x, y: INTEGER] RETURNS [INTEGER, INTEGER] = INLINE
    BEGIN
    RETURN[((bwxoff + x)*bwScaleN)/bwScaleD, ((bwyoff + y)*bwScaleN)/bwScaleD];
    END;
  bwscaleRect: PUBLIC PROCEDURE [x1, y1, x2, y2: INTEGER]
    RETURNS [BOOLEAN, INTEGER, INTEGER, INTEGER, INTEGER] =
    BEGIN
    t: INTEGER;
    IF x1 > x2 THEN BEGIN t ← x1; x1 ← x2; x2 ← t; END;
    IF y1 > y2 THEN BEGIN t ← y1; y1 ← y2; y2 ← t; END;
    IF x1 > bwClipx2 OR x2 < bwClipx1 OR y1 > bwClipy2 OR y2 < bwClipy1 THEN
      RETURN[FALSE, 0, 0, 0, 0];
    [x1, y1] ← bwscale[MAX[x1, bwClipx1], MAX[y1, bwClipy1]];
    [x2, y2] ← bwscale[MIN[x2, bwClipx2], MIN[y2, bwClipy2]];
    RETURN[TRUE, x1, y1, x2, y2];
    END;
  bwsAndClip: PROCEDURE [x1, y1, x2, y2: INTEGER, cr: POINTER TO Rect]
    RETURNS [BOOLEAN, INTEGER, INTEGER, INTEGER, INTEGER] = INLINE
    BEGIN
    IF x1 > cr.x2 OR x2 < cr.x1 OR y1 > cr.y2 OR y2 < cr.y1 THEN
      RETURN[FALSE, 0, 0, 0, 0];
    [x1, y1] ← bwscale[MAX[x1, cr.x1], MAX[y1, cr.y1]];
    [x2, y2] ← bwscale[MIN[x2, cr.x2], MIN[y2, cr.y2]];
    RETURN[TRUE, x1, y1, x2, y2];
    END;
  outlineBW: PUBLIC PROCEDURE [
    w, x, y, z: INTEGER, q: color, clip: POINTER TO Rect ← NIL] =
    BEGIN
      oulBwArea[w, x, w, z, clip];
      oulBwArea[y, x, y, z, clip];
      oulBwArea[w, z, y, z, clip];
      oulBwArea[w, x, y, x, clip];
    END;
  orBwArea: PUBLIC PROCEDURE [
    w, x, y, z: INTEGER, l: level, clip: POINTER TO Rect ← NIL] =
    BEGIN
    a, b, c, d: INTEGER;
    bb: BOOLEAN;
    [bb, a, b, c, d] ← bwsAndClip[w, x, y, z, clip];
    IF bb THEN BEGIN SetGrayLevel[grayLtab[l]]; PutGray[a, b, c, d]; END;
    END;
  oulBwArea: PROCEDURE [
    w, x, y, z: INTEGER, clip: POINTER TO Rect ← NIL] =
    BEGIN
    a, b, c, d: INTEGER;
    bb: BOOLEAN;
    [bb, a, b, c, d] ← bwsAndClip[w, x, y, z, clip];
    IF bb THEN PutArea[a, b, c, d];
    END;

  repBwArea: PUBLIC PROCEDURE [
    w, x, y, z: INTEGER, l: level, clip: POINTER TO Rect ← NIL] =
    BEGIN
    a, b, c, d: INTEGER;
    bb: BOOLEAN;
    IF clip = NIL THEN [bb, a, b, c, d] ← bwscaleRect[w, x, y, z]
    ELSE [bb, a, b, c, d] ← bwsAndClip[w, x, y, z, clip];
    IF bb THEN BEGIN SetGrayLevel[grayLtab[l]]; ReplaceGray[a, b, c, d]; END;
    END;

  eraseBwArea: PUBLIC PROCEDURE [w, x, y, z: INTEGER] =
    BEGIN
    a, b, c, d: INTEGER;
    bb: BOOLEAN;
    [bb, a, b, c, d] ← bwscaleRect[w, x, y, z];
    IF bb THEN EraseArea[a, b, c, d];
    END;

  drawBwMark: PROCEDURE [x, y: INTEGER] =
    BEGIN
    a, b, i: INTEGER;
    bb: BOOLEAN;
    [bb, a, b,,] ← bwscaleRect[x, y, x, y];
    IF bb THEN
      BEGIN
      PutArea[a,b,a+6,b];
      PutArea[a,b,a,b+6];
      FOR i IN [1..6] DO PutPoint[a+i,b+i];ENDLOOP;
      END;
    END;
  drawBWText: PUBLIC PROCEDURE [
    x, y, sx, sy: INTEGER, s: STRING, clip: POINTER TO Rect] =
    BEGIN
    a, b, c, d: INTEGER;
    bb: BOOLEAN;
    IF x + 4 < bwClipx1 THEN RETURN;
    IF clip = NIL THEN [bb, a, b, c, d] ← bwscaleRect[x, y, x + sx, y + sy]
    ELSE [bb, a, b, c, d] ← bwsAndClip[x, y, x + sx, y + sy, clip];
    IF bb THEN BEGIN c ← ReplaceText[s, a, b, fnt, normal]; END;
    END;
  drawBWText10: PROCEDURE [
    x, y, sx, sy: INTEGER, s: STRING, clip: POINTER TO Rect] =
    BEGIN
    a, b, c, d: INTEGER;
    bb: BOOLEAN;
    IF x + 5 < bwClipx1 THEN RETURN;
    IF clip = NIL THEN [bb, a, b, c, d] ← bwscaleRect[x, y, x, yy]
    ELSE [bb, a, b, c, d] ← bwsAndClip[x, y, x, y, clip];
    IF bb THEN BEGIN c ← ReplaceText[s, a + 1, b + 11, fnt, normal]; END;
    END;

  drawString: PUBLIC PROCEDURE [s: STRING, x, y: INTEGER] =
    BEGIN
    pos: CARDINAL;
    pos ← ReplaceText[s, x, y, fnt, normal];
    pos ← ReplaceText["   ", pos, y, fnt, normal];
    END;

  bwremArray: LONG DESCRIPTOR FOR ARRAY OF rems ← DESCRIPTOR[
    LongDataSegmentAddress[NewDataSegment[DefaultANYBase, remPages]], remLen];
  bwremIdx: CARDINAL ← 0;

  bwDrR: drRecord ← [
    [0, 0, 0, 0], [0, 0, 0, 0], orBwArea, rememberBW, outlineBW, drawBWText10, 1];

  abortBW: PUBLIC BOOLEAN ← FALSE;

  updateBW: PUBLIC PROC =
    BEGIN OPEN ProcessDefs;
    DO
      bp: LONG CARDINAL;
      dangerousUpdateBW[! ANY =>
        {MiscDefs.CallDebugger[
          "B/W repainter signalled, ↑P to continue after next backup pass"]; CONTINUE}];
      bp ← ppoutdefs.backupPass;
      WHILE ppoutdefs.backupPass=bp DO Pause[SecondsToTicks[1]] ENDLOOP;
      ENDLOOP;
    END;

  dangerousUpdateBW: PROC =
    BEGIN

    BWPaintList: PROC [head: LONG POINTER TO listPtr,
      background: BOOLEAN ← FALSE, pushee: listPtr ← NIL] =
      BEGIN
      next: listPtr;
      finished: BOOLEAN ← FALSE;
      WHILE NOT (finished OR abortBW) DO
        FOR lp: listPtr ← head↑, next WHILE lp # NIL DO
          next ← lp.nxt;
          IF abortBW OR lp.deleted THEN EXIT;
          IF lp # pushee THEN
            BEGIN
            lp.ob.p.drawme[lp.idx][lp.ob, lp.lx, lp.ly, @bwDrR];
            IF lp.selected AND NOT background THEN
              BEGIN
              ii: [0..1] = ChipOrient.Rot90[lp.idx];
              outlineBW[
                lp.lx, lp.ly, lp.lx + lp.ob.size[ii], lp.ly + lp.ob.size[1-ii],
                15, @bwEScreenRect];
              END;
            END;
          IF NOT background THEN
            BEGIN
            ps: STRING ← [200];
            ps.length ← 0;
            AppendProps[to: ps, from: lp.props];
            IF ps.length>0 THEN drawBWText10[lp.lx, lp.ly, 0, 0, ps, @bwEScreenRect];
            END;
          ProcessDefs.Yield[];
          REPEAT
            FINISHED => finished ← TRUE;
          ENDLOOP;
        ENDLOOP;
      END; -- of BWPaintList

    doBwRemember: PROC [first, afterLast: CARDINAL] =
      BEGIN
      r: Rect;
      l: level;
      FOR i: CARDINAL IN [first..afterLast) DO
        IF abortBW THEN RETURN;
        [r: r, l: l] ← bwremArray[i];
        repBwArea[r.x1, r.y1, r.x2, r.y2, l, NIL];
        ENDLOOP;
      END; -- of doBwRemember

    bwScreenRect, bwEScreenRect: Rect;
    cmd: sCmd;
    ProcessDefs.SetPriority[0];
    abortBW ← FALSE;

    DO
      ProcessDefs.Yield[];
      cmd ← getBwNewRect[];
      bwScreenRect ← [x1: bwClipx1, y1: bwClipy1, x2: bwClipx2, y2: bwClipy2];
        -- entire b/w design screen in design coords, can be changed by user cmd
      bwEScreenRect ← [x1: bwScreenRect.x1-1, y1: bwScreenRect.y1-1,
        x2: bwScreenRect.x2+1, y2: bwScreenRect.y2+1];

      bwDrR.minSize ← (bwGrain*bwScaleD)/bwScaleN;
      SELECT cmd.cmd FROM
        rect, all =>
          BEGIN
          r, cmprect: Rect;
          bwRemBkgIdx: CARDINAL;
          SELECT cmd.cmd FROM
            all => r ← bwScreenRect;
            ENDCASE =>
              BEGIN
              cmd.r ← cannonRect[cmd.r];
               r ← ClipRect[cmd.r, bwScreenRect];
              END;
          cmprect ← bwDrR.bigr ←
            [x1: MAX[bwScreenRect.x1, r.x1 - wellSurround],
            x2: MIN[bwScreenRect.x2, r.x2 + wellSurround],
            y1: MAX[bwScreenRect.y1, r.y1 - wellSurround],
            y2: MIN[bwScreenRect.y2, r.y2 + wellSurround]];
          bwDrR.r ← r ← IF NOT cmd.ers THEN r ELSE cmprect;

          IF cmd.ers THEN
            eraseBwArea[cmprect.x1, cmprect.y1, cmprect.x2, cmprect.y2];

          bwremIdx ← 0;
          FOR bkg: LONG POINTER TO cellSE ← cellStack, bkg.nxt
            WHILE bkg#NIL AND bkg.instance#NIL DO
            IF abortBW THEN EXIT;
            BWPaintList[head: @bkg.lp, background: TRUE, pushee: bkg.instance];
            ENDLOOP;
          -- dim out the background here
          bwRemBkgIdx ← bwremIdx;

          BWPaintList[IF cellNameMode THEN @cnList ELSE @masterList];

          doBwRemember[first: 0, afterLast: bwRemBkgIdx]; -- make these dim
          doBwRemember[first: bwRemBkgIdx, afterLast: bwremIdx];

          IF didBW AND NOT abortBW THEN
            drawBwMark[markPnt.x, markPnt.y];

          -- show where the color display is
          [, savCBbox.x1, savCBbox.y1] ← deScaledCursor[0, 0];
          [, savCBbox.x2, savCBbox.y2] ← deScaledCursor[colWidth-1, colHeight-1];
          IF NOT (abortBW OR cellNameMode) THEN
            outlineBW[
              savCBbox.x1, savCBbox.y1, savCBbox.x2, savCBbox.y2, 0, @bwEScreenRect];
          END;

        sel =>
          BEGIN
          lp: listPtr = cmd.p;
          ii: [0..1] = ChipOrient.Rot90[lp.idx];
          outlineBW[lp.lx, lp.ly, lp.lx + lp.ob.size[ii], lp.ly + lp.ob.size[1-ii], 15,
            @bwEScreenRect];
          END;

        ENDCASE => ERROR;
      ENDLOOP;
    END;

  rememberBW: PROCEDURE [
    x1, y1, x2, y2: INTEGER, l: level, clip: POINTER TO Rect] =
    BEGIN
    IF bwremIdx >= remLen OR (l = cut AND bwScale < 8) THEN RETURN;
    bwremArray[bwremIdx].r ← ClipRect[[x1, y1, x2, y2], clip↑];
    IF NOT Empty[bwremArray[bwremIdx].r] THEN
      BEGIN
      bwremArray[bwremIdx].l ← l;
      bwremIdx ← bwremIdx + 1;
      END;
    END;

  END.