(FILECREATED " 9-Jun-85 22:54:39" {ERIS}<LISPCORE>LIBRARY>GRAPHER.;40 134537 

      changes to:  (FNS SCALE/TONODES SCALE/GRAPH SET/LABEL/SIZE DRAWAREABOX DRAW/GRAPHNODE/BORDER)

      previous date: " 8-Jun-85 11:14:11" {ERIS}<LISPCORE>LIBRARY>GRAPHER.;39)


(* Copyright (c) 1983, 1984, 1985 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT GRAPHERCOMS)

(RPAQQ GRAPHERCOMS [[COMS (* For Harmony, if SHIFTDOWNP isn't defined)
			  (FNS GRAPHER.SHIFTDOWNP)
			  (P (MOVD? (QUOTE GRAPHER.SHIFTDOWNP)
				    (QUOTE SHIFTDOWNP]
	(FNS ADD/AND/DISPLAY/LINK APPLYTOSELECTEDNODE CALL.MOVENODEFN CHANGE.NODEFONT.SIZE 
	     CHOOSE.GRAPH.FONT CLOSEST/NODE DEFAULT.ADDNODEFN DELETE/AND/DISPLAY/LINK DISPLAY/NAME 
	     DISPLAYGRAPH DISPLAYLINK DISPLAYLINK/BT DISPLAYLINK/LR DISPLAYLINK/RL DISPLAYLINK/TB 
	     EDITTOGGLEBORDER ERASE/GRAPHNODE DISPLAYNODE DISPLAYNODELINKS DRAW/GRAPHNODE/BORDER 
	     DRAWAREABOX EDITADDLINK EDITADDNODE EDITAPPLYTOLINK EDITCHANGEFONT EDITDELETELINK 
	     EDITDELETENODE EDITGRAPH EDITGRAPH1 EDITGRAPHMENU EDITMOVENODE EDITTOGGLELABEL FLIPNODE 
	     FONTNAMELIST FROMLINKS GETNODEFROMID GN/BOTTOM GN/LEFT GN/RIGHT GN/TOP GRAPHADDLINK 
	     GRAPHADDNODE GRAPHDELETELINK GRAPHDELETENODE GRAPHEDITCOMMANDFN GRAPHEDITEVENTFN 
	     GRAPHER/CENTERPRINTINAREA GRAPHMOVENODE GRAPHNODE/BORDER/WIDTH GRAPHREGION HARDCOPYGRAPH 
	     INTERSECT/REGIONP/LBWH INVERTED/GRAPHNODE/BORDER INVERTED/SHADE/FOR/GRAPHER 
	     LAYOUT/POSITION LINKPARAMETERS MANHATTANDIST MAX/RIGHT MAX/TOP MEASUREGRAPHNODE 
	     MEMBTONODES MIN/BOTTOM MIN/LEFT MOVENODE NODECREATE NODELST/AS/MENU NODEREGION 
	     PRINTDISPLAYNODE FILL/GRAPHNODE/LABEL FIX/SCALE PROMPTINWINDOW READ/NODE REDISPLAYGRAPH 
	     REMOVETONODES RESET/NODE/BORDER RESET/NODE/LABELSHADE SCALE/GRAPH SCALE/GRAPHNODE/BORDER 
	     SCALE/TONODES SET/LABEL/SIZE SET/LAYOUT/POSITION SHOWGRAPH SIZE/GRAPH/WINDOW 
	     TOGGLE/DIRECTEDFLG TOGGLE/SIDESFLG TOLINKS TRACKCURSOR TRACKNODE)
	(COMS (* functions for finding larger and smaller fonts)
	      (FNS NEXTSIZEFONT DECREASING.FONT.LIST SCALE.FONT)
	      [DECLARE: DONTEVAL@LOAD DOCOPY (VARS (DECREASING.FONT.LIST (DECREASING.FONT.LIST]
	      (GLOBALVARS DECREASING.FONT.LIST))
	(* functions for LAYOUTGRAPH And LAYOUTLATTICE)
	(FNS BRH/LAYOUT BRH/LAYOUT/DAUGHTERS BRH/OFFSET BRHC/INTERTREE/SPACE BRHC/LAYOUT 
	     BRHC/LAYOUT/DAUGHTERS BRHC/LAYOUT/TERMINAL BRHC/OFFSET BRHL/LAYOUT BRHL/LAYOUT/DAUGHTERS 
	     BRHL/MOVE/RIGHT BROWSE/LAYOUT/HORIZ BROWSE/LAYOUT/HORIZ/COMPACTLY BROWSE/LAYOUT/LATTICE 
	     BRV/OFFSET EXTEND/TRANSITION/CHAIN FOREST/BREAK/CYCLES INIT/NODES/FOR/LAYOUT 
	     INTERPRET/MARK/FORMAT LATTICE/BREAK/CYCLES LAYOUTFOREST LAYOUTGRAPH LAYOUTLATTICE 
	     LAYOUTSEXPR LAYOUTSEXPR1 MARK/GRAPH/NODE NEW/INSTANCE/OF/GRAPHNODE 
	     RAISE/TRANSITION/CHAIN REFLECT/GRAPH/DIAGONALLY REFLECT/GRAPH/HORIZONTALLY 
	     REFLECT/GRAPH/VERTICALLY SWITCH/NODE/HEIGHT/WIDTH)
	(CONSTANTS (LINKPARAMS (QUOTE Link% Parameters)))
	(VARS DEFAULT.GRAPH.NODEBORDER DEFAULT.GRAPH.NODEFONT DEFAULT.GRAPH.NODELABELSHADE 
	      ScalableLinkParameters (CACHE/NODE/LABEL/BITMAPS)
	      (EDITGRAPHMENU)
	      (GRAPHEDITWINDOW)
	      (NODEBORDERWIDTH 1)
	      (ORIGIN (CREATEPOSITION 0 0)))
	(P (MOVD? (FUNCTION NILL)
		  (FUNCTION IMAGEOBJP)
		  T))
	(LOCALVARS . T)
	(GLOBALVARS EDITGRAPHMENU GRAPHEDITWINDOW NODEBORDERWIDTH ORIGIN)
	(RECORDS GRAPHNODE GRAPH)
	(DECLARE: DONTCOPY (MACROS HALF))
	(COMS (* Grapher image objects)
	      (FNS GRAPHERCOPYBUTTONEVENTFN GRAPHOBJ.FINDGRAPH)
	      (FNS ALIGNMENTNODE GRAPHOBJ.CHECKALIGN)
	      (FNS GRAPHEROBJ GRAPHOBJ.BUTTONEVENTINFN GRAPHOBJ.COPYFN GRAPHOBJ.DISPLAYFN 
		   GRAPHOBJ.GETALIGN GRAPHOBJ.GETFN GRAPHOBJ.IMAGEBOXFN GRAPHOBJ.PUTALIGN 
		   GRAPHOBJ.PUTFN)
	      (FNS COPYGRAPH DUMPGRAPH READGRAPH)
	      (VARS (GRAPHERIMAGEFNS))
	      (ALISTS (IMAGEOBJGETFNS GRAPHOBJ.GETFN])



(* For Harmony, if SHIFTDOWNP isn't defined)

(DEFINEQ

(GRAPHER.SHIFTDOWNP
  [LAMBDA (SHIFT)                                            (* rmk: " 4-Feb-85 14:50")
                                                             (* Tells whether a given shift is down)
    (SELECTQ SHIFT
	     (LOCK (ffetch (SHIFTSTATE LOCK) of \SHIFTSTATE))
	     (META (ffetch (SHIFTSTATE META) of \SHIFTSTATE))
	     (SHIFT (ffetch (SHIFTSTATE SHIFT) of \SHIFTSTATE))
	     (1SHIFT (ffetch (SHIFTSTATE 1SHIFT) of \SHIFTSTATE))
	     (2SHIFT (ffetch (SHIFTSTATE 2SHIFT) of \SHIFTSTATE))
	     (SHIFTORLOCK (ffetch (SHIFTSTATE SHIFTORLOCK) of \SHIFTSTATE))
	     (CTRL (ffetch (SHIFTSTATE CTRL) of \SHIFTSTATE))
	     (FONT (ffetch (SHIFTSTATE FONT) of \SHIFTSTATE))
	     (USERMODE1 (ffetch (SHIFTSTATE USERMODE1) of \SHIFTSTATE))
	     (USERMODE2 (ffetch (SHIFTSTATE USERMODE2) of \SHIFTSTATE))
	     (USERMODE3 (ffetch (SHIFTSTATE USERMODE3) of \SHIFTSTATE))
	     (\ILLEGAL.ARG SHIFT])
)
(MOVD? (QUOTE GRAPHER.SHIFTDOWNP)
       (QUOTE SHIFTDOWNP))
(DEFINEQ

(ADD/AND/DISPLAY/LINK
  [LAMBDA (FROMND TOND WIN G)                                (* dgb: "22-Jan-85 06:51")
                                                             (* adds and displays a link.)
    (COND
      ((MEMBTONODES (fetch NODEID of TOND)
		    (TOLINKS FROMND))
	(PRIN1 " link already exists. " T)
	(TERPRI T)
	NIL)
      (T (GRAPHADDLINK FROMND TOND G WIN)
	 (DISPLAYLINK FROMND TOND (CONSTANT (create POSITION
						    XCOORD ← 0
						    YCOORD ← 0))
		      WIN G)
	 T])

(APPLYTOSELECTEDNODE
  [LAMBDA (WINDOW)                                           (* kvl " 3-MAY-82 20:45")
                                                             (* applys a function whenever the node is selected.
							     Is used as BUTTONEVENTFN and gets called whenever 
							     cursor moves or button is down.)
    (PROG ((LEFTFNOFNODE (WINDOWPROP WINDOW (QUOTE BROWSER/LEFTFN)))
	   (MIDDLEFNOFNODE (WINDOWPROP WINDOW (QUOTE BROWSER/MIDDLEFN)))
	   [NODELST (fetch (GRAPH GRAPHNODES) of (WINDOWPROP WINDOW (QUOTE GRAPH]
	   (DS (WINDOWPROP WINDOW (QUOTE DSP)))
	   BUTTON OLDPOS REG NOW NEAR)                       (* note which button is down.)
          (TOTOPW WINDOW)
          (COND
	    ((LASTMOUSESTATE LEFT)
	      (OR LEFTFNOFNODE (RETURN))
	      (SETQ BUTTON (QUOTE LEFT)))
	    ((LASTMOUSESTATE MIDDLE)
	      (OR MIDDLEFNOFNODE (RETURN))
	      (SETQ BUTTON (QUOTE MIDDLE)))
	    (T                                               (* no button down, not interested.)
	       (RETURN)))                                    (* get the region of this window.)
          (SETQ REG (WINDOWPROP WINDOW (QUOTE REGION)))
          [SETQ NEAR (NODELST/AS/MENU NODELST (SETQ OLDPOS (CURSORPOSITION NIL DS]
      FLIP(AND NOW (FLIPNODE NOW DS))
          (AND NEAR (FLIPNODE NEAR DS))
          (SETQ NOW NEAR)
      LP                                                     (* wait for a button up or move out of region)
          (GETMOUSESTATE)
          (COND
	    ((NOT (LASTMOUSESTATE (OR LEFT MIDDLE)))         (* button up, process it.)
	      (AND NOW (FLIPNODE NOW DS))                    (* NOW node has been selected.)
	      (RETURN (APPLY* (SELECTQ BUTTON
				       (LEFT LEFTFNOFNODE)
				       (MIDDLE MIDDLEFNOFNODE)
				       (SHOULDNT))
			      NOW WINDOW)))
	    ((NOT (INSIDE? (WINDOWPROP WINDOW (QUOTE REGION))
			   LASTMOUSEX LASTMOUSEY))           (* outside of region, return)
	      (AND NOW (FLIPNODE NOW DS))
	      (RETURN))
	    ([EQ NOW (SETQ NEAR (NODELST/AS/MENU NODELST (CURSORPOSITION NIL DS OLDPOS]
	      (GO LP))
	    (T (GO FLIP])

(CALL.MOVENODEFN
  [LAMBDA (NODE NEWPOS GRAPH WINDOW)                         (* rrb " 1-NOV-83 12:02")
                                                             (* calls a graphs movenodefn.)
    (PROG ((MOVEFN (fetch (GRAPH GRAPH.MOVENODEFN) of GRAPH)))
          (AND MOVEFN (APPLY* MOVEFN NODE NEWPOS GRAPH WINDOW])

(CHANGE.NODEFONT.SIZE
  [LAMBDA (HOW NODE GRAPH WINDOW)                            (* kvl "20-Aug-84 10:36")
                                                             (* makes the label font of a node larger.)
    (PROG [(NEWFONT (NEXTSIZEFONT HOW (fetch (GRAPHNODE NODEFONT) of NODE]
          (COND
	    (NEWFONT (DISPLAYNODE NODE (CONSTANT (create POSITION
							 XCOORD ← 0
							 YCOORD ← 0))
				  WINDOW GRAPH)
		     (PROG ((CHNGFN (fetch (GRAPH GRAPH.FONTCHANGEFN) of GRAPH)))
		           (AND CHNGFN (APPLY* CHNGFN HOW NODE GRAPH WINDOW)))
		     (replace (GRAPHNODE NODEFONT) of NODE with NEWFONT)
		     (replace (GRAPHNODE NODEWIDTH) of NODE with NIL)
		     (replace (GRAPHNODE NODEHEIGHT) of NODE with NIL)
		     (MEASUREGRAPHNODE NODE)
		     (DISPLAYNODE NODE (CONSTANT (create POSITION
							 XCOORD ← 0
							 YCOORD ← 0))
				  WINDOW GRAPH])

(CHOOSE.GRAPH.FONT
  [LAMBDA (GRAPH)                                            (* rrb " 1-NOV-83 11:57")
                                                             (* picks a font for a new node in a graph)
                                                             (* for now use the same font as the first node.)
    (fetch (GRAPHNODE NODEFONT) of (CAR (fetch (GRAPH GRAPHNODES) of GRAPH])

(CLOSEST/NODE
  [LAMBDA (NODELST POS)                                      (* rmk: " 2-Feb-84 22:35")
                                                             (* finds the node that is closest to POS)
    (PROG (CLOSEST (MINDIST 65000)
		   DIST)
      LP  (COND
	    ((NULL NODELST)
	      (RETURN CLOSEST))
	    ((IGREATERP MINDIST (SETQ DIST (MANHATTANDIST (fetch NODEPOSITION of (CAR NODELST))
							  POS)))
	      (SETQ CLOSEST (CAR NODELST))
	      (SETQ MINDIST DIST)))
          (SETQ NODELST (CDR NODELST))
          (GO LP])

(DEFAULT.ADDNODEFN
  [LAMBDA (GRAPH WINDOW BOXED FONT)                          (* rrb " 2-NOV-83 20:29")
                                                             (* reads a node label name from the user and puts a 
							     node at the current cursor position.)
    (PROG (NODELABEL NODENAME)
          (SETQ NODELABEL (PROMPTINWINDOW "Node label?                  "))
      LP  (COND
	    ((FASSOC (SETQ NODENAME (PACK* NODELABEL (GENSYM)))
		     (fetch (GRAPH GRAPHNODES) of GRAPH))
	      (GO LP)))
          (RETURN (NODECREATE NODENAME NODELABEL (CURSORPOSITION NIL WINDOW)
			      NIL NIL (OR FONT (CHOOSE.GRAPH.FONT GRAPH))
			      BOXED])

(DELETE/AND/DISPLAY/LINK
  [LAMBDA (FROMND TOND WIN G)                                (* rht: " 5-Apr-85 11:18")
                                                             (* delete a link and updates the display.)

          (* * rht 4/4/85: Added temporary var LINKPARAMS to hold link parameters since they'll get tossed by 
	  GRAPHDELETELINK.)


    (COND
      ([NOT (OR (MEMBTONODES (fetch NODEID of TOND)
			     (TOLINKS FROMND))
		(AND (MEMBTONODES (fetch NODEID of FROMND)
				  (TOLINKS TOND))
		     (NOT (fetch (GRAPH DIRECTEDFLG) of G))
		     (PROG ((TMP FROMND))                    (* editting graph, don't distinguish between links.)
		           (SETQ FROMND TOND)
		           (SETQ TOND TMP)
		           (RETURN T]
	(PRIN1 " link does not exist. " T)
	(TERPRI T)
	NIL)
      (T (PROG ((LPARAMS (LINKPARAMETERS FROMND TOND)))
	       (GRAPHDELETELINK FROMND TOND G WIN)
	       (DISPLAYLINK FROMND TOND (CONSTANT (create POSITION
							  XCOORD ← 0
							  YCOORD ← 0))
			    WIN G NIL LPARAMS))
	 T])

(DISPLAY/NAME
  [LAMBDA (ND)                                               (* rrb "13-JUL-81 10:56")
    (fetch NODELABEL of ND])

(DISPLAYGRAPH
  [LAMBDA (GRAPH STREAM CLIP/REG TRANS)                      (* rmk: "27-Aug-84 10:04")

          (* Displays GRAPH with coordinates system translated to TRANS on STREAM. POS=NIL is interpreted as 0,0.
	  Draws links first then labels so that lattices don't have lines through the labels.)


    (PROG (SCALE (LINEWIDTH 1))
          [OR (type? POSITION TRANS)
	      (SETQ TRANS (CONSTANT (create POSITION
					    XCOORD ← 0
					    YCOORD ← 0]
          (SETQ STREAM (\GETSTREAM STREAM (QUOTE OUTPUT)))
          (COND
	    ((DISPLAYSTREAMP STREAM)

          (* This is because PRIN3 on displaystreams can sometimes cause CR's to be output. GRAPHER/CENTERPRINTINAREA doesn't 
	  have the rightmargin kludge that the CENTERPRINTINAREA in MENU has.)


	      (DSPRIGHTMARGIN 65000 STREAM))
	    (T (SETQ SCALE (DSPSCALE NIL STREAM))
	       (SETQ GRAPH (SCALE/GRAPH GRAPH STREAM SCALE))
	       [SETQ TRANS (create POSITION
				   XCOORD ←(FIXR (FTIMES SCALE (fetch XCOORD of TRANS)))
				   YCOORD ←(FIXR (FTIMES SCALE (fetch YCOORD of TRANS]
	       (SETQ LINEWIDTH SCALE)))
          (for N in (fetch (GRAPH GRAPHNODES) of GRAPH) do (DISPLAYNODELINKS N TRANS STREAM GRAPH T 
									     LINEWIDTH))
          (for N in (fetch (GRAPH GRAPHNODES) of GRAPH) do (PRINTDISPLAYNODE N TRANS STREAM CLIP/REG])

(DISPLAYLINK
  [LAMBDA (FRND TOND TRANS STREAM G LINEWIDTH PARAMS)        (* rht: "13-Mar-85 13:58")
                                                             (* draws in a link from FRND TO TOND, translated by 
							     TRANS)
    (COND
      ((fetch (GRAPH SIDESFLG) of G)
	(COND
	  ((OR (fetch (GRAPH DIRECTEDFLG) of G)
	       (IGREATERP (GN/LEFT TOND)
			  (GN/RIGHT FRND)))                  (* in the horizontal case of LATTICE, always draw from 
							     right to left.)
	    (DISPLAYLINK/RL TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	  ((IGREATERP (GN/LEFT FRND)
		      (GN/RIGHT TOND))
	    (DISPLAYLINK/LR TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	  ((IGREATERP (GN/BOTTOM FRND)
		      (GN/TOP TOND))
	    (DISPLAYLINK/BT TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	  ((IGREATERP (GN/BOTTOM TOND)
		      (GN/TOP FRND))
	    (DISPLAYLINK/TB TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	  (T                                                 (* if on top of each other, don't draw.)
	     NIL)))
      (T (COND
	   ((OR (fetch (GRAPH DIRECTEDFLG) of G)
		(IGREATERP (GN/BOTTOM FRND)
			   (GN/TOP TOND)))                   (* if LATTICE, always draw from FROMNODE BOTTOM to 
							     TONODE TOP. Otherwise find the one that looks best.)
	     (DISPLAYLINK/BT TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	   ((IGREATERP (GN/BOTTOM TOND)
		       (GN/TOP FRND))
	     (DISPLAYLINK/TB TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	   ((IGREATERP (GN/LEFT TOND)
		       (GN/RIGHT FRND))
	     (DISPLAYLINK/RL TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	   ((IGREATERP (GN/LEFT FRND)
		       (GN/RIGHT TOND))
	     (DISPLAYLINK/LR TRANS FRND TOND LINEWIDTH NIL STREAM PARAMS))
	   (T                                                (* if on top of each other, don't draw.)
	      NIL])

(DISPLAYLINK/BT
  [LAMBDA (TRANS GNB GNT WIDTH OPERATION STREAM PARAMS)      (* rht: "13-Mar-85 13:56")
                                                             (* draws a line from the bottom edge of GNB to the top 
							     edge of GNT translated by TRANS)
    (APPLY* (OR (LISTGET PARAMS (QUOTE DRAWLINKFN))
		(QUOTE DRAWLINE))
	    (IPLUS (fetch XCOORD of TRANS)
		   (fetch XCOORD of (fetch NODEPOSITION of GNB)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (SUB1 (GN/BOTTOM GNB)))
	    (IPLUS (fetch XCOORD of TRANS)
		   (fetch XCOORD of (fetch NODEPOSITION of GNT)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (ADD1 (GN/TOP GNT)))
	    (OR (LISTGET PARAMS (QUOTE LINEWIDTH))
		WIDTH 1)
	    OPERATION STREAM (LISTGET PARAMS (QUOTE COLOR))
	    (LISTGET PARAMS (QUOTE DASHING))
	    PARAMS])

(DISPLAYLINK/LR
  [LAMBDA (TRANS GNL GNR WIDTH OPERATION STREAM PARAMS)      (* dgb: "23-Jan-85 08:44")
                                                             (* draws a line from the left edge of GNL to the right 
							     edge of GNR, translated by TRANS)
    (APPLY* (OR (LISTGET PARAMS (QUOTE DRAWLINKFN))
		(QUOTE DRAWLINE))
	    (IPLUS (fetch XCOORD of TRANS)
		   (SUB1 (GN/LEFT GNL)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (fetch YCOORD of (fetch NODEPOSITION of GNL)))
	    (IPLUS (fetch XCOORD of TRANS)
		   (ADD1 (GN/RIGHT GNR)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (fetch YCOORD of (fetch NODEPOSITION of GNR)))
	    (OR (LISTGET PARAMS (QUOTE LINEWIDTH))
		WIDTH 1)
	    OPERATION STREAM (LISTGET PARAMS (QUOTE COLOR))
	    (LISTGET PARAMS (QUOTE DASHING))
	    PARAMS])

(DISPLAYLINK/RL
  [LAMBDA (TRANS GNR GNL WIDTH OPERATION STREAM PARAMS)      (* rht: "13-Mar-85 13:54")
                                                             (* draws a line from the right edge of GNR, to the left
							     edge of GNL translated by TRANS)
    (APPLY* (OR (LISTGET PARAMS (QUOTE DRAWLINKFN))
		(QUOTE DRAWLINE))
	    (IPLUS (fetch XCOORD of TRANS)
		   (ADD1 (GN/RIGHT GNR)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (fetch YCOORD of (fetch NODEPOSITION of GNR)))
	    (IPLUS (fetch XCOORD of TRANS)
		   (SUB1 (GN/LEFT GNL)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (fetch YCOORD of (fetch NODEPOSITION of GNL)))
	    (OR (LISTGET PARAMS (QUOTE LINEWIDTH))
		WIDTH 1)
	    OPERATION STREAM (LISTGET PARAMS (QUOTE COLOR))
	    (LISTGET PARAMS (QUOTE DASHING))
	    PARAMS])

(DISPLAYLINK/TB
  [LAMBDA (TRANS GNT GNB WIDTH OPERATION STREAM PARAMS)      (* dgb: "23-Jan-85 08:44")
                                                             (* draws a line from the top edge of GNT to the bottom 
							     edge of GNR, translated by TRANS)
    (APPLY* (OR (LISTGET PARAMS (QUOTE DRAWLINKFN))
		(QUOTE DRAWLINE))
	    (IPLUS (fetch XCOORD of TRANS)
		   (fetch XCOORD of (fetch NODEPOSITION of GNT)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (ADD1 (GN/TOP GNT)))
	    (IPLUS (fetch XCOORD of TRANS)
		   (fetch XCOORD of (fetch NODEPOSITION of GNB)))
	    (IPLUS (fetch YCOORD of TRANS)
		   (SUB1 (GN/BOTTOM GNB)))
	    (OR (LISTGET PARAMS (QUOTE LINEWIDTH))
		WIDTH 1)
	    OPERATION STREAM (LISTGET PARAMS (QUOTE COLOR))
	    (LISTGET PARAMS (QUOTE DASHING))
	    PARAMS])

(EDITTOGGLEBORDER
  [LAMBDA (W)                                                (* rmk: "14-Dec-84 13:50")
                                                             (* prompts the user for a node and inverts its border)
    (RESETFORM (TTYDISPLAYSTREAM PROMPTWINDOW)
	       (CLRPROMPT)
	       (PROG ((GRAPH (WINDOWPROP W (QUOTE GRAPH)))
		      (DS (WINDOWPROP W (QUOTE DSP)))
		      NODE)
		     (COND
		       ((NOT (fetch (GRAPH GRAPHNODES) of GRAPH))
			 (PROMPTPRINT " No nodes to invert. ")
			 (RETURN)))
		     (PROMPTPRINT " Select node to have border inverted. ")
		     (SETQ NODE (READ/NODE (fetch (GRAPH GRAPHNODES) of GRAPH)
					   DS))
		     (TERPRI T)
		     (RESET/NODE/BORDER NODE (QUOTE INVERT)
					W GRAPH)
		     (AND (fetch (GRAPH GRAPH.INVERTBORDERFN) of GRAPH)
			  (APPLY* (fetch (GRAPH GRAPH.INVERTBORDERFN) of GRAPH)
				  NODE GRAPH W))
		     (printout T "Node " (fetch NODELABEL of NODE)
			       " inverted." T)
		     (RETURN NODE])

(ERASE/GRAPHNODE
  [LAMBDA (NODE STREAM TRANS)                                (* kvl " 5-Sep-84 18:22")
                                                             (* erases a node at its position translated by TRANS)
    (OR [NOT (OR (WINDOWP STREAM)
		 (IMAGESTREAMTYPEP STREAM (QUOTE DISPLAY]
	(ZEROP (fetch (GRAPHNODE NODEHEIGHT) of NODE))
	(NULL (fetch NODEFONT of NODE))
	(BITBLT NIL NIL NIL STREAM (COND
		  (TRANS (IPLUS (fetch XCOORD of TRANS)
				(GN/LEFT NODE)))
		  (T (GN/LEFT NODE)))
		(COND
		  (TRANS (IPLUS (fetch YCOORD of TRANS)
				(GN/BOTTOM NODE)))
		  (T (GN/BOTTOM NODE)))
		(fetch NODEWIDTH of NODE)
		(fetch NODEHEIGHT of NODE)
		(QUOTE TEXTURE)
		(QUOTE REPLACE)
		WHITESHADE])

(DISPLAYNODE
  [LAMBDA (NODE TRANS STREAM G TOSONLY)                      (* kvl "10-Aug-84 19:08")
                                                             (* displays a node and its links.
							     IF TOSONLY IS NON-NIL, DRAWS ONLY THE TO LINKS.)
    (DISPLAYNODELINKS NODE TRANS STREAM G TOSONLY)
    (PRINTDISPLAYNODE NODE TRANS STREAM (DSPCLIPPINGREGION NIL STREAM])

(DISPLAYNODELINKS
  [LAMBDA (NODE TRANS STREAM G TOSONLY LINEWIDTH)            (* dgb: "23-Jan-85 08:30")
                                                             (* displays a node links. IF TOSONLY IS NON-NIL, DRAWS 
							     ONLY THE TO LINKS.)
    (PROG ((NODELST (fetch (GRAPH GRAPHNODES) of G)))
          (for TONODEID TONODE in (TOLINKS NODE) do (DISPLAYLINK NODE (SETQ TONODE (GETNODEFROMID
								     TONODEID NODELST))
								 TRANS STREAM G LINEWIDTH
								 (LINKPARAMETERS NODE TONODE)))
          (OR TOSONLY (for FROMNDID FROMND in (FROMLINKS NODE) do (DISPLAYLINK (SETQ FROMND
										 (GETNODEFROMID
										   FROMNDID NODELST))
									       NODE TRANS STREAM G 
									       LINEWIDTH
									       (LINKPARAMETERS FROMND 
											     NODE])

(DRAW/GRAPHNODE/BORDER
  [LAMBDA (BORDER LEFT BOTTOM WIDTH HEIGHT STREAM)           (* lmm " 9-Jun-85 22:38")

          (* interprets the node border. If the border is a shade, then bitblt twice in invert mode. This will look ugly if a 
	  link runs underneath the node, but at least the label will be legible.)


    (COND
      ((EQ BORDER NIL))
      ((EQ BORDER T)
	(DRAWAREABOX LEFT BOTTOM WIDTH HEIGHT 1 NIL STREAM))
      ((FIXP BORDER)
	(OR (ILEQ BORDER 0)
	    (DRAWAREABOX LEFT BOTTOM WIDTH HEIGHT BORDER NIL STREAM)))
      ((LISTP BORDER)                                        (* Extract the PROG after Intermezzo is released)
	(DRAWAREABOX LEFT BOTTOM WIDTH HEIGHT (CAR BORDER)
		     NIL STREAM (CADR BORDER)))
      (T (ERROR "Illegal border:" BORDER])

(DRAWAREABOX
  [LAMBDA (BOXLEFT BOXBOTTOM BOXWIDTH BOXHEIGHT BORDER OP W TEXTURE)
                                                             (* lmm " 9-Jun-85 22:36")
    (OR TEXTURE (SETQ TEXTURE BLACKSHADE))                   (* lmm " 9-Jun-85 22:04")
                                                             (* draws lines inside the region.)
                                                             (* draw left edge)
    (BITBLT NIL NIL NIL W BOXLEFT BOXBOTTOM BORDER BOXHEIGHT (QUOTE TEXTURE)
	    OP TEXTURE)                                      (* draw top)
    (BITBLT NIL NIL NIL W (PLUS BOXLEFT BORDER)
	    (DIFFERENCE (PLUS BOXBOTTOM BOXHEIGHT)
			BORDER)
	    (DIFFERENCE BOXWIDTH (PLUS BORDER BORDER))
	    BORDER
	    (QUOTE TEXTURE)
	    OP TEXTURE)                                      (* draw bottom)
    (BITBLT NIL NIL NIL W (PLUS BOXLEFT BORDER)
	    BOXBOTTOM
	    (DIFFERENCE BOXWIDTH (PLUS BORDER BORDER))
	    BORDER
	    (QUOTE TEXTURE)
	    OP TEXTURE)                                      (* draw right edge)
    (BITBLT NIL NIL NIL W (DIFFERENCE (PLUS BOXLEFT BOXWIDTH)
				      BORDER)
	    BOXBOTTOM BORDER BOXHEIGHT (QUOTE TEXTURE)
	    OP TEXTURE])

(EDITADDLINK
  [LAMBDA (W)                                                (* kvl "20-APR-82 13:53")
                                                             (* reads and adds a link to the graph)
    (EDITAPPLYTOLINK (FUNCTION ADD/AND/DISPLAY/LINK)
		     (QUOTE added)
		     (WINDOWPROP W (QUOTE GRAPH))
		     W])

(EDITADDNODE
  [LAMBDA (W)                                                (* kvl "10-Aug-84 19:06")
                                                             (* adds a node to the graph in the window W and 
							     displays it.)
    (PROG [NODE (GRAPH (WINDOWPROP W (QUOTE GRAPH]
          (OR (SETQ NODE (GRAPHADDNODE GRAPH W))
	      (RETURN))
          (MEASUREGRAPHNODE NODE)
          (printout PROMPTWINDOW T "Position node " (DISPLAY/NAME NODE))
          (PRINTDISPLAYNODE NODE (CONSTANT (create POSITION
						   XCOORD ← 0
						   YCOORD ← 0))
			    W
			    (DSPCLIPPINGREGION NIL W))
          (TRACKCURSOR NODE (WINDOWPROP W (QUOTE DSP))
		       GRAPH)
          (RETURN NODE])

(EDITAPPLYTOLINK
  [LAMBDA (FN MSG GRAPH DS)                                  (* kvl "20-APR-82 14:29")
    (RESETFORM (TTYDISPLAYSTREAM PROMPTWINDOW)
	       (COND
		 [(fetch (GRAPH GRAPHNODES) of GRAPH)
		   (PROG (FROM TO)
		         (printout T "Specify the link by selecting the FROM node, then the TO node." 
				   T)
		         (PRIN1 "FROM?" T)
		         (SETQ FROM (READ/NODE (fetch (GRAPH GRAPHNODES) of GRAPH)
					       DS))
		         (CLRPROMPT)
		         (FLIPNODE FROM DS)
		         (PRIN1 "TO?" T)
		         [SETQ TO (COND
			     [(CAR (ERSETQ (READ/NODE (fetch (GRAPH GRAPHNODES) of GRAPH)
						      DS]
			     (T (FLIPNODE FROM DS)
				(ERROR!]
		         (CLRPROMPT)
		         (FLIPNODE FROM DS)
		         (COND
			   ((APPLY* FN FROM TO DS GRAPH)     (* return non-nil if changed anything.)
			     (printout T "Link from " (DISPLAY/NAME FROM)
				       " to "
				       (DISPLAY/NAME TO)
				       , MSG T]
		 (T (TERPRI T)
		    (PRINT "There are no nodes.  You can create nodes with the Add Node command." T])

(EDITCHANGEFONT
  [LAMBDA (HOW W)                                            (* rrb " 2-NOV-83 21:26")
                                                             (* prompts the user for a node and deletes it)
    (PROG ((GRAPH (WINDOWPROP W (QUOTE GRAPH)))
	   (DS (WINDOWPROP W (QUOTE DSP)))
	   NODE)
          (COND
	    ((NOT (fetch (GRAPH GRAPHNODES) of GRAPH))
	      (PROMPTPRINT " No nodes yet. ")
	      (RETURN)))
          (printout PROMPTWINDOW T " Select node to be made " (COND
		      ((EQ HOW (QUOTE SMALLER))
			"smaller.")
		      (T "larger.")))
          (SETQ NODE (READ/NODE (fetch (GRAPH GRAPHNODES) of GRAPH)
				DS))
          (AND NODE (CHANGE.NODEFONT.SIZE HOW NODE GRAPH W])

(EDITDELETELINK
  [LAMBDA (W)                                                (* kvl "20-APR-82 13:54")
                                                             (* reads and adds a link to the graph)
    (EDITAPPLYTOLINK (FUNCTION DELETE/AND/DISPLAY/LINK)
		     (QUOTE deleted)
		     (WINDOWPROP W (QUOTE GRAPH))
		     W])

(EDITDELETENODE
  [LAMBDA (W)                                                (* rmk: "10-Apr-84 12:33")
                                                             (* prompts the user for a node and deletes it)
    (RESETFORM (TTYDISPLAYSTREAM PROMPTWINDOW)
	       (CLRPROMPT)
	       (PROG ((GRAPH (WINDOWPROP W (QUOTE GRAPH)))
		      (DS (WINDOWPROP W (QUOTE DSP)))
		      NODE NODELABEL)
		     (COND
		       ((NOT (fetch (GRAPH GRAPHNODES) of GRAPH))
			 (PROMPTPRINT " No nodes to delete. ")
			 (RETURN)))
		     (PROMPTPRINT " Select node to be deleted. ")
		     (SETQ NODE (READ/NODE (fetch (GRAPH GRAPHNODES) of GRAPH)
					   DS))
		     (TERPRI T)
		     (FLIPNODE NODE DS)
		     (COND
		       ((EQ [ASKUSER NIL NIL (LIST "delete node " (SETQ NODELABEL (DISPLAY/NAME
						       NODE]
			    (QUOTE Y))
			 (FLIPNODE NODE DS)
			 (DISPLAYNODE NODE (CONSTANT (create POSITION
							     XCOORD ← 0
							     YCOORD ← 0))
				      DS GRAPH)
			 (for TOND in (APPEND (TOLINKS NODE))
			    do (GRAPHDELETELINK NODE (GETNODEFROMID TOND (fetch (GRAPH GRAPHNODES)
									    of GRAPH))
						GRAPH W))
			 (for FROMND in (APPEND (FROMLINKS NODE))
			    do (GRAPHDELETELINK (GETNODEFROMID FROMND (fetch (GRAPH GRAPHNODES)
									 of GRAPH))
						NODE GRAPH W))
			 (GRAPHDELETENODE NODE GRAPH W)
			 (printout T "Node " NODELABEL " deleted." T)
			 (RETURN NODE))
		       (T (FLIPNODE NODE DS)
			  (printout T "nothing deleted." T)
			  (RETURN NIL])

(EDITGRAPH
  [LAMBDA (GRAPH WINDOW)                                     (* kvl "10-Aug-84 19:56")

          (* top level function for editing a graph. If there is no graph, create one empty. IF there is no window, create on 
	  the right size for the graph. After getting the arguments right, put the right button functions on, display it and 
	  enter the main loop.)


    (OR GRAPH (SETQ GRAPH (create GRAPH)))
    (SETQ WINDOW (SIZE/GRAPH/WINDOW GRAPH WINDOW))
    (WINDOWPROP WINDOW (QUOTE GRAPH)
		GRAPH)
    (WINDOWPROP WINDOW (QUOTE REPAINTFN)
		(FUNCTION REDISPLAYGRAPH))
    (WINDOWPROP WINDOW (QUOTE SCROLLFN)
		(FUNCTION SCROLLBYREPAINTFN))
    (DSPOPERATION (QUOTE INVERT)
		  WINDOW)
    (REDISPLAYGRAPH WINDOW)
    (EDITGRAPH1 WINDOW)
    GRAPH])

(EDITGRAPH1
  [LAMBDA (W)                                                (* rrb " 7-NOV-83 14:51")

          (* Can also be called from top level if the given window W has a graph on its GRAPH windowprop and the graph has 
	  been displayed by SHOWGRAPH or its equivalent. It waits for mouse hits, does the comand, then waits for mouse clear.
	  Each edit command function takes only the window so that they can be hung separately on button event functions.
	  However, the window must have INVERT as its display operation mode.)


    (PROG (VAL)
          (CLRPROMPT)
          (printout PROMPTWINDOW "Use the left button to move nodes." T 
		    "Use the middle button to get a menu of edit commands."
		    T "During an edit command, the middle button can be used to abort.")
      LP  (until (MOUSESTATE (OR LEFT MIDDLE)) do)
          (COND
	    [(LASTMOUSESTATE MIDDLE)
	      (SETQ VAL (ERSETQ (GRAPHEDITCOMMANDFN W)))
	      (COND
		((NULL VAL)                                  (* aborted)
		  (printout PROMPTWINDOW T T "command aborted." T))
		((EQ (CAR VAL)
		     (QUOTE STOP))
		  (RETURN (CLRPROMPT]
	    ((fetch (GRAPH GRAPHNODES) of (WINDOWPROP W (QUOTE GRAPH)))
                                                             (* track the nearest node.)
	      (TRACKNODE W))
	    (T (printout PROMPTWINDOW T "There are no nodes to move yet." T 
			 "Press the middle button and select the 'Add a node' command.")))
          (until (MOUSESTATE UP) do)
          (GO LP])

(EDITGRAPHMENU
  [LAMBDA NIL                                                (* rrb " 6-JAN-82 12:29")
    (COND
      ((type? MENU EDITGRAPHMENU)
	EDITGRAPHMENU)
      (T (SETQ EDITGRAPHMENU (create MENU
				     ITEMS ←(QUOTE (("Add Node" (QUOTE ADDNODE))
						     ("Delete Node" (QUOTE DELETENODE))
						     ("Add Link" (QUOTE ADDLINK))
						     ("Delete Link" (QUOTE DELETELINK))
						     ("Toggle DirectedFlg" (QUOTE DIRECTED))
						     ("Toggle SidesFlg" (QUOTE SIDES))
						     STOP))
				     CENTERFLG ← T
				     CHANGEOFFSETFLG ← T])

(EDITMOVENODE
  [LAMBDA (WINDOW)                                           (* rrb "31-OCT-83 21:47")
                                                             (* hilite nodes until the cursor goes down then move 
							     it)
    (PROG ((DS (WINDOWPROP WINDOW (QUOTE DSP)))
	   (REG (WINDOWPROP WINDOW (QUOTE REGION)))
	   (GRAPH (WINDOWPROP WINDOW (QUOTE GRAPH)))
	   OLDPOS NOW NEAR NODELST)
          (COND
	    (GRAPH (SETQ NODELST (fetch (GRAPH GRAPHNODES) of GRAPH)))
	    (T (RETURN)))
          (printout PROMPTWINDOW T "Move the cursor to the node " "you want to move " 
		    "and press any button.")
          [SETQ NEAR (NODELST/AS/MENU NODELST (SETQ OLDPOS (CURSORPOSITION NIL DS]
      FLIP(AND NOW (FLIPNODE NOW DS))
          (AND NEAR (FLIPNODE NEAR DS))
          (SETQ NOW NEAR)
      LP  (GETMOUSESTATE)
          (COND
	    ((LASTMOUSESTATE (NOT UP))                       (* button up, process it.)
	      (AND NOW (FLIPNODE NOW DS))                    (* NOW node has been selected.)
	      )
	    ([EQ NOW (SETQ NEAR (NODELST/AS/MENU NODELST (CURSORPOSITION NIL DS OLDPOS]
	      (GO LP))
	    (T (GO FLIP)))
          (printout PROMPTWINDOW T "Holding the button down, " "move the node to its new position" 
		    "and release the button.")
          (TRACKCURSOR NOW DS GRAPH)
          (printout PROMPTWINDOW T "Done."])

(EDITTOGGLELABEL
  [LAMBDA (W)                                                (* kvl " 5-Sep-84 19:16")
                                                             (* prompts the user for a node and inverts its lable)
    (RESETFORM (TTYDISPLAYSTREAM PROMPTWINDOW)
	       (CLRPROMPT)
	       (PROG ((GRAPH (WINDOWPROP W (QUOTE GRAPH)))
		      (DS (WINDOWPROP W (QUOTE DSP)))
		      NODE)
		     (COND
		       ((NOT (fetch (GRAPH GRAPHNODES) of GRAPH))
			 (PROMPTPRINT " No nodes to invert.")
			 (RETURN)))
		     (PROMPTPRINT " Select node to have label inverted. ")
		     (SETQ NODE (READ/NODE (fetch (GRAPH GRAPHNODES) of GRAPH)
					   DS))
		     (TERPRI T)
		     (RESET/NODE/LABELSHADE NODE (QUOTE INVERT)
					    W)
		     (AND (fetch (GRAPH GRAPH.INVERTLABELFN) of GRAPH)
			  (APPLY* (fetch (GRAPH GRAPH.INVERTLABELFN) of GRAPH)
				  NODE GRAPH W))
		     (printout T "Node " (fetch NODELABEL of NODE)
			       " inverted." T)
		     (RETURN NODE])

(FLIPNODE
  [LAMBDA (NODE DS)                                          (* kvl "10-Aug-84 17:27")
                                                             (* flips the region around a node.)
    (BITBLT NIL NIL NIL DS (IDIFFERENCE (GN/LEFT NODE)
					1)
	    (IDIFFERENCE (GN/BOTTOM NODE)
			 1)
	    (IPLUS (fetch NODEWIDTH of NODE)
		   2)
	    (IPLUS (fetch NODEHEIGHT of NODE)
		   2)
	    (QUOTE TEXTURE)
	    (QUOTE INVERT)
	    BLACKSHADE])

(FONTNAMELIST
  [LAMBDA (FONTDESC)                                         (* rrb " 2-NOV-83 21:00")
    (LIST (FONTPROP FONTDESC (QUOTE FAMILY))
	  (FONTPROP FONTDESC (QUOTE SIZE))
	  (FONTPROP FONTDESC (QUOTE FACE])

(FROMLINKS
  [LAMBDA (NODE)                                             (* rrb "13-JUL-81 10:55")
    (fetch FROMNODES of NODE])

(GETNODEFROMID
  [LAMBDA (ID NODELST)                                       (* dgb: "24-Jan-85 08:06")
                                                             (* Allow Link parameters to be passed as a property 
							     list of the node description.)
    (OR (FASSOC ID NODELST)
	(AND (LISTP ID)
	     (EQ (QUOTE Link% Parameters)
		 (CAR ID))
	     (FASSOC (CADR ID)
		     NODELST))
	(ERROR "No graphnode for nodeid:" ID])

(GN/BOTTOM
  [LAMBDA (NODE)                                             (* kvl "10-Aug-84 17:08")
    (IDIFFERENCE (fetch YCOORD of (fetch NODEPOSITION of NODE))
		 (HALF (fetch NODEHEIGHT of NODE])

(GN/LEFT
  [LAMBDA (NODE)                                             (* kvl "10-Aug-84 17:03")
    (IDIFFERENCE (fetch XCOORD of (fetch NODEPOSITION of NODE))
		 (HALF (fetch NODEWIDTH of NODE])

(GN/RIGHT
  [LAMBDA (NODE)                                             (* rmk: " 2-Jan-85 08:37")
                                                             (* Assumes that the big-half of width is to the left of
							     the center, for even width)
    (IPLUS (fetch XCOORD of (fetch NODEPOSITION of NODE))
	   (SUB1 (HALF (ADD1 (fetch NODEWIDTH of NODE])

(GN/TOP
  [LAMBDA (NODE)                                             (* rmk: " 2-Jan-85 08:38")
                                                             (* Assumes that big-half of height is under the center,
							     for even height. Result is -1 for height=0, which is 
							     correct.)
    (IPLUS (fetch YCOORD of (fetch NODEPOSITION of NODE))
	   (SUB1 (HALF (ADD1 (fetch NODEHEIGHT of NODE])

(GRAPHADDLINK
  [LAMBDA (FROM TO GRAPH WINDOW)                             (* rrb " 1-NOV-83 09:18")
                                                             (* links two nodes)
    (PROG ((ADDFN (fetch (GRAPH GRAPH.ADDLINKFN) of GRAPH)))
          (AND ADDFN (APPLY* ADDFN FROM TO GRAPH WINDOW)))
    (push (fetch FROMNODES of TO)
	  (fetch NODEID of FROM))
    (push (fetch TONODES of FROM)
	  (fetch NODEID of TO])

(GRAPHADDNODE
  [LAMBDA (GRAPH W)                                          (* rrb " 2-NOV-83 20:29")
                                                             (* adds a node to the graph GRAPH)
    (PROG (ADDFN NODE)
          (OR [SETQ NODE (COND
		  ((SETQ ADDFN (fetch (GRAPH GRAPH.ADDNODEFN) of GRAPH))
		    (APPLY* ADDFN GRAPH W))
		  (T (DEFAULT.ADDNODEFN GRAPH W T]
	      (RETURN))
          (replace (GRAPH GRAPHNODES) of GRAPH with (NCONC1 (fetch (GRAPH GRAPHNODES) of GRAPH)
							    NODE))
          (RETURN NODE])

(GRAPHDELETELINK
  [LAMBDA (FROM TO GRAPH WINDOW)                             (* rht: " 4-Apr-85 19:37")
                                                             (* deletes a link from a graph)

          (* * rht 4/4/85: Changed to call REMOVETONODES to remove either nodeID or paramlist thingie for nodeID.)


    (PROG ((DELFN (fetch (GRAPH GRAPH.DELETELINKFN) of GRAPH)))
          (AND DELFN (APPLY* DELFN FROM TO GRAPH WINDOW)))
    (replace TONODES of FROM with (REMOVETONODES (fetch NODEID of TO)
						 (fetch TONODES of FROM)))
    (replace FROMNODES of TO with (REMOVE (fetch NODEID of FROM)
					  (fetch FROMNODES of TO])

(GRAPHDELETENODE
  [LAMBDA (NODE GRAPH WINDOW)                                (* kvl " 5-Sep-84 19:03")
    (PROG ((DELFN (fetch (GRAPH GRAPH.DELETENODEFN) of GRAPH)))
          (AND DELFN (APPLY* DELFN NODE GRAPH WINDOW))
          (replace (GRAPH GRAPHNODES) of GRAPH with (DREMOVE NODE (fetch (GRAPH GRAPHNODES)
								     of GRAPH])

(GRAPHEDITCOMMANDFN
  [LAMBDA (GRAPHWINDOW)                                      (* kvl " 5-Sep-84 19:14")
    (SELECTQ [MENU (COND
		     ((type? MENU EDITGRAPHMENU)
		       EDITGRAPHMENU)
		     (T (SETQ EDITGRAPHMENU (create MENU
						    ITEMS ←(QUOTE (("Move Node" (QUOTE MOVENODE))
								    ("Add Node" (QUOTE ADDNODE))
								    ("Delete Node" (QUOTE DELETENODE))
								    ("Add Link" (QUOTE ADDLINK))
								    ("Delete Link" (QUOTE DELETELINK))
								    ("label smaller" (QUOTE SMALLER))
								    ("label larger" (QUOTE LARGER))
								    ("<-> Directed" (QUOTE DIRECTED))
								    ("<-> Sides" (QUOTE SIDES))
								    ("<-> Border" (QUOTE BORDER))
								    ("<-> Shade" (QUOTE SHADE))
								    STOP))
						    CENTERFLG ← T
						    CHANGEOFFSETFLG ← T]
	     (STOP (QUOTE STOP))
	     (MOVENODE (EDITMOVENODE GRAPHWINDOW))
	     (ADDNODE (EDITADDNODE GRAPHWINDOW))
	     (DELETENODE (EDITDELETENODE GRAPHWINDOW))
	     (ADDLINK (EDITADDLINK GRAPHWINDOW))
	     (SMALLER (EDITCHANGEFONT (QUOTE SMALLER)
				      GRAPHWINDOW))
	     (LARGER (EDITCHANGEFONT (QUOTE LARGER)
				     GRAPHWINDOW))
	     (DELETELINK (EDITDELETELINK GRAPHWINDOW))
	     (DIRECTED (TOGGLE/DIRECTEDFLG GRAPHWINDOW))
	     (SIDES (TOGGLE/SIDESFLG GRAPHWINDOW))
	     (BORDER (EDITTOGGLEBORDER GRAPHWINDOW))
	     (SHADE (EDITTOGGLELABEL GRAPHWINDOW))
	     NIL])

(GRAPHEDITEVENTFN
  [LAMBDA (GRWINDOW)                                         (* rmk: "16-Feb-85 10:15")
                                                             (* implements a graph editor on the right button 
							     transition of a window.)
    (COND
      ((NOT (INSIDE? (DSPCLIPPINGREGION NIL GRWINDOW)
		     (LASTMOUSEX GRWINDOW)
		     (LASTMOUSEY GRWINDOW)))
	(DOWINDOWCOM GRWINDOW))
      ((SHIFTDOWNP (QUOTE CTRL))
	(TRACKNODE GRWINDOW))
      ((EQ (GRAPHEDITCOMMANDFN GRWINDOW)
	   (QUOTE STOP))                                     (* do menu)
	(CLOSEW GRWINDOW])

(GRAPHER/CENTERPRINTINAREA
  [LAMBDA (EXP X Y WIDTH HEIGHT STREAM)                      (* kvl "15-Aug-84 11:01")
                                                             (* prints an expression in a box.
							     The system CENTERPRINTINAREA on MENU worried about 
							     overflowing the right margin, which we ignore here.)
    (SETQ STREAM (\GETSTREAM STREAM (QUOTE OUTPUT)))
    (PROG (XPOS (STRWIDTH (STRINGWIDTH EXP STREAM)))
          (MOVETO (SETQ XPOS (IPLUS X (IQUOTIENT (ADD1 (IDIFFERENCE WIDTH STRWIDTH))
						 2)))
		  (IPLUS Y (IQUOTIENT (IPLUS (IDIFFERENCE HEIGHT (FONTPROP STREAM (QUOTE ASCENT)))
					     (FONTPROP STREAM (QUOTE DESCENT)))
				      2))
		  STREAM)
          (PRIN3 EXP STREAM])

(GRAPHMOVENODE
  [LAMBDA (NODE NEWPOS GRAPH WINDOW)                         (* rmk: " 2-Feb-84 22:35")
                                                             (* moves a node but doesn't change any display.)
    (COND
      ((EQUAL (fetch NODEPOSITION of NODE)
	      NEWPOS)                                        (* don't move if position hasn't changed)
	NIL)
      (T (SET/LAYOUT/POSITION NODE NEWPOS)
	 (CALL.MOVENODEFN NODE NEWPOS GRAPH WINDOW])

(GRAPHNODE/BORDER/WIDTH
  [LAMBDA (BORDER)                                           (* kvl " 5-Sep-84 16:19")
                                                             (* returns a non-negative interger)
    (COND
      ((NULL BORDER)
	0)
      ((EQ BORDER T)
	1)
      ((FIXP BORDER)
	(ABS BORDER))
      ((AND (LISTP BORDER)
	    (FIXP (CAR BORDER))
	    (IGEQ (CAR BORDER)
		  0))
	(CAR BORDER))
      (T (ERROR "Illegal border:" BORDER])

(GRAPHREGION
  [LAMBDA (GRAPH)                                            (* kvl "10-Aug-84 20:14")
                                                             (* Returns the minimum region containing the graph.)
    (PROG (LEFTOFFSET BOTTOMOFFSET (NODELST (fetch GRAPHNODES of GRAPH)))
          (RETURN (COND
		    [NODELST                                 (* Determine the dimensions of the node labels)
			     (for N in NODELST do (MEASUREGRAPHNODE N))
			     (CREATEREGION (SETQ LEFTOFFSET (MIN/LEFT NODELST))
					   (SETQ BOTTOMOFFSET (MIN/BOTTOM NODELST))
					   (ADD1 (IDIFFERENCE (MAX/RIGHT NODELST)
							      LEFTOFFSET))
					   (ADD1 (IDIFFERENCE (MAX/TOP NODELST)
							      BOTTOMOFFSET]
		    (T (CREATEREGION 0 0 0 0])

(HARDCOPYGRAPH
  [LAMBDA (GRAPH/WINDOW FILE IMAGETYPE TRANS)                (* rmk: " 2-Mar-85 11:35")
    (PROG [(STREAM (OR (AND FILE (OPENP FILE (QUOTE OUTPUT))
			    (GETSTREAM FILE))
		       (OPENIMAGESTREAM FILE IMAGETYPE]
          (DISPLAYGRAPH (COND
			  ((WINDOWP GRAPH/WINDOW)
			    (WINDOWPROP GRAPH/WINDOW (QUOTE GRAPH)))
			  (T GRAPH/WINDOW))
			STREAM NIL TRANS)
          (RETURN (CLOSEF STREAM])

(INTERSECT/REGIONP/LBWH
  [LAMBDA (L B W H REG)                                      (* kvl "20-Aug-84 09:54")
                                                             (* like intersect regions, but without requiring the 
							     consing)
    (NOT (OR (IGREATERP (fetch BOTTOM of REG)
			(IPLUS B H))
	     (ILESSP (fetch PRIGHT of REG)
		     L)
	     (IGREATERP (fetch LEFT of REG)
			(IPLUS L W))
	     (ILESSP (fetch PTOP of REG)
		     B])

(INVERTED/GRAPHNODE/BORDER
  [LAMBDA (BORDER)                                           (* kvl " 5-Sep-84 18:49")
                                                             (* returns the right thing to invert a graphnode's 
							     border)
    (COND
      ((EQ BORDER T)
	NIL)
      ((NULL BORDER)
	T)
      ((FIXP BORDER)
	(IMINUS BORDER))
      ((AND (LISTP BORDER)
	    (FIXP (CAR BORDER)))
	(LIST (CAR BORDER)
	      (INVERTED/SHADE/FOR/GRAPHER (CADR BORDER])

(INVERTED/SHADE/FOR/GRAPHER
  [LAMBDA (SHADE)                                            (* kvl " 5-Sep-84 18:50")
                                                             (* funny name because hopefully will become system 
							     function)
    (COND
      ((EQ SHADE T)
	NIL)
      ((NULL SHADE)
	T)
      ((FIXP SHADE)
	(LOGNOT SHADE))
      ((BITMAPP SHADE)
	(PROG ((NB (COPYBITMAP SHADE)))
	      (BITBLT NIL NIL NIL NB NIL NIL NIL NIL (QUOTE TEXTURE)
		      (QUOTE INVERT)
		      BLACKSHADE)
	      (RETURN NB)))
      (T (ERROR "Illegal shade:" SHADE])

(LAYOUT/POSITION
  [LAMBDA (NODE)                                             (* rrb "13-JUL-81 10:54")
    (fetch NODEPOSITION of NODE])

(LINKPARAMETERS
  [LAMBDA (FROMND TOND)                                      (* dgb: "24-Jan-85 08:29")
    (PROG (TOPARAMS)
          (RETURN (AND (SETQ TOPARAMS (MEMBTONODES (fetch NODEID of TOND)
						   (TOLINKS FROMND)))
		       (LISTP TOPARAMS)
		       (EQ (QUOTE Link% Parameters)
			   (CAR TOPARAMS))
		       (CDDR TOPARAMS])

(MANHATTANDIST
  [LAMBDA (POS1 POS2)                                        (* rrb "13-FEB-81 16:19")
                                                             (* simple measure of closeness)
    (IPLUS (ABS (IDIFFERENCE (fetch XCOORD of POS1)
			     (fetch XCOORD of POS2)))
	   (ABS (IDIFFERENCE (fetch YCOORD of POS1)
			     (fetch YCOORD of POS2])

(MAX/RIGHT
  [LAMBDA (NODES)                                            (* rmk: "20-Dec-84 09:33")
    (for NODE in NODES largest (GN/RIGHT NODE) finally (RETURN $$EXTREME])

(MAX/TOP
  [LAMBDA (NODES)                                            (* rmk: "20-Dec-84 09:34")
    (for NODE in NODES largest (GN/TOP NODE) finally (RETURN $$EXTREME])

(MEASUREGRAPHNODE
  [LAMBDA (NODE)                                             (* rmk: " 2-Feb-84 21:19")
                                                             (* Measure the nodelabel image)
    (SET/LABEL/SIZE NODE)
    (SET/LAYOUT/POSITION NODE (OR (fetch NODEPOSITION of NODE)
				  (ERROR "This graphnode has not been given a position:" NODE])

(MEMBTONODES
  [LAMBDA (TOND TONODES)                                     (* dgb: "24-Jan-85 08:05")
    (for Z in TONODES do (COND
			   ([OR (EQ TOND Z)
				(AND (LISTP Z)
				     (EQ (CAR Z)
					 (QUOTE Link% Parameters))
				     (EQ TOND (CADR Z]
			     (RETURN Z])

(MIN/BOTTOM
  [LAMBDA (NODES)                                            (* rmk: "20-Dec-84 09:34")
                                                             (* returns the bottommost point of the graph.)
    (for NODE in NODES smallest (GN/BOTTOM NODE) finally (RETURN $$EXTREME])

(MIN/LEFT
  [LAMBDA (NODES)                                            (* rmk: "20-Dec-84 09:34")
                                                             (* returns the leftmost point of the graph.)
    (for NODE in NODES smallest (GN/LEFT NODE) finally (RETURN $$EXTREME])

(MOVENODE
  [LAMBDA (NODE OLDPOS POS GRAPH STREAM)                     (* rmk: "10-Apr-84 12:31")
                                                             (* moves a node from its current position to POS)
    (COND
      ((EQUAL OLDPOS POS)                                    (* don't move if position hasn't changed)
	NIL)
      (T                                                     (* node is flipped, flip it back.)
	 (FLIPNODE NODE STREAM)                              (* erase current position)
	 (DISPLAYNODE NODE (CONSTANT (create POSITION
					     XCOORD ← 0
					     YCOORD ← 0))
		      STREAM GRAPH)                          (* put it in new one.)
	 (SET/LAYOUT/POSITION NODE POS)
	 (DISPLAYNODE NODE (CONSTANT (create POSITION
					     XCOORD ← 0
					     YCOORD ← 0))
		      STREAM GRAPH)
	 (FLIPNODE NODE STREAM])

(NODECREATE
  [LAMBDA (ID LABEL POS TONODEIDS FROMNODEIDS FONT BORDER LABELSHADE)
                                                             (* rmk: "15-Sep-84 00:11")
                                                             (* creates a node for a grapher.)
    (create GRAPHNODE
	    NODEID ← ID
	    NODEPOSITION ← POS
	    NODELABEL ← LABEL
	    NODEFONT ←(OR FONT DEFAULT.GRAPH.NODEFONT (FONTNAMELIST DEFAULTFONT))
	    TONODES ← TONODEIDS
	    FROMNODES ← FROMNODEIDS
	    NODEBORDER ← BORDER
	    NODELABELSHADE ← LABELSHADE])

(NODELST/AS/MENU
  [LAMBDA (NODELST POS)                                      (* kvl "10-Aug-84 18:55")
                                                             (* finds the node that is closest to POS)
    (for N in NODELST
       bind (X ←(fetch XCOORD of POS))
	    (Y ←(fetch YCOORD of POS))
	    T1 T2
       thereis (AND (ILESSP [IDIFFERENCE (SETQ T1 (fetch YCOORD of (fetch NODEPOSITION of N)))
					 (SETQ T2 (HALF (fetch NODEHEIGHT of N]
			    Y)
		    (ILESSP Y (IPLUS T1 T2))
		    (ILESSP [IDIFFERENCE (SETQ T1 (fetch XCOORD of (fetch NODEPOSITION of N)))
					 (SETQ T2 (HALF (fetch NODEWIDTH of N]
			    X)
		    (ILESSP X (IPLUS T1 T2])

(NODEREGION
  [LAMBDA (NODE)                                             (* kvl "10-Aug-84 17:25")
                                                             (* returns the region taken up by NODE)
    (CREATEREGION (GN/LEFT NODE)
		  (GN/BOTTOM NODE)
		  (fetch (GRAPHNODE NODEWIDTH) of NODE)
		  (fetch (GRAPHNODE NODEHEIGHT) of NODE])

(PRINTDISPLAYNODE
  [LAMBDA (NODE TRANS STREAM CLIP/REG)                       (* rrb " 8-Jun-85 11:00")

          (* prints a node at its position translated by TRANS. Takes the operation from the stream so that when editor has 
	  set the operation to invert, this may erase as well as draw; but when the operation is paint, then nodes obliterate 
	  any link lines that they are drawn over.)


    (OR (ZEROP (fetch (GRAPHNODE NODEHEIGHT) of NODE))
	(PROG [(LEFT (IPLUS (fetch XCOORD of TRANS)
			    (GN/LEFT NODE)))
	       (BOTTOM (IPLUS (fetch YCOORD of TRANS)
			      (GN/BOTTOM NODE)))
	       (WIDTH (fetch NODEWIDTH of NODE))
	       (HEIGHT (fetch NODEHEIGHT of NODE))
	       (FONT (fetch (GRAPHNODE NODEFONT) of NODE))
	       (NBW (GRAPHNODE/BORDER/WIDTH (fetch NODEBORDER of NODE]
	      (COND
		((AND CLIP/REG (NOT (INTERSECT/REGIONP/LBWH LEFT BOTTOM WIDTH HEIGHT CLIP/REG)))
		  (RETURN NODE))
		((BITMAPP (fetch NODELABELBITMAP of NODE))
		  (BITBLT (fetch NODELABELBITMAP of NODE)
			  0 0 STREAM LEFT BOTTOM WIDTH HEIGHT (QUOTE INPUT)))
		[(BITMAPP (fetch NODELABEL of NODE))
		  (COND
		    ((NEQ 0 NBW)
		      (DRAW/GRAPHNODE/BORDER (fetch NODEBORDER of NODE)
					     LEFT BOTTOM WIDTH HEIGHT STREAM)
		      (BITBLT (fetch NODELABEL of NODE)
			      0 0 STREAM (IPLUS LEFT NBW)
			      (IPLUS BOTTOM NBW)
			      WIDTH HEIGHT (QUOTE INPUT)))
		    (T (BITBLT (fetch NODELABEL of NODE)
			       0 0 STREAM LEFT BOTTOM WIDTH HEIGHT (QUOTE INPUT]
		((IMAGEOBJP (fetch NODELABEL of NODE))
		  (COND
		    ((NEQ 0 NBW)
		      (DRAW/GRAPHNODE/BORDER (fetch NODEBORDER of NODE)
					     LEFT BOTTOM WIDTH HEIGHT STREAM)
		      (MOVETO (IPLUS NBW LEFT)
			      (IPLUS NBW BOTTOM)
			      STREAM))
		    (T (MOVETO LEFT BOTTOM STREAM)))
		  (APPLY* (IMAGEOBJPROP (fetch NODELABEL of NODE)
					(QUOTE DISPLAYFN))
			  (fetch NODELABEL of NODE)
			  STREAM))
		((NULL FONT))
		[(FONTP FONT)                                (* fontp checks gets the situation where the font is 
							     SHADE indicating that the smallest font was too large.)
		  (AND (NEQ NBW 0)
		       (DRAW/GRAPHNODE/BORDER (fetch NODEBORDER of NODE)
					      LEFT BOTTOM WIDTH HEIGHT STREAM))
		  (DSPFONT FONT STREAM)
		  (GRAPHER/CENTERPRINTINAREA (fetch NODELABEL of NODE)
					     LEFT BOTTOM WIDTH HEIGHT STREAM)
		  (AND (fetch NODELABELSHADE of NODE)
		       (FILL/GRAPHNODE/LABEL (fetch NODELABELSHADE of NODE)
					     LEFT BOTTOM WIDTH HEIGHT NBW STREAM))
		  (COND
		    ((AND CACHE/NODE/LABEL/BITMAPS CLIP/REG (INTERSECT/REGIONP/LBWH LEFT BOTTOM WIDTH 
										    HEIGHT CLIP/REG))
		      (replace NODELABELBITMAP of NODE with (BITMAPCREATE WIDTH HEIGHT))
		      (BITBLT STREAM LEFT BOTTOM (fetch NODELABELBITMAP of NODE)
			      0 0 WIDTH HEIGHT (QUOTE INPUT]
		(T                                           (* so small just use texture)
		   (BITBLT NIL NIL NIL STREAM LEFT BOTTOM 2 2 (QUOTE TEXTURE)
			   NIL BLACKSHADE)))
	      (RETURN NODE])

(FILL/GRAPHNODE/LABEL
  [LAMBDA (SHADE LEFT BOTTOM WIDTH HEIGHT NBW STREAM)        (* kvl "10-Sep-84 14:41")
                                                             (* NBW is the border, which must be subtracted from the
							     node's region)
    (PROG ((NS SHADE))
          (OR (WINDOWP STREAM)
	      (DISPLAYSTREAMP STREAM)
	      (RETURN))
          (COND
	    ((EQ SHADE T)
	      (SETQ NS BLACKSHADE))
	    ((NULL SHADE)
	      (SETQ NS WHITESHADE)))
          (BITBLT NIL NIL NIL STREAM (IPLUS LEFT NBW)
		  (IPLUS BOTTOM NBW)
		  (IDIFFERENCE WIDTH (IPLUS NBW NBW))
		  (IDIFFERENCE HEIGHT (IPLUS NBW NBW))
		  (QUOTE TEXTURE)
		  (QUOTE INVERT)
		  NS])

(FIX/SCALE
  [LAMBDA (PARAMVALUE SCALE)                                 (* dgb: "28-Jan-85 10:01")

          (* * fixes PARAMVALUE by SCALE If PARAMVALUE is a list, then fixes the elements of the list)


    (COND
      ((LISTP PARAMVALUE)
	(for V in PARAMVALUE collect (FIX/SCALE V SCALE)))
      (T                                                     (* Note that some parameters may go to zero)
	 (FIXR (FTIMES SCALE PARAMVALUE])

(PROMPTINWINDOW
  [LAMBDA (PROMPTSTR POSITION WHICHCORNER BORDERSIZE)        (* rrb "16-Jan-84 11:48")
                                                             (* opens a small window for prompting at a position and
							     PROMPTFORWORD's a word.)
                                                             (* POSITION is the location in screen coordinate of the
							     window. Default is the cursor position.)

          (* WHICHCORNER can be a list of up to two of the atoms LEFT RIGHT TOP BOTTOM which specify which corner position is 
	  intended to be. Default is lower left.)

                                                             (* BORDERSIZE is the border size of the prompt window.
							     Default is 6.0)
    (PROG ((PROMPTWBORDER (OR (NUMBERP BORDERSIZE)
			      6))
	   (X (COND
		(POSITION (fetch (POSITION XCOORD) of POSITION))
		(T LASTMOUSEX)))
	   (Y (COND
		(POSITION (fetch (POSITION YCOORD) of POSITION))
		(T LASTMOUSEY)))
	   HGHT WDTH READSTR PREVTTY)
          (SETQ HGHT (HEIGHTIFWINDOW (ITIMES (FONTPROP (DEFAULTFONT (QUOTE DISPLAY))
						       (QUOTE HEIGHT))
					     2)
				     T PROMPTWBORDER))
          (SETQ WDTH (WIDTHIFWINDOW (IMAX (STRINGWIDTH PROMPTSTR WindowTitleDisplayStream)
					  60)
				    PROMPTWBORDER))
          (SETQ PREVTTY (TTYDISPLAYSTREAM (CREATEW (CREATEREGION (COND
								   ((MEMB (QUOTE RIGHT)
									  WHICHCORNER)
								     (DIFFERENCE X WDTH))
								   (T X))
								 (COND
								   ((MEMB (QUOTE TOP)
									  WHICHCORNER)
								     (DIFFERENCE Y HGHT))
								   (T Y))
								 WDTH HGHT)
						   PROMPTSTR PROMPTWBORDER)))
          (DSPLEFTMARGIN (IMAX 0 (fetch (CURSOR CURSORHOTSPOTX) of (CARET)))
			 (TTYDISPLAYSTREAM))
          (MOVETOUPPERLEFT (TTYDISPLAYSTREAM))
          [SETQ READSTR (ERSETQ (PROMPTFORWORD NIL NIL NIL NIL NIL NIL (CONS (CHARCODE EOL]
          (CLOSEW (TTYDISPLAYSTREAM PREVTTY))
          (RETURN (COND
		    (READSTR (CAR READSTR))
		    (T                                       (* pass back the error.)
		       (ERROR!])

(READ/NODE
  [LAMBDA (NODES DS)                                         (* kvl "10-Aug-84 19:26")
    (until (MOUSESTATE (OR LEFT MIDDLE RIGHT)) do)
    (PROG (NEAR NOW OLDPOS)
          [SETQ NEAR (CLOSEST/NODE NODES (SETQ OLDPOS (CURSORPOSITION NIL DS]
      FLIP                                                   (* turn off old flip (if one) and turn on new flip.)
          (AND NOW (FLIPNODE NOW DS))
          (FLIPNODE (SETQ NOW NEAR)
		    DS)
      LP  (COND
	    ((MOUSESTATE UP)
	      (FLIPNODE NOW DS)
	      (RETURN NOW))
	    ([EQ NOW (SETQ NEAR (CLOSEST/NODE NODES (CURSORPOSITION NIL DS OLDPOS]
	      (GO LP))
	    (T (GO FLIP])

(REDISPLAYGRAPH
  [LAMBDA (WINDOW REGION)                                    (* kvl "10-Aug-84 19:52")

          (* displays the graph that is in a window. REGION if given is the clipping region. Later this could be used to make 
	  things run faster.)


    (DSPFILL NIL NIL (QUOTE REPLACE)
	     WINDOW)
    (DISPLAYGRAPH (WINDOWPROP WINDOW (QUOTE GRAPH))
		  WINDOW
		  (OR REGION (DSPCLIPPINGREGION NIL WINDOW])

(REMOVETONODES
  [LAMBDA (TOND TONODES)                                     (* rht: " 4-Apr-85 19:32")

          (* * Removes either TOND or a paramlist thingie for TOND.)


    (for Z in TONODES unless [OR (EQ Z TOND)
				 (AND (LISTP Z)
				      (EQ (CAR Z)
					  (QUOTE Link% Parameters))
				      (EQ TOND (CADR Z]
       collect Z])

(RESET/NODE/BORDER
  [LAMBDA (NODE BORDER STREAM GRAPH TRANS)                   (* rmk: "31-Dec-84 11:42")

          (* gives the node a new border, and displays it if there is a stream. Might not be a stream if being called just to 
	  finagle a graph datastructure.)


    (PROG [(ONBW (GRAPHNODE/BORDER/WIDTH (fetch NODEBORDER of NODE]
          [OR TRANS (SETQ TRANS (CONSTANT (create POSITION
						  XCOORD ← 0
						  YCOORD ← 0]
          (COND
	    (STREAM (ERASE/GRAPHNODE NODE STREAM TRANS)
		    [OR GRAPH (AND (WINDOWP STREAM)
				   (SETQ GRAPH (WINDOWPROP STREAM (QUOTE GRAPH]
		    (DISPLAYNODELINKS NODE TRANS STREAM GRAPH)))
          (replace NODEBORDER of NODE with (COND
					     ((EQ BORDER (QUOTE INVERT))
					       (INVERTED/GRAPHNODE/BORDER (fetch NODEBORDER
									     of NODE)))
					     (T BORDER)))
          (OR (IEQP ONBW (GRAPHNODE/BORDER/WIDTH (fetch NODEBORDER of NODE)))
	      (SET/LABEL/SIZE NODE T))
          (AND STREAM (DISPLAYNODE NODE TRANS STREAM GRAPH))
          (RETURN NODE])

(RESET/NODE/LABELSHADE
  [LAMBDA (NODE SHADE STREAM TRANS)                          (* kvl " 5-Sep-84 19:23")
                                                             (* gives the node a new SHADE and displays it if there 
							     is a stream)
    (AND STREAM (ERASE/GRAPHNODE NODE STREAM TRANS))
    (replace NODELABELSHADE of NODE with (COND
					   ((EQ SHADE (QUOTE INVERT))
					     (INVERTED/SHADE/FOR/GRAPHER (fetch NODELABELSHADE
									    of NODE)))
					   (T SHADE)))
    (AND STREAM (PRINTDISPLAYNODE NODE (OR TRANS (CONSTANT (create POSITION
								   XCOORD ← 0
								   YCOORD ← 0)))
				  STREAM))
    NODE])

(SCALE/GRAPH
  [LAMBDA (GRAPH STREAM SCALE)                               (* lmm " 9-Jun-85 21:50")
    (create GRAPH using GRAPH GRAPHNODES ←(for N in (fetch GRAPHNODES of GRAPH)
					     collect
					      (SETQ N
						(create GRAPHNODE
						   using N NODEPOSITION ←[create
							   POSITION
							   XCOORD ←[FIXR (FTIMES SCALE
										 (fetch XCOORD
										    of (fetch 
										     NODEPOSITION
											  of N]
							   YCOORD ←(FIXR (FTIMES SCALE
										 (fetch YCOORD
										    of (fetch 
										     NODEPOSITION
											  of N]
							 NODELABELBITMAP ← NIL NODEWIDTH ← NIL 
							 NODEHEIGHT ← NIL NODEFONT ←(FONTCREATE
							   (fetch NODEFONT N)
							   NIL NIL NIL STREAM)
							 TONODES ←(SCALE/TONODES N SCALE)
							 NODEBORDER ←(SCALE/GRAPHNODE/BORDER
							   (fetch NODEBORDER of N)
							   SCALE)))
					      (SET/LABEL/SIZE N NIL STREAM)
					      N])

(SCALE/GRAPHNODE/BORDER
  [LAMBDA (BORDER SCALE)                                     (* kvl " 5-Sep-84 18:06")
                                                             (* returns a new setting for the border appropriate for
							     the given SCALE)
    (COND
      ((NULL BORDER)
	0)
      ((EQ BORDER T)
	(FIXR (FTIMES SCALE NODEBORDERWIDTH)))
      ((FIXP BORDER)
	(FIXR (FTIMES SCALE BORDER)))
      ((AND (LISTP BORDER)
	    (FIXP (CAR BORDER)))
	(CONS (FIXR (FTIMES SCALE (CAR BORDER)))
	      (CDR BORDER])

(SCALE/TONODES
  [LAMBDA (NODE SCALE)                                       (* lmm " 9-Jun-85 21:47")
    (for NODEID in (fetch TONODES of NODE) collect (COND
						     [(AND (LISTP NODEID)
							   (EQ (QUOTE Link% Parameters)
							       (CAR NODEID))
							   (for prop val in ScalableLinkParameters
							      do (AND (SETQ val (LISTGET NODEID prop))
								      (LISTPUT NODEID prop
									       (FIX/SCALE val SCALE]
						     (T NODEID])

(SET/LABEL/SIZE
  [LAMBDA (NODE RESET/FLG STREAM)                            (* lmm " 9-Jun-85 21:50")
                                                             (* the SHADE and null font stuff is for ZOOMGRAPH)
    (OR (AND (NOT RESET/FLG)
	     (FIXP (fetch NODEHEIGHT of NODE))
	     (FIXP (fetch NODEWIDTH of NODE)))
	(PROG ((FONT (fetch (GRAPHNODE NODEFONT) of NODE))
	       (LAB (fetch (GRAPHNODE NODELABEL) of NODE))
	       (NBW (GRAPHNODE/BORDER/WIDTH (fetch NODEBORDER of NODE)))
	       WIDTH HEIGHT)
	      [COND
		((BITMAPP LAB)
		  (SETQ WIDTH (BITMAPWIDTH LAB))
		  (SETQ HEIGHT (BITMAPHEIGHT LAB)))
		((EQ FONT (QUOTE SHADE))                     (* node image is very small)
		  (SETQ WIDTH (SETQ HEIGHT 2)))
		((IMAGEOBJP LAB)
		  (SETQ WIDTH (APPLY* (IMAGEOBJPROP LAB (QUOTE IMAGEBOXFN))
				      LAB STREAM))
		  (SETQ HEIGHT (fetch (IMAGEBOX YSIZE) of WIDTH))
		  (SETQ WIDTH (fetch (IMAGEBOX XSIZE) of WIDTH)))
		[(NULL FONT)                                 (* FONT of NIL means that the node is smaller than 
							     displays)
		  (SETQ NBW (SETQ WIDTH (SETQ HEIGHT 0]
		(T (OR (FONTP FONT)
		       (SETQ FONT (FONTCREATE FONT NIL NIL NIL STREAM)))
		   [SETQ WIDTH (IPLUS (STRINGWIDTH (fetch NODELABEL of NODE)
						   FONT)
				      (FONTPROP FONT (QUOTE DESCENT]
		   (SETQ HEIGHT (IPLUS (FONTPROP FONT (QUOTE HEIGHT))
				       (FONTPROP FONT (QUOTE DESCENT]
	      (OR (AND (NOT RESET/FLG)
		       (FIXP (fetch NODEWIDTH of NODE)))
		  (replace NODEWIDTH of NODE with (IPLUS WIDTH NBW NBW)))
	      (OR (AND (NOT RESET/FLG)
		       (FIXP (fetch NODEHEIGHT of NODE)))
		  (replace NODEHEIGHT of NODE with (IPLUS HEIGHT NBW NBW)))
	      (RETURN NODE])

(SET/LAYOUT/POSITION
  [LAMBDA (NODE POS)                                         (* kvl "10-Aug-84 17:32")
                                                             (* sets a nodes position)
    (replace XCOORD of (fetch NODEPOSITION of NODE) with (fetch XCOORD of POS))
    (replace YCOORD of (fetch NODEPOSITION of NODE) with (fetch YCOORD of POS))
    NODE])

(SHOWGRAPH
  [LAMBDA (GRAPH WINDOW LEFTBUTTONFN MIDDLEBUTTONFN TOPJUSTIFYFLG ALLOWEDITFLG COPYBUTTONEVENTFN)
                                                             (* rmk: "15-Feb-85 14:47")
                                                             (* Harmony version, since expects shift-select to 
							     unambiguously mean copy, not move.
							     Goes along with redefinition of SHIFTP)
                                                             (* puts a graph in the given window, creating one if a 
							     window is not given.)
    (SETQ WINDOW (SIZE/GRAPH/WINDOW (COND
				      ((NULL GRAPH)
					(SETQ GRAPH (create GRAPH)))
				      (T GRAPH))
				    (COND
				      (WINDOW)
				      (ALLOWEDITFLG          (* put on a blank title so there will be a place to get
							     window commands.)
						    ""))
				    TOPJUSTIFYFLG))
    (WINDOWPROP WINDOW (QUOTE GRAPH)
		GRAPH)
    (WINDOWPROP WINDOW (QUOTE REPAINTFN)
		(FUNCTION REDISPLAYGRAPH))
    (WINDOWPROP WINDOW (QUOTE SCROLLFN)
		(FUNCTION SCROLLBYREPAINTFN))
    (WINDOWPROP WINDOW (QUOTE HARDCOPYFN)
		(FUNCTION HARDCOPYGRAPH))
    (COND
      (ALLOWEDITFLG                                          (* change the mode to invert so lines can be erased by 
							     being redrawn.)
		    (DSPOPERATION (QUOTE INVERT)
				  WINDOW)
		    (WINDOWPROP WINDOW (QUOTE RIGHTBUTTONFN)
				(FUNCTION GRAPHEDITEVENTFN)))
      (T (WINDOWPROP WINDOW (QUOTE RIGHTBUTTONFN)
		     NIL)))
    (WINDOWPROP WINDOW (QUOTE COPYBUTTONEVENTFN)
		(OR COPYBUTTONEVENTFN (FUNCTION GRAPHERCOPYBUTTONEVENTFN)))
    (WINDOWPROP WINDOW (QUOTE BUTTONEVENTFN)
		(FUNCTION APPLYTOSELECTEDNODE))
    (WINDOWPROP WINDOW (QUOTE BROWSER/LEFTFN)
		LEFTBUTTONFN)
    (WINDOWPROP WINDOW (QUOTE BROWSER/MIDDLEFN)
		MIDDLEBUTTONFN)
    (REDISPLAYGRAPH WINDOW)
    WINDOW])

(SIZE/GRAPH/WINDOW
  [LAMBDA (GRAPH WINDOW/TITLE TOPJUSTIFYFLG)                 (* kvl "10-Aug-84 20:18")

          (* returns a window sized to fit the given graph. WINDOW/TITLE can be either a window to be printed in or a title of
	  a window to be created. If TOPJUSTIFYFLG is true, scrolls so top of graph is at top of window, else puts bottom of 
	  graph at bottom of window.)


    (PROG ((GRAPHREG (GRAPHREGION GRAPH))
	   TITLE WINDOW)
          (COND
	    ((WINDOWP WINDOW/TITLE)
	      (SETQ WINDOW WINDOW/TITLE))
	    (T (SETQ TITLE WINDOW/TITLE)))                   (* if there is not already a window, ask the user for 
							     one to fit.)
          (COND
	    ((NULL WINDOW)
	      (SETQ WINDOW (CREATEW (GETBOXREGION (WIDTHIFWINDOW (IMIN (IMAX (fetch (REGION WIDTH)
										of GRAPHREG)
									     100)
								       500))
						  (HEIGHTIFWINDOW (IMIN (IMAX (fetch (REGION HEIGHT)
										 of GRAPHREG)
									      60)
									(IQUOTIENT SCREENHEIGHT 2))
								  TITLE))
				    TITLE)))
	    (T (CLEARW WINDOW)))
          (WINDOWPROP WINDOW (QUOTE EXTENT)
		      GRAPHREG)
          (WXOFFSET (IDIFFERENCE (WXOFFSET NIL WINDOW)
				 (fetch (REGION LEFT) of GRAPHREG))
		    WINDOW)
          (WYOFFSET [IDIFFERENCE (WYOFFSET NIL WINDOW)
				 (COND
				   [TOPJUSTIFYFLG (IDIFFERENCE (fetch (REGION PTOP) of GRAPHREG)
							       (WINDOWPROP WINDOW (QUOTE HEIGHT]
				   (T (fetch (REGION BOTTOM) of GRAPHREG]
		    WINDOW)
          (RETURN WINDOW])

(TOGGLE/DIRECTEDFLG
  [LAMBDA (WIN)                                              (* kvl "20-APR-82 13:38")
                                                             (* flips the value of the flag that indicates whether 
							     the graph is a lattice.)
    [replace (GRAPH DIRECTEDFLG) of (WINDOWPROP WIN (QUOTE GRAPH))
       with (NOT (fetch (GRAPH DIRECTEDFLG) of (WINDOWPROP WIN (QUOTE GRAPH]
    (DSPFILL NIL (DSPTEXTURE NIL WIN)
	     (QUOTE REPLACE)
	     WIN)
    (REDISPLAYGRAPH WIN])

(TOGGLE/SIDESFLG
  [LAMBDA (WIN)                                              (* kvl "20-APR-82 13:15")
                                                             (* flips the value of the flag that indicates whether 
							     the graph is to be layed out vertically or 
							     horizontally.)
    [replace (GRAPH SIDESFLG) of (WINDOWPROP WIN (QUOTE GRAPH))
       with (NOT (fetch (GRAPH SIDESFLG) of (WINDOWPROP WIN (QUOTE GRAPH]
    (DSPFILL NIL (DSPTEXTURE NIL WIN)
	     (QUOTE REPLACE)
	     WIN)
    (REDISPLAYGRAPH WIN])

(TOLINKS
  [LAMBDA (NODE)                                             (* rrb "13-JUL-81 10:55")
    (fetch TONODES of NODE])

(TRACKCURSOR
  [LAMBDA (ND DS GRAPH)                                      (* rmk: " 2-Feb-84 22:36")
                                                             (* causes ND to follow cursor.)
    (PROG (OLDPOS ORIGPOS DOWNFLG)                           (* maybe there aren't any nodes)
          (OR ND (RETURN))
          (SETQ ORIGPOS (COPYALL (fetch NODEPOSITION of ND)))
          (SETQ OLDPOS (CURSORPOSITION (fetch NODEPOSITION of ND)
				       DS))
          (FLIPNODE ND DS)
          (until (COND
		   (DOWNFLG (MOUSESTATE UP))
		   ((SETQ DOWNFLG (MOUSESTATE (NOT UP)))
		     NIL))
	     do (MOVENODE ND (fetch NODEPOSITION of ND)
			  (CURSORPOSITION NIL DS OLDPOS)
			  GRAPH DS))
          (FLIPNODE ND DS)
          (COND
	    ([NOT (EQUAL ORIGPOS (SETQ OLDPOS (fetch NODEPOSITION of ND]
	      (EXTENDEXTENT (WFROMDS DS)
			    (NODEREGION ND))
	      (CALL.MOVENODEFN ND OLDPOS GRAPH (WFROMDS DS])

(TRACKNODE
  [LAMBDA (W)                                                (* kvl "20-APR-82 13:43")
                                                             (* grabs the nearest nodes and hauls it around with the
							     cursor, leaving it where it is when the button goes 
							     up.)
    (TRACKCURSOR (CLOSEST/NODE (fetch (GRAPH GRAPHNODES) of (WINDOWPROP W (QUOTE GRAPH)))
			       (CURSORPOSITION NIL W))
		 (WINDOWPROP W (QUOTE DSP))
		 (WINDOWPROP W (QUOTE GRAPH])
)



(* functions for finding larger and smaller fonts)

(DEFINEQ

(NEXTSIZEFONT
  [LAMBDA (WHICHDIR NOWFONT)                                 (* rmk: "15-Sep-84 00:14")
                                                             (* returns the next sized font either SMALLER or LARGER
							     that on of size FONT. (NEXTSIZEFONT 
							     (QUOTE LARGER) DEFAULTFONT))
    (PROG [(NOWSIZE (FONTPROP NOWFONT (QUOTE HEIGHT]
          (RETURN (COND
		    [(EQ WHICHDIR (QUOTE LARGER))
		      (COND
			((IGEQ NOWSIZE (FONTPROP (CAR DECREASING.FONT.LIST)
						 (QUOTE HEIGHT)))
                                                             (* nothing larger)
			  NIL)
			(T (for FONTTAIL on DECREASING.FONT.LIST
			      when [AND (CDR FONTTAIL)
					(IGEQ NOWSIZE (FONTPROP (CADR FONTTAIL)
								(QUOTE HEIGHT]
			      do (RETURN (FONTNAMELIST (CAR FONTTAIL]
		    (T (for FONT in DECREASING.FONT.LIST when (LESSP (FONTPROP FONT (QUOTE HEIGHT))
								     NOWSIZE)
			  do (RETURN (FONTNAMELIST FONT])

(DECREASING.FONT.LIST
  [LAMBDA NIL                                                (* rrb "16-Dec-83 12:28")
                                                             (* returns a list of the font descriptors for the fonts
							     sketch windows are willing to print in.)
    (for SIZE in (QUOTE (18 14 12 10 8 5)) collect (FONTCREATE (QUOTE HELVETICA)
							       SIZE])

(SCALE.FONT
  [LAMBDA (WID STR)                                          (* rrb " 7-NOV-83 11:35")
                                                             (* returns the font that text should be printed in to 
							     have the text STR fit into a region WID points wide)
    (COND
      ((GREATERP WID (TIMES (STRINGWIDTH STR (CAR DECREASING.FONT.LIST))
			    1.5))                            (* scale it too large for even the largest font.)
	NIL)
      (T (for FONT in DECREASING.FONT.LIST when (NOT (GREATERP (STRINGWIDTH STR FONT)
							       WID))
	    do (RETURN FONT) finally (RETURN (QUOTE SHADE])
)
(DECLARE: DONTEVAL@LOAD DOCOPY 

(RPAQ DECREASING.FONT.LIST (DECREASING.FONT.LIST))
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS DECREASING.FONT.LIST)
)



(* functions for LAYOUTGRAPH And LAYOUTLATTICE)

(DEFINEQ

(BRH/LAYOUT
  [LAMBDA (N X Y MOMLST GN)                                  (* kvl "26-DEC-83 16:44")

          (* X and Y are the lower left corner of the box that will surround the tree headed by the browsenode N.
	  MOMLST is the mother node inside a cons cell. GN is the graphnode for the nodeid N. It is crucial that the 
	  NODEPOSITION be set before recursion because this marks that the node has been (is being) laid out already.
	  BRH/OFFSET is used to raise the daughters in those rare cases where the label is bigger than the daughters.)


    (DECLARE (USEDFREE MOTHERD PERSONALD NODELST))
    (PROG ((DS (fetch (GRAPHNODE TONODES) of GN))
	   (W (fetch (GRAPHNODE NODEWIDTH) of GN))
	   (YHEIGHT (IPLUS PERSONALD (fetch (GRAPHNODE NODEHEIGHT) of GN)))
	   DHEIGHT)
          (replace (GRAPHNODE FROMNODES) of GN with MOMLST)
          [replace (GRAPHNODE NODEPOSITION) of GN with (create POSITION
							       XCOORD ←(IPLUS X (HALF W]
          (COND
	    ((NULL DS))
	    [[IGREATERP YHEIGHT (SETQ DHEIGHT (BRH/LAYOUT/DAUGHTERS DS (IPLUS X W MOTHERD)
								    Y
								    (LIST N]
	      (BRH/OFFSET DS (HALF (IDIFFERENCE YHEIGHT DHEIGHT]
	    (T (SETQ YHEIGHT DHEIGHT)))
          (replace YCOORD of (fetch (GRAPHNODE NODEPOSITION) of GN) with (IPLUS Y (HALF YHEIGHT)))
          (RETURN YHEIGHT])

(BRH/LAYOUT/DAUGHTERS
  [LAMBDA (DS X Y MOMLST)                                    (* rmk: " 5-Feb-84 15:01")

          (* DS are the daughters of (CAR MOMLST). X is where the left edge of their labels will be, and Y is the bottom of 
	  the mother's box. Returns the height of the mother's box. Tests to see if a node has been layout out already If so, 
	  it replaces the daughter with one that has no descendents, and splices into the mother's daughter list, 
	  side-effecting the graphnode structure.)


    (DECLARE (USEDFREE NODELST))
    (for D (FLOOR ← Y) in DS do [SETQ FLOOR (IPLUS FLOOR (BRH/LAYOUT D X FLOOR MOMLST
								     (GETNODEFROMID D NODELST]
       finally (RETURN (IDIFFERENCE FLOOR Y])

(BRH/OFFSET
  [LAMBDA (NODEIDS YINC)
    (DECLARE (USEDFREE NODELST))                             (* kvl "11-Dec-84 14:35")
    (for N in NODEIDS
       do (SETQ N (GETNODEFROMID N NODELST))
	  (add (fetch YCOORD of (fetch (GRAPHNODE NODEPOSITION) of N))
	       YINC)
	  (BRH/OFFSET (fetch (GRAPHNODE TONODES) of N)
		      YINC])

(BRHC/INTERTREE/SPACE
  [LAMBDA (TTC BTC)                                          (* kvl "21-DEC-83 10:23")

          (* Given the top transition chain of the old daughter and the bottom transition chain of the new daughter, where BTC
	  is sitting on the bottom of the box, calculate how much the bottom must be raised so that it just clears the TTC.
	  OP is the top left corner of some label. NP is the bottom left corner.)


    (PROG ((RAISE -1000)
	   NP DIST OP)
          (SETQ OP (pop TTC))
          (SETQ NP (pop BTC))
      L   (SETQ DIST (IDIFFERENCE (fetch YCOORD of OP)
				  (fetch YCOORD of NP)))
          (AND (IGREATERP DIST RAISE)
	       (SETQ RAISE DIST))
          [COND
	    ((NULL BTC)
	      (RETURN RAISE))
	    ((NULL TTC)
	      (RETURN RAISE))
	    ((IEQP (fetch XCOORD of (CAR BTC))
		   (fetch XCOORD of (CAR TTC)))
	      (SETQ NP (pop BTC))
	      (SETQ OP (pop TTC)))
	    ((ILESSP (fetch XCOORD of (CAR BTC))
		     (fetch XCOORD of (CAR TTC)))
	      (SETQ NP (pop BTC)))
	    (T (SETQ OP (pop TTC]
          (GO L])

(BRHC/LAYOUT
  [LAMBDA (N X MOMLST GN)                                    (* rmk: " 5-Feb-84 14:47")

          (* See comment on BRH/LAYOUT. Instead of keeping only the graphnode in layed out node's position field, keep the 
	  offset as well. The offset is how much this nodes box must be raised relative to the inclosing box.
	  Uses two free variables to return transition chains. RETURNTTC is the top left corners of all the labels.
	  RETURNBTC is the bottom left corners.)


    (DECLARE (USEDFREE PERSONALD RETURNTTC RETURNBTC))
    (PROG ((DS (fetch (GRAPHNODE TONODES) of GN))
	   (W (fetch (GRAPHNODE NODEWIDTH) of GN))
	   (H (fetch (GRAPHNODE NODEHEIGHT) of GN))
	   YCENTER X/SW H/2)
          (SETQ H/2 (HALF H))
          (SETQ X/SW (IPLUS X W))
          (replace (GRAPHNODE FROMNODES) of GN with MOMLST)
          (replace (GRAPHNODE NODEPOSITION) of GN with (LIST 0))
          [SETQ YCENTER (COND
	      (DS (BRHC/LAYOUT/DAUGHTERS DS X/SW (LIST N)))
	      (T (BRHC/LAYOUT/TERMINAL GN X/SW]
          (RPLACD (fetch (GRAPHNODE NODEPOSITION) of GN)
		  (create POSITION
			  XCOORD ←(IPLUS X (HALF W))
			  YCOORD ← YCENTER))
          [push RETURNTTC (create POSITION
				  XCOORD ← X
				  YCOORD ←(IPLUS PERSONALD (IPLUS (IDIFFERENCE YCENTER H/2)
								  H]
          (push RETURNBTC (create POSITION
				  XCOORD ← X
				  YCOORD ←(IDIFFERENCE YCENTER H/2)))
          (RETURN YCENTER])

(BRHC/LAYOUT/DAUGHTERS
  [LAMBDA (DS X/SW MOMLST)
    (DECLARE (USEDFREE MOTHERD FAMILYD NODELST RETURNTTC RETURNBTC))
                                                             (* rmk: " 5-Feb-84 14:52")

          (* see comment on BRH/LAYOUT/DAUGHTERS. First daughter is always laid out on the bottom of the box.
	  Subsequent daughters have the amount that they are to be raised calculated by comparing the top edge of the old 
	  daughter (in TTC) with the bottom edge of the new daughter (in RETURNBTC). TTC is update by adding the new 
	  daughter's transition chain to the front, because the new daughter's front is guaranteed to be higher than the old 
	  daughter's front. Conversely, BTC is updated by adding the new daughter's transition chain to the back, because the 
	  old daughter's front is guaranteed to be lower.)


    (for D in DS bind GN BTC TTC 1ST/DCENTER LST/DCENTER (OFFSET ← 0)
		      (X ←(IPLUS X/SW MOTHERD))
       do (SETQ GN (GETNODEFROMID D NODELST))
	  (SETQ LST/DCENTER (BRHC/LAYOUT D X MOMLST GN))
	  [COND
	    ((NULL TTC)                                      (* first daughter)
	      (SETQ 1ST/DCENTER LST/DCENTER)
	      (SETQ TTC RETURNTTC)
	      (SETQ BTC RETURNBTC))
	    (T (SETQ OFFSET (BRHC/INTERTREE/SPACE TTC RETURNBTC))
	       (RPLACA (fetch (GRAPHNODE NODEPOSITION) of GN)
		       OFFSET)
	       (SETQ TTC (EXTEND/TRANSITION/CHAIN (RAISE/TRANSITION/CHAIN RETURNTTC OFFSET)
						  TTC))
	       (SETQ BTC (EXTEND/TRANSITION/CHAIN BTC (RAISE/TRANSITION/CHAIN RETURNBTC OFFSET]
       finally 

          (* add a mythical top left corner at the height of the highest daughter because diagnonal links are getting 
	  clobbered. Move lowest daughter's bottom left corner to the left for the same reason.)


	       (SETQ RETURNTTC (CONS (create POSITION
					     XCOORD ← X/SW
					     YCOORD ←(fetch YCOORD of (CAR TTC)))
				     TTC))
	       (replace XCOORD of (CAR BTC) with X/SW)
	       (add (fetch YCOORD of (CAR TTC))
		    FAMILYD)
	       (SETQ RETURNBTC BTC) 

          (* center of mother is halfway between first and last daughter's label centers using fact that offset of first 
	  daughter is zero and last daughter's offset is OFFSET)


	       (RETURN (HALF (IPLUS 1ST/DCENTER OFFSET LST/DCENTER])

(BRHC/LAYOUT/TERMINAL
  [LAMBDA (GN X/SW)                                          (* rmk: " 3-Feb-84 09:55")
                                                             (* initiallizes the transition chains to the right edge
							     of the node label, and returns the label's center.)
    (DECLARE (USEDFREE RETURNTTC RETURN/TBC))
    (SETQ RETURNTTC (LIST (create POSITION
				  XCOORD ← X/SW
				  YCOORD ← 0)))
    [SETQ RETURNBTC (LIST (create POSITION
				  XCOORD ← X/SW
				  YCOORD ←(fetch (GRAPHNODE NODEHEIGHT) of GN]
    (HALF (fetch (GRAPHNODE NODEHEIGHT) of GN])

(BRHC/OFFSET
  [LAMBDA (N ABSY)                                           (* dgb: "22-Jan-85 07:17")
                                                             (* Adds in all the offsets. See comment on 
							     BRHC/LAYOUT/DAUGHTERS.)
    (DECLARE (USEDFREE NODELST))
    (PROG ((GN (GETNODEFROMID N NODELST)))
          [SETQ ABSY (IPLUS ABSY (pop (fetch (GRAPHNODE NODEPOSITION) of GN]
          [replace YCOORD of (fetch (GRAPHNODE NODEPOSITION) of GN)
	     with (IPLUS ABSY (fetch YCOORD of (fetch (GRAPHNODE NODEPOSITION) of GN]
          (for D in (fetch (GRAPHNODE TONODES) of GN) do (BRHC/OFFSET D ABSY])

(BRHL/LAYOUT
  [LAMBDA (N X Y MOMLST GN)                                  (* kvl "26-DEC-83 16:36")

          (* X and Y are the lower left corner of the box that will surround the tree headed by the browsenode N.
	  MOMLST is the mother node inside a cons cell. GN is the graphnode for the nodeid N. It is crucial that the 
	  NODEPOSITION be set before recursion because this marks that the node has been laid out already.
	  If in addition, the YCOORD is NIL, then the node is still in the process of being laid out. BRHL/LAYOUT/DAUGHTERS 
	  uses this fact to break loops by inserting boxed nodes.)


    (DECLARE (USEDFREE MOTHERD PERSONALD NODELST))
    (COND
      ((fetch (GRAPHNODE NODEPOSITION) of GN)

          (* This case only occurs if this node has been put in the roots list, and has already been visited by recursion.
	  Value won't be used)


	0)
      (T (PROG [(DS (fetch (GRAPHNODE TONODES) of GN))
		(W (fetch (GRAPHNODE NODEWIDTH) of GN))
		(YHEIGHT (IPLUS PERSONALD (fetch (GRAPHNODE NODEHEIGHT) of GN]
	       (replace (GRAPHNODE FROMNODES) of GN with MOMLST)
                                                             (* This is first time for layout, so set FROMNODES)
	       [replace (GRAPHNODE NODEPOSITION) of GN with (create POSITION
								    XCOORD ←(IPLUS X (HALF W]
	       (AND DS (SETQ YHEIGHT (IMAX (BRHL/LAYOUT/DAUGHTERS DS (IPLUS X W MOTHERD)
								  Y
								  (LIST N))
					   YHEIGHT)))
	       (replace YCOORD of (fetch (GRAPHNODE NODEPOSITION) of GN) with (IPLUS Y (HALF YHEIGHT))
			)
	       (RETURN YHEIGHT])

(BRHL/LAYOUT/DAUGHTERS
  [LAMBDA (DS X Y MOMLST)                                    (* kvl "26-DEC-83 16:14")

          (* DS are the daughters of (CAR MOMLST). X is where their the left edge of their labels will be, and Y is the bottom
	  of the mother's box. Returns the height of the mother's box. Tests to see if a node has been laid out out already If
	  so, it sees if the node is far enought to the right; if not it moves the node and its daughters.)


    (DECLARE (USEDFREE NODELST YHEIGHT))
    (for DTAIL on DS bind D GN NP DELTA (FLOOR ← Y) finally (RETURN (IDIFFERENCE FLOOR Y))
       do (SETQ GN (GETNODEFROMID (SETQ D (CAR DTAIL))
				  NODELST))
	  (COND
	    ((SETQ NP (fetch (GRAPHNODE NODEPOSITION) of GN))
	      [COND
		[(NULL (fetch YCOORD of NP))
		  (SETQ GN (NEW/INSTANCE/OF/GRAPHNODE GN))
		  (RPLACA DTAIL (fetch NODEID of GN))
		  (SETQ FLOOR (IPLUS FLOOR (BRHL/LAYOUT (fetch NODEID of GN)
							X FLOOR MOMLST GN]
		(T (BRHL/MOVE/RIGHT GN X NIL)
		   (push (fetch (GRAPHNODE FROMNODES) of GN)
			 (CAR MOMLST]                        (* Add this mother to the fromLinks)
	      )
	    (T (SETQ FLOOR (IPLUS FLOOR (BRHL/LAYOUT D X FLOOR MOMLST GN])

(BRHL/MOVE/RIGHT
  [LAMBDA (GN X STACK)                                       (* kvl "26-DEC-83 16:25")
                                                             (* Move this node and its children right)
    (DECLARE (USEDFREE NODELST))
    (PROG ((W (fetch (GRAPHNODE NODEWIDTH) of GN))
	   (NP (fetch NODEPOSITION of GN)))
          (AND (FMEMB GN STACK)
	       (ERROR "Loop caught in BRHL/MOVE/RIGHT at" (fetch NODELABEL of GN)))
          (COND
	    ((ILESSP X (IDIFFERENCE (fetch XCOORD of NP)
				    (HALF W)))
	      (RETURN)))
          (for D in (TOLINKS GN)
	     bind (NEWX ←(IPLUS X W MOTHERD))
		  (NSTACK ←(CONS GN STACK))
	     do (BRHL/MOVE/RIGHT (GETNODEFROMID D NODELST)
				 NEWX NSTACK))
          (replace XCOORD of NP with (IPLUS X (HALF W])

(BROWSE/LAYOUT/HORIZ
  [LAMBDA (ROOTIDS)                                          (* kvl "10-Aug-84 19:56")

          (* each subtree is given a box centered vertically on its label. Sister boxes abut but do not intrude as they do in 
	  the compacting version.)


    (DECLARE (USEDFREE NODELST))
    [for N in ROOTIDS bind (Y ← 0) do (SETQ Y (IPLUS Y (BRH/LAYOUT N 0 Y NIL (GETNODEFROMID N NODELST]
    (create GRAPH
	    GRAPHNODES ← NODELST
	    SIDESFLG ← T
	    DIRECTEDFLG ← NIL])

(BROWSE/LAYOUT/HORIZ/COMPACTLY
  [LAMBDA (ROOTS)
    (DECLARE (USEDFREE NODELST MOTHERD))                     (* kvl "10-Aug-84 19:56")

          (* See comments on BRH/LAYOUT and BRH/LAYOUT/DAUGHTERS first. This differs in that it keeps 
	  (on the stack) a representation of the shape of the tree that fills the node's box. The representation is a list of 
	  POSITIONs. If one starts drawing a line from left to right starting at the CAR, each point is a step in the line, 
	  and the point begins the new plateau (or valley). The last point is where the line would turn around and head back 
	  to the left.)

                                                             (* builds dummy top node for ROOTS if necessary, and 
							     adjusts the horizontal distance accordingly.)
    [PROG (RETURNTTC RETURNBTC)
          (DECLARE (SPECVARS RETURNTTC RETURNBTC))
          (COND
	    ((NLISTP ROOTS)
	      (BRHC/LAYOUT ROOTS 0 NIL (GETNODEFROMID ROOTS NODELST))
	      (BRHC/OFFSET ROOTS 0))
	    ((NULL (CDR ROOTS))
	      (BRHC/LAYOUT (CAR ROOTS)
			   0 NIL (GETNODEFROMID (CAR ROOTS)
						NODELST))
	      (BRHC/OFFSET (CAR ROOTS)
			   0))
	    (T (PROG ((GN (create GRAPHNODE
				  NODELABEL ←(PACK)
				  NODEID ←(CONS)
				  TONODES ← ROOTS
				  NODEWIDTH ← 0
				  NODEHEIGHT ← 0))
		      TOPNODE)
		     (push NODELST GN)
		     (SETQ TOPNODE (fetch (GRAPHNODE NODEID) of GN))
		     (BRHC/LAYOUT TOPNODE (IMINUS MOTHERD)
				  NIL GN)
		     (BRHC/OFFSET TOPNODE 0)
		     [for N GN in ROOTS do (replace (GRAPHNODE FROMNODES) of (SETQ GN
									       (FASSOC N NODELST))
					      with (DREMOVE TOPNODE (fetch (GRAPHNODE FROMNODES)
								       of GN]
		     (SETQ NODELST (DREMOVE GN NODELST]
    (create GRAPH
	    GRAPHNODES ← NODELST
	    SIDESFLG ← T
	    DIRECTEDFLG ← NIL])

(BROWSE/LAYOUT/LATTICE
  [LAMBDA (NS)                                               (* kvl "10-Aug-84 19:56")

          (* almost the same as BROWSE/LAYOUT/HORIZ, except that it doesn't box nodes unless there are cycles.
	  Instead, a single node is placed at the rightmost of the positions that would be laid out by for all of its 
	  (boxed) occurrences by BROWSE/LAYOUT/HORIZ.)


    (DECLARE (USEDFREE NODELST))
    [for N in NS bind (Y ← 0) do (SETQ Y (IPLUS Y (BRHL/LAYOUT N 0 Y NIL (GETNODEFROMID N NODELST]
    (create GRAPH
	    GRAPHNODES ← NODELST
	    SIDESFLG ← T
	    DIRECTEDFLG ← NIL])

(BRV/OFFSET
  [LAMBDA (N ABSX)                                           (* dgb: "22-Jan-85 07:25")

          (* Adds in offset which are kept in car of NODEPOSITION. TERMY is Y of lowest node. Adding it in raises tree so 
	  lowest node is at zero.)


    (DECLARE (USEDFREE NODELST TERMY))
    (PROG (P (GN (GETNODEFROMID N NODELST)))
          [SETQ ABSX (IPLUS ABSX (pop (fetch (GRAPHNODE NODEPOSITION) of GN]
          (replace XCOORD of (SETQ P (fetch (GRAPHNODE NODEPOSITION) of GN))
	     with (IPLUS ABSX (fetch XCOORD of P)))
          (replace YCOORD of P with (IDIFFERENCE (fetch YCOORD of P)
						 TERMY))
          (for D in (fetch (GRAPHNODE TONODES) of GN) do (BRV/OFFSET D ABSX])

(EXTEND/TRANSITION/CHAIN
  [LAMBDA (LTC RTC)                                          (* kvl "21-DEC-83 11:00")

          (* Extends the left transition chain by appending the part of the right transition chain that is to the right of the
	  end of the left transition chain. End point of left transition chain is changed to intersect right transition chain)


    (PROG ((LTAIL LTC)
	   (RTAIL RTC)
	   LX RX)
      L   [COND
	    ((NULL (CDR RTAIL))
	      (replace YCOORD of (CAR (FLAST LTAIL)) with (fetch YCOORD of (CAR RTAIL)))
	      (RETURN LTC))
	    ((NULL (CDR LTAIL))
	      (RPLACD LTAIL (CDR RTAIL))
	      (replace YCOORD of (CAR LTAIL) with (fetch YCOORD of (CAR RTAIL)))
	      (RETURN LTC))
	    ([IEQP (SETQ LX (fetch XCOORD of (CADR LTAIL)))
		   (SETQ RX (fetch XCOORD of (CADR RTAIL]
	      (SETQ LTAIL (CDR LTAIL))
	      (SETQ RTAIL (CDR RTAIL)))
	    ((ILESSP LX RX)
	      (SETQ LTAIL (CDR LTAIL)))
	    (T (SETQ RTAIL (CDR RTAIL]
          (GO L])

(FOREST/BREAK/CYCLES
  [LAMBDA (NODE)                                             (* kvl "14-Aug-84 09:19")
                                                             (* Breaks any cycles by inserting new nodes and boxing)
    (DECLARE (USEDFREE NODELST))
    (replace (GRAPHNODE NODEPOSITION) of NODE with T)
    (for DTAIL DN on (fetch (GRAPHNODE TONODES) of NODE)
       do (SETQ DN (GETNODEFROMID (CAR DTAIL)
				  NODELST))
	  (COND
	    ((fetch (GRAPHNODE NODEPOSITION) of DN)          (* We've seen this before)
	      (SETQ DN (NEW/INSTANCE/OF/GRAPHNODE DN))
	      (RPLACA DTAIL (fetch (GRAPHNODE NODEID) of DN)))
	    (T (FOREST/BREAK/CYCLES DN])

(INIT/NODES/FOR/LAYOUT
  [LAMBDA (NS FORMAT ROOTIDS FONT)                           (* rmk: "22-Feb-85 10:32")
    (for GN in NS
       do [replace (GRAPHNODE NODEPOSITION) of GN with (NOT (NOT (FMEMB (fetch (GRAPHNODE NODEID)
									   of GN)
									ROOTIDS]
                                                             (* T Used to indicate prior visitation.
							     Roots are already visited)
	  (OR (fetch (GRAPHNODE NODEFONT) of GN)
	      (replace (GRAPHNODE NODEFONT) of GN with FONT)))
    [for R in ROOTIDS do (COND
			   ((EQMEMB (QUOTE LATTICE)
				    FORMAT)
			     (LATTICE/BREAK/CYCLES (GETNODEFROMID R NODELST)
						   NIL))
			   (T (FOREST/BREAK/CYCLES (GETNODEFROMID R NODELST]
    (for GN in NODELST
       do (replace (GRAPHNODE NODEPOSITION) of GN with NIL)
	  (SET/LABEL/SIZE GN])

(INTERPRET/MARK/FORMAT
  [LAMBDA (FORMAT)                                           (* kvl " 5-Sep-84 17:29")
                                                             (* sets specvars for NEW/INSTANCE/OF/GRAPHNODE and 
							     MARK/GRAPH/NODE)
    (DECLARE (SPECVARS BOX/BOTH/FLG BOX/LEAVES/FLG BORDER/FOR/MARKING LABELSHADE/FOR/MARKING))
    (PROG (PL)
          (AND (EQMEMB (QUOTE COPIES/ONLY)
		       FORMAT)
	       (SETQ BOX/BOTH/FLG NIL))
          (AND (EQMEMB (QUOTE NOT/LEAVES)
		       FORMAT)
	       (SETQ BOX/LEAVES/FLG NIL))
          (COND
	    ((NLISTP FORMAT)
	      (RETURN))
	    ((EQ (CAR FORMAT)
		 (QUOTE MARK))
	      (SETQ PL (CDR FORMAT)))
	    ((SETQ PL (FASSOC (QUOTE MARK)
			      FORMAT))
	      (SETQ PL (CDR PL)))
	    (T (RETURN)))
          [COND
	    [(FMEMB (QUOTE BORDER)
		    PL)
	      (SETQ BORDER/FOR/MARKING (LISTGET PL (QUOTE BORDER]
	    (T (SETQ BORDER/FOR/MARKING (QUOTE DON'T]
          (COND
	    [(FMEMB (QUOTE LABELSHADE)
		    PL)
	      (SETQ LABELSHADE/FOR/MARKING (LISTGET PL (QUOTE LABELSHADE]
	    (T (SETQ LABELSHADE/FOR/MARKING (QUOTE DON'T])

(LATTICE/BREAK/CYCLES
  [LAMBDA (NODE STACK)                                       (* kvl "14-Aug-84 09:14")
    (replace (GRAPHNODE NODEPOSITION) of NODE with T)
    (for DTAIL on (fetch (GRAPHNODE TONODES) of NODE) bind D GN
       do (SETQ GN (GETNODEFROMID (SETQ D (CAR DTAIL))
				  NODELST))
	  (COND
	    ((FMEMB D STACK)
	      (SETQ GN (NEW/INSTANCE/OF/GRAPHNODE GN))
	      (RPLACA DTAIL (fetch NODEID of GN)))
	    ((NULL (fetch (GRAPHNODE NODEPOSITION) of GN))
	      (LATTICE/BREAK/CYCLES GN (CONS D STACK])

(LAYOUTFOREST
  [LAMBDA (NODELST ROOTIDS FORMAT BOXING FONT MOTHERD PERSONALD FAMILYD)
                                                             (* rmk: " 2-Feb-84 16:55")
                                                             (* This is an older version of LayoutGraph, kept around
							     temporarily but de-documented)
    (LAYOUTGRAPH NODELST ROOTIDS (CONS FORMAT BOXING)
		 FONT MOTHERD PERSONALD])

(LAYOUTGRAPH
  [LAMBDA (NODELST ROOTIDS FORMAT FONT MOTHERD PERSONALD FAMILYD)
                                                             (* rmk: "15-Sep-84 00:15")

          (* takes a list of GRAPHNODE records and a list node ids for the top level nodes, where the graphnodes have only the
	  NODEID, NODELABEL and TONODES fields filled in. It fills in the other fields appropriately according the format 
	  switch and the boxing switch so that the graph becomes a forest. If there are loops in the graph, they are snapped 
	  and the NODELST is extended with Push This function returns a GRAPH record with the display slots filled in 
	  appropriately.)


    (DECLARE (SPECVARS NODELST MOTHERD PERSONALD FAMILYD))
    (PROG ((BOX/BOTH/FLG T)
	   (BOX/LEAVES/FLG T)
	   (BORDER/FOR/MARKING T)
	   (LABELSHADE/FOR/MARKING (QUOTE DON'T))
	   G)
          (DECLARE (SPECVARS BOX/BOTH/FLG BOX/LEAVES/FLG BORDER/FOR/MARKING LABELSHADE/FOR/MARKING))
          (OR (LISTP ROOTIDS)
	      (ERROR "LAYOUTGRAPH needs a LIST of root node ids"))
          (for R in ROOTIDS unless (FASSOC R NODELST) do (ERROR R 
					      "is in ROOTIDS but no GRAPHNODE for it in NODELST."))
          (OR FONT (SETQ FONT DEFAULTFONT))
          (OR MOTHERD (SETQ MOTHERD (STRINGWIDTH "AAAAAA" FONT)))
          [OR PERSONALD (SETQ PERSONALD (COND
		  ((EQMEMB (QUOTE VERTICAL)
			   FORMAT)
		    (STRINGWIDTH "AA" FONT))
		  (T 0]
          [OR FAMILYD (SETQ FAMILYD (HALF (FONTPROP FONT (QUOTE ASCENT]
          (INTERPRET/MARK/FORMAT FORMAT)
          (INIT/NODES/FOR/LAYOUT NODELST FORMAT ROOTIDS FONT)
          (AND (EQMEMB (QUOTE VERTICAL)
		       FORMAT)
	       (SWITCH/NODE/HEIGHT/WIDTH NODELST))
          [SETQ G (COND
	      ((EQMEMB (QUOTE LATTICE)
		       FORMAT)
		(BROWSE/LAYOUT/LATTICE ROOTIDS))
	      ((EQMEMB (QUOTE FAST)
		       FORMAT)
		(BROWSE/LAYOUT/HORIZ ROOTIDS))
	      (T (BROWSE/LAYOUT/HORIZ/COMPACTLY ROOTIDS]
          [for N in NODELST do (OR (type? POSITION (fetch NODEPOSITION of N))
				   (ERROR "Disconnected graph.  Root(s) didn't connect to:"
					  (fetch NODELABEL of N]
          [COND
	    ((EQMEMB (QUOTE VERTICAL)
		     FORMAT)
	      (SWITCH/NODE/HEIGHT/WIDTH NODELST)
	      (REFLECT/GRAPH/DIAGONALLY G)
	      (OR (EQMEMB (QUOTE REVERSE)
			  FORMAT)
		  (REFLECT/GRAPH/VERTICALLY G))
	      (AND (EQMEMB (QUOTE REVERSE/DAUGHTERS)
			   FORMAT)
		   (REFLECT/GRAPH/HORIZONTALLY G)))
	    (T (AND (EQMEMB (QUOTE REVERSE)
			    FORMAT)
		    (REFLECT/GRAPH/HORIZONTALLY G))
	       (AND (EQMEMB (QUOTE REVERSE/DAUGHTERS)
			    FORMAT)
		    (REFLECT/GRAPH/VERTICALLY G]
          (RETURN G])

(LAYOUTLATTICE
  [LAMBDA (NODELST ROOTIDS FORMAT FONT MOTHERD PERSONALD FAMILYD)
                                                             (* rmk: "15-Sep-84 00:15")

          (* takes a list of GRAPHNODE records and a list node ids for the top level nodes, where the graphnodes have only the
	  NODEID, NODELABEL and TONODES fields filled in. It fills in the other fields appropriately according the format 
	  switch If there are loops in the graph, they are detected in BRHL/MOVE/RIGHT and an error occurs.
	  This function returns a GRAPH record with the display slots filled in appropriately.)


    (DECLARE (SPECVARS NODELST MOTHERD PERSONALD FAMILYD))
    (for R in ROOTIDS unless (FASSOC R NODELST) do (ERROR R 
					      "is in ROOTIDS but no GRAPHNODE for it in NODELST."))
    (SETQ FONT (OR FONT DEFAULTFONT))
    (INIT/NODES/FOR/LAYOUT NODELST ROOTIDS FORMAT FONT)
    [OR FAMILYD (SETQ FAMILYD (HALF (FONTPROP FONT (QUOTE ASCENT]
    (OR MOTHERD (SETQ MOTHERD (STRINGWIDTH "AAAAAA" FONT)))
    [OR PERSONALD (SETQ PERSONALD (COND
	    ((EQ FORMAT (QUOTE VERTICAL))
	      (STRINGWIDTH "AA" FONT))
	    (T 0]
    (BROWSE/LAYOUT/LATTICE ROOTIDS])

(LAYOUTSEXPR
  [LAMBDA (TREE FORMAT BOXING FONT MOTHERD PERSONALD FAMILYD)
                                                             (* dgb: "23-Jan-85 08:28")
                                                             (* assumes CAR of tree is node label, CDR is daughter 
							     trees.)
    (COND
      [TREE (PROG (RESULT)
	          (DECLARE (SPECVARS RESULT))
	          (LAYOUTSEXPR1 TREE)
	          (RETURN (LAYOUTGRAPH RESULT (LIST TREE)
				       (APPEND (MKLIST FORMAT)
					       BOXING)
				       FONT MOTHERD PERSONALD FAMILYD]
      (T (ERROR "Cannot layout NIL as S-EXPRESSION"])

(LAYOUTSEXPR1
  [LAMBDA (TREE)                                             (* dgb: "22-Jan-85 07:07")
    (DECLARE (SPECVARS RESULT))
    (COND
      [(for R in RESULT thereis (EQ TREE (fetch (GRAPHNODE NODEID) of R]
      ((NLISTP TREE)
	(push RESULT (create GRAPHNODE
			     NODEID ← TREE
			     NODELABEL ← TREE)))
      (T [push RESULT (create GRAPHNODE
			      NODEID ← TREE
			      NODELABEL ←(CAR TREE)
			      TONODES ←(APPEND (CDR TREE]
	 (for D in (CDR TREE) do (LAYOUTSEXPR1 D])

(MARK/GRAPH/NODE
  [LAMBDA (NODE)                                             (* rmk: "15-Sep-84 00:18")
                                                             (* changes appearance of graph node to indicate that a 
							     link has been snapped.)
    (DECLARE (USEDFREE BORDER/FOR/MARKING LABELSHADE/FOR/MARKING))
    (OR (EQ BORDER/FOR/MARKING (QUOTE DON'T))
	(replace NODEBORDER of NODE with BORDER/FOR/MARKING))
    (OR (EQ LABELSHADE/FOR/MARKING (QUOTE DON'T))
	(replace NODELABELSHADE of NODE with LABELSHADE/FOR/MARKING])

(NEW/INSTANCE/OF/GRAPHNODE
  [LAMBDA (GN)
    (DECLARE (USEDFREE NODELST BOX/LEAVES/FLG BOX/BOTH/FLG))
                                                             (* kvl " 5-Sep-84 16:30")
                                                             (* returns a second instance of the node, boxing it 
							     appropriately. No daughters.)
    (PROG [(NEW (create GRAPHNODE
			NODEID ←(LIST (fetch (GRAPHNODE NODEID) of GN))
			NODELABEL ←(fetch (GRAPHNODE NODELABEL) of GN)
			NODEFONT ←(fetch (GRAPHNODE NODEFONT) of GN)
			NODEWIDTH ←(fetch (GRAPHNODE NODEWIDTH) of GN)
			NODEHEIGHT ←(fetch (GRAPHNODE NODEHEIGHT) of GN)
			NODEBORDER ←(COPY (fetch (GRAPHNODE NODEBORDER) of GN))
			NODELABELSHADE ←(fetch NODELABELSHADE of GN]
          (push NODELST NEW)
          [COND
	    ((OR BOX/LEAVES/FLG (fetch (GRAPHNODE TONODES) of GN))
	      (MARK/GRAPH/NODE NEW)
	      (COND
		(BOX/BOTH/FLG (MARK/GRAPH/NODE GN]
          (RETURN NEW])

(RAISE/TRANSITION/CHAIN
  [LAMBDA (TC RAISE)                                         (* kvl "21-DEC-83 10:25")
                                                             (* raises a daughters transition chain by adding in the
							     offset of the daughter's box relative to the mother's 
							     box.)
    (for P in TC do (add (fetch YCOORD of P)
			 RAISE)
       finally (RETURN TC])

(REFLECT/GRAPH/DIAGONALLY
  [LAMBDA (GRAPH)                                            (* kvl "26-DEC-83 10:58")
    (replace (GRAPH SIDESFLG) of GRAPH with (NOT (fetch (GRAPH SIDESFLG) of GRAPH)))
    [for N in (fetch (GRAPH GRAPHNODES) of GRAPH)
       do (SETQ N (fetch (GRAPHNODE NODEPOSITION) of N))
	  (replace XCOORD of N with (PROG1 (fetch YCOORD of N)
					   (replace YCOORD of N with (fetch XCOORD of N]
    GRAPH])

(REFLECT/GRAPH/HORIZONTALLY
  [LAMBDA (GRAPH)                                            (* kvl "10-Aug-84 17:23")
    (for N in (fetch (GRAPH GRAPHNODES) of GRAPH) bind [W ←(IPLUS (MAX/RIGHT (fetch (GRAPH GRAPHNODES)
										of GRAPH))
								  (MIN/LEFT (fetch (GRAPH GRAPHNODES)
									       of GRAPH]
       do (SETQ N (fetch (GRAPHNODE NODEPOSITION) of N))
	  (replace XCOORD of N with (IDIFFERENCE W (fetch XCOORD of N])

(REFLECT/GRAPH/VERTICALLY
  [LAMBDA (GRAPH)                                            (* kvl "10-Aug-84 16:48")
    (for N in (fetch (GRAPH GRAPHNODES) of GRAPH) bind [H ←(IPLUS (MAX/TOP (fetch (GRAPH GRAPHNODES)
									      of GRAPH))
								  (MIN/BOTTOM (fetch (GRAPH 
										       GRAPHNODES)
										 of GRAPH]
       do (SETQ N (fetch (GRAPHNODE NODEPOSITION) of N))
	  (replace YCOORD of N with (IDIFFERENCE H (fetch YCOORD of N])

(SWITCH/NODE/HEIGHT/WIDTH
  [LAMBDA (NL)                                               (* rmk: " 2-Feb-84 22:19")
    (for N in NL do (swap (fetch (GRAPHNODE NODEWIDTH) of N)
			  (fetch (GRAPHNODE NODEHEIGHT) of N])
)
(DECLARE: EVAL@COMPILE 

(RPAQQ LINKPARAMS Link% Parameters)

(CONSTANTS (LINKPARAMS (QUOTE Link% Parameters)))
)

(RPAQQ DEFAULT.GRAPH.NODEBORDER NIL)

(RPAQQ DEFAULT.GRAPH.NODEFONT NIL)

(RPAQQ DEFAULT.GRAPH.NODELABELSHADE NIL)

(RPAQQ ScalableLinkParameters (DASHING LINEWIDTH))

(RPAQQ CACHE/NODE/LABEL/BITMAPS NIL)

(RPAQQ EDITGRAPHMENU NIL)

(RPAQQ GRAPHEDITWINDOW NIL)

(RPAQQ NODEBORDERWIDTH 1)

(RPAQ ORIGIN (CREATEPOSITION 0 0))
(MOVD? (FUNCTION NILL)
       (FUNCTION IMAGEOBJP)
       T)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(LOCALVARS . T)
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS EDITGRAPHMENU GRAPHEDITWINDOW NODEBORDERWIDTH ORIGIN)
)
[DECLARE: EVAL@COMPILE 

(RECORD GRAPHNODE (NODEID NODEPOSITION NODELABELBITMAP NIL NODELABELSHADE NODEWIDTH NODEHEIGHT 
			  TONODES FROMNODES NODEFONT NODELABEL NODEBORDER)
		  NODEBORDER ← DEFAULT.GRAPH.NODEBORDER NODELABELSHADE ← DEFAULT.GRAPH.NODELABELSHADE 
		  NODEFONT ← DEFAULT.GRAPH.NODEFONT)

(RECORD GRAPH (GRAPHNODES SIDESFLG DIRECTEDFLG GRAPH.MOVENODEFN GRAPH.ADDNODEFN GRAPH.DELETENODEFN 
			  GRAPH.ADDLINKFN GRAPH.DELETELINKFN GRAPH.FONTCHANGEFN GRAPH.INVERTBORDERFN 
			  GRAPH.INVERTLABELFN))
]
(DECLARE: DONTCOPY 
(DECLARE: EVAL@COMPILE 
(PUTPROPS HALF MACRO ((X)
	   (LRSH X 1)))
)
)



(* Grapher image objects)

(DEFINEQ

(GRAPHERCOPYBUTTONEVENTFN
  [LAMBDA (WINDOW)                                           (* rmk: "22-Dec-84 11:33")

          (* Called on down transition in WINDOW. If GRAPHOBJ.FINDGRAPH locates a graph in window, it is copy inserted.
	  Another callers of GRAPHOBJ.FINDGRAPH might also specify alignments to GRAPHEROBJ.)


    (PROG ((GRAPH (GRAPHOBJ.FINDGRAPH WINDOW)))
          (AND GRAPH (COPYINSERT (GRAPHEROBJ GRAPH])

(GRAPHOBJ.FINDGRAPH
  [LAMBDA (WINDOW)                                           (* rmk: "22-Dec-84 11:29")
                                                             (* Get control on down transition, track until key goes
							     up or mouse leaves the window)
    (bind (DS ←(GETSTREAM WINDOW))
	  (REG ←(WINDOWPROP WINDOW (QUOTE REGION))) first (DSPFILL NIL BLACKSHADE (QUOTE INVERT)
								   DS)
       do (GETMOUSESTATE)
	  (COND
	    ((NOT (INSIDE? REG LASTMOUSEX LASTMOUSEY))
	      (DSPFILL NIL BLACKSHADE (QUOTE INVERT)
		       DS)
	      (RETURN))
	    ((NOT (LASTMOUSESTATE (OR LEFT MIDDLE RIGHT)))
	      (DSPFILL NIL BLACKSHADE (QUOTE INVERT)
		       DS)
	      (RETURN (COPYGRAPH (WINDOWPROP WINDOW (QUOTE GRAPH])
)
(DEFINEQ

(ALIGNMENTNODE
  [LAMBDA (NODESPEC GRAPH)                                   (* rmk: " 2-Jan-85 10:22")
                                                             (* Returns the alignment node specified by NODESPEC)
    (SELECTQ NODESPEC
	     (*TOP (for N in (fetch GRAPHNODES of GRAPH) largest (GN/TOP N)))
	     (*BOTTOM (for N in (fetch GRAPHNODES of GRAPH) smallest (GN/BOTTOM N)))
	     (*RIGHT (for N in (fetch GRAPHNODES of GRAPH) largest (GN/RIGHT N)))
	     (*LEFT (for N in (fetch GRAPHNODES of GRAPH) smallest (GN/LEFT N)))
	     (GETNODEFROMID NODESPEC (fetch GRAPHNODES of GRAPH])

(GRAPHOBJ.CHECKALIGN
  [LAMBDA (GRAPH ALIGNSPEC)                                  (* rmk: " 2-Jan-85 10:22")
                                                             (* Makes sure that the ALIGNMENTSPEC is valid, putting 
							     it into standard form if necessary)
    (OR (AND (NULL ALIGNSPEC)
	     (SETQ ALIGNSPEC 0))
	(NUMBERP ALIGNSPEC)
	[AND (LISTP ALIGNSPEC)
	     (SELECTQ (CAR ALIGNSPEC)
		      ((*TOP *BOTTOM *LEFT *RIGHT)
			T)
		      (GETNODEFROMID (CAR ALIGNSPEC)
				     (fetch GRAPHNODES of GRAPH)))
	     (LISTP (CDR ALIGNSPEC))
	     (OR (NUMBERP (CADR ALIGNSPEC))
		 (EQ (CADR ALIGNSPEC)
		     (QUOTE BASELINE))
		 (AND (NULL (CADR ALIGNSPEC))
		      (SETQ ALIGNSPEC (LIST (CAR ALIGNSPEC)
					    0]
	(ERROR "ILLEGAL GRAPH ALIGNMENT SPECIFICATION" ALIGNSPEC))
    ALIGNSPEC])
)
(DEFINEQ

(GRAPHEROBJ
  [LAMBDA (GRAPH HALIGN VALIGN)                              (* rmk: "15-Feb-85 15:03")
                                                             (* Constructs a Grapher image object.)

          (* HALIGN and VALIGN specify the horizontal or vertical alignment. Each can be a floating point number between 0 and
	  1, specifying that the alignment point is located at that portion of the width/height of the graphregion, or a list 
	  of the form (nodespec align), where nodespec is a node ID or one of the atoms LEFT, RIGHT, BOTTOM, TOP, and align is
	  either a floating point number bewtween 0 and 1, or the atom BASELINE)


    (IMAGEOBJCREATE (LIST GRAPH (GRAPHOBJ.CHECKALIGN GRAPH HALIGN)
			  (GRAPHOBJ.CHECKALIGN GRAPH VALIGN))
		    (COND
		      ((IMAGEFNSP GRAPHERIMAGEFNS))
		      (T (SETQ GRAPHERIMAGEFNS (IMAGEFNSCREATE (FUNCTION GRAPHOBJ.DISPLAYFN)
							       (FUNCTION GRAPHOBJ.IMAGEBOXFN)
							       (FUNCTION GRAPHOBJ.PUTFN)
							       (FUNCTION GRAPHOBJ.GETFN)
							       (FUNCTION GRAPHOBJ.COPYFN)
							       (FUNCTION GRAPHOBJ.BUTTONEVENTINFN)
							       (FUNCTION NILL)
							       (FUNCTION NILL)
							       (FUNCTION NILL)
							       (FUNCTION NILL)
							       (FUNCTION NILL)
							       (FUNCTION NILL)
							       NIL
							       (QUOTE GRAPHER])

(GRAPHOBJ.BUTTONEVENTINFN
  [LAMBDA (GROBJ WINDOW)                                     (* rmk: " 8-Jan-85 15:27")
                                                             (* the user has pressed a button inside the grapher 
							     object IMAGEOBJ.)
    (COND
      ([MENU (create MENU
		     ITEMS ←(QUOTE ((Edit% graph T " Opens a window to edit this graph"]
	(PROG [W (DATUM (IMAGEOBJPROP GROBJ (QUOTE OBJECTDATUM]
	      (SETQ W (SIZE/GRAPH/WINDOW (CAR DATUM)
					 NIL T))
	      (IMAGEOBJPROP GROBJ (QUOTE OBJECTDATUM)
			    (LIST (EDITGRAPH (COPYGRAPH (CAR DATUM))
					     W)
				  (CADR DATUM)
				  (CADDR DATUM)))
	      (CLOSEW W))
	(QUOTE CHANGED])

(GRAPHOBJ.COPYFN
  [LAMBDA (GROBJ)                                            (* rmk: " 8-Jan-85 15:17")
                                                             (* makes a copy of a grapher image object.)
    (SETQ GROBJ (IMAGEOBJPROP GROBJ (QUOTE OBJECTDATUM)))
    (GRAPHEROBJ (COPYGRAPH (CAR GROBJ))
		(CADR GROBJ)
		(CADDR GROBJ])

(GRAPHOBJ.DISPLAYFN
  [LAMBDA (GROBJ STREAM)                                     (* rmk: " 2-Apr-85 10:56")
                                                             (* display function for a grapher image object)

          (* Scale the streams position back to display coordinates, since DISPLAYGRAPH translates the translation.
	  Might be simplest to define DISPLAYGRAPH without a translation, as locating the graph coordinate system at the 
	  current X,Y position)


    (PROG [REG (BOX (IMAGEOBJPROP GROBJ (QUOTE BOUNDBOX)))
	       (SCALE (DSPSCALE NIL STREAM))
	       (GRAPH (CAR (IMAGEOBJPROP GROBJ (QUOTE OBJECTDATUM]
          (OR BOX (SETQ BOX (APPLY* (IMAGEOBJPROP GROBJ (QUOTE IMAGEBOXFN))
				    GROBJ STREAM)))
          [SETQ REG (GRAPHREGION (COND
				   ((EQP SCALE 1)
				     GRAPH)
				   (T (SCALE/GRAPH GRAPH STREAM SCALE]

          (* Kludgy: we have to scale the graph to get the real region, but then DISPLAYGRAPH will do it again, cause it 
	  assumes screen points.)

                                                             (* Other kludge is that the translation is also in 
							     screen points)
          (DISPLAYGRAPH GRAPH STREAM NIL (CREATEPOSITION (QUOTIENT (DIFFERENCE (DIFFERENCE
										 (DSPXPOSITION NIL 
											   STREAM)
										 (fetch XKERN
										    of BOX))
									       (fetch (REGION LEFT)
										  of REG))
								   SCALE)
							 (QUOTIENT (DIFFERENCE (DIFFERENCE
										 (DSPYPOSITION NIL 
											   STREAM)
										 (fetch YDESC
										    of BOX))
									       (fetch (REGION BOTTOM)
										  of REG))
								   SCALE])

(GRAPHOBJ.GETALIGN
  [LAMBDA (STREAM GRAPH)                                     (* rmk: " 2-Jan-85 10:22")
    (PROG ((ALIGN (READ STREAM FILERDTBL)))
          [if [AND (LISTP ALIGN)
		   (NOT (MEMB (CAR ALIGN)
			      (QUOTE (*TOP *BOTTOM *LEFT *RIGHT]
	      then (SETQ ALIGN (CONS [fetch NODEID of (CAR (NTH (CAR ALIGN)
								(fetch GRAPHNODES of GRAPH]
				     (CDR ALIGN]
          (RETURN ALIGN])

(GRAPHOBJ.GETFN
  [LAMBDA (STREAM)                                           (* rmk: "31-Dec-84 12:22")
                                                             (* reads a grapher image object from a file.)
    (OR (EQ (SKIPSEPRS STREAM FILERDTBL)
	    (QUOTE %())
	(ERROR "ILLEGAL GRAPHOBJECT FORMAT"))
    (READC STREAM)                                           (* Read the paren)
    (PROG ((GRAPH (READGRAPH STREAM)))
          (RETURN (PROG1 (GRAPHEROBJ GRAPH (GRAPHOBJ.GETALIGN STREAM GRAPH)
				     (GRAPHOBJ.GETALIGN STREAM GRAPH))
                                                             (* Skip the closing paren)
			 (RATOM STREAM FILERDTBL])

(GRAPHOBJ.IMAGEBOXFN
  [LAMBDA (GROBJ STREAM)                                     (* rmk: "15-Feb-85 08:28")
                                                             (* size function for a tedit bitmap object.)
    (PROG (REGION GRAPH HALIGN VALIGN ALNODE (DATUM (IMAGEOBJPROP GROBJ (QUOTE OBJECTDATUM)))
		  (SCALE (DSPSCALE NIL STREAM))
		  BMW BMH)
          (SETQ GRAPH (CAR DATUM))
          (SETQ HALIGN (CADR DATUM))
          (SETQ VALIGN (CADDR DATUM))
          (OR (EQ 1 SCALE)
	      (SETQ GRAPH (SCALE/GRAPH GRAPH STREAM SCALE)))
          (SETQ REGION (GRAPHREGION GRAPH))
          (RETURN (create IMAGEBOX
			  XSIZE ←(fetch WIDTH of REGION)
			  YSIZE ←(fetch HEIGHT of REGION)
			  YDESC ←[COND
			    ((NUMBERP VALIGN)
			      (TIMES VALIGN (fetch HEIGHT of REGION)))
			    (T                               (* Must be a list, cause of checks in GRAPHEROBJ)
			       (SETQ ALNODE (ALIGNMENTNODE (CAR VALIGN)
							   GRAPH))
			       (PLUS (GN/BOTTOM ALNODE)
				     (COND
				       ((EQ (CADR VALIGN)
					    (QUOTE BASELINE))
					 (IQUOTIENT (IPLUS (IDIFFERENCE (fetch NODEHEIGHT
									   of ALNODE)
									(FONTPROP (fetch NODEFONT
										     of ALNODE)
										  (QUOTE ASCENT)))
							   (FONTPROP (fetch NODEFONT of ALNODE)
								     (QUOTE DESCENT)))
						    2))
				       (T (TIMES (CADR VALIGN)
						 (fetch NODEHEIGHT of ALNODE]
			  XKERN ←(COND
			    ((NUMBERP HALIGN)
			      (TIMES HALIGN (fetch WIDTH of REGION)))
			    (T                               (* Must be a list, cause of checks in GRAPHEROBJ)
			       (SETQ ALNODE (ALIGNMENTNODE (CAR HALIGN)
							   GRAPH))
			       (PLUS (GN/LEFT ALNODE)
				     (TIMES (COND
					      ((EQ (CADR HALIGN)
						   (QUOTE BASELINE))
						0)
					      (T (CADR HALIGN)))
					    (fetch NODEWIDTH of ALNODE])

(GRAPHOBJ.PUTALIGN
  [LAMBDA (STREAM GRAPH ALIGN)                               (* rmk: " 2-Jan-85 10:22")
    (PRIN2 [COND
	     ([OR (NLISTP ALIGN)
		  (MEMB (CAR ALIGN)
			(QUOTE (*TOP *BOTTOM *LEFT *RIGHT]
	       ALIGN)
	     (T                                              (* Convert node ID to node index)
		(CONS (for I from 1 as N in (fetch GRAPHNODES of GRAPH)
			 when (EQ (CAR ALIGN)
				  (fetch NODEID of N))
			 do (RETURN I))
		      (CDR ALIGN]
	   STREAM FILERDTBL])

(GRAPHOBJ.PUTFN
  [LAMBDA (GROBJ STREAM)                                     (* rmk: "31-Dec-84 12:25")
                                                             (* Put a description of a grapher object into the 
							     file.)
    (PROG [ALIGN GRAPH (DATUM (IMAGEOBJPROP GROBJ (QUOTE OBJECTDATUM]
          (PRIN1 "(" STREAM)
          (SETQ GRAPH (CAR DATUM))
          (DUMPGRAPH GRAPH STREAM)
          (TERPRI STREAM)
          (GRAPHOBJ.PUTALIGN STREAM GRAPH (CADR DATUM))
          (SPACES 1 STREAM)
          (GRAPHOBJ.PUTALIGN STREAM GRAPH (CADDR DATUM))
          (printout STREAM ")" T])
)
(DEFINEQ

(COPYGRAPH
  [LAMBDA (GRAPH)                                            (* dgb: "28-Jan-85 11:10")
    (create GRAPH using GRAPH GRAPHNODES ←(for N in (fetch GRAPHNODES of GRAPH)
					     collect (create GRAPHNODE
							using N NODEPOSITION ←(create POSITION
										 using (fetch 
										     NODEPOSITION
											  of N])

(DUMPGRAPH
  [LAMBDA (GRAPH STREAM)                                     (* rmk: "11-Mar-85 20:10")
                                                             (* Put a description of a graph into a file.)
    (RESETLST (RESETSAVE (SETREADTABLE FILERDTBL))
	      (PROG (BORDERS FONTS IDS SHADES (#BORDERS 0)
			     (#FONTS 0)
			     (#SHADES 0)
			     (#IDS 0))
		    (printout STREAM "(" T "FIELDS (")
		    (if (fetch SIDESFLG of GRAPH)
			then (printout STREAM 2 "SIDESFLG " .P2 (fetch SIDESFLG of GRAPH)))
		    (if (fetch DIRECTEDFLG of GRAPH)
			then (printout STREAM 2 "DIRECTEDFLG " .P2 (fetch DIRECTEDFLG of GRAPH)))
		    (if (fetch GRAPH.MOVENODEFN of GRAPH)
			then (printout STREAM 2 "MOVENODEFN " .P2 (fetch GRAPH.MOVENODEFN
								     of GRAPH)))
		    (if (fetch GRAPH.ADDNODEFN of GRAPH)
			then (printout STREAM 2 "ADDNODEFN " .P2 (fetch GRAPH.ADDNODEFN of GRAPH)))
		    (if (fetch GRAPH.DELETENODEFN of GRAPH)
			then (printout STREAM 2 "DELETENODEFN " .P2 (fetch GRAPH.DELETENODEFN
								       of GRAPH)))
		    (if (fetch GRAPH.ADDLINKFN of GRAPH)
			then (printout STREAM 2 "ADDLINKFN " .P2 (fetch GRAPH.ADDLINKFN of GRAPH)))
		    (if (fetch GRAPH.DELETELINKFN of GRAPH)
			then (printout STREAM 2 "DELETELINKFN " .P2 (fetch GRAPH.DELETELINKFN
								       of GRAPH)))
		    (if (fetch GRAPH.FONTCHANGEFN of GRAPH)
			then (printout STREAM 2 "FONTCHANGEFN " .P2 (fetch GRAPH.FONTCHANGEFN
								       of GRAPH)))
		    (if (fetch GRAPH.INVERTBORDERFN of GRAPH)
			then (printout STREAM 2 "INVERTBORDERFN " .P2 (fetch GRAPH.INVERTBORDERFN
									 of GRAPH)))
		    (if (fetch GRAPH.INVERTLABELFN of GRAPH)
			then (printout STREAM 2 "INVERTLABELFN " .P2 (fetch GRAPH.INVERTLABELFN
									of GRAPH)))
		    (PRIN1 ")" STREAM)
		    [for N TEMP in (fetch (GRAPH GRAPHNODES) of GRAPH)
		       do [OR (ASSOC (fetch NODEID of N)
				     IDS)
			      (push IDS (CONS (fetch NODEID of N)
					      (add #IDS 1]
			  [AND (SETQ TEMP (fetch NODELABELSHADE of N))
			       (OR (ASSOC TEMP SHADES)
				   (push SHADES (CONS TEMP (add #SHADES 1]
			  [OR (ASSOC (fetch NODEFONT of N)
				     FONTS)
			      (push FONTS (CONS (fetch NODEFONT of N)
						(add #FONTS 1]
			  (SELECTQ (SETQ TEMP (fetch NODEBORDER of N))
				   ((T NIL))
				   (OR (ASSOC TEMP BORDERS)
				       (push BORDERS (CONS TEMP (add #BORDERS 1]
		    (printout STREAM T "IDS " #IDS ,)
		    (for X in (SETQ IDS (DREVERSE IDS))
		       do (PRIN2 (CAR X)
				 STREAM)
			  (SPACES 1 STREAM))
		    (printout STREAM T "FONTS " #FONTS ,)
		    (for X in (SETQ FONTS (DREVERSE FONTS))
		       do (SETQ X (CAR X))
			  (PRIN2 (if (LISTP X)
				   elseif (type? FONTDESCRIPTOR X)
				     then (FONTUNPARSE X)
				   elseif (FONTP X)
				     then                    (* Mark it as a class)
					  (CONS (QUOTE CLASS)
						(FONTCLASSUNPARSE X)))
				 STREAM)
			  (SPACES 1 STREAM))
		    [COND
		      (BORDERS (printout STREAM T "BORDERS " #BORDERS ,)
			       (for X (POS ←(POSITION STREAM)) in (SETQ BORDERS (DREVERSE BORDERS))
				  do (TAB POS 1 STREAM)
				     (HPRINT (CAR X)
					     STREAM]
		    [COND
		      (SHADES (printout STREAM T "SHADES " #SHADES ,)
			      (for X (POS ←(POSITION STREAM)) in (SETQ SHADES (DREVERSE SHADES))
				 do (TAB POS 1 STREAM)
				    (HPRINT (CAR X)
					    STREAM]
		    (printout STREAM T "NODES (")
		    (for N POS in (fetch (GRAPH GRAPHNODES) of GRAPH)
		       do (printout STREAM 2 "(" .P2 (CDR (ASSOC (fetch NODEID of N)
								 IDS))
				    ,)
			  (SETQ POS (POSITION STREAM))
			  (HPRINT (fetch NODELABEL of N)
				  STREAM)
			  (printout STREAM , .TAB POS .P2 (fetch NODEPOSITION of N)
				    , .P2 (CDR (ASSOC (fetch NODEFONT of N)
						      FONTS))
				    , .P2 (SELECTQ (fetch NODEBORDER of N)
						   ((NIL T)
						     (fetch NODEBORDER of N))
						   (CDR (ASSOC (fetch NODEBORDER of N)
							       BORDERS)))
				    , .P2 (AND (fetch NODELABELSHADE of N)
					       (CDR (ASSOC (fetch NODELABELSHADE of N)
							   SHADES)))
				    ,)
			  (if (fetch TONODES of N)
			      then (PRIN1 "(" STREAM)
				   (for X in (fetch TONODES of N)
				      do (printout STREAM .P2
						   [COND
						     [(EQ (CAR (LISTP X))
							  (QUOTE Link% Parameters))
						       (CONS (CAR X)
							     (CONS (CDR (ASSOC (CADR X)
									       IDS))
								   (CDDR X]
						     (T (CDR (ASSOC X IDS]
						   ,))
				   (PRIN1 ") " STREAM)
			    else (PRIN1 "NIL " STREAM))
			  (if (fetch FROMNODES of N)
			      then (PRIN1 "(" STREAM)
				   (for X in (fetch FROMNODES of N)
				      do (printout STREAM .P2 (CDR (ASSOC X IDS))
						   ,))
				   (PRIN1 ")" STREAM)
			    else (PRIN1 NIL STREAM))
			  (printout STREAM ")" T))
		    (PRIN1 "))" STREAM])

(READGRAPH
  [LAMBDA (STREAM)                                           (* rmk: "15-Feb-85 16:56")
                                                             (* reads a graph from a file.)
    (OR (EQ (SKIPSEPRS STREAM FILERDTBL)
	    (QUOTE %())
	(ERROR "ILLEGAL GRAPH FORMAT"))
    (READC STREAM)                                           (* Read the paren)
    (bind NUM TEMP FONTS BORDERS SHADES IDS (GRAPH ←(create GRAPH))
       do (SELECTQ (SETQ TEMP (RATOM STREAM FILERDTBL))
		   [FIELDS (for F on (READ STREAM FILERDTBL) by (CDDR F)
			      do (SELECTQ (CAR F)
					  (SIDESFLG (replace SIDESFLG of GRAPH with (CADR F)))
					  (DIRECTEDFLG (replace DIRECTEDFLG of GRAPH
							  with (CADR F)))
					  (MOVENODEFN (replace GRAPH.MOVENODEFN of GRAPH
							 with (CADR F)))
					  (ADDNODEFN (replace GRAPH.ADDNODEFN of GRAPH
							with (CADR F)))
					  (DELETENODEFN (replace GRAPH.DELETENODEFN of GRAPH
							   with (CADR F)))
					  (ADDLINKFN (replace GRAPH.ADDLINKFN of GRAPH
							with (CADR F)))
					  (DELETELINKFN (replace GRAPH.DELETELINKFN of GRAPH
							   with (CADR F)))
					  (FONTCHANGEFN (replace GRAPH.FONTCHANGEFN of GRAPH
							   with (CADR F)))
					  (INVERTBORDERFN (replace GRAPH.INVERTBORDERFN of GRAPH
							     with (CADR F)))
					  (INVERTLABELFN (replace GRAPH.INVERTLABELFN of GRAPH
							    with (CADR F)))
					  (ERROR "UNRECOGNIZED GRAPH FIELD" (CAR F]
		   [IDS (SETQ NUM (RATOM STREAM FILERDTBL))
			(SETQ IDS (ARRAY NUM))
			(for I to NUM do (SETA IDS I (READ STREAM FILERDTBL]
		   [BORDERS (SETQ NUM (RATOM STREAM FILERDTBL))
			    (SETQ BORDERS (ARRAY NUM))
			    (for I to NUM do (SETA BORDERS I (HREAD STREAM]
		   [FONTS (SETQ NUM (RATOM STREAM FILERDTBL))
			  (SETQ FONTS (ARRAY NUM))
			  (for I to NUM do (SETA FONTS I (COND
						   ((EQ (SETQ TEMP (READ STREAM FILERDTBL))
							(QUOTE C))
                                                             (* A font class)
						     (SETQ TEMP (READ STREAM FILERDTBL))
						     (FONTCLASS (CAR TEMP)
								(CDR TEMP)))
						   ((EQ (CAR (LISTP TEMP))
							(QUOTE CLASS))
						     (FONTCLASS (CADR TEMP)
								(CDDR TEMP)))
						   (T TEMP]
		   (NODES (RATOM STREAM)                     (* Skip paren)
			  [replace GRAPHNODES of GRAPH
			     with (while (EQ (SKIPSEPRS STREAM FILERDTBL)
					     (QUOTE %())
				     collect
				      (READC STREAM)
				      (PROG1 (create GRAPHNODE
						     NODEID ←(ELT IDS (RATOM STREAM FILERDTBL))
						     NODELABEL ←(HREAD STREAM)
						     NODEPOSITION ←(READ STREAM FILERDTBL)
						     NODEFONT ←(ELT FONTS (RATOM STREAM FILERDTBL))
						     NODEBORDER ←(SELECTQ (SETQ TEMP
									    (RATOM STREAM FILERDTBL))
									  ((NIL T)
									    TEMP)
									  (ELT BORDERS TEMP))
						     NODELABELSHADE ←(AND (SETQ TEMP
									    (RATOM STREAM FILERDTBL))
									  (ELT SHADES TEMP))
						     TONODES ←[for X in (READ STREAM FILERDTBL)
								 collect
								  (COND
								    [(EQ (CAR (LISTP X))
									 (QUOTE Link% Parameters))
								      (CONS
									(CAR X)
									(CONS (ELT IDS (CADR X))
									      (CDDR X]
								    (T (ELT IDS X]
						     FROMNODES ←(for X in (READ STREAM FILERDTBL)
								   collect (ELT IDS X)))
                                                             (* Skip the closing paren)
					     (RATOM STREAM FILERDTBL]
                                                             (* Skip the closing paren)
			  (RATOM STREAM FILERDTBL))
		   [SHADES (SETQ NUM (RATOM STREAM FILERDTBL))
			   (SETQ SHADES (ARRAY NUM))
			   (for I to NUM do (SETA SHADES I (HREAD STREAM]
		   (%)                                       (* The closing paren)
		       (RETURN GRAPH))
		   (ERROR "INVALID GRAPHER IMAGE OBJECT" STREAM])
)

(RPAQQ GRAPHERIMAGEFNS NIL)

(ADDTOVAR IMAGEOBJGETFNS (GRAPHOBJ.GETFN))
(PUTPROPS GRAPHER COPYRIGHT ("Xerox Corporation" 1983 1984 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (3936 4970 (GRAPHER.SHIFTDOWNP 3946 . 4968)) (5032 75507 (ADD/AND/DISPLAY/LINK 5042 . 
5590) (APPLYTOSELECTEDNODE 5592 . 7957) (CALL.MOVENODEFN 7959 . 8313) (CHANGE.NODEFONT.SIZE 8315 . 
9302) (CHOOSE.GRAPH.FONT 9304 . 9736) (CLOSEST/NODE 9738 . 10354) (DEFAULT.ADDNODEFN 10356 . 11093) (
DELETE/AND/DISPLAY/LINK 11095 . 12253) (DISPLAY/NAME 12255 . 12400) (DISPLAYGRAPH 12402 . 13906) (
DISPLAYLINK 13908 . 15942) (DISPLAYLINK/BT 15944 . 16904) (DISPLAYLINK/LR 16906 . 17867) (
DISPLAYLINK/RL 17869 . 18829) (DISPLAYLINK/TB 18831 . 19792) (EDITTOGGLEBORDER 19794 . 20907) (
ERASE/GRAPHNODE 20909 . 21750) (DISPLAYNODE 21752 . 22158) (DISPLAYNODELINKS 22160 . 23044) (
DRAW/GRAPHNODE/BORDER 23046 . 23887) (DRAWAREABOX 23889 . 25194) (EDITADDLINK 25196 . 25548) (
EDITADDNODE 25550 . 26338) (EDITAPPLYTOLINK 26340 . 27540) (EDITCHANGEFONT 27542 . 28342) (
EDITDELETELINK 28344 . 28704) (EDITDELETENODE 28706 . 30417) (EDITGRAPH 30419 . 31269) (EDITGRAPH1 
31271 . 32898) (EDITGRAPHMENU 32900 . 33508) (EDITMOVENODE 33510 . 35031) (EDITTOGGLELABEL 35033 . 
36141) (FLIPNODE 36143 . 36657) (FONTNAMELIST 36659 . 36912) (FROMLINKS 36914 . 37058) (GETNODEFROMID 
37060 . 37549) (GN/BOTTOM 37551 . 37785) (GN/LEFT 37787 . 38018) (GN/RIGHT 38020 . 38433) (GN/TOP 
38435 . 38899) (GRAPHADDLINK 38901 . 39402) (GRAPHADDNODE 39404 . 40016) (GRAPHDELETELINK 40018 . 
40764) (GRAPHDELETENODE 40766 . 41156) (GRAPHEDITCOMMANDFN 41158 . 42680) (GRAPHEDITEVENTFN 42682 . 
43343) (GRAPHER/CENTERPRINTINAREA 43345 . 44171) (GRAPHMOVENODE 44173 . 44669) (GRAPHNODE/BORDER/WIDTH
 44671 . 45180) (GRAPHREGION 45182 . 46025) (HARDCOPYGRAPH 46027 . 46507) (INTERSECT/REGIONP/LBWH 
46509 . 47041) (INVERTED/GRAPHNODE/BORDER 47043 . 47581) (INVERTED/SHADE/FOR/GRAPHER 47583 . 48216) (
LAYOUT/POSITION 48218 . 48371) (LINKPARAMETERS 48373 . 48771) (MANHATTANDIST 48773 . 49193) (MAX/RIGHT
 49195 . 49400) (MAX/TOP 49402 . 49603) (MEASUREGRAPHNODE 49605 . 49996) (MEMBTONODES 49998 . 50335) (
MIN/BOTTOM 50337 . 50657) (MIN/LEFT 50659 . 50973) (MOVENODE 50975 . 51884) (NODECREATE 51886 . 52449)
 (NODELST/AS/MENU 52451 . 53252) (NODEREGION 53254 . 53633) (PRINTDISPLAYNODE 53635 . 57047) (
FILL/GRAPHNODE/LABEL 57049 . 57814) (FIX/SCALE 57816 . 58297) (PROMPTINWINDOW 58299 . 60637) (
READ/NODE 60639 . 61382) (REDISPLAYGRAPH 61384 . 61844) (REMOVETONODES 61846 . 62251) (
RESET/NODE/BORDER 62253 . 63440) (RESET/NODE/LABELSHADE 63442 . 64161) (SCALE/GRAPH 64163 . 65206) (
SCALE/GRAPHNODE/BORDER 65208 . 65812) (SCALE/TONODES 65814 . 66355) (SET/LABEL/SIZE 66357 . 68401) (
SET/LAYOUT/POSITION 68403 . 68836) (SHOWGRAPH 68838 . 70870) (SIZE/GRAPH/WINDOW 70872 . 72559) (
TOGGLE/DIRECTEDFLG 72561 . 73133) (TOGGLE/SIDESFLG 73135 . 73748) (TOLINKS 73750 . 73890) (TRACKCURSOR
 73892 . 74957) (TRACKNODE 74959 . 75505)) (75567 77808 (NEXTSIZEFONT 75577 . 76681) (
DECREASING.FONT.LIST 76683 . 77103) (SCALE.FONT 77105 . 77806)) (78026 110316 (BRH/LAYOUT 78036 . 
79518) (BRH/LAYOUT/DAUGHTERS 79520 . 80305) (BRH/OFFSET 80307 . 80706) (BRHC/INTERTREE/SPACE 80708 . 
81956) (BRHC/LAYOUT 81958 . 83545) (BRHC/LAYOUT/DAUGHTERS 83547 . 86052) (BRHC/LAYOUT/TERMINAL 86054
 . 86699) (BRHC/OFFSET 86701 . 87437) (BRHL/LAYOUT 87439 . 89182) (BRHL/LAYOUT/DAUGHTERS 89184 . 90542
) (BRHL/MOVE/RIGHT 90544 . 91448) (BROWSE/LAYOUT/HORIZ 91450 . 91998) (BROWSE/LAYOUT/HORIZ/COMPACTLY 
92000 . 94017) (BROWSE/LAYOUT/LATTICE 94019 . 94685) (BRV/OFFSET 94687 . 95521) (
EXTEND/TRANSITION/CHAIN 95523 . 96690) (FOREST/BREAK/CYCLES 96692 . 97454) (INIT/NODES/FOR/LAYOUT 
97456 . 98421) (INTERPRET/MARK/FORMAT 98423 . 99714) (LATTICE/BREAK/CYCLES 99716 . 100344) (
LAYOUTFOREST 100346 . 100786) (LAYOUTGRAPH 100788 . 103751) (LAYOUTLATTICE 103753 . 105041) (
LAYOUTSEXPR 105043 . 105711) (LAYOUTSEXPR1 105713 . 106303) (MARK/GRAPH/NODE 106305 . 106915) (
NEW/INSTANCE/OF/GRAPHNODE 106917 . 107994) (RAISE/TRANSITION/CHAIN 107996 . 108444) (
REFLECT/GRAPH/DIAGONALLY 108446 . 108980) (REFLECT/GRAPH/HORIZONTALLY 108982 . 109510) (
REFLECT/GRAPH/VERTICALLY 109512 . 110056) (SWITCH/NODE/HEIGHT/WIDTH 110058 . 110314)) (111660 112979 (
GRAPHERCOPYBUTTONEVENTFN 111670 . 112130) (GRAPHOBJ.FINDGRAPH 112132 . 112977)) (112980 114649 (
ALIGNMENTNODE 112990 . 113709) (GRAPHOBJ.CHECKALIGN 113711 . 114647)) (114650 123705 (GRAPHEROBJ 
114660 . 116097) (GRAPHOBJ.BUTTONEVENTINFN 116099 . 116866) (GRAPHOBJ.COPYFN 116868 . 117251) (
GRAPHOBJ.DISPLAYFN 117253 . 119062) (GRAPHOBJ.GETALIGN 119064 . 119563) (GRAPHOBJ.GETFN 119565 . 
120304) (GRAPHOBJ.IMAGEBOXFN 120306 . 122438) (GRAPHOBJ.PUTALIGN 122440 . 123024) (GRAPHOBJ.PUTFN 
123026 . 123703)) (123706 134368 (COPYGRAPH 123716 . 124109) (DUMPGRAPH 124111 . 129892) (READGRAPH 
129894 . 134366)))))
STOP