(FILECREATED "20-Mar-86 09:31:40" {INDIGO}<GSLWS>KOTO>LIBRARY>EQUATIONS.;3 72244  

      changes to:  (FNS EQIO.ButtonEventIn EQIO.MakeSelectionMenu)
		   (VARS EQUATIONSCOMS)

      previous date: " 6-Mar-86 16:18:59" {INDIGO}<GSLWS>KOTO>LIBRARY>EQUATIONS.;1)


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

(PRETTYCOMPRINT EQUATIONSCOMS)

(RPAQQ EQUATIONSCOMS ((* * EQUATION module: Part 1 of 3)
	(* functions for image object)
	(FNS EQIO.CreateFns EQIO.Create EQIO.Imagebox EQIO.Display EQIO.ButtonEventIn EQIO.Copy 
	     EQIO.CopyList EQIO.Get EQIO.Put EQIO.WhenDeleted EQIO.SelectRegion EQIO.Selection 
	     EQIO.DefaultSelectFn EQIO.MakeSelectionMenu)
	(* * functions to handle individual equation props and data)
	(FNS EQIO.EqnType EQIO.EqnDataList EQIO.SetDataList EQIO.EqnData EQIO.EqnProperty 
	     EQIO.AllProps EQIO.Specify EQIO.GetInitialProps EQIO.NumPieces EQIO.NewStructure)
	(* * functions to handle equation specification info)
	(FNS EQIO.AddType EQIO.GetInfo EQIO.SetInfo EQIO.TypeProp EQIO.ResetTypeProps EQIO.IsDefined 
	     EQIO.GetBox EQIO.GetDataSpec EQIO.GetDataSpecList EQIO.GetDataPosition 
	     EQIO.GetDataSelectRegion EQIO.MakeSpec EQIO.MakeDataSpec)
	(* * variable specification)
	(GLOBALVARS EquationInfo EquationTypeMenu EquationImageFns UnknownEquationData 
		    EquationDefaultSelectFn)
	(VARS (EquationImageFns NIL))
	(INITVARS EquationInfo (EquationDefaultSelectFn (QUOTE EQIO.DefaultSelectFn)))
	(P (TEDIT.ADD.MENUITEM TEDIT.DEFAULT.MENU (QUOTE (Equation (QUOTE EQN.Equation)))))
	(P (* needed to force the getfn to be recognized before any new eqns defined)
	   (SETQ EquationImageFns (EQIO.CreateFns)))
	(VARS UnknownEquationData)
	(PROP ARGNAMES EQIO.TypeProp EQIO.NumPieces EQIO.AllProps EQIO.EqnProperty)
	(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS
		  (ADDVARS (NLAMA)
			   (NLAML)
			   (LAMA EQN.ObjEditWindow EQN.ContinueFlg EQN.PieceNumber EQN.ResultObj 
				 EQN.ResultWindow EQN.EditWindow EQIO.TypeProp EQIO.NumPieces 
				 EQIO.AllProps EQIO.EqnProperty)))
	(* * EQUATIONEDIT module: Part 2 of 3)
	(* functions to edit data pieces)
	(FNS EQN.AbortEdit EQN.StopEdit EQN.ContinueEdit EQN.FinishEdit EQN.MakeEditWindow 
	     EQN.SetUpEdit EQN.StartEdit EQN.StartNextEdit EQN.UpdateEdit EQN.DefaultData 
	     EQN.TypeMenu)
	(* * hooks to control behavior of equation subeditor)
	(FNS EQN.Equation EQN.NextPiece EQN.FinishEqn EQN.NoUpdateAbort EQN.PreventUpdate EQN.CharFn 
	     EQN.TEditSpecialChar EQN.SnuggleWindows EQN.SnuggleMainWindow)
	(* * functions to handle equation fonts)
	(FNS EQN.EquationFontNumber EQN.EquationFont EQN.GetEqnFont EQN.MakeFS)
	(* * utilities)
	(FNS EQN.AdjustWindow EQN.CheckWindowSize)
	(FNS EQN.SubEditorP EQN.WindowFromText EQN.EditWindow EQN.ResultWindow EQN.ResultObj 
	     EQN.PieceNumber EQN.ContinueFlg EQN.ValidEditWindow EQN.ObjEditWindow)
	(FNS EQN.Make)
	(GLOBALVARS EquationFontSpecs)
	(VARS EquationFontSpecs)
	(PROP ARGNAMES EQN.ObjEditWindow EQN.ContinueFlg EQN.PieceNumber EQN.ResultObj 
	      EQN.ResultWindow EQN.EditWindow)
	(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS
		  (ADDVARS (NLAMA)
			   (NLAML)
			   (LAMA EQN.ObjEditWindow EQN.ContinueFlg EQN.PieceNumber EQN.ResultObj 
				 EQN.ResultWindow EQN.EditWindow)))
	(* * FORMATSTRING module: Part 3 of 3)
	(FNS FS.Box FS.Copy FS.Display FS.Get FS.Put FS.ItemFont FS.ItemValue FS.MakeItem FS.Extract 
	     FS.ExtractFont FS.Insert FS.AllowedChar FS.RealStringP)
	(* * Now load EQUATIONFORMS)
	(FILES EQUATIONFORMS)))
(* * EQUATION module: Part 1 of 3)




(* functions for image object)

(DEFINEQ

(EQIO.CreateFns
  (LAMBDA NIL                                                (* thh: " 5-Dec-85 10:50")
    (IMAGEFNSCREATE (FUNCTION EQIO.Display)
		      (FUNCTION EQIO.Imagebox)
		      (FUNCTION EQIO.Put)
		      (FUNCTION EQIO.Get)
		      (FUNCTION EQIO.Copy)
		      (FUNCTION EQIO.ButtonEventIn)
		      (FUNCTION NILL)
		      (FUNCTION NILL)
		      (FUNCTION NILL)
		      (FUNCTION EQIO.WhenDeleted)
		      (FUNCTION NILL)
		      (FUNCTION NILL)
		      (FUNCTION NILL))))

(EQIO.Create
  (LAMBDA (kind dataList fontSpec objectProps)               (* thh: " 5-Dec-85 10:50")
                                                             (* makes an equation image object of specified kind 
							     and data)
                                                             (* fontSpec, if non-NIL, is used as fontSpec prop of 
							     eqn)
                                                             (* objectProps specifies properties for this object --
							     if NIL then default props for this kind will be used)
    (PROG ((obj (IMAGEOBJCREATE (CONS kind dataList)
				    (COND
				      ((AND (BOUNDP (QUOTE EquationImageFns))
					      (IMAGEFNSP EquationImageFns))
					EquationImageFns)
				      (T (SETQ EquationImageFns (EQIO.CreateFns)))))))
	    (COND
	      ((NOT objectProps)
		(SETQ objectProps (COPYALL (EQIO.GetInfo kind (QUOTE objProps))))))
	    (EQIO.AllProps obj objectProps)
	    (COND
	      (fontSpec (EQIO.EqnProperty obj (QUOTE fontSpec)
					    (COND
					      ((NUMBERP fontSpec)
						(EQN.GetEqnFont fontSpec))
					      (T fontSpec)))))
	    (RETURN obj))))

(EQIO.Imagebox
  (LAMBDA (eqnObj imageStream)                               (* THH "21-May-85 12:13")
                                                             (* determines size of equation)
    (PROG ((spec (EQIO.Specify eqnObj imageStream)))
	    (RETURN (COND
			(spec (EQIO.GetBox spec))
			(T (FS.Box UnknownEquationData imageStream)))))))

(EQIO.Display
  (LAMBDA (eqnObj imageStream)                               (* thh: "31-May-85 09:30")
                                                             (* displays equation)
    (PROG ((curX (DSPXPOSITION NIL imageStream))
	     (curY (DSPYPOSITION NIL imageStream))
	     (spec (EQIO.Specify eqnObj imageStream T))
	     (invertPiece (PROG ((editWindow (EQN.ObjEditWindow eqnObj)))
			          (RETURN (COND
					      (editWindow (EQN.PieceNumber editWindow))
					      (T NIL))))))
	    (COND
	      (spec (for i from 1 to (EQIO.NumPieces eqnObj)
		       bind data pos (desc ←(fetch YDESC of (EQIO.GetBox spec)))
		       do (SETQ data (EQIO.EqnData eqnObj i))
			    (SETQ pos (EQIO.GetDataPosition (EQIO.GetDataSpec spec i)))
			    (COND
			      ((AND pos data)
				(MOVETO (PLUS curX (fetch XCOORD of pos))
					  (PLUS curY (fetch YCOORD of pos)
						  (MINUS desc))
					  imageStream)
				(FS.Display data imageStream (EQ invertPiece i))))))
	      (T (FS.Display UnknownEquationData imageStream invertPiece))))))

(EQIO.ButtonEventIn
  (LAMBDA (eqnObj windowStream selection relX relY window textStream button)
                                                             (* thh: "19-Mar-86 09:23")
                                                             (* handles button press in equation)
    (PROG ((editWindow (EQN.EditWindow window))
	     (CHOICEMENU (CONSTANT (create MENU
					       CENTERFLG ← T
					       ITEMS ←(QUOTE ((Select (QUOTE SELECT)
									"Select the image object")
								 (Edit (QUOTE EDIT)
								       
							    "Edit selected piece of the equation")))))
			 )
	     underEdit)
	    (SETQ underEdit (AND editWindow (EQ eqnObj (EQN.ResultObj editWindow))))
                                                             (* non-NIL if eqnObj is currently being edited)
	    (RETURN (COND
			((OR (KEYDOWNP (QUOTE RSHIFT))
			       (KEYDOWNP (QUOTE LSHIFT))
			       (KEYDOWNP (QUOTE CTRL)))
                                                             (* note: using COPYBUTTONEVENTIN fn instead of this 
							     test doesnt work since it is never called)
			  (COND
			    (underEdit                       (* abort sub edit when obj specially selected in main 
							     window)
				       (EQN.AbortEdit window)
				       (QUOTE CHANGED))
			    (T NIL)))
			(T (SPAWN.MOUSE)
			   (OR (COND
				   ((EQ button (QUOTE LEFT))
                                                             (* check for direct selection of piece within the 
							     equation)
				     (AND (EQ (MENU CHOICEMENU)
						  (QUOTE EDIT))
					    (LET ((piece# (EQIO.Selection eqnObj windowStream relX 
									    relY)))
					         (COND
						   (piece# (EQN.StartEdit eqnObj window piece#)
							   (QUOTE CHANGED))
						   (T NIL)))))
				   ((EQ button (QUOTE MIDDLE))
                                                             (* use menu to allow selection of piece to edit)
				     (LET ((selectFn (EQIO.GetInfo (EQIO.EqnType eqnObj)
								     (QUOTE specialSelectFn)))
					   piece#)
				          (COND
					    ((NOT selectFn)
					      (SETQ selectFn EquationDefaultSelectFn)))
				          (COND
					    ((AND selectFn (SETQ piece# (APPLY* selectFn eqnObj)
						      ))
					      (EQN.StartEdit eqnObj window piece#)
					      (QUOTE CHANGED))
					    (T NIL))))
				   (T NIL))
				 (LET ((wholeEditFn (EQIO.GetInfo (EQIO.EqnType eqnObj)
								    (QUOTE wholeEditFn))))
                                                             (* treat as top level selection and check for edits of
							     global properties)
				      (COND
					(underEdit (EQN.AbortEdit window)))
				      (COND
					((AND wholeEditFn (APPLY* wholeEditFn eqnObj window 
								      button))
					  (QUOTE CHANGED))
					(underEdit (QUOTE CHANGED))
					(T NIL))))))))))

(EQIO.Copy
  (LAMBDA (eqnObj)                                           (* THH "12-Jul-85 10:40")
    (LET ((dataList (EQIO.EqnDataList eqnObj)))
         (EQIO.Create (COPY (EQIO.EqnType eqnObj))
			(for data in dataList collect (FS.Copy data))
			NIL
			(EQIO.CopyList (EQIO.AllProps eqnObj))))))

(EQIO.CopyList
  (LAMBDA (list)                                             (* THH "12-Jul-85 10:44")
                                                             (* copies list down to atoms or strings but sets 
							     anything else to NIL)
                                                             (* datatype values set to NIL -- allows caching such 
							     data only)
    (COND
      ((OR (ATOM list)
	     (STRINGP list))
	list)
      ((LISTP list)
	(for item in list collect (EQIO.CopyList item)))
      (T                                                     (* set value to NIL)
	 NIL))))

(EQIO.Get
  (LAMBDA (fileStream)                                       (* thh: "24-May-85 08:47")
    (PROG ((kind (READ fileStream))
	     (dataList (FS.Get fileStream)))
	    (RETURN (EQIO.Create kind dataList NIL (READ fileStream))))))

(EQIO.Put
  (LAMBDA (eqnObj fileStream)                                (* THH "21-May-85 12:19")
    (PRIN2 (EQIO.EqnType eqnObj)
	     fileStream)
    (FS.Put (EQIO.EqnDataList eqnObj)
	      fileStream)
    (PRIN2 (EQIO.AllProps eqnObj)
	     fileStream)))

(EQIO.WhenDeleted
  (LAMBDA (eqnObj window)                                    (* thh: "15-May-85 11:27")
                                                             (* called when eqnObj is about to be deleted from edit
							     window)
                                                             (* abort any sub edit of this object)
    (PROG ((editWindow (EQN.ValidEditWindow (EQN.EditWindow window)
						eqnObj)))
	    (COND
	      (editWindow (EQN.AbortEdit window))))))

(EQIO.SelectRegion
  (LAMBDA (spec data piece# imageStream)                     (* THH "21-May-85 12:13")
                                                             (* determines selection region for piece in eqnObj)
    (PROG ((dataSpec (EQIO.GetDataSpec spec piece#)))
	    (RETURN (COND
			((EQIO.GetDataSelectRegion dataSpec))
			(data (PROG ((dataBox (FS.Box data imageStream))
				       (pos (EQIO.GetDataPosition dataSpec)))
				      (RETURN (create REGION
							  LEFT ←(fetch XCOORD of pos)
							  BOTTOM ←(DIFFERENCE (fetch YCOORD
										   of pos)
										(fetch YDESC
										   of dataBox))
							  WIDTH ←(fetch XSIZE of dataBox)
							  HEIGHT ←(fetch YSIZE of dataBox)))))
			(T NIL))))))

(EQIO.Selection
  (LAMBDA (eqnObj imageStream relX relY)                     (* thh: "31-May-85 09:31")
                                                             (* returns piece number of data within which selection
							     was made, if any)
                                                             (* note: if slection region for a piece is zero size, 
							     then cannot select that piece)
                                                             (* new TEdit: relY is measured from baseline of object
							     so must adjust since eqn forms measure regions w.r.t.
							     l.l. corner of box)
    (PROG ((spec (EQIO.Specify eqnObj imageStream))
	     piece#)
	    (RETURN (COND
			(spec (add relY (fetch YDESC of (EQIO.GetBox spec)))
			      (SETQ piece# (for i from 1 to (EQIO.NumPieces eqnObj)
						bind region
						do (SETQ region (EQIO.SelectRegion
							 spec
							 (EQIO.EqnData eqnObj i)
							 i imageStream))
						     (COND
						       ((AND region (INSIDEP region relX relY))
							 (RETURN i))))))
			(T                                   (* unknown equation -- not able to select)
			   NIL))))))

(EQIO.DefaultSelectFn
  (LAMBDA (eqnObj)                                           (* thh: "31-May-85 08:34")

          (* provides a menu-based selection of a part of the equation -- returns the piece# of the part selected or NIL if 
	  no part was selected)

                                                             (* this is useful for selecting parts whose select 
							     region on the screen is zero size)
    (PROG ((type (EQIO.EqnType eqnObj))
	     menu)
	    (COND
	      ((EQIO.GetInfo type (QUOTE variable?))
		(SETQ menu (EQIO.EqnProperty eqnObj (QUOTE selectionMenu)))
		(COND
		  ((NOT (type? MENU menu))
		    (SETQ menu (EQIO.MakeSelectionMenu type (EQIO.NumPieces eqnObj)))
		    (EQIO.EqnProperty eqnObj (QUOTE selectionMenu)
					menu))))
	      (T (SETQ menu (EQIO.TypeProp type (QUOTE selectionMenu)))
		 (COND
		   ((NOT (type? MENU menu))
		     (SETQ menu (EQIO.MakeSelectionMenu type (EQIO.NumPieces eqnObj)))
		     (EQIO.TypeProp type (QUOTE selectionMenu)
				      menu)))))
	    (RETURN (COND
			(menu (MENU menu))
			(T NIL))))))

(EQIO.MakeSelectionMenu
  (LAMBDA (type numPieces)                                   (* thh: "19-Mar-86 09:30")
                                                             (* creates a selection menu for the specified type of 
							     equation)
                                                             (* numPieces may be NIL if this is an unknown type of 
							     equation)
    (COND
      ((AND (FIXP numPieces)
	      (IGREATERP numPieces 0))
	(PROG ((pieceNames (EQIO.GetInfo type (QUOTE pieceNames))))
	        (RETURN (create MENU
				    CENTERFLG ← T
				    TITLE ← "Eqn piece?"
				    ITEMS ←(for i from 1 to numPieces bind name
					      collect (SETQ name (CAR pieceNames))
							(COND
							  (name (SETQ pieceNames (CDR pieceNames))
								(LIST name i))
							  (T i)))))))
      (T NIL))))
)
(* * functions to handle individual equation props and data)

(DEFINEQ

(EQIO.EqnType
  (LAMBDA (eqnObj)                                           (* THH " 2-May-85 12:59")
                                                             (* returns type of equation)
    (CAR (IMAGEOBJPROP eqnObj (QUOTE OBJECTDATUM)))))

(EQIO.EqnDataList
  (LAMBDA (eqnObj)                                           (* THH " 2-May-85 12:59")
                                                             (* returns list of data pieces in the equation)
    (CDR (IMAGEOBJPROP eqnObj (QUOTE OBJECTDATUM)))))

(EQIO.SetDataList
  (LAMBDA (eqnObj newDataList)                               (* thh: " 3-Jun-85 08:34")
                                                             (* replaces entire data list of eqn -- caller must 
							     make sure any props, e.g. numPieces, are suitably 
							     adjusted)
    (IMAGEOBJPROP eqnObj (QUOTE OBJECTDATUM)
		    (CONS (EQIO.EqnType eqnObj)
			    newDataList))))

(EQIO.EqnData
  (LAMBDA (eqnObj piece#)                                    (* THH " 2-May-85 13:52")
    (CAR (NTH (EQIO.EqnDataList eqnObj)
		  piece#))))

(EQIO.EqnProperty
  (LAMBDA eqn                                                (* THH " 8-May-85 08:48")
                                                             (* gets and sets individual eqn props)
                                                             (* eqn is of form (eqnObj prop {newValue}))
    (COND
      ((IEQP eqn 2)
	(LISTGET (IMAGEOBJPROP (ARG eqn 1)
				   (QUOTE props))
		   (ARG eqn 2)))
      ((IEQP eqn 3)
	(PROG ((props (IMAGEOBJPROP (ARG eqn 1)
					(QUOTE props))))
	        (COND
		  (props (LISTPUT props (ARG eqn 2)
				    (ARG eqn 3)))
		  (T (SETQ props (LIST (ARG eqn 2)
					   (ARG eqn 3)))))
	        (IMAGEOBJPROP (ARG eqn 1)
				(QUOTE props)
				props))))))

(EQIO.AllProps
  (LAMBDA eqn                                                (* THH " 8-May-85 08:48")
                                                             (* gets and sets all props for eqnObj)
                                                             (* eqn is of form (eqnObj {newProps}))
    (COND
      ((IEQP eqn 1)
	(IMAGEOBJPROP (ARG eqn 1)
			(QUOTE props)))
      ((IEQP eqn 2)
	(IMAGEOBJPROP (ARG eqn 1)
			(QUOTE props)
			(ARG eqn 2))))))

(EQIO.Specify
  (LAMBDA (eqnObj imageStream draw?)                         (* THH " 2-May-85 13:45")
                                                             (* returns specification for equation on imageStream, 
							     and if draw? is not NIL, draws the non-data parts of 
							     the equation)
    (PROG ((formFn (EQIO.GetInfo (EQIO.EqnType eqnObj)
				     (QUOTE formFn))))
	    (RETURN (COND
			(formFn (APPLY* formFn eqnObj imageStream draw?))
			(T NIL))))))

(EQIO.GetInitialProps
  (LAMBDA (type)                                             (* thh: "31-May-85 09:02")
                                                             (* gets initial prop list to use when new equation of 
							     specified type is created)
    (PROG ((props (COPY (EQIO.GetInfo type (QUOTE objectProps))))
	     (initialPropFn (EQIO.GetInfo type (QUOTE initialPropFn)))
	     newProps)
	    (COND
	      ((AND initialPropFn (SETQ newProps (APPLY* initialPropFn type)))
		(COND
		  (props (repeatwhile newProps
			    do (LISTPUT props (CAR newProps)
					    (CADR newProps))
				 (SETQ newProps (CDDR newProps))))
		  (T (SETQ props newProps)))))
	    (COND
	      ((AND props (LISTGET props (QUOTE numPieces))
		      (NOT (EQIO.GetInfo type (QUOTE variable?))))
                                                             (* this equation does not allow a variable number of 
							     pieces)
		(ERROR "EQIO.GetInitialProps: can't specify numPieces for fixed size eqn type = " 
			 type)))
	    (RETURN props))))

(EQIO.NumPieces
  (LAMBDA eqn                                                (* thh: "31-Jul-85 08:49")
                                                             (* gets or sets current number of parts for eqn -- 
							     args are (eqnObj {newValue}))
    (COND
      ((IGREATERP eqn 0)
	(PROG ((eqnObj (ARG eqn 1))
		 type value)
	        (SETQ type (EQIO.EqnType eqnObj))
	        (RETURN (COND
			    ((IEQP eqn 1)
			      (COND
				((AND (EQIO.GetInfo type (QUOTE variable?))
					(FIXP (SETQ value (EQIO.EqnProperty eqnObj
										  (QUOTE numPieces))
						  )))
				  value)
				(T                           (* not variable or different number of parts not 
							     specified)
				   (EQIO.GetInfo type (QUOTE numPieces)))))
			    ((EQIO.GetInfo type (QUOTE variable?))
			      (EQIO.EqnProperty eqnObj (QUOTE numPieces)
						  (ARG eqn 2))
			      (EQIO.NewStructure eqnObj))
			    (T (ERROR "EQIO.NumPieces: equation has fixed # of parts, type = " type)
			       ))))))))

(EQIO.NewStructure
  (LAMBDA (eqnObj)                                           (* thh: " 3-Jun-85 09:21")
                                                             (* called when eqn structure is changed -- e.g. 
							     different number of parts -- to reset any saved menus,
							     etc.)
    (EQIO.EqnProperty eqnObj (QUOTE selectionMenu)
			NIL)
    (PROG ((changeFn (EQIO.GetInfo (EQIO.EqnType eqnObj)
				       (QUOTE changeFn))))
	    (COND
	      (changeFn (APPLY* changeFn eqnObj))))))
)
(* * functions to handle equation specification info)

(DEFINEQ

(EQIO.AddType
  (LAMBDA (type formFn numPieces PROPS)                      (* THH " 1-Jul-85 08:37")
                                                             (* creates info for new equation type)
    (PROG ((newValue (APPEND (LIST (QUOTE formFn)
					 formFn
					 (QUOTE numPieces)
					 numPieces)
				 PROPS)))
	    (PUTPROP type (QUOTE equationInfo)
		       newValue)
	    (COND
	      ((NOT (MEMB type EquationInfo))
		(push EquationInfo type))))
    (EQIO.ResetTypeProps type)))

(EQIO.GetInfo
  (LAMBDA (type info)                                        (* thh: "28-Jun-85 15:17")
                                                             (* returns specified info for equation type)
    (LISTGET (GETPROP type (QUOTE equationInfo))
	       info)))

(EQIO.SetInfo
  (LAMBDA (type info newValue)                               (* thh: "28-Jun-85 15:38")
                                                             (* allows setting particular equation info items for 
							     previously defined equation types)
    (COND
      ((EQIO.IsDefined type)
	(LET ((spec (GETPROP type (QUOTE equationInfo))))
	     (COND
	       (spec (LISTPUT spec info newValue)
		     (PUTPROP type (QUOTE equationInfo)
				spec)
		     (EQIO.ResetTypeProps type)
		     newValue)
	       (T (ERROR "EQIO.SetInfo: warning -- no specifications for eqn type = " type))))))))

(EQIO.TypeProp
  (LAMBDA type                                               (* thh: "31-May-85 09:11")
                                                             (* associates properties with equation types -- e.g. 
							     can be used to store selection menus for equations 
							     with fixed number of parts)
                                                             (* args are (type prop {newValue}))
    (COND
      ((IEQP type 2)
	(LISTGET (GETPROP (ARG type 1)
			      (QUOTE equationProps))
		   (ARG type 2)))
      ((IEQP type 3)
	(PROG ((list (GETPROP (ARG type 1)
				  (QUOTE equationProps))))
	        (COND
		  (list (LISTPUT list (ARG type 2)
				   (ARG type 3)))
		  (T (SETQ list (LIST (ARG type 2)
					  (ARG type 3)))))
	        (PUTPROP (ARG type 1)
			   (QUOTE equationProps)
			   list))))))

(EQIO.ResetTypeProps
  (LAMBDA (type)                                             (* THH " 1-Jul-85 08:36")
                                                             (* removes all props associated with this equation 
							     type -- called when type info redefined)
    (SETQ EquationTypeMenu NIL)
    (PUTPROP type (QUOTE equationProps)
	       NIL)))

(EQIO.IsDefined
  (LAMBDA (type)                                             (* thh: "28-Jun-85 15:27")
                                                             (* returns type if it is a currently defined equation 
							     type, else NIL)
    (COND
      ((MEMB type EquationInfo)
	type)
      (T NIL))))

(EQIO.GetBox
  (LAMBDA (specification)                                    (* THH " 2-May-85 13:22")
                                                             (* gets image box)
    (CAR specification)))

(EQIO.GetDataSpec
  (LAMBDA (specification piece#)                             (* THH " 2-May-85 13:26")
                                                             (* gets data spec for corresponding piece)
    (CAR (NTH specification (ADD1 piece#)))))

(EQIO.GetDataSpecList
  (LAMBDA (specification)                                    (* THH "12-Jul-85 10:22")
    (CDR specification)))

(EQIO.GetDataPosition
  (LAMBDA (dataSpec)                                         (* THH " 2-May-85 13:26")
    (CAR dataSpec)))

(EQIO.GetDataSelectRegion
  (LAMBDA (dataSpec)                                         (* THH " 2-May-85 13:26")
    (CDR dataSpec)))

(EQIO.MakeSpec
  (LAMBDA (box dataSpecList)                                 (* THH " 2-May-85 13:26")
                                                             (* constructs specification)
    (CONS box dataSpecList)))

(EQIO.MakeDataSpec
  (LAMBDA (position selectRegion)                            (* THH " 2-May-85 13:26")
    (CONS position selectRegion)))
)
(* * variable specification)

(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS EquationInfo EquationTypeMenu EquationImageFns UnknownEquationData 
	    EquationDefaultSelectFn)
)

(RPAQQ EquationImageFns NIL)

(RPAQ? EquationInfo NIL)

(RPAQ? EquationDefaultSelectFn (QUOTE EQIO.DefaultSelectFn))
(TEDIT.ADD.MENUITEM TEDIT.DEFAULT.MENU (QUOTE (Equation (QUOTE EQN.Equation))))
(* needed to force the getfn to be recognized before any new eqns defined)
(SETQ EquationImageFns (EQIO.CreateFns))

(RPAQQ UnknownEquationData (((Gacha 10)
			       "[unknown equation]")))

(PUTPROPS EQIO.TypeProp ARGNAMES (NIL (type prop {newValue})
					args))

(PUTPROPS EQIO.NumPieces ARGNAMES (NIL (eqnObj {newValue})
					 args))

(PUTPROPS EQIO.AllProps ARGNAMES (NIL (eqnObj {newValue})
					args))

(PUTPROPS EQIO.EqnProperty ARGNAMES (NIL (eqnObj prop {newValue})
					   args))
(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS 

(ADDTOVAR NLAMA )

(ADDTOVAR NLAML )

(ADDTOVAR LAMA EQN.ObjEditWindow EQN.ContinueFlg EQN.PieceNumber EQN.ResultObj EQN.ResultWindow 
				   EQN.EditWindow EQIO.TypeProp EQIO.NumPieces EQIO.AllProps 
				   EQIO.EqnProperty)
)
(* * EQUATIONEDIT module: Part 2 of 3)




(* functions to edit data pieces)

(DEFINEQ

(EQN.AbortEdit
  (LAMBDA (mainWindow)                                       (* thh: " 3-May-85 11:17")
                                                             (* terminates any eqn edit without allowing any 
							     continuation)
    (PROG ((editWindow (EQN.EditWindow mainWindow)))
	    (COND
	      ((WINDOWP editWindow)
		(EQN.ContinueFlg editWindow NIL)
		(EQN.StopEdit mainWindow))))))

(EQN.StopEdit
  (LAMBDA (mainWindow)                                       (* thh: " 3-May-85 10:31")
                                                             (* terminates any eqn edit)
    (PROG ((editWindow (EQN.EditWindow mainWindow)))
	    (COND
	      ((WINDOWP editWindow)
		(EQN.FinishEdit editWindow)
		(TEDIT.QUIT (TEXTSTREAM editWindow))
		(CLOSEW editWindow))))))

(EQN.ContinueEdit
  (LAMBDA (window)                                           (* thh: "28-Jun-85 14:14")
                                                             (* called after sub edit quits to see if eqn edit 
							     should continue with next piece)

          (* continueFlg is NIL to stop, T to continue incrementing by 1, FIXP to increment by that amount once, 
	  (FIXP . end) to increment up/down to end (end = NIL to contnue until no more), or a function to determine next 
	  piece from current piece (NIL to end))

                                                             (* selection is pending delete for selections that 
							     continue beyond current piece)
    (PROG ((process (WINDOWPROP (EQN.ResultWindow window)
				    (QUOTE PROCESS))))     (* return TTY process to result window)
	    (COND
	      (process (TTY.PROCESS process))))
    (PROG ((continueFlg (EQN.ContinueFlg window))
	     (newPiece# (EQN.PieceNumber window))
	     increment end)
	    (COND
	      ((COND
		  ((EQ continueFlg T)
		    (add newPiece# 1)
		    T)
		  ((NULL continueFlg)
		    NIL)
		  ((FIXP continueFlg)                      (* treat pieces as circular list)
		    (LET ((oldPiece# newPiece#)
			  (numPieces (EQIO.NumPieces (EQN.ResultObj window))))
		         (SETQ newPiece# (IMOD (PLUS oldPiece# continueFlg)
						   numPieces))
		         (COND
			   ((ZEROP newPiece#)
			     (SETQ newPiece# numPieces)))
		         (SETQ continueFlg NIL)            (* this is a one-shot continuation so continueFlg for 
							     new edit to NIL)
		         (NOT (IEQP newPiece# oldPiece#))))
		  ((LISTP continueFlg)
		    (COND
		      ((AND (FIXP (SETQ increment (CAR continueFlg)))
			      (NOT (ZEROP increment))
			      (OR (FIXP (SETQ end (CDR continueFlg)))
				    (NULL end)))
			(add newPiece# increment)
			(COND
			  ((NULL end)                      (* always continue)
			    T)
			  ((MINUSP increment)
			    (IGEQ newPiece# end))
			  (T (ILEQ newPiece# end))))
		      (T                                     (* bad format list -- don't continue)
			 NIL)))
		  ((LITATOM continueFlg)
		    (SETQ newPiece# (APPLY* continueFlg newPiece#))
                                                             (* continue if the function returned a valid piece 
							     number)
		    (FIXP newPiece#))
		  (T (ERROR "EQN.ContinueEdit: Invalid value for continueFlg = " continueFlg)
		     NIL))                                   (* continue with edit of newPiece#)

          (* * continuation of edit requested -- start new edit)


		(EQN.StartNextEdit (EQN.ResultObj window)
				     (EQN.ResultWindow window)
				     newPiece# continueFlg (COND
				       (continueFlg (QUOTE PENDINGDEL))
				       (T NIL))))))))

(EQN.FinishEdit
  (LAMBDA (window)                                           (* thh: " 5-Dec-85 11:06")
                                                             (* returns edited data to calling TEdit)
    (PROG ((mainWindow (EQN.ResultWindow window)))
	    (EQN.ObjEditWindow (EQN.ResultObj window)
				 NIL)
	    (EQN.AbortEdit window)                         (* abort any sub edits)
	    (EQN.UpdateEdit mainWindow (WINDOWPROP window (QUOTE NOUPDATE)))
	    (EQN.EditWindow mainWindow NIL))               (* return T to allow TEdit to quit without user 
							     confirmation)
    T))

(EQN.MakeEditWindow
  (LAMBDA (mainWindow XSIZE YSIZE)                           (* thh: " 6-Dec-85 11:34")
                                                             (* creates window for subeditor)
    (LET ((editWindow (CREATEW (CREATEREGION 0 0 (fetch (REGION WIDTH)
							of (WINDOWPROP mainWindow (QUOTE REGION)
									   ))
						 (PLUS 10 (HEIGHTIFWINDOW (TIMES 2 YSIZE)
									      T)))
				 "Eqn edit" NIL T)))
         (ATTACHWINDOW editWindow mainWindow (QUOTE BOTTOM)
			 (QUOTE LEFT)
			 (QUOTE LOCALCLOSE))               (* note: edit window is justified -- later may 
							     automatically reshape it as new text is entered)
         (WINDOWADDPROP editWindow (QUOTE CLOSEFN)
			  (QUOTE DETACHWINDOW))            (* edit window will be detached when closed)

          (* * allow main and edit windows to be independently reshaped)


         (WINDOWDELPROP editWindow (QUOTE PASSTOMAINCOMS)
			  (QUOTE SHAPEW))
         (WINDOWADDPROP editWindow (QUOTE REJECTMAINCOMS)
			  (QUOTE SHAPEW))

          (* * make windows snuggle after reshape)


         (WINDOWADDPROP editWindow (QUOTE RESHAPEFN)
			  (QUOTE EQN.SnuggleWindows))
         (WINDOWADDPROP mainWindow (QUOTE RESHAPEFN)
			  (QUOTE EQN.SnuggleWindows))
     editWindow)))

(EQN.SetUpEdit
  (LAMBDA (editWindow mainWindow eqnObj continueFlg piece#)
                                                             (* thh: " 5-Dec-85 10:59")
                                                             (* sets up props for sub edit)
    (EQN.ResultWindow editWindow mainWindow)
    (EQN.ResultObj editWindow eqnObj)
    (EQN.ContinueFlg editWindow continueFlg)
    (EQN.PieceNumber editWindow piece#)
    (WINDOWPROP editWindow (QUOTE TEDIT.MENU.COMMANDS)
		  (QUOTE (Find Looks Substitute Character% Looks (Equation (QUOTE EQN.Equation))
				 (Exit (QUOTE Quit)
				       "exit from equation editor"
				       (SUBITEMS (Next% Piece (QUOTE EQN.NextPiece))
						 (Finish% Eqn (QUOTE EQN.FinishEqn))
						 (Abort (QUOTE EQN.NoUpdateAbort)
							"Terminates eqn editor without changing eqn.")
						 )))))
    (EQN.ObjEditWindow eqnObj editWindow)))

(EQN.StartEdit
  (LAMBDA (eqnObj mainWindow piece# continueFlg initialSEL)
                                                             (* thh: " 6-Dec-85 11:21")
                                                             (* Starts edit of specified piece of eqnObj which is 
							     currently in TEdit mainWindow.
							     Starts new edit only if piece exists.)
                                                             (* continueFlg determines action on normal exit)
                                                             (* initialSEL is initial selection or char number)
    (EQN.AbortEdit mainWindow)                             (* abort any previous eqn edit)
    (COND
      ((AND (IGREATERP piece# 0)
	      (ILEQ piece# (EQIO.NumPieces eqnObj)))
	(PROG ((data (EQIO.EqnData eqnObj piece#))
		 editWindow editStream box len)
	        (SETQ box (FS.Box data (DECODE/WINDOW/OR/DISPLAYSTREAM mainWindow)))
	        (SETQ editWindow (EQN.MakeEditWindow mainWindow (fetch XSIZE of box)
							 (fetch YSIZE of box)))
	        (TEDIT NIL editWindow NIL (APPEND (QUOTE (QUITFN EQN.FinishEdit AFTERQUITFN 
								       EQN.ContinueEdit CHARFN 
								       EQN.CharFn))
						      (LIST (QUOTE PROMPTWINDOW)
							      (OR (TEXTPROP (TEXTSTREAM 
										       mainWindow)
										(QUOTE PROMPTWINDOW)
										)
								    (GETPROMPTWINDOW mainWindow)))))
                                                             (* sub edit uses same prompt window as main editor)
	        (EQN.SetUpEdit editWindow mainWindow eqnObj continueFlg piece#)
	        (SETQ editStream (TEXTSTREAM editWindow))
	        (SETQ len (FS.Insert data editStream))
	        (COND
		  ((EQ initialSEL (QUOTE PENDINGDEL))
		    (TEDIT.SETSEL editStream 1 len (QUOTE RIGHT)
				    T))
		  ((FIXP initialSEL)
		    (TEDIT.SETSEL editStream initialSEL 0 (QUOTE RIGHT)))
		  ((type? SELECTION initialSEL)
		    (TEDIT.SETSEL editStream initialSEL)))
	        (EQN.EditWindow mainWindow editWindow)
	        (COND
		  ((NOT (EQN.SubEditorP mainWindow))

          (* this is a main edit window -- make sure sub edits are aborted when main edit is done (don't call EQN.FinishEdit 
	  since want QUITFN to return NIL to allow user to confirm quit at top level))


		    (TEXTPROP (TEXTSTREAM mainWindow)
				(QUOTE QUITFN)
				(QUOTE EQN.AbortEdit))))   (* old TEdit version: (WINDOWPROP mainWindow 
							     (QUOTE TEDIT.QUITFN) (QUOTE EQN.FinishEdit)))
	    )))))

(EQN.StartNextEdit
  (LAMBDA (eqnObj mainWindow newPiece# continueFlg initialSEL)
                                                             (* thh: "29-May-85 10:10")
                                                             (* if another piece of eqnObj exists, starts an edit 
							     of it)
    (EQN.StartEdit eqnObj mainWindow newPiece# continueFlg initialSEL)
                                                             (* mark obj as changed to allow display indication of 
							     new piece being edited)
    (TEDIT.OBJECT.CHANGED (TEXTSTREAM mainWindow)
			    eqnObj)))

(EQN.UpdateEdit
  (LAMBDA (mainWindow noChangeFLG)                           (* thh: " 6-Dec-85 09:52")
                                                             (* updates sub edit in mainWindow)
                                                             (* noChangeFLG non-NIL means main eqn not changed, but
							     still must notify TEdit obj is changed to update 
							     display, e.g. uninvert edited piece)
    (PROG ((editWindow (EQN.EditWindow mainWindow))
	     value datum eqnObj piece# ptr)
	    (COND
	      ((WINDOWP editWindow)
		(SETQ eqnObj (EQN.ResultObj editWindow))
		(COND
		  ((NOT noChangeFLG)
		    (EQN.UpdateEdit editWindow)            (* get updates of any sub edits)
		    (SETQ piece# (EQN.PieceNumber editWindow))
		    (SETQ value (FS.Extract (TEXTSTREAM editWindow)))
		    (SETQ datum (EQIO.EqnDataList eqnObj))
		    (SETQ ptr (NTH datum piece#))
		    (COND
		      (ptr (RPLACA ptr value))
		      (T                                     (* put value on end of datum)
			 (EQIO.SetDataList eqnObj (NCONC1 datum value))))))
		(EQN.CheckWindowSize mainWindow eqnObj)
		(TEDIT.OBJECT.CHANGED (TEXTSTREAM mainWindow)
					eqnObj))))))

(EQN.DefaultData
  (LAMBDA (type fontSpec numPieces dataList)                 (* thh: " 6-Dec-85 09:44")
                                                             (* gets list of default data items to use for equation
							     specified type)
                                                             (* currently just a single item -- blank)

          (* if dataList is specified its values are used as the default data -- either directly if the item is a format 
	  string or with default font for the piece if it is a string)


    (COND
      ((NOT numPieces)
	(SETQ numPieces (EQIO.GetInfo type (QUOTE numPieces)))))
    (PROG ((initialData (EQIO.GetInfo type (QUOTE initialData))))
	    (RETURN
	      (COND
		((AND initialData (LITATOM initialData))
		  (APPLY* initialData fontSpec type numPieces dataList))
		(T
		  (COND
		    ((NLISTP initialData)
		      (SETQ initialData NIL)))
		  (PROG ((fontNumber (EQN.EquationFontNumber fontSpec)))
		          (RETURN
			    (COND
			      (numPieces (for i from 1 to numPieces bind initial item
					    collect
					     (SETQ initial (pop initialData))
					     (SETQ item (pop dataList)) 
                                                             (* each piece of the equation consists of a 
							     single-item format string (unless specified otherwise 
							     by value in dataList))
					     (COND
					       ((AND item (LISTP item))
						 item)
					       ((IMAGEOBJP item)
						 (LIST item))
					       (T (LIST (FS.MakeItem
							    (EQN.EquationFont
							      (PLUS fontNumber (COND
									((FIXP initial)
									  initial)
									(T 0))))
							    (COND
							      (item (MKSTRING item))
							      (T " "))))))))
			      (T NIL))))))))))

(EQN.TypeMenu
  (LAMBDA NIL                                                (* THH " 1-Jul-85 08:42")
                                                             (* returns menu of equation types)
    (COND
      ((AND (BOUNDP (QUOTE EquationTypeMenu))
	      (type? MENU EquationTypeMenu))
	EquationTypeMenu)
      (T                                                     (* compute menu from EquationInfo)
	 (SETQ EquationTypeMenu (create MENU
					    ITEMS ←(SORT (for item in EquationInfo
							      bind label
							      collect (SETQ label
									  (EQIO.GetInfo
									    item
									    (QUOTE menuLabel)))
									(COND
									  (label (LIST
										   label
										   (KWOTE item)))
									  (T item)))
							   T)
					    TITLE ← "Equation Types"))))))
)
(* * hooks to control behavior of equation subeditor)

(DEFINEQ

(EQN.Equation
  (LAMBDA (textStream)                                       (* thh: "31-May-85 08:58")
                                                             (* allows insertion of an equation at current 
							     selection in textStream)
    (PROG ((type (MENU (EQN.TypeMenu)))
	     currentFont window eqnObj props)
	    (COND
	      (type (SETQ currentFont (FS.ExtractFont textStream))
		    (SETQ window (EQN.WindowFromText textStream))
		    (SETQ props (EQIO.GetInitialProps type))
		    (SETQ eqnObj (EQIO.Create type (EQN.DefaultData type currentFont
									  (LISTGET props
										     (QUOTE 
											numPieces)))
						  currentFont props))
		    (EQN.CheckWindowSize window eqnObj)
		    (TEDIT.INSERT.OBJECT eqnObj textStream)
		    (EQN.StartEdit eqnObj window 1 T (QUOTE PENDINGDEL))
                                                             (* must mark obj changed to allow display to indicate 
							     obj is being edited)
                                                             (* TEDIT.OBJECT.CHANGED can not be called directly 
							     from EQN.StartEdit because that fcn is called by the 
							     button fcn)
		    (TEDIT.OBJECT.CHANGED textStream eqnObj))))))

(EQN.NextPiece
  (LAMBDA (textStream)                                       (* thh: "29-May-85 10:11")
                                                             (* aborts edit and continues with next piece of eqn)
    (PROG ((editWindow (EQN.WindowFromText textStream))
	     mainWindow)
	    (SETQ mainWindow (EQN.ResultWindow editWindow))
	    (COND
	      ((WINDOWP mainWindow)
		(EQN.ContinueFlg editWindow (COND
				     ((EQN.ContinueFlg editWindow))
				     (T 1)))
		(EQN.StopEdit mainWindow))))))

(EQN.FinishEqn
  (LAMBDA (textStream)                                       (* thh: " 3-May-85 11:53")
                                                             (* aborts edit without any continuation)
    (PROG ((editWindow (EQN.WindowFromText textStream))
	     mainWindow)
	    (SETQ mainWindow (EQN.ResultWindow editWindow))
	    (COND
	      ((WINDOWP mainWindow)
		(EQN.AbortEdit mainWindow))))))

(EQN.NoUpdateAbort
  (LAMBDA (textStream)                                       (* thh: " 5-Dec-85 11:21")
                                                             (* aborts equation editor without updating eqn in main
							     window)
    (EQN.PreventUpdate (EQN.WindowFromText textStream))
    (EQN.FinishEqn textStream)))

(EQN.PreventUpdate
  (LAMBDA (window)                                           (* thh: " 5-Dec-85 11:21")
                                                             (* prevents any update of this or any subeditors)
    (COND
      ((WINDOWP window)
	(WINDOWPROP window (QUOTE NOUPDATE)
		      T)
	(EQN.PreventUpdate (EQN.EditWindow window))))))

(EQN.CharFn
  (LAMBDA (textObj charcode)                                 (* thh: "19-Aug-85 08:31")
                                                             (* prevents control chars from being inserted into the
							     document)
                                                             (* allows any char that can be used in a format string
							     and a few special editing chars: backspace & delete)
                                                             (* allows NEXT syntax char to exit from editor)
    (LET ((syntax (EQN.TEditSpecialChar textObj charcode)))
         (COND
	   ((EQ syntax (QUOTE NEXT))                     (* next syntax key pressed -- see if this should quit 
							     eqn editor)
	     (COND
	       ((TEDIT.FIND (TEXTSTREAM textObj)
			      ">>*<<" NIL NIL T)             (* special char -- let TEdit advance to next slot)
		 T)
	       (T                                            (* force exit)
		  (EQN.FinishEdit (EQN.WindowFromText textObj))
                                                             (* TEDIT.QUIT does not automatically call the QUITFN)
		  (TEDIT.QUIT (TEXTSTREAM textObj))
		  NIL)))
	   (syntax                                           (* special character)
		   T)
	   ((FS.AllowedChar charcode)                      (* this character can be in format strings)
	     T)
	   (T                                                (* don't allow this char to be inserted)
	      (FLASHWINDOW (EQN.WindowFromText textObj))
	      NIL)))))

(EQN.TEditSpecialChar
  (LAMBDA (textObj charcode)                                 (* thh: "16-Aug-85 09:35")
                                                             (* if charcode is a control character for edit 
							     specified by textObj returns its syntax class, else 
							     NIL)
                                                             (* this may not correspond exactly to the procedure 
							     TEdit uses to determine syntax of a character -- need 
							     to also check terminal table??)
    (LET ((table (OR (READTABLEP (TEXTPROP textObj (QUOTE READTABLE)))
		       TEDIT.READTABLE))
	  syntax)
         (SETQ syntax (TEDIT.GETSYNTAX charcode table))
         (COND
	   ((EQ syntax (QUOTE NONE))
	     (SETQ syntax NIL)))
     syntax)))

(EQN.SnuggleWindows
  (LAMBDA (window)                                           (* thh: " 6-Dec-85 12:07")
                                                             (* reshape fn for independently reshapeable attached 
							     windows)

          (* * move attached windows)


    (REPOSITIONATTACHEDWINDOWS window)                     (* Does not work correctly when window itself has 
							     attached windows ??)

          (* * move main window)


    (EQN.SnuggleMainWindow window)))

(EQN.SnuggleMainWindow
  (LAMBDA (window)                                           (* thh: " 6-Dec-85 11:44")
                                                             (* moves all windows in main window chain)
    (LET ((mainW (MAINWINDOW window))
	  region)
         (COND
	   ((AND (WINDOWP mainW)
		   (NOT (EQ mainW window)))
	     (SETQ region (WINDOWREGION window))         (* position main window above window)
                                                             (* note that MOVEW must be rejected by window so that 
							     moving main window wont also move attached window)
	     (RESETLST (RESETSAVE (WINDOWADDPROP window (QUOTE REJECTMAINCOMS)
						       (QUOTE MOVEW))
				      (BQUOTE (WINDOWDELPROP , window REJECTMAINCOMS MOVEW)))
			 (MOVEW mainW (fetch (REGION LEFT) of region)
				  (PLUS (fetch (REGION BOTTOM) of region)
					  (fetch (REGION HEIGHT) of region))))
	     (EQN.SnuggleMainWindow mainW))))))
)
(* * functions to handle equation fonts)

(DEFINEQ

(EQN.EquationFontNumber
  (LAMBDA (fontSpec)                                         (* thh: "31-Jul-85 08:48")
                                                             (* returns number of the font to use for normal size 
							     parts of the equation)
                                                             (* fontSpec can be a number which then corresponds to 
							     the size of the font)
    (COND
      ((NOT fontSpec)
	(SETQ fontSpec DEFAULTFONT)))
    (PROG ((size (OR (NUMBERP fontSpec)
			 (FONTPROP fontSpec (QUOTE SIZE)))))
	    (RETURN (for i from 1 to (ARRAYSIZE EquationFontSpecs)
			 smallest (ABS (DIFFERENCE (FONTPROP (ELT EquationFontSpecs i)
								     (QUOTE SIZE))
							 size)))))))

(EQN.EquationFont
  (LAMBDA (n)                                                (* thh: " 5-Dec-85 11:26")
                                                             (* returns equation font number n)
    (COPY (ELT EquationFontSpecs (MAX 1 (MIN (ARRAYSIZE EquationFontSpecs)
						     n))))))

(EQN.GetEqnFont
  (LAMBDA (fontSpec)                                         (* thh: "31-Jul-85 08:52")
    (EQN.EquationFont (EQN.EquationFontNumber fontSpec))))

(EQN.MakeFS
  (LAMBDA (item fontSpec)                                    (* thh: "31-Jul-85 08:58")
                                                             (* constructs a single element format string)
    (COND
      ((IMAGEOBJP item)
	(LIST item))
      ((LISTP item)
	item)
      (T (LIST (FS.MakeItem fontSpec (MKSTRING item)))))))
)
(* * utilities)

(DEFINEQ

(EQN.AdjustWindow
  (LAMBDA (editWindow dWidth dHeight)                        (* thh: " 6-Dec-85 12:09")
                                                             (* reshapes subeditor window to have extra width and 
							     height)
    (PROG ((region (WINDOWPROP editWindow (QUOTE REGION)))
	     (attachedWindows (ATTACHEDWINDOWS editWindow))
	     newHeight howAttached)
	    (SETQ newHeight (MAX (HEIGHTIFWINDOW 10 T)
				     (PLUS (fetch HEIGHT of region)
					     dHeight)))      (* want to shape this window only, not any attached 
							     windows -- depends on correctly setting props when 
							     edit windows created)
                                                             (* SETQ howAttached (for window in attachedWindows 
							     collect (DETACHWINDOW window)))
	    (SHAPEW editWindow (create REGION
					   LEFT ←(fetch LEFT of region)
					   BOTTOM ←(DIFFERENCE (fetch BOTTOM of region)
								 (DIFFERENCE newHeight
									       (fetch HEIGHT
										  of region)))
					   WIDTH ←(MAX (WIDTHIFWINDOW 10)
							 (PLUS (fetch WIDTH of region)
								 dWidth))
					   HEIGHT ← newHeight))
                                                             (* reattach the windows -- note that LOCALCLOSE is 
							     assumed for all windows)
                                                             (* for window in attachedWindows as how in howAttached
							     do (ATTACHWINDOW window editWindow 
							     (CAR how) (CDR how) (QUOTE LOCALCLOSE)))
	)))

(EQN.CheckWindowSize
  (LAMBDA (window eqnObj)                                    (* thh: "29-May-85 08:52")
                                                             (* makes sure window can contain new obj -- currently 
							     only checks based on height of new obj, assuming YDESC
							     not too large)
    (COND
      ((EQN.SubEditorP window)                             (* only adjust for subeditors 
							     (They contain a single line of text))
	(PROG ((box (APPLY* (IMAGEOBJPROP eqnObj (QUOTE IMAGEBOXFN))
				eqnObj
				(DECODE/WINDOW/OR/DISPLAYSTREAM window)))
		 (height (WINDOWPROP window (QUOTE HEIGHT)))
		 extraHeight)
	        (SETQ extraHeight (DIFFERENCE (MIN 400 (TIMES 2 (fetch YSIZE of box)))
						  height))   (* for now require window to be twice as high as 
							     object so don't have to check YDESC -- should work for
							     most cases)
	        (COND
		  ((IGREATERP extraHeight 0)
		    (EQN.AdjustWindow window 0 extraHeight))))))))
)
(DEFINEQ

(EQN.SubEditorP
  (LAMBDA (window)                                           (* thh: "28-May-85 09:27")
                                                             (* non-NIL if window has a eqn subeditor running in 
							     it)
    (EQN.ResultWindow window)))

(EQN.WindowFromText
  (LAMBDA (textObjORStream)                                  (* thh: "28-Jun-85 14:32")
                                                             (* gets window corresponding to a text object or 
							     stream)
                                                             (* note: \WINDOW field actually is a list whose only 
							     element is the window)
    (LET ((w (fetch \WINDOW of (TEXTOBJ textObjORStream))))
         (OR (WINDOWP w)
	       (WINDOWP (CAR w))
	       (ERROR "EQN.WindowFromText: unable to find window for textobj/stream = " 
			textObjORStream)))))

(EQN.EditWindow
  (LAMBDA window                                             (* thh: " 3-May-85 08:55")
                                                             (* returns or sets window of any sub edit)
    (COND
      ((IEQP window 1)
	(PROG ((w (WINDOWPROP (ARG window 1)
				  (QUOTE EditWindow))))    (* test for valid window)
	        (RETURN (COND
			    ((WINDOWP w)
			      (COND
				((AND (OPENWP w)
					(EQ (EQN.ResultWindow w)
					      (ARG window 1)))
				  w)
				(T (WINDOWPROP (ARG window 1)
						 (QUOTE EditWindow)
						 NIL)
				   NIL)))
			    (T NIL)))))
      ((IEQP window 2)
	(WINDOWPROP (ARG window 1)
		      (QUOTE EditWindow)
		      (ARG window 2)))
      (T NIL))))

(EQN.ResultWindow
  (LAMBDA editWindow                                         (* THH " 2-May-85 16:20")
                                                             (* returns or sets main window for a sub edit)
    (COND
      ((IEQP editWindow 1)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE ResultWindow)))
      ((IEQP editWindow 2)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE ResultWindow)
		      (ARG editWindow 2)))
      (T NIL))))

(EQN.ResultObj
  (LAMBDA editWindow                                         (* THH " 2-May-85 16:25")
                                                             (* returns or sets object being edited)
    (COND
      ((IEQP editWindow 1)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE ResultObj)))
      ((IEQP editWindow 2)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE ResultObj)
		      (ARG editWindow 2)))
      (T NIL))))

(EQN.PieceNumber
  (LAMBDA editWindow                                         (* THH " 2-May-85 16:37")
                                                             (* returns or sets number of piece being edited)
    (COND
      ((IEQP editWindow 1)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE PieceNumber)))
      ((IEQP editWindow 2)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE PieceNumber)
		      (ARG editWindow 2)))
      (T NIL))))

(EQN.ContinueFlg
  (LAMBDA editWindow                                         (* THH " 2-May-85 16:25")
                                                             (* returns or sets continuation flag)
                                                             (* THH " 2-May-85 13:35")
    (COND
      ((IEQP editWindow 1)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE ContinueFlg)))
      ((IEQP editWindow 2)
	(WINDOWPROP (ARG editWindow 1)
		      (QUOTE ContinueFlg)
		      (ARG editWindow 2)))
      (T NIL))))

(EQN.ValidEditWindow
  (LAMBDA (editWindow eqnObj)                                (* THH " 8-May-85 09:44")
                                                             (* returns editWindow if it is a window currently 
							     being used to edit eqnObj, else NIL)
    (COND
      ((AND (WINDOWP editWindow)
	      (OPENWP editWindow)
	      (EQ (EQN.ResultObj editWindow)
		    eqnObj))
	editWindow)
      (T NIL))))

(EQN.ObjEditWindow
  (LAMBDA eqn                                                (* THH " 8-May-85 10:01")
                                                             (* gets or sets edit window for eqnObj)
                                                             (* eqn is of the form (eqnObj {newEditWindow}))
    (PROG (editWindow eqnObj)
	    (COND
	      ((AND (IGREATERP eqn 0)
		      (SETQ eqnObj (ARG eqn 1))
		      (IMAGEOBJP eqnObj))
		(RETURN (COND
			    ((IEQP eqn 1)
			      (SETQ editWindow (IMAGEOBJPROP eqnObj (QUOTE editWindow)))
			      (COND
				((EQN.ValidEditWindow editWindow eqnObj))
				(editWindow                  (* remove invalid edit window prop)
					    (IMAGEOBJPROP eqnObj (QUOTE editWindow)
							    NIL)
					    NIL)
				(T NIL)))
			    ((IEQP eqn 2)
			      (SETQ editWindow (EQN.ValidEditWindow (ARG eqn 2)
									eqnObj))
			      (IMAGEOBJPROP eqnObj (QUOTE editWindow)
					      editWindow)))))))))
)
(DEFINEQ

(EQN.Make
  (LAMBDA (type dataList fontSpec PROPS)                     (* thh: " 9-Jan-86 10:12")
                                                             (* creates equation of specified type with given 
							     dataList -- for variable piece eqns PROPS should 
							     include numPieces)
    (COND
      ((EQIO.IsDefined type)
	(LET ((numPieces (LISTGET PROPS (QUOTE numPieces))))
	     (EQIO.Create type (EQN.DefaultData type fontSpec (COND
						      ((EQIO.GetInfo type (QUOTE variable?))
							numPieces)
						      (numPieces (ERROR 
							    "Can't specify numPieces for type = "
									  type))
						      (T NIL))
						    dataList)
			    fontSpec PROPS)))
      (T (ERROR "Unknown equation type = " type)))))
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS EquationFontSpecs)
)

(RPAQ EquationFontSpecs (READARRAY 3 (QUOTE POINTER) 1))
((TimesRoman 8)
(TimesRoman 10)
(TimesRoman 12)
NIL
)

(PUTPROPS EQN.ObjEditWindow ARGNAMES (NIL (eqnObj {newEditWindow})
					    args))

(PUTPROPS EQN.ContinueFlg ARGNAMES (NIL (editWindow {continueFlg})
					  args))

(PUTPROPS EQN.PieceNumber ARGNAMES (NIL (editWindow {pieceNumber})
					  args))

(PUTPROPS EQN.ResultObj ARGNAMES (NIL (editWindow {resultObj})
					args))

(PUTPROPS EQN.ResultWindow ARGNAMES (NIL (editWindow {resultWindow})
					   args))

(PUTPROPS EQN.EditWindow ARGNAMES (NIL (window {editWindow})
					 args))
(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS 

(ADDTOVAR NLAMA )

(ADDTOVAR NLAML )

(ADDTOVAR LAMA EQN.ObjEditWindow EQN.ContinueFlg EQN.PieceNumber EQN.ResultObj EQN.ResultWindow 
				   EQN.EditWindow)
)
(* * FORMATSTRING module: Part 3 of 3)

(DEFINEQ

(FS.Box
  (LAMBDA (data imageStream)                                 (* thh: "31-Jul-85 08:12")

          (* determines box within which data will be displayed on imageStream -- data is a list whose elements are either 
	  image objs or lists of the form (FontSpec String))


    (for item in data
       bind (width ← 0)
	      (ascent ← 0)
	      (descent ← 0)
       do (PROG ((itemWidth 0)
		     (itemAscent 0)
		     (itemDescent 0)
		     fullFont imageBox)
		    (COND
		      ((IMAGEOBJP item)
			(SETQ imageBox (APPLY* (IMAGEOBJPROP item (QUOTE IMAGEBOXFN))
						   item imageStream))
			(SETQ itemWidth (fetch XSIZE of imageBox))
			(SETQ itemAscent (DIFFERENCE (fetch YSIZE of imageBox)
							 (fetch YDESC of imageBox)))
			(SETQ itemDescent (fetch YDESC of imageBox)))
		      ((FS.RealStringP item)
			(SETQ fullFont (FONTCREATE (FS.ItemFont item)
						       NIL NIL NIL imageStream))
			(SETQ itemWidth (STRINGWIDTH (FS.ItemValue item)
							 fullFont))
			(SETQ itemAscent (FONTPROP fullFont (QUOTE ASCENT)))
			(SETQ itemDescent (FONTPROP fullFont (QUOTE DESCENT)))))
		    (add width itemWidth)
		    (SETQ ascent (MAX ascent itemAscent))
		    (SETQ descent (MAX descent itemDescent)))
       finally (RETURN (create IMAGEBOX
				     XSIZE ← width
				     YSIZE ←(PLUS ascent descent)
				     YDESC ← descent
				     XKERN ← 0)))))

(FS.Copy
  (LAMBDA (data)                                             (* THH "21-May-85 12:38")

          (* constructs a copy of data -- data is a list whose elements are either image objs or lists of the form 
	  (FontSpec String))


    (for item in data collect (COND
				      ((IMAGEOBJP item)    (* note: COPYALL doesn't call imageobj copyfn so it 
							     can't be used here)
					(APPLY* (IMAGEOBJPROP item (QUOTE COPYFN))
						  item))
				      (T (COPYALL item))))))

(FS.Display
  (LAMBDA (data imageStream invert?)                         (* thh: "31-Jul-85 08:12")
                                                             (* displays data on imageStream -- data is a list 
							     whose elements are either image objs or lists of the 
							     form (FontSpec String))
    (PROG (xStart yStart)
	    (COND
	      (invert? (SETQ xStart (DSPXPOSITION NIL imageStream))
		       (SETQ yStart (DSPYPOSITION NIL imageStream))))
	    (for item in data do (COND
					 ((IMAGEOBJP item)
					   (PROG ((xPos (DSPXPOSITION NIL imageStream))
						    (yPos (DSPYPOSITION NIL imageStream)))
					           (APPLY* (IMAGEOBJPROP item (QUOTE DISPLAYFN))
							     item imageStream)
					           (MOVETO
						     (PLUS xPos (fetch XSIZE
								     of (APPLY*
									    (IMAGEOBJPROP
									      item
									      (QUOTE IMAGEBOXFN))
									    item imageStream)))
						     yPos imageStream)))
					 ((FS.RealStringP item)
					   (PROG ((oldFont (DSPFONT NIL imageStream)))
					           (DSPFONT (FS.ItemFont item)
							      imageStream)
					           (PRIN1 (FS.ItemValue item)
							    imageStream)
					           (DSPFONT oldFont imageStream)))))
	    (COND
	      (invert? (PROG ((box (FS.Box data imageStream)))
			       (DSPFILL (create REGION
						    LEFT ← xStart
						    BOTTOM ←(DIFFERENCE yStart
									  (fetch YDESC
									     of box))
						    WIDTH ←(fetch XSIZE of box)
						    HEIGHT ←(fetch YSIZE of box))
					  BLACKSHADE
					  (QUOTE INVERT)
					  imageStream)))))))

(FS.Get
  (LAMBDA (fileStream)                                       (* thh: "13-Jun-85 09:17")
                                                             (* reads data from fileStream -- data is a list whose 
							     elements are either image objs or lists of the form 
							     (FontSpec String))
                                                             (* also reads a list of such data items)
    (HREAD fileStream)))

(FS.Put
  (LAMBDA (data fileStream)                                  (* THH " 2-May-85 14:31")
                                                             (* puts data on fileStream -- data is a list whose 
							     elements are either image objs or lists of the form 
							     (FontSpec String))
                                                             (* also writes a list of such data items)
    (HPRINT data fileStream)))

(FS.ItemFont
  (LAMBDA (dataItem)                                         (* thh: "15-May-85 11:29")
                                                             (* returns font spec of single data item)
    (COND
      ((LISTP dataItem)
	(CAR dataItem))
      (T NIL))))

(FS.ItemValue
  (LAMBDA (dataItem)                                         (* THH "21-May-85 12:28")
                                                             (* returns string of single data item or image object)
    (COND
      ((LISTP dataItem)
	(CADR dataItem))
      ((IMAGEOBJP dataItem)
	dataItem))))

(FS.MakeItem
  (LAMBDA (fontSpec string)                                  (* thh: "15-May-85 11:29")
                                                             (* makes data item from fontSpec and string)
    (LIST fontSpec string)))

(FS.Extract
  (LAMBDA (stream)                                           (* thh: "31-Jul-85 08:16")
                                                             (* extracts data from TEdit stream)
    (SETFILEPTR stream 0)                                  (* BIN gets imageObj or individual characters)
    (PROG ((EOFptr (GETEOFPTR stream))
	     (CHcount 0)
	     data result)
	    (SETQ data (while (ILESSP CHcount EOFptr)
			    collect (add CHcount 1)
				      (CONS CHcount (BIN stream))))
                                                             (* data has (ch# . item))
                                                             (* now combine characters into strings and get font 
							     information)
	    (SETQ data (for item in data collect item
			    unless (AND (NUMBERP (CDR item))
					    (NOT (FS.AllowedChar (CDR item))))))
                                                             (* remove control characters, e.g. CR, LF, tab...)
	    (SETQ result (while data bind item fontSpec
			      collect (SETQ item (CAR data))
					(SETQ data (CDR data)) 
                                                             (* note that imageobjs are not copied so changes to 
							     returned obj will also change original)
					(COND
					  ((IMAGEOBJP (CDR item)))
					  (T (SETQ fontSpec (FS.ExtractFont stream (CAR item)))
					     (PROG ((string (MKSTRING (CHARACTER (CDR item))))
						      (nextItem (CAR data)))
						     (while (AND nextItem
								     (NOT (IMAGEOBJP
									      (CDR nextItem)))
								     (EQUAL fontSpec
									      (FS.ExtractFont
										stream
										(CAR nextItem))))
							do (SETQ string
							       (CONCAT string (CHARACTER
									   (CDR nextItem))))
							     (SETQ data (CDR data))
							     (SETQ nextItem (CAR data)))
						     (RETURN (FS.MakeItem fontSpec string)))))))
	    (RETURN (COND
			((AND result (FS.RealStringP (CAR result)))
                                                             (* first item is a string)
			  result)
			(T                                   (* preserve initial font by including a null string 
							     item at beginning of list)
			   (CONS (FS.MakeItem (FS.ExtractFont stream (COND
								      ((ZEROP EOFptr)
									NIL)
								      (T 1)))
						  "")
				   result)))))))

(FS.ExtractFont
  (LAMBDA (stream selOrCh#)                                  (* thh: "20-Feb-86 14:05")
                                                             (* gets font spec for specified selection)
    (PROG ((looks (TEDIT.GET.LOOKS stream selOrCh#)))
	    (RETURN (LIST (LISTGET looks (QUOTE FAMILY))
			      (LISTGET looks (QUOTE SIZE))
			      (LIST (LISTGET looks (QUOTE WEIGHT))
				      (LISTGET looks (QUOTE SLOPE))
				      (LISTGET looks (QUOTE EXPANSION))))))))

(FS.Insert
  (LAMBDA (data stream)                                      (* thh: "13-Aug-85 10:59")
                                                             (* inserts data list into TEdit stream)
    (for item in data bind (length ← 0) do (COND
						     ((IMAGEOBJP item)
						       (add length 1)
						       (TEDIT.INSERT.OBJECT item stream))
						     ((FS.RealStringP item)
						       (add length (NCHARS (FS.ItemValue item)))
						       (TEDIT.INSERT stream (FS.ItemValue item)
								       NIL
								       (FONTCREATE (FS.ItemFont
										       item))))
						     (T      (* null string -- preserve font info)
							(TEDIT.CARETLOOKS stream
									    (FONTCREATE
									      (FS.ItemFont item)))))
       finally (RETURN length))))

(FS.AllowedChar
  (LAMBDA (charcode)                                         (* thh: "19-Aug-85 08:29")
                                                             (* returns T if charcode can be included in format 
							     strings)
    (IGEQ charcode (CHARCODE " "))))

(FS.RealStringP
  (LAMBDA (item nullOk)                                      (* thh: "31-Jul-85 08:11")
    (AND (LISTP item)
	   (OR nullOk (NOT (EQUAL "" (FS.ItemValue item)))))))
)
(* * Now load EQUATIONFORMS)

(FILESLOAD EQUATIONFORMS)
(PUTPROPS EQUATIONS COPYRIGHT ("Xerox Corporation" 1986))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (3630 16486 (EQIO.CreateFns 3640 . 4190) (EQIO.Create 4192 . 5449) (EQIO.Imagebox 5451
 . 5835) (EQIO.Display 5837 . 7036) (EQIO.ButtonEventIn 7038 . 10131) (EQIO.Copy 10133 . 10479) (
EQIO.CopyList 10481 . 11153) (EQIO.Get 11155 . 11425) (EQIO.Put 11427 . 11717) (EQIO.WhenDeleted 11719
 . 12241) (EQIO.SelectRegion 12243 . 13059) (EQIO.Selection 13061 . 14337) (EQIO.DefaultSelectFn 14339
 . 15554) (EQIO.MakeSelectionMenu 15556 . 16484)) (16554 22480 (EQIO.EqnType 16564 . 16832) (
EQIO.EqnDataList 16834 . 17125) (EQIO.SetDataList 17127 . 17568) (EQIO.EqnData 17570 . 17745) (
EQIO.EqnProperty 17747 . 18559) (EQIO.AllProps 18561 . 19078) (EQIO.Specify 19080 . 19606) (
EQIO.GetInitialProps 19608 . 20788) (EQIO.NumPieces 20790 . 21918) (EQIO.NewStructure 21920 . 22478)) 
(22541 27075 (EQIO.AddType 22551 . 23101) (EQIO.GetInfo 23103 . 23399) (EQIO.SetInfo 23401 . 24060) (
EQIO.TypeProp 24062 . 25010) (EQIO.ResetTypeProps 25012 . 25400) (EQIO.IsDefined 25402 . 25739) (
EQIO.GetBox 25741 . 25962) (EQIO.GetDataSpec 25964 . 26242) (EQIO.GetDataSpecList 26244 . 26390) (
EQIO.GetDataPosition 26392 . 26533) (EQIO.GetDataSelectRegion 26535 . 26680) (EQIO.MakeSpec 26682 . 
26919) (EQIO.MakeDataSpec 26921 . 27073)) (28369 42800 (EQN.AbortEdit 28379 . 28818) (EQN.StopEdit 
28820 . 29243) (EQN.ContinueEdit 29245 . 32291) (EQN.FinishEdit 32293 . 32947) (EQN.MakeEditWindow 
32949 . 34358) (EQN.SetUpEdit 34360 . 35298) (EQN.StartEdit 35300 . 38021) (EQN.StartNextEdit 38023 . 
38652) (EQN.UpdateEdit 38654 . 39964) (EQN.DefaultData 39966 . 41923) (EQN.TypeMenu 41925 . 42798)) (
42861 50058 (EQN.Equation 42871 . 44205) (EQN.NextPiece 44207 . 44768) (EQN.FinishEqn 44770 . 45215) (
EQN.NoUpdateAbort 45217 . 45576) (EQN.PreventUpdate 45578 . 45962) (EQN.CharFn 45964 . 47595) (
EQN.TEditSpecialChar 47597 . 48445) (EQN.SnuggleWindows 48447 . 48987) (EQN.SnuggleMainWindow 48989 . 
50056)) (50106 51836 (EQN.EquationFontNumber 50116 . 50943) (EQN.EquationFont 50945 . 51272) (
EQN.GetEqnFont 51274 . 51452) (EQN.MakeFS 51454 . 51834)) (51859 54644 (EQN.AdjustWindow 51869 . 53539
) (EQN.CheckWindowSize 53541 . 54642)) (54645 60015 (EQN.SubEditorP 54655 . 54940) (EQN.WindowFromText
 54942 . 55603) (EQN.EditWindow 55605 . 56419) (EQN.ResultWindow 56421 . 56919) (EQN.ResultObj 56921
 . 57403) (EQN.PieceNumber 57405 . 57902) (EQN.ContinueFlg 57904 . 58481) (EQN.ValidEditWindow 58483
 . 58944) (EQN.ObjEditWindow 58946 . 60013)) (60016 60833 (EQN.Make 60026 . 60831)) (61802 72103 (
FS.Box 61812 . 63369) (FS.Copy 63371 . 63915) (FS.Display 63917 . 65684) (FS.Get 65686 . 66148) (
FS.Put 66150 . 66615) (FS.ItemFont 66617 . 66912) (FS.ItemValue 66914 . 67252) (FS.MakeItem 67254 . 
67505) (FS.Extract 67507 . 70158) (FS.ExtractFont 70160 . 70717) (FS.Insert 70719 . 71586) (
FS.AllowedChar 71588 . 71886) (FS.RealStringP 71888 . 72101)))))
STOP