--  ALEDisp.mesa  
--    Edited by Sweet, September 29, 1980  2:43 PM

DIRECTORY
  ALEOps,
  DisplayDefs USING [DestroyDisplay],
  Inline,
  KeyDefs USING [KeyBits, Keys],
  MiscDefs USING [DestroyFakeModule],
  SegmentDefs,
  Storage USING [Node],
  StringDefs,
  UserTerminal USING [SetState],
  UserTerminalOps USING [SetBitmapBox, StartUserTerminal],
  Window,
  WindowFont,
  WindowOps;

ALEDisp: PROGRAM IMPORTS ALEOps, DisplayDefs, Inline, MiscDefs, SegmentDefs, Storage, StringDefs, UserTerminal, UserTerminalOps, Window, WindowFont
  EXPORTS ALEOps =
  BEGIN OPEN ALEOps;

  feedbackWindow, frameWindow, pictureWindow: PUBLIC Window.Handle;
  originWindow, sourceWindow, destWindow, upperWindow, lowerWindow:
    PUBLIC Window.Handle;

  upperIn, lowerIn: BOOLEAN ← FALSE;

  MarksOut: PUBLIC PROC =
    BEGIN
    IF ~originWindow.notInTree THEN Window.RemoveFromTree[originWindow];
    IF ~sourceWindow.notInTree THEN Window.RemoveFromTree[sourceWindow];
    IF ~destWindow.notInTree THEN Window.RemoveFromTree[destWindow];
    IF upperWindow.notInTree THEN upperIn ← FALSE 
    ELSE {upperIn ← TRUE; Window.RemoveFromTree[upperWindow]};
    IF lowerWindow.notInTree THEN lowerIn ← FALSE 
    ELSE {lowerIn ← TRUE; Window.RemoveFromTree[lowerWindow]};
    END;

  MarksIn: PUBLIC PROC =
    BEGIN
    IF originWindow.notInTree THEN
      {originWindow.sibling ← NIL; Window.InsertIntoTree[originWindow]};
    IF destWindow.notInTree THEN
      {destWindow.sibling ← originWindow; Window.InsertIntoTree[destWindow]};
    IF sourceWindow.notInTree THEN
      BEGIN
      sourceWindow.sibling ← destWindow;
      Window.InsertIntoTree[sourceWindow];
      END;
    IF lowerIn AND lowerWindow.notInTree THEN
      BEGIN
      lowerWindow.sibling ← sourceWindow;
      Window.InsertIntoTree[lowerWindow];
      END;
    IF upperIn AND upperWindow.notInTree THEN
      BEGIN
      upperWindow.sibling ← IF lowerIn THEN lowerWindow ELSE sourceWindow;
      Window.InsertIntoTree[upperWindow];
      END;
    END;

  originValueBox, sourceValueBox, destValueBox, textBox: PUBLIC Window.Box;

  Disjoint: PUBLIC PROC [b1, b2: POINTER TO Window.Box] RETURNS [BOOLEAN] =
    BEGIN
    IF b1.place.x + b1.dims.w < b2.place.x OR
      b1.place.y + b1.dims.h < b2.place.y OR
      b2.place.x + b2.dims.w < b1.place.x OR
      b2.place.y + b2.dims.h < b1.place.y THEN RETURN [TRUE];
    RETURN [FALSE];
    END;

  Inside: PUBLIC PROC [place: Window.Place, box: POINTER TO Window.Box]
      RETURNS [BOOLEAN] =
    BEGIN
    RETURN [(place.x - box.place.x) IN [0..box.dims.w] AND
      (place.y - box.place.y) IN [0..box.dims.h]];
    END;

  ZoomDetail: PUBLIC PROC [pos1, pos2: APosition] =
    BEGIN
    mag: [0..4];
    upper, lower: APosition;
    xDist, yDist: ADistance;
    cplace: Window.Place;
    upper ← [x: MIN[pos1.x, pos2.x], y: MIN[pos1.y, pos2.y]];
    lower ← [x: MAX[pos1.x, pos2.x], y: MAX[pos1.y, pos2.y]];
    IF ~upperWindow.notInTree THEN Window.RemoveFromTree[upperWindow];
    IF ~lowerWindow.notInTree THEN Window.RemoveFromTree[lowerWindow];
    cornerPos ← ARoundToInch[upper];
    mag ← state.minMagnify;
    xDist ← lower.x - cornerPos.x;
    yDist ← lower.y - cornerPos.y;
    WHILE mag < 4 AND
        DotsForADistance[xDist, mag+1] <= FrameBox.dims.w AND
        DotsForADistance[yDist, mag+1] <= FrameBox.dims.h DO
      mag ← mag + 1;
      ENDLOOP;
    IF mag # state.magnify THEN
      Window.InvalidateBox[pictureWindow, [PicturePlace[cornerPos], FrameBox.dims]];
    state.magnify ← mag;
    cplace ← PicturePlace[cornerPos];
    Window.Slide[pictureWindow, [x: -cplace.x, y: -cplace.y]];
    ASetOriginPos[GetOriginPos[FALSE]];
    ASetSourcePos[Absolute[GetSourcePos[FALSE]]];
    ASetDestPos[Absolute[GetDestPos[FALSE]]];
    END;

  SlideCorner: PUBLIC PROC [pos: APosition] =
    BEGIN
    cplace: Window.Place;
    IF ~upperWindow.notInTree THEN Window.RemoveFromTree[upperWindow];
    cornerPos ← ARoundToInch[pos];
    cplace ← PicturePlace[cornerPos];
    Window.Slide[pictureWindow, [x: -cplace.x, y: -cplace.y]];
    ASetOriginPos[GetOriginPos[FALSE]];
    ASetSourcePos[Absolute[GetSourcePos[FALSE]]];
    ASetDestPos[Absolute[GetDestPos[FALSE]]];
    END;

  ZoomGlobal: PUBLIC PROC =
    BEGIN
    IF state.magnify # state.minMagnify THEN 
      Window.DisplayWhite[pictureWindow, [[0,0], FrameBox.dims]];
    Window.Slide[pictureWindow, [0,0]];
    cornerPos ← [0,0];
    IF state.magnify # state.minMagnify THEN 
      Window.InvalidateBox[pictureWindow, [[0,0], FrameBox.dims]];
    state.magnify ← state.minMagnify;
    ASetOriginPos[GetOriginPos[FALSE]];
    ASetSourcePos[Absolute[GetSourcePos[FALSE]]];
    ASetDestPos[Absolute[GetDestPos[FALSE]]];
    END;

  DisplayFeedback: PROC [window: Window.Handle] =
    BEGIN
    window.clearingNotRequired ← TRUE;
    Window.EnumerateInvalidBoxes[window, DisplayFeedbackBox];
    END;

  Whiten: PROC [window: Window.Handle] =
    BEGIN
    DoIt: PROC [window: Window.Handle, box: Window.Box] RETURNS [Window.Box] =
      {Window.DisplayWhite[window, box]; RETURN[box]};
    Window.EnumerateInvalidBoxes[window, DoIt];
    END;

  DisplayFeedbackBox: PROC [window: Window.Handle, box: Window.Box] 
      RETURNS [Window.Box] =
    BEGIN
    StripeBox: Window.Box ← [
      [x: 0, y: FeedbackBox.dims.h-2],
      [w: FeedbackBox.dims.w, h: 1]];
    IF ~Disjoint[@box, @originValueBox] THEN DisplayOriginValue[];
    IF ~Disjoint[@box, @sourceValueBox] THEN DisplaySourceValue[];
    IF ~Disjoint[@box, @destValueBox] THEN DisplayDestValue[];
    IF ~Disjoint[@box, @StripeBox] THEN
      Window.DisplayBlack[window, StripeBox];
    IF ~Disjoint[@box, @textBox] THEN PaintText[];
    RETURN [[[0,0], window.box.dims]];
    END;

  DisplayOriginValue: PROC =
    BEGIN
    Window.DisplayData[
      window: feedbackWindow,
      box: [[x: -3, y: iconY], [16, 16]],
      data: @Cursors[origin],
      wpl: 1,
      bbop: replace];
    PaintValue[[x: 11 + 5, y: textY], LOOPHOLE[GetOriginPos[TRUE]]];
    END;

  DisplaySourceValue: PROC =
    BEGIN
    Window.DisplayData[
      window: feedbackWindow,
      box: [[x: sourceValueBox.place.x-1, y: iconY], [16, 16]],
      data: @Cursors[source],
      wpl: 1,
      bbop: replace];
    PaintValue[[x: sourceValueBox.place.x+8+5, y: textY], GetSourcePos[TRUE]];
    END;

  DisplayDestValue: PROC =
    BEGIN
    Window.DisplayData[
      window: feedbackWindow,
      box: [[x: destValueBox.place.x-8, y: iconY], [16, 16]],
      data: @Cursors[dest],
      wpl: 1,
      bbop: replace];
    PaintValue[[x: destValueBox.place.x+8+5, y: textY], GetDestPos[TRUE]];
    END;

  PaintValue: PROC [place: Window.Place, pos: RPosition] =
    BEGIN OPEN StringDefs;
    s: STRING ← [25];
    AppendString[s, "x:"L];
    AppendDistance[s, pos.x];
    AppendString[s, "  y:"L];
    AppendDistance[s, pos.y];
    [] ← Window.DisplayString[
      window: feedbackWindow,
      s: s,
      place: place,
      bbop: replace];
    END;

  AppendDistance: PROC [s: STRING, dist: ADistance] =
    BEGIN
    ns: STRING ← [10];
    a, i: LONG CARDINAL;
    f: CARDINAL;
    a ← ABS[dist];
    i ← a / 16;
    f ←  CARDINAL[Inline.LowHalf[a]] MOD 16;
    StringDefs.AppendLongDecimal[ns,
	IF dist > 0 THEN i ELSE -LOOPHOLE[i, LONG INTEGER]];
    THROUGH [ns.length..4) DO StringDefs.AppendChar[s, ' ] ENDLOOP;
    StringDefs.AppendString[s, ns];
    IF f = 0 THEN StringDefs.AppendString[s, "   "L]
    ELSE
      BEGIN
      StringDefs.AppendChar[s, '-];
      ns.length ← 0;
      StringDefs.AppendDecimal[ns, f];
      IF ns.length < 2 THEN StringDefs.AppendChar[s, ' ];
      StringDefs.AppendString[s, ns];
      END;
    END;

  textY, iconY, valueHeight: INTEGER;

  DisplayPicture: PROC [window: Window.Handle] =
    BEGIN
    Window.EnumerateInvalidBoxes[window, DisplayPictureBox];
    IF state.displayTicks THEN DisplayBoxTicks[TRUE];
    END;

  DisplayPictureBox: PROC [window: Window.Handle, box: Window.Box] 
      RETURNS [Window.Box] =
    BEGIN
    aBox: ABox ← ABoxForBox[box];
    keys: POINTER TO KeyDefs.KeyBits = KeyDefs.Keys;
    ThisPoint: PointScan =
      BEGIN
      IF pth.selected THEN
	BEGIN
        pBox: Window.Box ← BoxForPoint[p];
	IF ~Disjoint[@pBox, @box] THEN 
	  BEGIN
	  pPlace: Window.Place = PicturePlace[pth.pos];
	  Window.DisplayData[
	  window: pictureWindow,
	    box: [[pPlace.x-8, pPlace.y-8], [16, 16]],
	    data: @Cursors[selPt],
            wpl: 1];
	  END;
	END;
      END;
    ThisLine: LineScan =
      BEGIN
      DisplayLine[l, BoxForLine[l]];
      RETURN[FALSE];
      END;
    ThisLabel: LabelScan =
      BEGIN
      labelBox: Window.Box ← BoxForLabel[lb];
      IF ~Disjoint[@labelBox, @box] THEN PaintLabel[lb];
      RETURN[FALSE];
      END;
    [] ← LinesInABox[@aBox, ThisLine];
    IF state.showingLabels THEN
      [] ← AllLabels[ThisLabel];
    [] ← SelectedPoints[ThisPoint];
    RETURN [box];
    END;

  tickSpace: ARRAY [-3..4] OF ADistance = [
    16*128, 16*96, 16*48, 16*24, 16*12, 16*6, 16*3, 8*3];
  Triple: TYPE = RECORD [a,b,c: CARDINAL];
  tickMarks: ARRAY [0..12] OF Triple ← ALL[[100000B, 200B, 0]];

  DisplayBoxTicks: PUBLIC PROC [on: BOOLEAN] =
    BEGIN
    space: ADistance = tickSpace[state.magnify];
    cPlace: Window.Place = PicturePlace[cornerPos];
    rcp: RPosition = Relative[cornerPos];
    rft: RPosition = [
      x: ((rcp.x)/space)*space,
      y: ((rcp.y)/space) * space];
    tickStart: Window.Place ← PicturePlace[Absolute[rft]];
    tbox: Window.Box ← [
      tickStart, 
      [w: FrameBox.dims.w + cPlace.x - tickStart.x, h: 1]];
    lastY: INTEGER = cPlace.y + FrameBox.dims.h;
    WHILE tbox.place.y < lastY DO
      Window.DisplayData[
        window: pictureWindow,
	data: BASE[tickMarks],
	bbop: IF on THEN paint ELSE erase,
	wpl: 40,
	box: tbox];
      tbox.place.y ← tbox.place.y + 24;
      ENDLOOP;
    END;

  DisplayOrigin: PROC [window: Window.Handle] =
    BEGIN
    Window.DisplayOffsetData[
      window: window,
      box: [[0,0], window.box.dims],
      data: @Cursors[origin] + 3,
      wpl: 1,
      offset: 3,
      bbop: replace];
    END;

  DisplaySource: PROC [window: Window.Handle] =
    BEGIN
    Window.DisplayOffsetData[
      window: window,
      box: [[0,0], window.box.dims],
      data: @Cursors[source] + 4,
      wpl: 1,
      offset: 1,
      bbop: replace];
    END;

  DisplayDest: PROC [window: Window.Handle] =
    BEGIN
    Window.DisplayOffsetData[
      window: window,
      box: [[0,0], window.box.dims],
      data: @Cursors[dest] + 4,
      wpl: 1,
      offset: 8,
      bbop: replace];
    END;

  DisplayUpper: PROC [window: Window.Handle] =
    BEGIN
    Window.DisplayOffsetData[
      window: window,
      box: [[0,0], window.box.dims],
      data: @Cursors[upper] + 8,
      wpl: 1,
      offset: 8,
      bbop: replace];
    END;

  DisplayLower: PROC [window: Window.Handle] =
    BEGIN
    Window.DisplayOffsetData[
      window: window,
      box: [[0,0], window.box.dims],
      data: @Cursors[lower] + 1,
      wpl: 1,
      offset: 1,
      bbop: replace];
    END;

  root: Window.Object ← [];

  StartDisplay: PUBLIC PROC =
    BEGIN
    DisplayDefs.DestroyDisplay[];
    UserTerminalOps.StartUserTerminal[FALSE];
    Window.DefineRoot[window: @root, grey:, bitmapExists: FALSE];
    [] ← UserTerminalOps.SetBitmapBox[BitmapBox];
    [] ← UserTerminal.SetState[off];
    Window.DefineRoot[window: @root, grey:[0,0,0,0], bitmapExists: TRUE];
    [] ← UserTerminal.SetState[on];
    LoadFont[];
    feedbackWindow ← Storage.Node[SIZE[Window.Object]];
    frameWindow ← Storage.Node[SIZE[Window.Object]];
    pictureWindow ← Storage.Node[SIZE[Window.Object]];
    originWindow ← Storage.Node[
      SIZE[Window.Object] + SIZE[Window.MinusLandBitmapUnder]] + 
      SIZE[Window.MinusLandBitmapUnder];
    sourceWindow ← Storage.Node[
      SIZE[Window.Object] + SIZE[Window.MinusLandBitmapUnder]] + 
      SIZE[Window.MinusLandBitmapUnder];
    destWindow ← Storage.Node[
      SIZE[Window.Object] + SIZE[Window.MinusLandBitmapUnder]] + 
      SIZE[Window.MinusLandBitmapUnder];
    upperWindow ← Storage.Node[
      SIZE[Window.Object] + SIZE[Window.MinusLandBitmapUnder]] + 
      SIZE[Window.MinusLandBitmapUnder];
    lowerWindow ← Storage.Node[
      SIZE[Window.Object] + SIZE[Window.MinusLandBitmapUnder]] + 
      SIZE[Window.MinusLandBitmapUnder];
    feedbackWindow↑ ← [
      parent: Window.rootWindow,
      sibling: frameWindow,
      box: FeedbackBox,
      display: DisplayFeedback,
      boxesCount: one];
    frameWindow↑ ← [
      parent: Window.rootWindow,
      child: pictureWindow,
      box: FrameBox,
      display: Whiten];
    pictureWindow↑ ← [
      parent: frameWindow,
      child: originWindow,
      boxesCount: one,
      box: PictureBox,
      display: DisplayPicture];
    originWindow↑ ← [
      parent: pictureWindow,
      box: originBox,
      display: DisplayOrigin,
      underVariant: TRUE,
      clearingNotRequired: TRUE,
      boxesCount: none];
    [] ← Window.SetBitmapUnder[
      originWindow, Storage.Node[Window.WordsForBitmapUnder[originWindow]]];
    sourceWindow↑ ← [
      parent: pictureWindow,
      box: sourceBox,
      display: DisplaySource,
      underVariant: TRUE,
      clearingNotRequired: TRUE,
      boxesCount: none];
    [] ← Window.SetBitmapUnder[
      sourceWindow, Storage.Node[Window.WordsForBitmapUnder[sourceWindow]]];
    destWindow↑ ← [
      parent: pictureWindow,
      box: destBox,
      display: DisplayDest,
      underVariant: TRUE,
      clearingNotRequired: TRUE,
      boxesCount: none];
    [] ← Window.SetBitmapUnder[
      destWindow, Storage.Node[Window.WordsForBitmapUnder[destWindow]]];
    upperWindow↑ ← [
      parent: pictureWindow,
      box: upperBox,
      display: DisplayUpper,
      underVariant: TRUE,
      clearingNotRequired: TRUE,
      boxesCount: none];
    [] ← Window.SetBitmapUnder[
      upperWindow, Storage.Node[Window.WordsForBitmapUnder[sourceWindow]]];
    lowerWindow↑ ← [
      parent: pictureWindow,
      box: lowerBox,
      display: DisplayLower,
      underVariant: TRUE,
      clearingNotRequired: TRUE,
      boxesCount: none];
    [] ← Window.SetBitmapUnder[
      lowerWindow, Storage.Node[Window.WordsForBitmapUnder[destWindow]]];
    -- get ready to display pos values
    textY ← 2; iconY ← textY + WindowFont.FontHeight[]/2 - 8;
    valueHeight ← MAX[WindowFont.FontHeight[], 11];
    originValueBox ← [
      [x: 0, y: 0], [w: FeedbackBox.dims.w/3, h: valueHeight]];
    sourceValueBox ← [
      [x: FeedbackBox.dims.w/3, y: 0],
      [w: FeedbackBox.dims.w/3, h: valueHeight]];
    destValueBox ← [
      [x: (2*FeedbackBox.dims.w)/3, y: 0],
      [w: FeedbackBox.dims.w/3, h: valueHeight]];
    textBox ← [
      [x: 0, y: valueHeight + 1],
      [w: FeedbackBox.dims.w, h: WindowFont.FontHeight[]]];
    Window.InsertIntoTree[frameWindow];
    Window.InsertIntoTree[feedbackWindow];
    Window.ValidateTree[];
    END;

  fontAscent, smallFontAscent, largeFontAscent: PUBLIC INTEGER;
  smallFont, largeFont: PUBLIC WindowFont.Handle;

  LoadFont: PROC =
    BEGIN OPEN SegmentDefs;
    font: WindowFont.Handle ← Storage.Node[SIZE[WindowFont.Object]];
    fsb: WindowOps.Strike;
    fseg: FileSegmentHandle ← MiscDefs.DestroyFakeModule[
      LOOPHOLE[ALEOps.Gacha10]].seg;
    MakeSwappedIn[seg: fseg, info: HardUp];
    font.address ← fsb ← SegmentAddress[fseg];
    fontAscent ← fsb.body.ascent;
    font.swapper ← NIL;
    WindowFont.Initialize[font];
    WindowFont.SetDefault[font];
    font ← Storage.Node[SIZE[WindowFont.Object]];
    fseg ← MiscDefs.DestroyFakeModule[
      LOOPHOLE[ALEOps.Helvetica8]].seg;
    MakeSwappedIn[seg: fseg, info: HardUp];
    font.address ← fsb ← SegmentAddress[fseg];
    smallFontAscent ← fsb.body.ascent;
    font.swapper ← NIL;
    WindowFont.Initialize[font];
    smallFont ← font;
    font ← Storage.Node[SIZE[WindowFont.Object]];
    fseg ← MiscDefs.DestroyFakeModule[
      LOOPHOLE[ALEOps.Helvetica14]].seg;
    MakeSwappedIn[seg: fseg, info: HardUp];
    font.address ← fsb ← SegmentAddress[fseg];
    largeFontAscent ← fsb.body.ascent;
    font.swapper ← NIL;
    WindowFont.Initialize[font];
    largeFont ← font;
    SetupLand[];
    END;
    
  END.