(FILECREATED "18-Mar-86 15:43:29" {INDIGO}<GSLWS>KOTO>LIBRARY>EQUATIONFORMS.;3 84800  

      changes to:  (FNS EQ.Root)
		   (VARS EQUATIONFORMSCOMS)

      previous date: " 6-Mar-86 16:39:42" {INDIGO}<GSLWS>KOTO>LIBRARY>EQUATIONFORMS.;1)


(* Copyright (c) 1986 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT EQUATIONFORMSCOMS)

(RPAQQ EQUATIONFORMSCOMS ((* * ATTACHEDBOX module: Part 1 of 5)
	(* Utility functions to manipulate attached regions)
	(* These functions use two sets of coords: global coords in which positions are given w.r.t. 
	   the lower left corner of a box, and side coords in which positions are given w.r.t. a 
	   particular side of the box. For the side coords, the origin is at the point on the side 
	   closest to the l.l. corner of the box, the x-axis points along the side toward the other 
	   end, and the y-axis points away from the box region)
	(FNS AB.RealPosition AB.PointPos AB.SidePosition AB.PlaceRegion AB.AdjustToLL AB.OppositeSide 
	     AB.RegionToBox AB.BoxToRegion AB.RelativePos AB.BiggerRegion AB.Check AB.PositionRegion 
	     AB.Position2Regions)
	(* * EQGROUP module: Part 2 of 5)
	(* group equation functions)
	(FNS EQ.Group EQ.GroupCreate EQ.Make.group)
	(* set up data definitions)
	(P (EQIO.AddType (QUOTE group)
			 (QUOTE EQ.Group)
			 1
			 (QUOTE (objectProps (enclosureKind NIL enclosureSide NIL)
					     pieceNames
					     ("item")
					     wholeEditFn EQ.EnclosureEdit initialPropFn 
					     EQ.GroupCreate))))
	(* * specific enclosure data)
	(RECORDS EQ.EnclosureData)
	(FNS EQ.AddEnclosure EQ.GetEnclosureData)
	(* set up data for enclosures)
	(P (EQ.AddEnclosure (QUOTE angles)
			    (FUNCTION EQ.angles)
			    "< angle brackets >")
	   (EQ.AddEnclosure (QUOTE bars)
			    (FUNCTION EQ.bars)
			    "| bars |")
	   (EQ.AddEnclosure (QUOTE braces)
			    (FUNCTION EQ.braces)
			    "{ braces }")
	   (EQ.AddEnclosure (QUOTE brackets)
			    (FUNCTION EQ.brackets)
			    "[ brackets ]")
	   (EQ.AddEnclosure (QUOTE parentheses)
			    (FUNCTION EQ.parentheses)
			    "( parentheses )")
	   (EQIO.TypeProp (QUOTE group)
			  (QUOTE defaultEnclosure)
			  (QUOTE brackets)))
	(* * general enclosure functions)
	(FNS EQ.enclosure EQ.EnclosureCreate EQ.EnclosureEdit EQ.EnclosureKind EQ.EnclosureSide)
	(* * enclosure form functions)
	(FNS EQ.angles EQ.bars EQ.braces EQ.brackets EQ.parentheses EQ.enclosureForm 
	     EQ.enclosureWidth)
	(* * enclosure drawing functions)
	(FNS EQ.DrawAngles EQ.DrawBars EQ.DrawBraces EQ.DrawBrackets EQ.DrawParentheses)
	(* * EQMATRIX module: Part 3 of 5)
	(* matrix equation functions)
	(FNS EQ.Matrix EQ.Make.matrix EQ.layout EQ.MatrixAdd EQ.MatrixChanged EQ.MatrixCreate 
	     EQ.MatrixDelete EQ.MatrixEdit EQ.MatrixGetMenu EQ.MatrixSelect)
	(INITVARS (EQ.Matrix.MaxPieces 100))
	(GLOBALVARS EQ.Matrix.MaxPieces)
	(P (EQIO.AddType (QUOTE matrix)
			 (QUOTE EQ.Matrix)
			 1
			 (QUOTE (objectProps (rows 1 columns 1 enclosureKind NIL enclosureSide NIL)
					     variable? T wholeEditFn EQ.MatrixEdit specialSelectFn 
					     EQ.MatrixSelect initialPropFn EQ.MatrixCreate changeFn 
					     EQ.MatrixChanged))))
	(* * EQNFORMS module: Part 4 of 5)
	(* fraction)
	(FNS EQ.Fraction EQ.Make.fraction)
	(* * sum group)
	(FNS EQ.SumGroup EQ.Make.sum EQ.Make.product EQ.Make.union EQ.Make.intersection)
	(* * integral group)
	(FNS EQ.IntegralGroup EQ.Make.integral EQ.Make.lineIntegral)
	(* * super- and sub- scripts)
	(FNS EQ.Script EQ.Make.sub/superscripts)
	(* * max/min/limit etc)
	(FNS EQ.MaxMin EQ.Make.max/min)
	(* * utilities)
	(FNS EQ.StreamSize EQ.UseNS?)
	(GLOBALVARS EQ.UseNSChars)
	(* EQ.UseNSChars = NIL to use press fonts for display)
	(INITVARS EQ.UseNSChars)
	(P (EQIO.AddType (QUOTE fraction)
			 (QUOTE EQ.Fraction)
			 2
			 (QUOTE (pieceNames ("numerator" "denominator"))))
	   (EQIO.AddType (QUOTE sum)
			 (QUOTE EQ.SumGroup)
			 3
			 (QUOTE (initialData (-2 -2 0)
					     pieceNames
					     ("index" "limit" "summand"))))
	   (EQIO.AddType (QUOTE product)
			 (QUOTE EQ.SumGroup)
			 3
			 (QUOTE (initialData (-2 -2 0)
					     pieceNames
					     ("index" "limit" "factor"))))
	   (EQIO.AddType (QUOTE union)
			 (QUOTE EQ.SumGroup)
			 3
			 (QUOTE (initialData (-2 -2 0)
					     pieceNames
					     ("index" "limit" "set"))))
	   (EQIO.AddType (QUOTE intersection)
			 (QUOTE EQ.SumGroup)
			 3
			 (QUOTE (initialData (-2 -2 0)
					     pieceNames
					     ("index" "limit" "set"))))
	   (EQIO.AddType (QUOTE integral)
			 (QUOTE EQ.IntegralGroup)
			 3
			 (QUOTE (initialData (-2 -2 0)
					     pieceNames
					     ("lower limit" "upper limit" "integrand"))))
	   (EQIO.AddType (QUOTE lineIntegral)
			 (QUOTE EQ.IntegralGroup)
			 3
			 (QUOTE (initialData (-2 -2 0)
					     pieceNames
					     ("lower limit" "upper limit" "integrand")
					     menuLabel "line integral")))
	   (EQIO.AddType (QUOTE sub/superscripts)
			 (QUOTE EQ.Script)
			 5
			 (QUOTE (initialData (0 -1 -1 -1 -1)
					     pieceNames
					     ("main value" "right subscript" "right superscript" 
							   "left subscript"
							   "left superscript"))))
	   (EQIO.AddType (QUOTE max/min)
			 (QUOTE EQ.MaxMin)
			 3
			 (QUOTE (initialData (0 -2 0)
					     pieceNames
					     ("function" "index" "value")
					     menuLabel "max min limit"))))
	(* * EQROOT module: Part 5 of 5)
	(FNS EQ.Root EQ.Make.root)
	(FNS EQ.DrawRadicalSign)
	(P (EQIO.AddType (QUOTE root)
			 (QUOTE EQ.Root)
			 2
			 (QUOTE (pieceNames ("radicand" "index")
					    initialData
					    (0 -1)))))))
(* * ATTACHEDBOX module: Part 1 of 5)




(* Utility functions to manipulate attached regions)




(* These functions use two sets of coords: global coords in which positions are given w.r.t. 
the lower left corner of a box, and side coords in which positions are given w.r.t. a 
particular side of the box. For the side coords, the origin is at the point on the side closest
 to the l.l. corner of the box, the x-axis points along the side toward the other end, and the 
y-axis points away from the box region)

(DEFINEQ

(AB.RealPosition
  (LAMBDA (pos box side)                                     (* THH " 8-May-85 11:31")
                                                             (* returns position of pt. relative to l.l.
							     corner of box given position relative to specified 
							     side of box)
    (SELECTQ side
	       ((top bottom)
		 (create POSITION
			   XCOORD ←(fetch XCOORD of pos)
			   YCOORD ←(COND
			     ((EQ side (QUOTE top))
			       (PLUS (fetch YSIZE of box)
				       (fetch YCOORD of pos)))
			     (T (MINUS (fetch YCOORD of pos))))))
	       ((left right)
		 (create POSITION
			   YCOORD ←(fetch XCOORD of pos)
			   XCOORD ←(COND
			     ((EQ side (QUOTE right))
			       (PLUS (fetch XSIZE of box)
				       (fetch YCOORD of pos)))
			     (T (MINUS (fetch YCOORD of pos))))))
	       NIL)))

(AB.PointPos
  (LAMBDA (box side pt)                                      (* THH " 8-May-85 11:34")
                                                             (* returns position of pt relative to side -- pt is an
							     atom specifying relative position along the side)
    (PROG ((horizSide (OR (EQ side (QUOTE top))
			      (EQ side (QUOTE bottom)))))
	    (RETURN (create POSITION
				XCOORD ←(SELECTQ pt
						   (low      (* lower end of side)
							0)
						   (display 
                                                             (* display pt of side)
							    (COND
							      (horizSide 0)
							      (T (fetch YDESC of box))))
						   (center 
                                                             (* center of side)
							   (IQUOTIENT (COND
									  (horizSide (fetch XSIZE
											of box))
									  (T (fetch YSIZE
										of box)))
									2))
						   (high     (* upper end of side)
							 (COND
							   (horizSide (fetch XSIZE of box))
							   (T (fetch YSIZE of box))))
						   NIL)
				YCOORD ← 0)))))

(AB.SidePosition
  (LAMBDA (pos box side)                                     (* THH " 8-May-85 11:32")
                                                             (* returns position of pt rel.
							     to side given position rel.
							     to l.l. corner of box)
    (SELECTQ side
	       ((top bottom)
		 (create POSITION
			   XCOORD ←(fetch XCOORD of pos)
			   YCOORD ←(COND
			     ((EQ side (QUOTE top))
			       (DIFFERENCE (fetch YCOORD of pos)
					     (fetch YSIZE of box)))
			     (T (MINUS (fetch YCOORD of pos))))))
	       ((left right)
		 (create POSITION
			   XCOORD ←(fetch YCOORD of pos)
			   YCOORD ←(COND
			     ((EQ side (QUOTE right))
			       (DIFFERENCE (fetch XCOORD of pos)
					     (fetch XSIZE of box)))
			     (T (MINUS (fetch XCOORD of pos))))))
	       NIL)))

(AB.PlaceRegion
  (LAMBDA (mainBox side mainPt addBox addPt gap shift)       (* THH "10-May-85 16:51")
                                                             (* returns placed region relative to l.l.
							     corner of main box when addBox is placed as specified)
    (PROG ((posMainPt (AB.PointPos mainBox side mainPt))
	     (opposite (AB.OppositeSide side))
	     posAddPt posSide)
	    (SETQ posAddPt (create POSITION
				       XCOORD ←(PLUS (fetch XCOORD of posMainPt)
						       shift)
				       YCOORD ←(PLUS (fetch YCOORD of posMainPt)
						       gap)))
	    (SETQ posSide (AB.PointPos addBox opposite addPt))
	    (replace XCOORD of posSide with (DIFFERENCE (fetch XCOORD of posAddPt)
								(fetch XCOORD of posSide)))
	    (replace YCOORD of posSide with (fetch YCOORD of posAddPt))
	    (SETQ posSide (AB.AdjustToLL (AB.RealPosition posSide mainBox side)
					     addBox side))
	    (RETURN (create REGION
				LEFT ←(fetch XCOORD of posSide)
				BOTTOM ←(fetch YCOORD of posSide)
				WIDTH ←(fetch XSIZE of addBox)
				HEIGHT ←(fetch YSIZE of addBox))))))

(AB.AdjustToLL
  (LAMBDA (pos addBox side)                                  (* THH "10-May-85 14:58")
                                                             (* gets position of l.l. corner of addBox w.r.t.
							     l.l of main box given pos of side opposite side of 
							     main box)
    (SELECTQ side
	       ((top right)
		 NIL)
	       (left (replace XCOORD of pos with (DIFFERENCE (fetch XCOORD of pos)
								     (fetch XSIZE of addBox))))
	       (bottom (replace YCOORD of pos with (DIFFERENCE (fetch YCOORD of pos)
								       (fetch YSIZE of addBox))))
	       NIL)
    pos))

(AB.OppositeSide
  (LAMBDA (side)                                             (* THH " 8-May-85 14:11")
    (SELECTQ side
	       (top (QUOTE bottom))
	       (bottom (QUOTE top))
	       (left (QUOTE right))
	       (right (QUOTE left))
	       NIL)))

(AB.RegionToBox
  (LAMBDA (region displayYPos)                               (* thh: "13-May-85 10:16")
                                                             (* returns image box corresponding to region whose y 
							     display position, relative to 
							     (0,0) is given by displayYPos)
    (COND
      ((NOT displayYPos)
	(SETQ displayYPos 0)))
    (create IMAGEBOX
	      XSIZE ←(fetch WIDTH of region)
	      YSIZE ←(fetch HEIGHT of region)
	      YDESC ←(DIFFERENCE displayYPos (fetch BOTTOM of region))
	      XKERN ← 0)))

(AB.BoxToRegion
  (LAMBDA (box cornerXPos cornerYPos)                        (* thh: "13-May-85 09:54")

          (* returns region corresponding to image box whose l.l. corner is positioned at cornerXPos, cornerYPos -- if 
	  cornerYPos is NIL then cornerXPos should be a position)


    (COND
      ((NOT cornerYPos)
	(SETQ cornerYPos cornerXPos:YCOORD)
	(SETQ cornerXPos cornerXPos:XCOORD)))
    (create REGION
	      LEFT ← cornerXPos
	      BOTTOM ← cornerYPos
	      WIDTH ←(fetch XSIZE of box)
	      HEIGHT ←(fetch YSIZE of box))))

(AB.RelativePos
  (LAMBDA (region bigRegion yShift)                          (* thh: "13-May-85 10:27")
                                                             (* returns relative position of l.l.
							     of region w.r.t. l.l. of bigRegion)
    (create POSITION
	      XCOORD ←(DIFFERENCE (fetch LEFT of region)
				    (fetch LEFT of bigRegion))
	      YCOORD ←(PLUS (DIFFERENCE (fetch BOTTOM of region)
					    (fetch BOTTOM of bigRegion))
			      yShift))))

(AB.BiggerRegion
  (LAMBDA (region extra)                                     (* THH "23-May-85 14:03")
                                                             (* creates a region that has extra space all around)
                                                             (* extra should be nonnegative)
    (COND
      ((OR (NOT extra)
	     (ZEROP extra))
	region)
      (T (create REGION
		   LEFT ←(DIFFERENCE (fetch LEFT of region)
				       extra)
		   BOTTOM ←(DIFFERENCE (fetch BOTTOM of region)
					 extra)
		   WIDTH ←(PLUS (fetch WIDTH of region)
				  (TIMES 2 extra))
		   HEIGHT ←(PLUS (fetch HEIGHT of region)
				   (TIMES 2 extra)))))))

(AB.Check
  (LAMBDA (region regionList side clear)                     (* THH "23-May-85 14:02")
                                                             (* moves region away from side if it overlaps any 
							     regions in regionList)
    (COND
      ((NOT clear)
	(SETQ clear 0)))
    (COND
      ((GREATERP clear 0)
	(SETQ regionList (for r in regionList collect (AB.BiggerRegion r clear)))))
                                                             (* must go through list repeatedly since moving region
							     could cause it to overlap previous regions)
    (repeatwhile overlap bind overlap
       do (SETQ overlap NIL)
	    (for r in regionList do (COND
					    ((REGIONSINTERSECTP region r)
					      (SETQ overlap T)
					      (SELECTQ side
							 (top (replace BOTTOM of region
								 with (PLUS (fetch BOTTOM
										   of r)
										(fetch HEIGHT
										   of r))))
							 (bottom (replace BOTTOM of region
								    with (DIFFERENCE
									     (fetch BOTTOM
										of r)
									     (fetch HEIGHT
										of region))))
							 (left (replace LEFT of region
								  with (DIFFERENCE (fetch
											 LEFT
											  of r)
										       (fetch
											 WIDTH
											  of region)
										       )))
							 (right (replace LEFT of region
								   with (PLUS (fetch LEFT
										     of r)
										  (fetch WIDTH
										     of r))))
							 (SHOULDNT))))))
    region))

(AB.PositionRegion
  (LAMBDA (mainBox addedRegions side mainPt addBox addPt gap shift clear)
                                                             (* thh: " 9-Jan-86 10:00")

          (* positions addBox next to side of mainBox so that addPt on the added box is at the specified relative position to
	  the mainPt on the main box, then moves addBox away from mainBox if necessary to avoid being within distance clear 
	  of added regions on other sides as specified in addedRegions. Returns (region newAddedRegions) where region is 
	  region of added box w.r.t. l.l. corner of mainBox and newAddedRegions includes this new box to prevent future 
	  additions from overlapping it)


    (PROG ((place (AB.Check (AB.PlaceRegion mainBox side mainPt addBox addPt gap shift)
				addedRegions side clear)))
	    (RETURN (CONS place addedRegions)))))

(AB.Position2Regions
  (LAMBDA (mainBox addedRegions side highBox highPt lowBox lowPt highGap lowGap highShift lowShift 
		   clear)                                    (* thh: " 9-Jan-86 10:00")

          (* positions highBox and lowBox next to side on mainBox -- moves the boxes apart if they are closer than clear 
	  apart, and moves them away from mainBox if they overlap previous regions as specfied by addedRegions)

                                                             (* returns (highRegion lowRegion newAddedRegions) 
							     where regions are w.r.t. l.l.
							     corner of mainBox and newAddedRegions includes the 
							     added regions)
    (PROG (placeHigh placeLow)
	    (SETQ placeHigh (AB.PlaceRegion mainBox side (QUOTE high)
						highBox highPt highGap highShift))
	    (SETQ placeLow (AB.PlaceRegion mainBox side (QUOTE low)
					       lowBox lowPt lowGap lowShift))
	    (COND
	      ((NOT clear)
		(SETQ clear 0)))
	    (COND
	      ((REGIONSINTERSECTP placeHigh (AB.BiggerRegion placeLow clear))
                                                             (* move regions apart)
		(PROG (shift totalSize)                    (* if the two added regions overlap then separate 
							     them)
		        (SELECTQ side
				   ((top bottom)
				     (SETQ shift (DIFFERENCE (PLUS (fetch LEFT of placeLow)
									 (fetch WIDTH of placeLow)
									 clear)
								 (fetch LEFT of placeHigh)))
				     (COND
				       ((GREATERP shift 0)
					 (SETQ totalSize (PLUS (fetch WIDTH of placeLow)
								   (fetch WIDTH of placeHigh)))
					 (add (fetch LEFT of placeLow)
						(MINUS (FIX (PLUS .5
									(FQUOTIENT
									  (TIMES shift
										   (fetch WIDTH
										      of placeLow))
									  totalSize)))))
					 (add (fetch LEFT of placeHigh)
						(FIX (PLUS .5
							       (FQUOTIENT (TIMES shift
										     (fetch WIDTH
											of 
											placeHigh))
									    totalSize)))))))
				   ((left right)
				     (SETQ shift (DIFFERENCE (PLUS (fetch BOTTOM
									    of placeLow)
									 (fetch HEIGHT
									    of placeLow)
									 clear)
								 (fetch BOTTOM of placeHigh)))
				     (COND
				       ((GREATERP shift 0)
					 (SETQ totalSize (PLUS (fetch HEIGHT of placeLow)
								   (fetch HEIGHT of placeHigh)))
					 (add (fetch BOTTOM of placeLow)
						(MINUS (FIX (PLUS .5
									(FQUOTIENT
									  (TIMES shift
										   (fetch HEIGHT
										      of placeLow))
									  totalSize)))))
					 (add (fetch BOTTOM of placeHigh)
						(FIX (PLUS .5
							       (FQUOTIENT (TIMES shift
										     (fetch HEIGHT
											of 
											placeHigh))
									    totalSize)))))))
				   (SHOULDNT)))))
	    (SETQ placeLow (AB.Check placeLow addedRegions side clear))
	    (SETQ placeHigh (AB.Check placeHigh addedRegions side clear))
	    (RETURN (CONS placeHigh (CONS placeLow addedRegions))))))
)
(* * EQGROUP module: Part 2 of 5)




(* group equation functions)

(DEFINEQ

(EQ.Group
  (LAMBDA (eqnObj imageStream draw?)                         (* THH "12-Jul-85 08:24")
                                                             (* form function for group -- one argument with 
							     enclosure)
    (LET ((innerBox (FS.Box (EQIO.EqnData eqnObj 1)
			      imageStream))
	  enclose pos)
         (SETQ enclose (EQ.enclosure innerBox eqnObj imageStream draw?))
         (SETQ pos (CDR enclose))
         (add (fetch YCOORD of pos)
		(fetch YDESC of innerBox))
         (EQIO.MakeSpec (CAR enclose)
			  (LIST (EQIO.MakeDataSpec pos))))))

(EQ.GroupCreate
  (LAMBDA NIL                                                (* thh: " 1-Jul-85 14:57")
    (EQ.EnclosureCreate T)))

(EQ.Make.group
  (LAMBDA (data enclosureKind enclosureSide fontSpec)        (* thh: " 9-Jan-86 10:24")
    (EQN.Make (QUOTE group)
		(LIST data)
		fontSpec
		(LIST (QUOTE enclosureKind)
			enclosureKind
			(QUOTE enclosureSide)
			enclosureSide))))
)



(* set up data definitions)

(EQIO.AddType (QUOTE group)
	      (QUOTE EQ.Group)
	      1
	      (QUOTE (objectProps (enclosureKind NIL enclosureSide NIL)
				  pieceNames
				  ("item")
				  wholeEditFn EQ.EnclosureEdit initialPropFn EQ.GroupCreate)))
(* * specific enclosure data)

[DECLARE: EVAL@COMPILE 

(RECORD EQ.EnclosureData (formFn label))
]
(DEFINEQ

(EQ.AddEnclosure
  (LAMBDA (kind formFn label)                                (* THH "12-Jul-85 08:18")
                                                             (* adds data for new form of enclosure)
    (LET ((enclosures (EQIO.TypeProp (QUOTE group)
				       (QUOTE enclosures)))
	  (newValue (create EQ.EnclosureData
			      formFn ← formFn
			      label ← label)))
         (COND
	   (enclosures (LISTPUT enclosures kind newValue))
	   (T (SETQ enclosures (LIST kind newValue))))
         (EQIO.TypeProp (QUOTE group)
			  (QUOTE enclosures)
			  enclosures)
         (EQIO.TypeProp (QUOTE group)
			  (QUOTE kindMenu)
			  NIL))))

(EQ.GetEnclosureData
  (LAMBDA (kind)                                             (* THH "12-Jul-85 08:19")
    (LISTGET (EQIO.TypeProp (QUOTE group)
				(QUOTE enclosures))
	       kind)))
)



(* set up data for enclosures)

(EQ.AddEnclosure (QUOTE angles)
		 (FUNCTION EQ.angles)
		 "< angle brackets >")
(EQ.AddEnclosure (QUOTE bars)
		 (FUNCTION EQ.bars)
		 "| bars |")
(EQ.AddEnclosure (QUOTE braces)
		 (FUNCTION EQ.braces)
		 "{ braces }")
(EQ.AddEnclosure (QUOTE brackets)
		 (FUNCTION EQ.brackets)
		 "[ brackets ]")
(EQ.AddEnclosure (QUOTE parentheses)
		 (FUNCTION EQ.parentheses)
		 "( parentheses )")
(EQIO.TypeProp (QUOTE group)
	       (QUOTE defaultEnclosure)
	       (QUOTE brackets))
(* * general enclosure functions)

(DEFINEQ

(EQ.enclosure
  (LAMBDA (innerBox eqnObj imageStream draw?)                (* THH "12-Jul-85 08:32")

          (* returns (outerBox . pos) where outerBox is box with enclosures and pos is position of l.l.
	  corner of inner box wrt l.l. corner of outer box)

                                                             (* if draw? is non-NIL, draws the enclosures)
    (LET ((kind (OR (EQIO.EqnProperty eqnObj (QUOTE enclosureKind))
		      (EQIO.TypeProp (QUOTE group)
				       (QUOTE defaultEnclosure))))
	  (which (EQIO.EqnProperty eqnObj (QUOTE enclosureSide))))
         (COND
	   ((NOT (OR (EQ which (QUOTE left))
			 (EQ which (QUOTE right))))
	     (SETQ which NIL)))
         (LET ((formFn (fetch (EQ.EnclosureData formFn) of (EQ.GetEnclosureData kind))))
	      (COND
		(formFn                                      (* note: use of kind arg allows same formFn to be used
							     for different enclosures)
			(APPLY* formFn innerBox imageStream draw? which kind))
		(T                                           (* no enclosure so outer box is same as inner box)
		   (CONS innerBox (create POSITION
					      XCOORD ← 0
					      YCOORD ← 0))))))))

(EQ.EnclosureCreate
  (LAMBDA (getWhich?)                                        (* thh: " 1-Jul-85 14:46")
                                                             (* returns prop list describing desired enclosure)
                                                             (* if getWhich? is non-NIL also asks for side 
							     specification for enclosure)
    (LET ((kind (EQ.EnclosureKind))
	  which)
         (COND
	   (getWhich? (SETQ which (EQ.EnclosureSide))
		      (LIST (QUOTE enclosureKind)
			      kind
			      (QUOTE enclosureSide)
			      which))
	   (T (LIST (QUOTE enclosureKind)
		      kind))))))

(EQ.EnclosureEdit
  (LAMBDA (eqnObj)                                           (* thh: " 1-Jul-85 14:55")
                                                             (* allows type of enclosure to be changed)
                                                             (* returns non-NIL if object changed)
    (LET ((editMenu (EQIO.TypeProp (QUOTE group)
				     (QUOTE editMenu)))
	  newValue)
         (COND
	   ((NOT (type? MENU editMenu))
	     (SETQ editMenu (create MENU
					CENTERFLG ← T
					TITLE ← "change what?"
					ITEMS ←(QUOTE (("symbol" (QUOTE kind))
							  ("which side" (QUOTE side))))))
	     (EQIO.TypeProp (QUOTE group)
			      (QUOTE editMenu)
			      editMenu)))
         (SELECTQ (MENU editMenu)
		    (kind (COND
			    ((SETQ newValue (EQ.EnclosureKind))
			      (EQIO.EqnProperty eqnObj (QUOTE enclosureKind)
						  newValue)
			      T)
			    (T NIL)))
		    (side (COND
			    ((SETQ newValue (EQ.EnclosureSide))
			      (EQIO.EqnProperty eqnObj (QUOTE enclosureSide)
						  newValue)
			      T)
			    (T NIL)))
		    NIL))))

(EQ.EnclosureKind
  (LAMBDA NIL                                                (* THH "12-Jul-85 08:39")
                                                             (* gets desired kind of enclosure)
    (LET ((kindMenu (EQIO.TypeProp (QUOTE group)
				     (QUOTE kindMenu))))
         (COND
	   ((NOT (type? MENU kindMenu))
	     (SETQ kindMenu (create MENU
					CENTERFLG ← T
					ITEMS ←(LET ((enclosures (EQIO.TypeProp (QUOTE group)
										  (QUOTE enclosures)
										  )))
						    (while enclosures bind kind data
						       collect (SETQ kind (CAR enclosures))
								 (SETQ data (CADR enclosures))
								 (SETQ enclosures (CDDR 
										       enclosures))
								 (LIST (fetch (EQ.EnclosureData
										    label)
									    of data)
									 (KWOTE kind))))
					TITLE ← "enclosures"))
	     (EQIO.TypeProp (QUOTE group)
			      (QUOTE kindMenu)
			      kindMenu)))
         (MENU kindMenu))))

(EQ.EnclosureSide
  (LAMBDA NIL                                                (* thh: " 1-Jul-85 14:48")
                                                             (* gets desired side for enclosure)
    (LET ((whichMenu (EQIO.TypeProp (QUOTE group)
				      (QUOTE whichMenu))))
         (COND
	   ((NOT (type? MENU whichMenu))
	     (SETQ whichMenu (create MENU
					 ITEMS ←(QUOTE (left right both))
					 TITLE ← "Which side?"))
	     (EQIO.TypeProp (QUOTE group)
			      (QUOTE whichMenu)
			      whichMenu)))
         (MENU whichMenu))))
)
(* * enclosure form functions)

(DEFINEQ

(EQ.angles
  (LAMBDA (innerBox imageStream draw? which)                 (* thh: "19-Aug-85 10:05")
    (LET ((size (EQ.StreamSize imageStream))
	  Hgap Hex Vgap Vex width height descent spacing overlap)
         (SETQ Hex size)
         (SETQ Vgap size)
         (SETQ Vex Hex)
         (SETQ height (PLUS (fetch YSIZE of innerBox)
				(TIMES 2 Vgap)))
         (SETQ width (EQ.enclosureWidth size height))
         (SETQ Hgap (MAX (TIMES 3 size)
			     (IQUOTIENT height 5)))
         (SETQ spacing (PLUS (fetch XSIZE of innerBox)
				 (TIMES 2 (PLUS Hgap width))))
         (SETQ descent (PLUS (fetch YDESC of innerBox)
				 Vgap))
         (SETQ overlap (MAX (TIMES 2 size)
				(IQUOTIENT (PLUS Hgap width)
					     2)))

          (* * draw angle brackets if requested)


         (COND
	   (draw? (EQ.DrawAngles height descent spacing Hex width overlap imageStream which)))

          (* * determine outer box and position of inner box)


         (EQ.enclosureForm spacing Hex height Vex descent width NIL))))

(EQ.bars
  (LAMBDA (innerBox imageStream draw? which)                 (* THH "16-Jul-85 09:16")
    (LET ((size (EQ.StreamSize imageStream))
	  Hgap Hex Vgap Vex width height descent spacing)
         (SETQ Hgap (TIMES 2 size))
         (SETQ Hex size)
         (SETQ Vgap Hgap)
         (SETQ Vex Hex)
         (SETQ height (PLUS (fetch YSIZE of innerBox)
				(TIMES 2 Vgap)))
         (SETQ width (EQ.enclosureWidth size height))
         (SETQ spacing (PLUS (fetch XSIZE of innerBox)
				 (TIMES 2 (PLUS Hgap width))))
         (SETQ descent (PLUS (fetch YDESC of innerBox)
				 Vgap))

          (* * draw bars if requested)


         (COND
	   (draw? (EQ.DrawBars height descent spacing Hex width imageStream which)))

          (* * determine outer box and position of inner box)


         (EQ.enclosureForm spacing Hex height Vex descent width NIL))))

(EQ.braces
  (LAMBDA (innerBox imageStream draw? which)                 (* THH "16-Jul-85 09:46")
    (LET ((size (EQ.StreamSize imageStream))
	  Hgap Hex Vgap Vex width height descent spacing overlap point space extra)
         (SETQ Vgap (TIMES 3 size))
         (SETQ Hex size)
         (SETQ Vex Hex)
         (SETQ height (PLUS (fetch YSIZE of innerBox)
				(TIMES 2 Vgap)))
         (SETQ width (EQ.enclosureWidth size height))
         (add height (TIMES 2 width))
         (SETQ descent (PLUS (fetch YDESC of innerBox)
				 Vgap width))
         (SETQ Hgap (MAX (TIMES 4 size)
			     (IQUOTIENT height 5)))
         (SETQ spacing (PLUS (fetch XSIZE of innerBox)
				 (TIMES 2 (PLUS Hgap width))))
         (SETQ overlap (PLUS Hgap width))
         (SETQ point (PLUS size (IQUOTIENT overlap 2)))
         (SETQ space (IQUOTIENT overlap 2))
         (SETQ extra space)

          (* * draw braces if requested)


         (COND
	   (draw? (EQ.DrawBraces height descent spacing Hex width overlap extra point space 
				   imageStream which)))

          (* * determine outer box and position of inner box)


         (EQ.enclosureForm spacing Hex height Vex descent width T))))

(EQ.brackets
  (LAMBDA (innerBox imageStream draw? which)                 (* thh: "19-Aug-85 09:52")
    (LET ((size (EQ.StreamSize imageStream))
	  Hgap Hex Vgap Vex width height descent spacing overlap)
         (SETQ Hgap (TIMES 3 size))
         (SETQ Hex size)
         (SETQ Vgap Hgap)
         (SETQ Vex Hex)
         (SETQ height (PLUS (fetch YSIZE of innerBox)
				(TIMES 2 Vgap)))
         (SETQ width (EQ.enclosureWidth size height))
         (add height (TIMES 2 width))
         (SETQ spacing (PLUS (fetch XSIZE of innerBox)
				 (TIMES 2 (PLUS Hgap width))))
         (SETQ descent (PLUS (fetch YDESC of innerBox)
				 Vgap width))
         (SETQ overlap (MAX (TIMES 3 size)
				(PLUS Hgap width)))

          (* * draw bars if requested)


         (COND
	   (draw? (EQ.DrawBrackets height descent spacing Hex width overlap imageStream which)))

          (* * determine outer box and position of inner box)


         (EQ.enclosureForm spacing Hex height Vex descent width T))))

(EQ.parentheses
  (LAMBDA (innerBox imageStream draw? which)                 (* thh: "19-Aug-85 10:06")
    (LET ((size (EQ.StreamSize imageStream))
	  Hgap Hex Vgap Vex width height descent spacing overlap)
         (SETQ Vgap (TIMES 2 size))
         (SETQ Hex size)
         (SETQ Vex Hex)
         (SETQ height (PLUS (fetch YSIZE of innerBox)
				(TIMES 2 Vgap)))
         (SETQ width (EQ.enclosureWidth size height))
         (add height (TIMES 2 width))
         (SETQ descent (PLUS (fetch YDESC of innerBox)
				 Vgap width))
         (SETQ Hgap (MAX (TIMES 2 size)
			     (IQUOTIENT height 8)))
         (SETQ spacing (PLUS (fetch XSIZE of innerBox)
				 (TIMES 2 (PLUS Hgap width))))
         (SETQ overlap (MAX (TIMES 3 size)
				(IQUOTIENT (PLUS Hgap width)
					     2)))

          (* * draw braces if requested)


         (COND
	   (draw? (EQ.DrawParentheses height descent spacing Hex width overlap imageStream which)))

          (* * determine outer box and position of inner box)


         (EQ.enclosureForm spacing Hex height Vex descent width T))))

(EQ.enclosureForm
  (LAMBDA (spacing Hex height Vex descent width verticalWidth?)
                                                             (* THH "12-Jul-85 08:49")
                                                             (* computes outer box and position of inner box from 
							     parameters -- verticalWidth? non-NIL means enclosure 
							     wraps under the box)
    (CONS (create IMAGEBOX
		      XSIZE ←(PLUS spacing (TIMES 2 Hex))
		      YSIZE ←(PLUS height (TIMES 2 Vex))
		      YDESC ←(PLUS descent Vex)
		      XKERN ← 0)
	    (create POSITION
		      XCOORD ←(PLUS Hgap width Hex)
		      YCOORD ←(PLUS Vgap (COND
					(verticalWidth? width)
					(T 0))
				      Vex)))))

(EQ.enclosureWidth
  (LAMBDA (size height)                                      (* THH "16-Jul-85 09:15")
    (MAX size (IQUOTIENT height 100))))
)
(* * enclosure drawing functions)

(DEFINEQ

(EQ.DrawAngles
  (LAMBDA (height descent spacing xShift width overlap imageStream which)
                                                             (* thh: "19-Aug-85 09:49")
                                                             (* draws specified angle brackets on imageStream)
    (LET ((halfWidth (IQUOTIENT width 2))
	  (halfWidth1 (IQUOTIENT (SUB1 width)
				   2))
	  (lowerX (PLUS (DSPXPOSITION NIL imageStream)
			  xShift))
	  (lowerY (DIFFERENCE (DSPYPOSITION NIL imageStream)
				descent))
	  top middle left right)
         (SETQ top (PLUS lowerY (SUB1 height)))
         (SETQ middle (PLUS lowerY (IQUOTIENT (SUB1 height)
						    2)))

          (* * left angle bracket)


         (COND
	   ((NOT (EQ which (QUOTE right)))
	     (SETQ left (PLUS lowerX overlap halfWidth))
	     (DRAWLINE left lowerY (PLUS lowerX halfWidth)
			 middle width NIL imageStream)
	     (DRAWLINE (PLUS lowerX halfWidth)
			 middle left top width NIL imageStream)))

          (* * right angle bracket)


         (COND
	   ((NOT (EQ which (QUOTE left)))
	     (SETQ right (PLUS lowerX (SUB1 spacing)
				   (MINUS (PLUS overlap halfWidth1))))
	     (DRAWLINE right lowerY (PLUS lowerX (SUB1 spacing)
					      (MINUS halfWidth1))
			 middle width NIL imageStream)
	     (DRAWLINE (PLUS lowerX (SUB1 spacing)
				 (MINUS halfWidth1))
			 middle right top width NIL imageStream))))))

(EQ.DrawBars
  (LAMBDA (height descent spacing xShift width imageStream which)
                                                             (* thh: "19-Aug-85 09:53")
                                                             (* draws specified vertical bar on imageStream)
    (PROG ((halfWidth (IQUOTIENT width 2))
	     (halfWidth1 (IQUOTIENT (SUB1 width)
				      2))
	     (lowerX (PLUS (DSPXPOSITION NIL imageStream)
			     xShift))
	     (lowerY (DIFFERENCE (DSPYPOSITION NIL imageStream)
				   descent)))

          (* * left bar)


	    (COND
	      ((NOT (EQ which (QUOTE right)))
		(MOVETO (PLUS lowerX halfWidth1)
			  lowerY imageStream)
		(RELDRAWTO 0 (SUB1 height)
			     width NIL imageStream)))

          (* * right bar)


	    (COND
	      ((NOT (EQ which (QUOTE left)))
		(MOVETO (DIFFERENCE (PLUS lowerX spacing)
					halfWidth)
			  lowerY imageStream)
		(RELDRAWTO 0 (SUB1 height)
			     width NIL imageStream))))))

(EQ.DrawBraces
  (LAMBDA (height descent spacing xShift width overlap extra point space imageStream which)
                                                             (* THH "16-Jul-85 09:20")
                                                             (* draws specified brace on imageStream)
    (LET ((halfWidth (IQUOTIENT width 2))
	  (halfWidth1 (IQUOTIENT (SUB1 width)
				   2))
	  (lowerX (PLUS (DSPXPOSITION NIL imageStream)
			  xShift))
	  (lowerY (DIFFERENCE (DSPYPOSITION NIL imageStream)
				descent))
	  top middle left1 left2 right1 right2)
         (SETQ top (PLUS lowerY (SUB1 height)))
         (SETQ middle (PLUS lowerY (IQUOTIENT (SUB1 height)
						    2)))

          (* * left brace)


         (COND
	   ((NOT (EQ which (QUOTE right)))
	     (SETQ left1 (PLUS lowerX (SUB1 overlap)))
	     (SETQ left2 (PLUS lowerX (SUB1 point)))
	     (DRAWCURVE (LIST (create POSITION
					    XCOORD ← left1
					    YCOORD ← lowerY)
				  (create POSITION
					    XCOORD ← left2
					    YCOORD ←(PLUS lowerY extra))
				  (create POSITION
					    XCOORD ← left2
					    YCOORD ←(DIFFERENCE middle (SUB1 space)))
				  (create POSITION
					    XCOORD ← lowerX
					    YCOORD ← middle))
			  NIL width NIL imageStream)
	     (DRAWCURVE (LIST (create POSITION
					    XCOORD ← lowerX
					    YCOORD ← middle)
				  (create POSITION
					    XCOORD ← left2
					    YCOORD ←(PLUS middle (SUB1 space)))
				  (create POSITION
					    XCOORD ← left2
					    YCOORD ←(DIFFERENCE top extra))
				  (create POSITION
					    XCOORD ← left1
					    YCOORD ← top))
			  NIL width NIL imageStream)))

          (* * right brace)


         (COND
	   ((NOT (EQ which (QUOTE left)))
	     (SETQ right1 (PLUS lowerX (SUB1 spacing)
				    (MINUS (SUB1 overlap))))
	     (SETQ right2 (PLUS lowerX (SUB1 spacing)
				    (MINUS (SUB1 point))))
	     (DRAWCURVE (LIST (create POSITION
					    XCOORD ← right1
					    YCOORD ← lowerY)
				  (create POSITION
					    XCOORD ← right2
					    YCOORD ←(PLUS lowerY extra))
				  (create POSITION
					    XCOORD ← right2
					    YCOORD ←(DIFFERENCE middle (SUB1 space)))
				  (create POSITION
					    XCOORD ←(PLUS lowerX (SUB1 spacing))
					    YCOORD ← middle))
			  NIL width NIL imageStream)
	     (DRAWCURVE (LIST (create POSITION
					    XCOORD ←(PLUS lowerX (SUB1 spacing))
					    YCOORD ← middle)
				  (create POSITION
					    XCOORD ← right2
					    YCOORD ←(PLUS middle (SUB1 space)))
				  (create POSITION
					    XCOORD ← right2
					    YCOORD ←(DIFFERENCE top extra))
				  (create POSITION
					    XCOORD ← right1
					    YCOORD ← top))
			  NIL width NIL imageStream))))))

(EQ.DrawBrackets
  (LAMBDA (height descent spacing xShift width overlap imageStream which)
                                                             (* THH "12-Jul-85 09:06")
                                                             (* draws specified bracket on imageStream)
    (PROG ((halfWidth (IQUOTIENT width 2))
	     (halfWidth1 (IQUOTIENT (SUB1 width)
				      2))
	     (lowerX (PLUS (DSPXPOSITION NIL imageStream)
			     xShift))
	     (lowerY (DIFFERENCE (DSPYPOSITION NIL imageStream)
				   descent)))

          (* * left bracket)


	    (COND
	      ((NOT (EQ which (QUOTE right)))
		(MOVETO (PLUS lowerX halfWidth1)
			  lowerY imageStream)
		(RELDRAWTO 0 (SUB1 height)
			     width NIL imageStream)
		(RELMOVETO 0 (MINUS halfWidth)
			     imageStream)
		(RELDRAWTO overlap 0 width NIL imageStream)
		(MOVETO (PLUS lowerX (SUB1 width))
			  (PLUS lowerY halfWidth1)
			  imageStream)
		(RELDRAWTO overlap 0 width NIL imageStream)))

          (* * right bracket)


	    (COND
	      ((NOT (EQ which (QUOTE left)))
		(MOVETO (DIFFERENCE (PLUS lowerX spacing)
					(PLUS overlap width))
			  (PLUS lowerY halfWidth1)
			  imageStream)
		(RELDRAWTO overlap 0 width NIL imageStream)
		(RELMOVETO halfWidth1 (MINUS halfWidth1)
			     imageStream)
		(RELDRAWTO 0 (SUB1 height)
			     width NIL imageStream)
		(RELMOVETO 0 (MINUS halfWidth)
			     imageStream)
		(RELDRAWTO (MINUS overlap)
			     0 width NIL imageStream))))))

(EQ.DrawParentheses
  (LAMBDA (height descent spacing xShift width overlap imageStream which)
                                                             (* THH "12-Jul-85 09:06")
                                                             (* draws specified parenthesis on imageStream)
    (LET ((halfWidth (IQUOTIENT width 2))
	  (halfWidth1 (IQUOTIENT (SUB1 width)
				   2))
	  (lowerX (PLUS (DSPXPOSITION NIL imageStream)
			  xShift))
	  (lowerY (DIFFERENCE (DSPYPOSITION NIL imageStream)
				descent))
	  top middle left right)
         (SETQ top (PLUS lowerY (SUB1 height)))
         (SETQ middle (PLUS lowerY (IQUOTIENT (SUB1 height)
						    2)))

          (* * left parenthesis)


         (COND
	   ((NOT (EQ which (QUOTE right)))
	     (SETQ left (PLUS lowerX overlap halfWidth))
	     (DRAWCURVE (LIST (create POSITION
					    XCOORD ← left
					    YCOORD ← lowerY)
				  (create POSITION
					    XCOORD ←(PLUS lowerX halfWidth)
					    YCOORD ← middle)
				  (create POSITION
					    XCOORD ← left
					    YCOORD ← top))
			  NIL width NIL imageStream)))

          (* * right parenthesis)


         (COND
	   ((NOT (EQ which (QUOTE left)))
	     (SETQ right (PLUS lowerX (SUB1 spacing)
				   (MINUS (PLUS overlap halfWidth1))))
	     (DRAWCURVE (LIST (create POSITION
					    XCOORD ← right
					    YCOORD ← lowerY)
				  (create POSITION
					    XCOORD ←(PLUS lowerX (SUB1 spacing)
							    (MINUS halfWidth1))
					    YCOORD ← middle)
				  (create POSITION
					    XCOORD ← right
					    YCOORD ← top))
			  NIL width NIL imageStream))))))
)
(* * EQMATRIX module: Part 3 of 5)




(* matrix equation functions)

(DEFINEQ

(EQ.Matrix
  (LAMBDA (eqnObj imageStream draw?)                         (* THH "12-Jul-85 09:50")
                                                             (* form function for matrix)
                                                             (* this equation form allows a variable number of 
							     parts arranged and stored in rows)
    (LET ((layout (EQ.layout eqnObj imageStream))
	  enclose specs)
         (SETQ enclose (EQ.enclosure (EQIO.GetBox layout)
					 eqnObj imageStream draw?))

          (* * enclose of form (outerBox . pos) -- must now shift positions of individual pieces in layout 
	  (assumes no selection region in layout -- it would also need to be shifted))


         (SETQ specs (EQIO.GetDataSpecList layout))
         (for dataSpec in specs bind pos (xShift ←(fetch (POSITION XCOORD)
							   of (CDR enclose)))
					   (yShift ←(fetch (POSITION YCOORD) of (CDR enclose))
						   )
	    do (SETQ pos (EQIO.GetDataPosition dataSpec))
		 (add (fetch (POSITION XCOORD) of pos)
			xShift)
		 (add (fetch (POSITION YCOORD) of pos)
			yShift))
         (EQIO.MakeSpec (CAR enclose)
			  specs))))

(EQ.Make.matrix
  (LAMBDA (rows columns dataList enclosureKind enclosureSide fontSpec)
                                                             (* thh: " 9-Jan-86 10:23")

          (* * may want to call initial prop fn???)


    (LET ((numPieces (TIMES rows columns)))
         (EQN.Make (QUOTE matrix)
		     dataList fontSpec (LIST (QUOTE numPieces)
					       numPieces
					       (QUOTE rows)
					       rows
					       (QUOTE columns)
					       columns
					       (QUOTE enclosureKind)
					       enclosureKind
					       (QUOTE enclosureSide)
					       enclosureSide)))))

(EQ.layout
  (LAMBDA (eqnObj imageStream)                               (* THH "12-Jul-85 10:26")
                                                             (* form function for table of parts)
                                                             (* this equation form allows a variable number of 
							     parts arranged and stored in rows)
                                                             (* layout defined by rowGap -- distance between rows, 
							     colGap -- distance between columns, shift -- distance 
							     of center above baseline)
    (LET ((size (EQ.StreamSize imageStream))
	  (columns (EQIO.EqnProperty eqnObj (QUOTE columns)))
	  (rows (EQIO.EqnProperty eqnObj (QUOTE rows)))
	  (fontSpec (FONTCREATE (COND
				    ((EQIO.EqnProperty eqnObj (QUOTE fontSpec)))
				    (T DEFAULTFONT))
				  NIL NIL NIL imageStream))
	  layoutBox boxList colData rowData colGap rowGap shift)

          (* * set quantities that define layout)


         (SETQ shift (IQUOTIENT (FONTPROP fontSpec (QUOTE ASCENT))
				    2))
         (SETQ colGap (STRINGWIDTH "  " fontSpec))
         (SETQ rowGap colGap)

          (* * determine overall box)


         (COND
	   ((OR (ILEQ columns 0)
		  (ILEQ rows 0))
	     (SETQ layoutBox (create IMAGEBOX
					 XSIZE ← 0
					 YSIZE ← 0)))
	   (T (SETQ boxList (for piece in (EQIO.EqnDataList eqnObj) collect (FS.Box
											piece 
										      imageStream)))
	      (SETQ colData (ARRAY columns (QUOTE FIXP)
				       0))
	      (SETQ rowData (ARRAY rows))
	      (for row from 1 to rows bind (boxes ← boxList)
						   rAscent rDesc
		 do (SETQ rAscent 0)
		      (SETQ rDesc 0)
		      (for col from 1 to columns bind b
			 do (SETQ b (CAR boxes))
			      (SETQ boxes (CDR boxes))
			      (SETQ rAscent (MAX rAscent (DIFFERENCE (fetch YSIZE
									      of b)
									   (fetch YDESC
									      of b))))
			      (SETQ rDesc (MAX rDesc (fetch YDESC of b)))
			      (SETA colData col (MAX (ELT colData col)
							 (fetch XSIZE of b))))
		      (SETA rowData row (CONS (PLUS rAscent rDesc)
						  rDesc)))
	      (SETQ layoutBox (create IMAGEBOX
					  XSIZE ←(PLUS (for col from 1 to columns
							    sum (ELT colData col))
							 (TIMES (SUB1 columns)
								  colGap))
					  YSIZE ←(PLUS (for row from 1 to rows
							    sum (CAR (ELT rowData row)))
							 (TIMES (SUB1 rows)
								  rowGap))))))
         (replace YDESC of layoutBox with (DIFFERENCE (IQUOTIENT (fetch YSIZE
									      of layoutBox)
									   2)
							      shift))
         (replace XKERN of layoutBox with 0)

          (* * return overall box and individual positions of all the parts)


         (LET ((xLow 0)
	       (yHigh (fetch YSIZE of layoutBox))
	       (colPos (ARRAY columns (QUOTE FIXP))))    (* (xLow,yHigh) is position of upper left corner of 
							     block of matrix parts)
	      (COND
		((IGREATERP columns 0)                     (* set colPos to horizontal position of left edge of 
							     each column)
		  (SETA colPos 1 xLow)
		  (for col from 2 to columns do (SETA colPos col
								(PLUS (ELT colPos (SUB1 col))
									colGap
									(ELT colData (SUB1 col))))
			 )))
	      (EQIO.MakeSpec layoutBox
			       (COND
				 ((AND (IGREATERP columns 0)
					 (IGREATERP rows 0))
				   (for row from 1 to rows bind rowValue (boxes ← boxList)
									(rowPos ←(PLUS yHigh rowGap)
										)
				      join (SETQ rowPos (DIFFERENCE
						 rowPos
						 (PLUS rowGap (CAR (SETQ rowValue
									 (ELT rowData row))))))
                                                             (* rowPos is vertical position of bottom of row)
					     (for col from 1 to columns bind b
						collect
						 (SETQ b (CAR boxes))
						 (SETQ boxes (CDR boxes))
						 (EQIO.MakeDataSpec
						   (create POSITION
							     XCOORD ←(PLUS
							       (ELT colPos col)
							       (IQUOTIENT (DIFFERENCE
									      (ELT colData col)
									      (fetch XSIZE
										 of b))
									    2))
							     YCOORD ←(PLUS rowPos (CDR rowValue)))
						   ))))
				 (T                          (* no pieces in this layout)
				    NIL)))))))

(EQ.MatrixAdd
  (LAMBDA (eqnObj which place window)                        (* thh: " 3-Jun-85 10:19")
                                                             (* adds new row/column to matrix)
                                                             (* currently copies lists when adding new data instead
							     of modifying the original lists)
    (PROG ((rows (EQIO.EqnProperty eqnObj (QUOTE rows)))
	     (columns (EQIO.EqnProperty eqnObj (QUOTE columns)))
	     (dataList (EQIO.EqnDataList eqnObj))
	     newData tempData firstPiece continueFlg)
	    (SELECTQ which
		       (row (SETQ newData (EQN.DefaultData (EQIO.EqnType eqnObj)
							       (EQIO.EqnProperty eqnObj
										   (QUOTE fontSpec))
							       columns))
                                                             (* insert newData after the place*columns piece)
			    (SETQ tempData (for d in dataList as i from 1
						to (TIMES place columns) collect
									      (SETQ dataList
										(CDR dataList))
									      d))
			    (EQIO.SetDataList eqnObj (APPEND tempData newData dataList))
			    (add rows 1)
			    (EQIO.EqnProperty eqnObj (QUOTE rows)
						rows)
			    (SETQ firstPiece (ADD1 (TIMES columns place)))
			    (SETQ continueFlg (CONS 1 (TIMES columns (ADD1 place)))))
		       (column (SETQ newData (EQN.DefaultData (EQIO.EqnType eqnObj)
								  (EQIO.EqnProperty eqnObj
										      (QUOTE 
											 fontSpec))
								  rows))
			       (EQIO.SetDataList eqnObj
						   (for i from 1 to rows bind newD
						      join (SETQ newD (CAR newData))
							     (SETQ newData (CDR newData))
							     (APPEND (for j from 1
									  to place bind d
									  collect (SETQ d
										      (CAR dataList)
										      )
										    (SETQ dataList
										      (CDR dataList)
										      )
										    d)
								       (LIST newD)
								       (for j from (ADD1 place)
									  to columns bind d
									  collect (SETQ d
										      (CAR dataList)
										      )
										    (SETQ dataList
										      (CDR dataList)
										      )
										    d))))
			       (add columns 1)
			       (EQIO.EqnProperty eqnObj (QUOTE columns)
						   columns)
			       (SETQ firstPiece (ADD1 place))
			       (SETQ continueFlg (LIST columns)))
		       (ERROR "EQ.MatrixAdd: invalid arg for which = " which))
	    (EQIO.NumPieces eqnObj (TIMES rows columns))
	    (EQN.StartEdit eqnObj window firstPiece continueFlg (QUOTE PENDINGDEL)))))

(EQ.MatrixChanged
  (LAMBDA (eqnObj)                                           (* thh: "31-May-85 14:21")
                                                             (* called when number of pieces in matrix changed)
    (EQIO.EqnProperty eqnObj (QUOTE rowMenu)
			NIL)
    (EQIO.EqnProperty eqnObj (QUOTE colMenu)
			NIL)))

(EQ.MatrixCreate
  (LAMBDA NIL                                                (* THH "12-Jul-85 10:04")
                                                             (* allows user to specify initial number of rows and 
							     columns in a new matrix)
    (LET (rows columns numPieces retry)
         (repeatwhile (GREATERP numPieces EQ.Matrix.MaxPieces)
	    do (COND
		   (retry (CLRPROMPT)
			  (PROMPTPRINT "Too many matrix elements: " numPieces " [max allowed is " 
					 EQ.Matrix.MaxPieces "]")))
		 (SETQ rows (MAX (RNUMBER "How many rows for matrix?")
				     0))
		 (SETQ columns (MAX (RNUMBER "How many columns for matrix?")
					0))
		 (SETQ numPieces (TIMES rows columns))
		 (SETQ retry T))
         (LIST (QUOTE numPieces)
		 numPieces
		 (QUOTE rows)
		 rows
		 (QUOTE columns)
		 columns))))

(EQ.MatrixDelete
  (LAMBDA (eqnObj which place)                               (* thh: " 3-Jun-85 11:56")
                                                             (* deletes row/column from matrix)
    (COND
      ((IGREATERP place 0)
	(PROG ((rows (EQIO.EqnProperty eqnObj (QUOTE rows)))
		 (columns (EQIO.EqnProperty eqnObj (QUOTE columns)))
		 (dataList (EQIO.EqnDataList eqnObj)))
	        (SELECTQ which
			   (row (EQIO.SetDataList eqnObj
						    (for d in dataList as i from 1
						       bind (start ←(TIMES (SUB1 place)
									       columns))
							      (stop ←(TIMES place columns))
						       collect d unless (AND (IGREATERP
										     i start)
										   (ILEQ i stop))))
				(add rows -1)
				(EQIO.EqnProperty eqnObj (QUOTE rows)
						    rows))
			   (column (EQIO.SetDataList eqnObj (for d in dataList
								 bind (j ← 0)
								 eachtime (COND
									      ((IGEQ j columns)
										(SETQ j 0)))
									    (add j 1)
								 collect d unless (IEQP j place)
								     ))
				   (add columns -1)
				   (EQIO.EqnProperty eqnObj (QUOTE columns)
						       columns))
			   (ERROR "EQ.MatrixDelete: invalid arg for which = " which))
	        (EQIO.NumPieces eqnObj (TIMES rows columns)))))))

(EQ.MatrixEdit
  (LAMBDA (eqnObj window button)                             (* THH "12-Jul-85 10:08")
                                                             (* adds and removes rows and columns from matrix)
                                                             (* returns non-NIL if eqnObj modified)
    (COND
      ((EQ (EQIO.EqnType eqnObj)
	     (QUOTE matrix))
	(LET ((editMenu (EQIO.TypeProp (QUOTE matrix)
					 (QUOTE editMenu)))
	      action place)
	     (COND
	       ((NOT (type? MENU editMenu))
		 (SETQ editMenu (create MENU
					    CENTERFLG ← T
					    ITEMS ←(QUOTE (("add before col" (QUOTE beforeCol))
							      ("add before row" (QUOTE beforeRow))
							      ("add after col" (QUOTE afterCol))
							      ("add after row" (QUOTE afterRow))
							      ("DELETE column" (QUOTE delCol))
							      ("DELETE row" (QUOTE delRow))
							      ("[change enclosure]" (QUOTE 
											enclosure)))))
		   )
		 (EQIO.TypeProp (QUOTE matrix)
				  (QUOTE editMenu)
				  editMenu)))
	     (SETQ action (MENU editMenu))
	     (COND
	       ((EQ action (QUOTE enclosure))
		 (EQ.EnclosureEdit eqnObj))
	       (T                                            (* edit layout)
		  (SETQ place (SELECTQ action
					   ((beforeCol afterCol delCol)
					     (COND
					       ((IGREATERP (EQIO.EqnProperty eqnObj (QUOTE
										   columns))
							     0)
						 (MENU (EQ.MatrixGetMenu eqnObj (QUOTE column)))
						 )
					       ((EQ action (QUOTE beforeCol))
						 1)
					       (T 0)))
					   ((beforeRow afterRow delRow)
					     (COND
					       ((IGREATERP (EQIO.EqnProperty eqnObj (QUOTE
										   rows))
							     0)
						 (MENU (EQ.MatrixGetMenu eqnObj (QUOTE row))))
					       ((EQ action (QUOTE beforeRow))
						 1)
					       (T 0)))
					   NIL))
		  (COND
		    (place (COND
			     ((EQ action (QUOTE beforeCol))
			       (add place -1)
			       (SETQ action (QUOTE afterCol)))
			     ((EQ action (QUOTE beforeRow))
			       (add place -1)
			       (SETQ action (QUOTE afterRow))))
			   (SELECTQ action
				      (afterCol (EQ.MatrixAdd eqnObj (QUOTE column)
								place window)
						T)
				      (afterRow (EQ.MatrixAdd eqnObj (QUOTE row)
								place window)
						T)
				      (delCol (EQ.MatrixDelete eqnObj (QUOTE column)
								 place)
					      T)
				      (delRow (EQ.MatrixDelete eqnObj (QUOTE row)
								 place)
					      T)
				      NIL)))))))
      (T                                                     (* eqnObj not a matrix)
	 NIL))))

(EQ.MatrixGetMenu
  (LAMBDA (eqnObj which)                                     (* thh: " 3-Jun-85 09:35")
                                                             (* gets menu for eqnObj, which is either row or 
							     column)
    (SELECTQ which
	       (row (PROG ((rowMenu (EQIO.EqnProperty eqnObj (QUOTE rowMenu))))
			    (COND
			      ((NOT (type? MENU rowMenu))
				(SETQ rowMenu (create MENU
							  TITLE ← "row #"
							  ITEMS ←(for i from 1
								    to (EQIO.EqnProperty
									   eqnObj
									   (QUOTE rows))
								    collect i)))
				(EQIO.EqnProperty eqnObj (QUOTE rowMenu)
						    rowMenu)))
			    (RETURN rowMenu)))
	       (column (PROG ((colMenu (EQIO.EqnProperty eqnObj (QUOTE colMenu))))
			       (COND
				 ((NOT (type? MENU colMenu))
				   (SETQ colMenu
				     (create MENU
					       TITLE ← "col #"
					       MENUROWS ← 1
					       ITEMS ←(for i from 1 to (EQIO.EqnProperty
									       eqnObj
									       (QUOTE columns))
							 collect i)))
				   (EQIO.EqnProperty eqnObj (QUOTE colMenu)
						       colMenu)))
			       (RETURN colMenu)))
	       NIL)))

(EQ.MatrixSelect
  (LAMBDA (eqnObj)                                           (* thh: " 3-Jun-85 09:20")
                                                             (* selects piece to edit by row and column number)
    (COND
      ((EQ (EQIO.EqnType eqnObj)
	     (QUOTE matrix))
	(PROG (row col)
	        (COND
		  ((IGREATERP (EQIO.NumPieces eqnObj)
				0)
		    (SETQ row (MENU (EQ.MatrixGetMenu eqnObj (QUOTE row))))
		    (COND
		      (row (SETQ col (MENU (EQ.MatrixGetMenu eqnObj (QUOTE column))))
			   (COND
			     (col (RETURN (PLUS (TIMES (EQIO.EqnProperty eqnObj (QUOTE
										   columns))
							     (SUB1 row))
						    col))))))))))
      (T                                                     (* eqnObj is not a matrix)
	 NIL))))
)

(RPAQ? EQ.Matrix.MaxPieces 100)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS EQ.Matrix.MaxPieces)
)
(EQIO.AddType (QUOTE matrix)
	      (QUOTE EQ.Matrix)
	      1
	      (QUOTE (objectProps (rows 1 columns 1 enclosureKind NIL enclosureSide NIL)
				  variable? T wholeEditFn EQ.MatrixEdit specialSelectFn 
				  EQ.MatrixSelect initialPropFn EQ.MatrixCreate changeFn 
				  EQ.MatrixChanged)))
(* * EQNFORMS module: Part 4 of 5)




(* fraction)

(DEFINEQ

(EQ.Fraction
  (LAMBDA (eqnObj imageStream draw?)                         (* THH "21-May-85 12:14")
                                                             (* form function for fraction)

          (* fraction defined by shift -- distance of line above base, gap -- space above and below the line, width -- width 
	  of the line and extend -- extra length of line on either side)

                                                             (* these parameters could be specified by props to 
							     allow user to change them)
    (PROG ((size (EQ.StreamSize imageStream))
	     shift gap width extend nBox dBox pos box pNumer pDenom)
	    (SETQ shift (IQUOTIENT (FONTPROP (FONTCREATE (COND
								   ((EQIO.EqnProperty eqnObj
											(QUOTE
											  fontSpec)))
								   (T DEFAULTFONT))
								 NIL NIL NIL imageStream)
						   (QUOTE ASCENT))
				       2))
	    (SETQ gap size)
	    (SETQ width size)
	    (SETQ extend size)
	    (SETQ nBox (FS.Box (EQIO.EqnData eqnObj 1)
				   imageStream))
	    (SETQ dBox (FS.Box (EQIO.EqnData eqnObj 2)
				   imageStream))
	    (SETQ pos (PLUS (fetch YSIZE of dBox)
				(TIMES 2 gap)
				width))                      (* pos is distance from bottom of box to bottom of 
							     numerator)
	    (SETQ box (create IMAGEBOX
				  XSIZE ←(PLUS (MAX (fetch XSIZE of nBox)
							(fetch XSIZE of dBox))
						 (TIMES 2 extend))
				  YSIZE ←(PLUS (fetch YSIZE of nBox)
						 pos)
				  YDESC ←(PLUS gap (fetch YSIZE of dBox)
						 (MINUS shift))
				  XKERN ← 0))
	    (SETQ pNumer (create POSITION
				     XCOORD ←(IQUOTIENT (DIFFERENCE (fetch XSIZE of box)
									(fetch XSIZE of nBox))
							  2)
				     YCOORD ←(PLUS pos (fetch YDESC of nBox))))
	    (SETQ pDenom (create POSITION
				     XCOORD ←(IQUOTIENT (DIFFERENCE (fetch XSIZE of box)
									(fetch XSIZE of dBox))
							  2)
				     YCOORD ←(fetch YDESC of dBox)))
	    (COND
	      (draw?                                         (* note that original x,y pos not preserved)
		     (RELMOVETO 0 shift imageStream)
		     (RELDRAWTO (fetch XSIZE of box)
				  0 width NIL imageStream)))
	    (RETURN (EQIO.MakeSpec box
				       (LIST (EQIO.MakeDataSpec pNumer
								    (create REGION
									      LEFT ← 0
									      BOTTOM ← pos
									      WIDTH ←(fetch XSIZE
											of box)
									      HEIGHT ←(fetch YSIZE
											 of nBox)))
					       (EQIO.MakeDataSpec pDenom
								    (create REGION
									      LEFT ← 0
									      BOTTOM ← 0
									      WIDTH ←(fetch XSIZE
											of box)
									      HEIGHT ←(fetch YSIZE
											 of dBox))))
				       ))                    (* selection region for numerator 
							     (denominator) is entire top 
							     (bottom) half of fraction)
	)))

(EQ.Make.fraction
  (LAMBDA (numerator denominator fontSpec)                   (* thh: " 9-Jan-86 10:14")
    (EQN.Make (QUOTE fraction)
		(LIST numerator denominator)
		fontSpec)))
)
(* * sum group)

(DEFINEQ

(EQ.SumGroup
  (LAMBDA (eqnObj imageStream draw?)                         (* thh: " 9-Jan-86 10:42")
                                                             (* form function for forms drawn like a summation)

          (* form defined by gap -- distance between symbol and index (below) and limits (above), and vGap -- distance 
	  between symbol and value)

                                                             (* uses Sigma 20 font for large symbols -- later need 
							     to use different font for interpress)
    (PROG ((size (EQ.StreamSize imageStream))
	     (char (LIST (COND
			     ((EQ.UseNS? imageStream)
			       (FS.MakeItem (QUOTE (Classic 24))
					      (MKSTRING (CHARACTER (SELECTQ (EQIO.EqnType
										    eqnObj)
										  (sum 9814)
										  (product 9811)
										  (union 61271)
										  (intersection
										    61270)
										  (SHOULDNT 
								      "eqn not a known sum group")))))
			       )
			     (T                              (* use press fonts)
				(FS.MakeItem (QUOTE (Sigma 20))
					       (SELECTQ (EQIO.EqnType eqnObj)
							  (sum (QUOTE "M"))
							  (product (QUOTE "P"))
							  (union (QUOTE "U"))
							  (intersection (QUOTE "I"))
							  (SHOULDNT "eqn not a known sum group")))))
			   ))
	     charBox indexBox limitBox valueBox indexRegion limitRegion valueRegion charRegion 
	     boxRegion box temp gap vGap)
	    (SETQ gap size)
	    (SETQ vGap (TIMES 2 size))
	    (SETQ charBox (FS.Box char imageStream))
	    (SETQ indexBox (FS.Box (EQIO.EqnData eqnObj 1)
				       imageStream))
	    (SETQ limitBox (FS.Box (EQIO.EqnData eqnObj 2)
				       imageStream))
	    (SETQ valueBox (FS.Box (EQIO.EqnData eqnObj 3)
				       imageStream))
	    (SETQ temp (AB.PositionRegion charBox NIL (QUOTE bottom)
					      (QUOTE center)
					      indexBox
					      (QUOTE center)
					      gap 0 size))
	    (SETQ indexRegion (CAR temp))
	    (SETQ temp (AB.PositionRegion charBox temp (QUOTE top)
					      (QUOTE center)
					      limitBox
					      (QUOTE center)
					      (TIMES -2 gap)
					      0 size))       (* -2*gap used instead of gap since symbol doesn't 
							     fill its box)
	    (SETQ limitRegion (CAR temp))
	    (SETQ temp (AB.PositionRegion charBox temp (QUOTE right)
					      (QUOTE display)
					      valueBox
					      (QUOTE display)
					      vGap 0 size))
	    (SETQ valueRegion (CAR temp))
	    (SETQ charRegion (AB.BoxToRegion charBox 0 0))
	    (SETQ boxRegion (UNIONREGIONS charRegion indexRegion limitRegion valueRegion))
	    (SETQ box (AB.RegionToBox boxRegion (fetch YDESC of charBox)))
	    (COND
	      (draw?                                         (* note that original x, y position not preserved)
		     (RELMOVETO (MINUS (fetch LEFT of boxRegion))
				  0 imageStream)
		     (FS.Display char imageStream)))
	    (RETURN (EQIO.MakeSpec box (LIST (EQIO.MakeDataSpec (AB.RelativePos
									  indexRegion boxRegion
									  (fetch YDESC
									     of indexBox)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  limitRegion boxRegion
									  (fetch YDESC
									     of limitBox)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  valueRegion boxRegion
									  (fetch YDESC
									     of valueBox)))))))))

(EQ.Make.sum
  (LAMBDA (lowerIndex upperLimit summand fontSpec)           (* thh: " 9-Jan-86 10:16")
    (EQN.Make (QUOTE sum)
		(LIST lowerIndex upperLimit summand)
		fontSpec)))

(EQ.Make.product
  (LAMBDA (lowerIndex upperLimit factor fontSpec)            (* thh: " 9-Jan-86 10:17")
    (EQN.Make (QUOTE product)
		(LIST lowerIndex upperLimit factor)
		fontSpec)))

(EQ.Make.union
  (LAMBDA (lowerIndex upperLimit set fontSpec)               (* thh: " 9-Jan-86 10:18")
    (EQN.Make (QUOTE union)
		(LIST lowerIndex upperLimit set)
		fontSpec)))

(EQ.Make.intersection
  (LAMBDA (lowerIndex upperLimit set fontSpec)               (* thh: " 9-Jan-86 10:18")
    (EQN.Make (QUOTE intersection)
		(LIST lowerIndex upperLimit set)
		fontSpec)))
)
(* * integral group)

(DEFINEQ

(EQ.IntegralGroup
  (LAMBDA (eqnObj imageStream draw?)                         (* thh: " 9-Jan-86 10:46")
                                                             (* form function for forms drawn like an integral)
                                                             (* form defined by gap -- distance between symbol and 
							     limits and vGap -- distance between symbol and value)
                                                             (* uses Sigma 20 font for large symbols -- later need 
							     to use different font for interpress)
    (PROG ((size (EQ.StreamSize imageStream))
	     (char (LIST (COND
			     ((EQ.UseNS? imageStream)
			       (FS.MakeItem (QUOTE (Classic 24))
					      (MKSTRING (CHARACTER (SELECTQ (EQIO.EqnType
										    eqnObj)
										  (integral 61301)
										  (lineIntegral
										    61302)
										  (SHOULDNT 
								 "eqn not a known integral group")))))
			       )
			     (T                              (* use press fonts)
				(FS.MakeItem (QUOTE (Sigma 20))
					       (SELECTQ (EQIO.EqnType eqnObj)
							  (integral (QUOTE "S"))
							  (lineIntegral (QUOTE "C"))
							  (SHOULDNT 
								 "eqn not a known integral group")))))
			   ))
	     charBox lowerBox upperBox valueBox lowerRegion upperRegion valueRegion charRegion 
	     boxRegion box temp gap vGap)
	    (SETQ gap size)
	    (SETQ vGap (TIMES 5 size))
	    (SETQ charBox (FS.Box char imageStream))
	    (SETQ lowerBox (FS.Box (EQIO.EqnData eqnObj 1)
				       imageStream))
	    (SETQ upperBox (FS.Box (EQIO.EqnData eqnObj 2)
				       imageStream))
	    (SETQ valueBox (FS.Box (EQIO.EqnData eqnObj 3)
				       imageStream))
	    (SETQ temp (AB.Position2Regions charBox NIL (QUOTE right)
						upperBox
						(QUOTE center)
						lowerBox
						(QUOTE center)
						(MINUS gap)
						(TIMES -6 gap)
						0 0 size))   (* negative gaps since symbol doesn't fill its box)
	    (SETQ upperRegion (CAR temp))
	    (SETQ lowerRegion (CADR temp))
	    (SETQ temp (AB.PositionRegion charBox temp (QUOTE right)
					      (QUOTE display)
					      valueBox
					      (QUOTE display)
					      vGap 0 size))
	    (SETQ valueRegion (CAR temp))
	    (SETQ charRegion (AB.BoxToRegion charBox 0 0))
	    (SETQ boxRegion (UNIONREGIONS charRegion upperRegion lowerRegion valueRegion))
	    (SETQ box (AB.RegionToBox boxRegion (fetch YDESC of charBox)))
	    (COND
	      (draw?                                         (* note that original x, y position not preserved)
		     (RELMOVETO (MINUS (fetch LEFT of boxRegion))
				  0 imageStream)
		     (FS.Display char imageStream)))
	    (RETURN (EQIO.MakeSpec box (LIST (EQIO.MakeDataSpec (AB.RelativePos
									  lowerRegion boxRegion
									  (fetch YDESC
									     of lowerBox)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  upperRegion boxRegion
									  (fetch YDESC
									     of upperBox)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  valueRegion boxRegion
									  (fetch YDESC
									     of valueBox)))))))))

(EQ.Make.integral
  (LAMBDA (lowerLimit upperLimit integrand fontSpec)         (* thh: " 9-Jan-86 10:19")
    (EQN.Make (QUOTE integral)
		(LIST lowerLimit upperLimit integrand)
		fontSpec)))

(EQ.Make.lineIntegral
  (LAMBDA (lowerLimit upperLimit integrand fontSpec)         (* thh: " 9-Jan-86 10:20")
    (EQN.Make (QUOTE lineIntegral)
		(LIST lowerLimit upperLimit integrand)
		fontSpec)))
)
(* * super- and sub- scripts)

(DEFINEQ

(EQ.Script
  (LAMBDA (eqnObj imageStream draw?)                         (* THH "23-May-85 14:07")
                                                             (* form function for forms with sub and superscripts)

          (* form defined by gap -- horizontal distance between main symbol and sub/superscripts, , and shift -- vertical 
	  distance of centers of sub/superscripts below/above corner of main symbol)


    (PROG ((size (EQ.StreamSize imageStream))
	     mainBox super1Box sub1Box super2Box sub2Box super1Region sub1Region super2Region 
	     sub2Region mainRegion boxRegion box temp gap shift)
	    (SETQ gap size)
	    (SETQ shift size)
	    (SETQ mainBox (FS.Box (EQIO.EqnData eqnObj 1)
				      imageStream))
	    (SETQ sub1Box (FS.Box (EQIO.EqnData eqnObj 2)
				      imageStream))
	    (SETQ super1Box (FS.Box (EQIO.EqnData eqnObj 3)
					imageStream))
	    (SETQ sub2Box (FS.Box (EQIO.EqnData eqnObj 4)
				      imageStream))
	    (SETQ super2Box (FS.Box (EQIO.EqnData eqnObj 5)
					imageStream))
	    (SETQ temp (AB.Position2Regions mainBox NIL (QUOTE right)
						super1Box
						(QUOTE center)
						sub1Box
						(QUOTE center)
						gap gap shift (MINUS shift)
						size))
	    (SETQ super1Region (CAR temp))
	    (SETQ sub1Region (CADR temp))
	    (SETQ temp (AB.Position2Regions mainBox (CADDR temp)
						(QUOTE left)
						super2Box
						(QUOTE center)
						sub2Box
						(QUOTE center)
						gap gap shift (MINUS shift)
						size))
	    (SETQ super2Region (CAR temp))
	    (SETQ sub2Region (CADR temp))
	    (SETQ mainRegion (AB.BoxToRegion mainBox 0 0))
	    (SETQ boxRegion (UNIONREGIONS mainRegion super1Region sub1Region super2Region 
					      sub2Region))
	    (SETQ box (AB.RegionToBox boxRegion (fetch YDESC of mainBox)))

          (* * this form has nothing extra to draw)


	    (RETURN (EQIO.MakeSpec box (LIST (EQIO.MakeDataSpec (AB.RelativePos
									  mainRegion boxRegion
									  (fetch YDESC
									     of mainBox)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  sub1Region boxRegion
									  (fetch YDESC
									     of sub1Box)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  super1Region boxRegion
									  (fetch YDESC
									     of super1Box)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  sub2Region boxRegion
									  (fetch YDESC
									     of sub2Box)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  super2Region boxRegion
									  (fetch YDESC
									     of super2Box)))))))))

(EQ.Make.sub/superscripts
  (LAMBDA (mainValue lowerRight upperRight lowerLeft upperLeft fontSpec)
                                                             (* thh: " 9-Jan-86 10:21")
    (EQN.Make (QUOTE sub/superscripts)
		(LIST mainValue lowerRight upperRight lowerLeft upperLeft)
		fontSpec)))
)
(* * max/min/limit etc)

(DEFINEQ

(EQ.MaxMin
  (LAMBDA (eqnObj imageStream draw?)                         (* thh: " 9-Jan-86 10:02")
                                                             (* form function for max/min/limit etc)
    (PROG ((size (EQ.StreamSize imageStream))
	     functionBox indexBox valueBox box functionRegion indexRegion valueRegion boxRegion gap 
	     vGap temp)
	    (SETQ gap (TIMES 2 size))
	    (SETQ vGap size)
	    (SETQ functionBox (FS.Box (EQIO.EqnData eqnObj 1)
					  imageStream))
	    (SETQ indexBox (FS.Box (EQIO.EqnData eqnObj 2)
				       imageStream))
	    (SETQ valueBox (FS.Box (EQIO.EqnData eqnObj 3)
				       imageStream))
	    (SETQ temp (AB.PositionRegion functionBox NIL (QUOTE bottom)
					      (QUOTE center)
					      indexBox
					      (QUOTE center)
					      vGap 0 size))
	    (SETQ indexRegion (CAR temp))
	    (SETQ temp (AB.PositionRegion functionBox temp (QUOTE right)
					      (QUOTE display)
					      valueBox
					      (QUOTE display)
					      gap 0 size))
	    (SETQ valueRegion (CAR temp))
	    (SETQ functionRegion (AB.BoxToRegion functionBox 0 0))
	    (SETQ boxRegion (UNIONREGIONS functionRegion indexRegion valueRegion))
	    (SETQ box (AB.RegionToBox boxRegion (fetch YDESC of functionBox)))

          (* * nothing extra to draw)


	    (RETURN (EQIO.MakeSpec box (LIST (EQIO.MakeDataSpec (AB.RelativePos
									  functionRegion boxRegion
									  (fetch YDESC
									     of functionBox)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  indexRegion boxRegion
									  (fetch YDESC
									     of indexBox)))
						   (EQIO.MakeDataSpec (AB.RelativePos
									  valueRegion boxRegion
									  (fetch YDESC
									     of valueBox)))))))))

(EQ.Make.max/min
  (LAMBDA (function index value fontSpec)                    (* thh: " 9-Jan-86 10:21")
    (EQN.Make (QUOTE max/min)
		(LIST function index value)
		fontSpec)))
)
(* * utilities)

(DEFINEQ

(EQ.StreamSize
  (LAMBDA (imageStream)                                      (* thh: " 3-May-85 08:37")
                                                             (* standard size factor for the stream)
    (MAX 1 (IQUOTIENT (STRINGWIDTH "A" (FONTCREATE DEFAULTFONT NIL NIL NIL imageStream))
			  5))))

(EQ.UseNS?
  (LAMBDA (imageStream)                                      (* thh: " 9-Jan-86 10:29")

          (* * returns non-NIL if NS characters should be used for special symbols on imageStream)


    (SELECTQ (IMAGESTREAMTYPE imageStream)
	       (DISPLAY EQ.UseNSChars)
	       (PRESS NIL)
	       (INTERPRESS T)
	       EQ.UseNSChars)))
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS EQ.UseNSChars)
)



(* EQ.UseNSChars = NIL to use press fonts for display)


(RPAQ? EQ.UseNSChars NIL)
(EQIO.AddType (QUOTE fraction)
	      (QUOTE EQ.Fraction)
	      2
	      (QUOTE (pieceNames ("numerator" "denominator"))))
(EQIO.AddType (QUOTE sum)
	      (QUOTE EQ.SumGroup)
	      3
	      (QUOTE (initialData (-2 -2 0)
				  pieceNames
				  ("index" "limit" "summand"))))
(EQIO.AddType (QUOTE product)
	      (QUOTE EQ.SumGroup)
	      3
	      (QUOTE (initialData (-2 -2 0)
				  pieceNames
				  ("index" "limit" "factor"))))
(EQIO.AddType (QUOTE union)
	      (QUOTE EQ.SumGroup)
	      3
	      (QUOTE (initialData (-2 -2 0)
				  pieceNames
				  ("index" "limit" "set"))))
(EQIO.AddType (QUOTE intersection)
	      (QUOTE EQ.SumGroup)
	      3
	      (QUOTE (initialData (-2 -2 0)
				  pieceNames
				  ("index" "limit" "set"))))
(EQIO.AddType (QUOTE integral)
	      (QUOTE EQ.IntegralGroup)
	      3
	      (QUOTE (initialData (-2 -2 0)
				  pieceNames
				  ("lower limit" "upper limit" "integrand"))))
(EQIO.AddType (QUOTE lineIntegral)
	      (QUOTE EQ.IntegralGroup)
	      3
	      (QUOTE (initialData (-2 -2 0)
				  pieceNames
				  ("lower limit" "upper limit" "integrand")
				  menuLabel "line integral")))
(EQIO.AddType (QUOTE sub/superscripts)
	      (QUOTE EQ.Script)
	      5
	      (QUOTE (initialData (0 -1 -1 -1 -1)
				  pieceNames
				  ("main value" "right subscript" "right superscript" 
						"left subscript"
						"left superscript"))))
(EQIO.AddType (QUOTE max/min)
	      (QUOTE EQ.MaxMin)
	      3
	      (QUOTE (initialData (0 -2 0)
				  pieceNames
				  ("function" "index" "value")
				  menuLabel "max min limit")))
(* * EQROOT module: Part 5 of 5)

(DEFINEQ

(EQ.Root
  (LAMBDA (eqnObj imageStream draw?)                         (* thh: "18-Mar-86 14:47")
                                                             (* form function for roots)

          (* layout defined by vGap -- extra vertical space on either side of radicand, gap -- extra horizontal space on 
	  either side of radicand, ivGap -- vertical space between index and radical sign, igap -- extra horizontal extent of
	  sign around index)


    (PROG ((size (EQ.StreamSize imageStream))
	     rBox iBox gap vGap ivGap igap baseLen barLen height rise desc toBottomLen toTopLen width 
	     box)
	    (SETQ gap (TIMES 2 size))
	    (SETQ vGap (TIMES 2 size))
	    (SETQ ivGap size)
	    (SETQ igap 0)
	    (SETQ width size)
	    (SETQ rBox (FS.Box (EQIO.EqnData eqnObj 1)
				   imageStream))
	    (SETQ iBox (FS.Box (EQIO.EqnData eqnObj 2)
				   imageStream))

          (* * determine size of parts of radical sign and draw it if requested)


	    (SETQ baseLen (MAX (TIMES 4 size)
				   (PLUS (TIMES 2 igap)
					   (fetch XSIZE of iBox))))
	    (SETQ barLen (PLUS (TIMES 2 gap)
				   (fetch XSIZE of rBox)))
	    (SETQ height (PLUS (TIMES 2 vGap)
				   (fetch YSIZE of rBox)
				   (QUOTIENT width 2)))
	    (SETQ rise (QUOTIENT height 2))
	    (SETQ desc (PLUS (fetch YDESC of rBox)
				 vGap))
	    (SETQ toBottomLen (TIMES 2 size))
	    (SETQ toTopLen (TIMES 4 toBottomLen))
	    (COND
	      (draw? (EQ.DrawRadicalSign height rise desc baseLen toBottomLen toTopLen barLen width 
					   imageStream)))

          (* * get size and position values)


	    (SETQ box (create IMAGEBOX
				  XSIZE ←(PLUS baseLen toBottomLen toTopLen barLen)
				  YSIZE ←(MAX (PLUS height (DIFFERENCE width (QUOTIENT width 
											       2)))
						(PLUS rise ivGap (fetch YSIZE of iBox)))
				  YDESC ← desc
				  XKERN ← 0))
	    (RETURN (EQIO.MakeSpec box (LIST (EQIO.MakeDataSpec (create POSITION
										  XCOORD ←(PLUS
										    baseLen 
										    toBottomLen 
										    toTopLen gap)
										  YCOORD ← desc))
						   (EQIO.MakeDataSpec
						     (create POSITION
							       XCOORD ←(QUOTIENT
								 (DIFFERENCE baseLen
									       (fetch XSIZE
										  of iBox))
								 2)
							       YCOORD ←(PLUS rise ivGap
									       (fetch YDESC
										  of iBox))))))))))

(EQ.Make.root
  (LAMBDA (radicand index fontSpec)                          (* thh: " 9-Jan-86 10:22")
    (EQN.Make (QUOTE root)
		(LIST radicand index)
		fontSpec)))
)
(DEFINEQ

(EQ.DrawRadicalSign
  (LAMBDA (height rise desc baseLen toBottomLen toTopLen barLen width imageStream)
                                                             (* thh: "28-Jun-85 13:04")
                                                             (* draws specified radical sign on imageStream)
    (RELMOVETO 0 (DIFFERENCE rise desc)
		 imageStream)
    (RELDRAWTO baseLen 0 width NIL imageStream)
    (RELDRAWTO toBottomLen (MINUS rise)
		 (TIMES 2 width)
		 NIL imageStream)
    (RELDRAWTO toTopLen height width NIL imageStream)
    (RELDRAWTO barLen 0 width NIL imageStream)))
)
(EQIO.AddType (QUOTE root)
	      (QUOTE EQ.Root)
	      2
	      (QUOTE (pieceNames ("radicand" "index")
				 initialData
				 (0 -1))))
(PUTPROPS EQUATIONFORMS COPYRIGHT ("Xerox Corporation" 1986))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (6065 19828 (AB.RealPosition 6075 . 7035) (AB.PointPos 7037 . 8224) (AB.SidePosition 
8226 . 9169) (AB.PlaceRegion 9171 . 10427) (AB.AdjustToLL 10429 . 11120) (AB.OppositeSide 11122 . 
11402) (AB.RegionToBox 11404 . 12013) (AB.BoxToRegion 12015 . 12607) (AB.RelativePos 12609 . 13144) (
AB.BiggerRegion 13146 . 13900) (AB.Check 13902 . 15591) (AB.PositionRegion 15593 . 16493) (
AB.Position2Regions 16495 . 19826)) (19906 20992 (EQ.Group 19916 . 20562) (EQ.GroupCreate 20564 . 
20708) (EQ.Make.group 20710 . 20990)) (21362 22300 (EQ.AddEnclosure 21372 . 22083) (
EQ.GetEnclosureData 22085 . 22298)) (22856 27704 (EQ.enclosure 22866 . 24156) (EQ.EnclosureCreate 
24158 . 24842) (EQ.EnclosureEdit 24844 . 26034) (EQ.EnclosureKind 26036 . 27087) (EQ.EnclosureSide 
27089 . 27702)) (27742 34561 (EQ.angles 27752 . 28917) (EQ.bars 28919 . 29899) (EQ.braces 29901 . 
31256) (EQ.brackets 31258 . 32396) (EQ.parentheses 32398 . 33629) (EQ.enclosureForm 33631 . 34396) (
EQ.enclosureWidth 34398 . 34559)) (34602 43655 (EQ.DrawAngles 34612 . 36182) (EQ.DrawBars 36184 . 
37249) (EQ.DrawBraces 37251 . 40241) (EQ.DrawBrackets 40243 . 41881) (EQ.DrawParentheses 41883 . 43653
)) (43735 61012 (EQ.Matrix 43745 . 45025) (EQ.Make.matrix 45027 . 45668) (EQ.layout 45670 . 50489) (
EQ.MatrixAdd 50491 . 53334) (EQ.MatrixChanged 53336 . 53689) (EQ.MatrixCreate 53691 . 54596) (
EQ.MatrixDelete 54598 . 56025) (EQ.MatrixEdit 56027 . 58859) (EQ.MatrixGetMenu 58861 . 60143) (
EQ.MatrixSelect 60145 . 61010)) (61476 64839 (EQ.Fraction 61486 . 64634) (EQ.Make.fraction 64636 . 
64837)) (64862 69365 (EQ.SumGroup 64872 . 68538) (EQ.Make.sum 68540 . 68739) (EQ.Make.product 68741 . 
68947) (EQ.Make.union 68949 . 69148) (EQ.Make.intersection 69150 . 69363)) (69393 73252 (
EQ.IntegralGroup 69403 . 72816) (EQ.Make.integral 72818 . 73029) (EQ.Make.lineIntegral 73031 . 73250))
 (73289 76438 (EQ.Script 73299 . 76114) (EQ.Make.sub/superscripts 76116 . 76436)) (76469 78617 (
EQ.MaxMin 76479 . 78415) (EQ.Make.max/min 78417 . 78615)) (78640 79348 (EQ.StreamSize 78650 . 78981) (
EQ.UseNS? 78983 . 79346)) (81109 83936 (EQ.Root 81119 . 83746) (EQ.Make.root 83748 . 83934)) (83937 
84578 (EQ.DrawRadicalSign 83947 . 84576)))))
STOP