mgkit/src/LinearArray.i3


 Copyright (C) 1992, Digital Equipment Corporation                         
 All rights reserved.                                                      
 See the file COPYRIGHT for a full description.                            
                                                                           
 by Steve Glassman and Stephen Harrison                                    
 Last modified on Mon Jul 20 23:41:21 1992 by steveg   

<*PRAGMA LL*>
Lists, Queues, Stacks and Buffers. Lumped together because they are all linear displays of things.

INTERFACE LinearArray;

IMPORT
  Axis, MG, MGV, PaintOp;

TYPE
  T <: TPublic;
  TPublic = MG.Group OBJECT
              <* LL = v.mu *>
              graphic        : MG.T;
              next, prev            : T;
              linkToNext, linkToPrev: LinkerRec;
            METHODS
              <* LL < v.mu *>
              init (v: V; graphic: MG.T): T;
              (* displays self using "graphic", sets the linker to the
                 default linker (if it is NIL), centers the graphic around
                 the origin, sets Pos(self) to the origin, and sets
                 visibility to 0.0 (invisible). *)

              <* LL = v.mu *>
              setNextPrev(v: V; np: NP; t: T);
              setNextPrevLink(v: V; np: NP; READONLY link: LinkerRec);
            END;

TYPE
  NP = {Next, Prev, Label};
  HT = {Head, Tail};

TYPE
  V <: VPublic;
  VPublic =
    MGV.V OBJECT
      <* LL = self.mu *>
      dx, dy := 5.0;
      (* separation distance between elements *)

      axis := Axis.T.Hor;
      (* axis of elements *)

      alignment := Alignment.AboveLeft;
      (* side of elements to locate elements that are "align"ed. *)

      linker: Linker := NIL;
      (* self.linker.new(from, to) returns a graphical element that acts as
         a link connecting "from" and "t".  The link ends should be
         individually controllable so "from" and "to" can move separately.

         If linker = NIL, linkerDefault is used and returns a MG.Line with
         MG.LineEnds at "from" and "to".  The visibility of "to" controls
         the visibility of the default link. *)

      (* internal state fields *)
      head, tail          : T := NIL;
      headLabel, tailLabel: T := NIL;
      labelLinks             := FALSE;

      aligned: T := NIL;
      (* list of aligned elements, so they are displayed *)

      cntElems := 0;
      (* count of elements in the linear array, maintained by insert and
         delete *)

      width, height: REAL;
      (* size of elements *)

    METHODS
      <* LL < self.mu *>
      init (width, height: REAL): V;
      (* dimensions of a box or label in the linear array *)

      <* LL = self.mu *>
      setLabel (ht: HT; graphic: MG.T);
      (* show "graphic" at the head/tail of the "list", include a link
         "self.labelLinks" is TRUE *)

      clear ();
      (* reset to have no elements *)

      align (t, dest: T);
      (* Creates and animation moving "t" to be aligned with "dest". *)

      insert (t, prev: T);
      (* Creates and animation to insert "t" after "prev".  If "prev" = NIL
         then insert as new head.  Handles next, prev, and links.  Updates
         head and tail as necessary *)

      delete (t: T);
      (* Creates and animation to delete "t" from "self"'s list.  Handles
         next, prev, and links.  Updates head and tail as necessary *)
    END;
A vbt displaying a linear array of elements.

<* LL < v.mu *>
PROCEDURE Align (v: V; t, dest: T);
PROCEDURE Clear (v: V);
PROCEDURE Delete (v: V; t: T);
PROCEDURE Insert (v: V; t, prev: T);
PROCEDURE Link (v: V; from, to: T);
The three above procedures handle locking, new shapes, animation, and redisplay for calls of the align, insert and delete methods

TYPE
  Alignment = {None, AboveLeft, AboveRight, BelowLeft, BelowRight};
  (*| Position of "align"ed elements relative to the destination
      element.  Head/Tail pointers (if any) are aligned on the opposite
      side (or "BelowRight" is used if "None" was specified) *)

TYPE
  LinkerRec = RECORD from, to: MG.T; fromT, toT: T END;
  Linker =
    OBJECT METHODS new (v: V; from, to: T; type: NP): LinkerRec END;
v.linker.new returns a pair of MG.T elements controlling a graphical link between from and to. If either from or to is NIL then a very short link should be produced with both ends controlled by the non-NIL end. type maybe be used to distinguish next, prev and label links.

VAR linkerDefault: Linker;
If v.linker = NIL, linkerDefault is used and returns a MG.Line with MG.LineEnds at from and to. The visibility of to controls the visibility of the default link.

TYPE
  List <: V;

TYPE
  DoublyLinkedList <: DoublyLinkedListPublic;
  DoublyLinkedListPublic = List OBJECT
    nextLinkColor, prevLinkColor: PaintOp.ColorScheme;
  END;
  (* Like a List except that linkToPrev is maintained and displayed *)

TYPE
  QSB = V OBJECT
       METHODS
         <* LL = self.mu *>
         push (t: T);
         pop  (): T;
       END;

  Queue <: QSB;
  (* A FIFO - self.push pushes at the tail and self.pop pops from the head *)

  Stack <: QSB;
  (* A LIFO - self.push pushes at the head and self.pop pops from the head *)

TYPE
  Buffer <: BufferPublic;
  BufferPublic =
    QSB OBJECT
      <* LL = self.mu *>
      pushSide, popSide: HT;
      (* pushSide = HT.Tail, popSide = HT.Head => Queue behavior pushSide =
         HT.Tail, popSide = HT.Tail => Stack behavior *)

      slots               : REF ARRAY OF MG.T := NIL;
      headIndex, tailIndex: INTEGER           := 0;

      emptyColor: PaintOp.ColorScheme := NIL;
      (* emptyColor rectangle will fill empty slots in the buffer.  if no
         color is given, then the empty slots will be invisible *)
    METHODS
      <* LL < self.mu *>
      init (width, height: REAL; size: CARDINAL; pushSide, popSide: HT):
            Buffer;

      <* LL = self.mu *>
      grow (newSize: CARDINAL);
    END;

<* LL < v.mu *>
PROCEDURE Push (v: QSB; t: T);
PROCEDURE Pop (v: QSB);

PROCEDURE GrowBuffer(v: Buffer; newSize: INTEGER);

END LinearArray.